halton-iot-mcp
Version:
MCP Server for Halton IoT Data API
303 lines • 9.68 kB
JavaScript
/**
* Halton IoT MCP Server
* Model Context Protocol server for Halton IoT Data API
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { HaltonApiClient } from "./api-client.js";
// Get API token from environment variable
const API_TOKEN = process.env.HALTON_API_TOKEN;
if (!API_TOKEN) {
console.error("Error: HALTON_API_TOKEN environment variable is required");
process.exit(1);
}
const apiClient = new HaltonApiClient(API_TOKEN);
// Create server instance
const server = new McpServer({
name: "halton-iot",
version: "1.0.0",
});
// ============ System Tools ============
server.tool("get_all_systems", "Get basic information about all accessible IoT systems", {}, async () => {
try {
const result = await apiClient.getAllSystems();
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
server.tool("get_systems", "Get basic information about specified IoT systems", {
systems: z
.array(z.string())
.describe("Array of system IDs to retrieve (e.g., ['FI02728', 'US02145'])"),
}, async ({ systems }) => {
try {
const result = await apiClient.getSystems(systems);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
// ============ Variable Tools ============
server.tool("get_system_variables", "Retrieve a list of variables (sensors/data points) for specified systems", {
systems: z
.array(z.string())
.describe("Array of system IDs to get variables for"),
}, async ({ systems }) => {
try {
const result = await apiClient.getSystemVariables(systems);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
server.tool("search_variables", "Search for variables across systems using search words", {
systems: z.array(z.string()).describe("Array of system IDs to search in"),
searchWords: z
.array(z.string())
.describe("Array of search terms (e.g., ['Airflow', 'Temperature'])"),
pageNumber: z.number().optional().default(1).describe("Page number for pagination"),
pageSize: z.number().optional().default(100).describe("Number of results per page"),
includeLastEventValues: z
.boolean()
.optional()
.default(false)
.describe("Include the last recorded value for each variable"),
}, async ({ systems, searchWords, pageNumber, pageSize, includeLastEventValues }) => {
try {
const result = await apiClient.searchSystemVariables({
systems,
searchWords,
pagination: {
pageNumber: pageNumber ?? 1,
pageSize: pageSize ?? 100,
orderByType: "Ascending",
},
}, includeLastEventValues);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
// ============ Time Series Data Tools ============
server.tool("get_aggregate_data", "Get aggregated time series data for a single variable (includes min, max, avg, median, etc.). Default interval is hourly.", {
variable: z.string().describe("The variable name to get data for"),
systems: z.array(z.string()).describe("Array of system IDs"),
fromDate: z.string().describe("Start date/time in ISO 8601 format"),
toDate: z.string().describe("End date/time in ISO 8601 format"),
intervalSeconds: z
.number()
.optional()
.default(3600)
.describe("Aggregation interval in seconds (default: 3600 = hourly)"),
}, async ({ variable, systems, fromDate, toDate, intervalSeconds }) => {
try {
const result = await apiClient.getAggregateSeries(variable, {
systems,
dateTimeRange: {
from: fromDate,
to: toDate,
},
intervalSeconds: intervalSeconds ?? 3600,
});
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
server.tool("get_aggregate_data_multiple", "Get aggregated time series data for multiple variables. Default interval is hourly.", {
variables: z
.array(z.string())
.describe("Array of variable names to get data for"),
systems: z.array(z.string()).describe("Array of system IDs"),
fromDate: z.string().describe("Start date/time in ISO 8601 format"),
toDate: z.string().describe("End date/time in ISO 8601 format"),
intervalSeconds: z
.number()
.optional()
.default(3600)
.describe("Aggregation interval in seconds (default: 3600 = hourly)"),
}, async ({ variables, systems, fromDate, toDate, intervalSeconds }) => {
try {
const result = await apiClient.getAggregateSeriesMultiple({
variables,
systems,
dateTimeRange: {
from: fromDate,
to: toDate,
},
intervalSeconds: intervalSeconds ?? 3600,
});
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
server.tool("get_last_value", "Get the most recent value for a single variable", {
variable: z.string().describe("The variable name to get the last value for"),
systems: z.array(z.string()).describe("Array of system IDs"),
}, async ({ variable, systems }) => {
try {
const result = await apiClient.getLastEventValue(variable, systems);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
server.tool("get_last_values_multiple", "Get the most recent values for multiple variables", {
variables: z
.array(z.string())
.describe("Array of variable names to get last values for"),
systems: z.array(z.string()).describe("Array of system IDs"),
}, async ({ variables, systems }) => {
try {
const result = await apiClient.getLastEventValueMultiple({
variables,
systems,
});
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
// ============ Main ============
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Halton IoT MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
//# sourceMappingURL=index.js.map