NodeMCU MCP Service
by amanasmuei
Verified
/**
* NodeMCU MCP Service using the official MCP TypeScript SDK
* This implementation follows the MCP specification and best practices
*/
// Import required dependencies
const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js');
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
const { z } = require('zod');
const dotenv = require('dotenv');
const deviceManager = require('./services/DeviceManager');
// Load environment variables
dotenv.config();
// Create the MCP server instance
const server = new McpServer({
name: "NodeMCU Manager",
version: "1.0.0"
});
// =========== Tool Implementations ===========
// Tool: List all registered devices
server.tool(
"list-devices",
{}, // No parameters required
async () => {
try {
const devices = deviceManager.getAllDevices();
return {
content: [{
type: "text",
text: JSON.stringify({
devices: devices.map(device => ({
id: device.id,
name: device.name,
status: device.status,
lastSeen: device.lastSeen
})),
count: devices.length
}, null, 2)
}]
};
} catch (error) {
console.error('Error listing devices:', error);
throw new Error(`Failed to list devices: ${error.message}`);
}
}
);
// Tool: Get detailed information about a specific device
server.tool(
"get-device",
{
deviceId: z.string().describe("The ID of the device to get information about")
},
async ({ deviceId }) => {
try {
if (!deviceId) {
throw new Error('Device ID is required');
}
const device = deviceManager.getDevice(deviceId);
if (!device) {
throw new Error(`Device not found: ${deviceId}`);
}
return {
content: [{
type: "text",
text: JSON.stringify(device, null, 2)
}]
};
} catch (error) {
console.error('Error getting device:', error);
throw new Error(`Failed to get device: ${error.message}`);
}
}
);
// Tool: Send a command to a device
server.tool(
"send-command",
{
deviceId: z.string().describe("The ID of the device to send the command to"),
command: z.string().describe("The command to send (restart, update, status, etc.)"),
params: z.record(z.any()).optional().describe("Optional parameters for the command")
},
async ({ deviceId, command, params = {} }) => {
try {
if (!deviceId) {
throw new Error('Device ID is required');
}
if (!command) {
throw new Error('Command is required');
}
const result = await deviceManager.sendCommand(deviceId, command, params);
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
deviceId,
command,
result
}, null, 2)
}]
};
} catch (error) {
console.error('Error sending command:', error);
throw new Error(`Failed to send command: ${error.message}`);
}
}
);
// Tool: Update device configuration
server.tool(
"update-config",
{
deviceId: z.string().describe("The ID of the device to update configuration for"),
config: z.record(z.any()).describe("Configuration parameters to update")
},
async ({ deviceId, config }) => {
try {
if (!deviceId) {
throw new Error('Device ID is required');
}
if (!config || Object.keys(config).length === 0) {
throw new Error('Configuration is required');
}
const result = await deviceManager.updateDeviceConfig(deviceId, config);
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
deviceId,
updatedConfig: result
}, null, 2)
}]
};
} catch (error) {
console.error('Error updating config:', error);
throw new Error(`Failed to update configuration: ${error.message}`);
}
}
);
// =========== Server Startup ===========
// Start the MCP server
async function startServer() {
try {
console.error("Starting NodeMCU MCP server...");
// Initialize the stdio transport
const transport = new StdioServerTransport();
// Connect the server to the transport
await server.connect(transport);
console.error("NodeMCU MCP server connected and ready");
} catch (error) {
console.error("Failed to start MCP server:", error);
process.exit(1);
}
}
// Start the server
startServer();