#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Get API key and device ID from command line arguments
const args = process.argv.slice(2);
const apiKeyIndex = args.indexOf("--api-key");
const deviceIdIndex = args.indexOf("--device-id");
const API_KEY =
apiKeyIndex !== -1 ? args[apiKeyIndex + 1] : process.env.DOT_API_KEY;
const DEVICE_ID =
deviceIdIndex !== -1 ? args[deviceIdIndex + 1] : process.env.DOT_DEVICE_ID;
if (!API_KEY) {
console.error(
"Error: API key is required. Use --api-key <key> or set DOT_API_KEY environment variable."
);
process.exit(1);
}
if (!DEVICE_ID) {
console.error(
"Error: Device ID is required. Use --device-id <id> or set DOT_DEVICE_ID environment variable."
);
process.exit(1);
}
const DOT_API_URL = "https://dot.mindreset.tech/api/open/text";
interface DotApiResponse {
code: number;
message: string;
result: {
message: string;
};
}
async function sendTextToDot(params: {
title?: string;
message?: string;
signature?: string;
icon?: string;
link?: string;
refreshNow?: boolean;
}): Promise<DotApiResponse> {
const response = await fetch(DOT_API_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
deviceId: DEVICE_ID,
refreshNow: params.refreshNow ?? true,
...params,
}),
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
}
return response.json() as Promise<DotApiResponse>;
}
// Create MCP server
const server = new McpServer({
name: "dot-mcp",
version: "1.0.0",
});
// Register the send_text tool
server.registerTool(
"send_text",
{
title: "Send Text to Dot Device",
description: `Send text content to a Dot device (an e-ink display device). The text will be displayed on the e-ink screen.
You should PROACTIVELY call this tool to notify the user when:
- You have completed a task (e.g., finished writing code, fixed a bug, completed a refactor)
- You encounter an important issue that needs user attention
- You want to remind the user about something important
- A long-running task has finished
IMPORTANT: When you PROACTIVELY send a notification (not requested by user), you MUST include your name/identity in the signature field.
NOTE: If the request fails, retry once as it may be a temporary API issue.
Example: After completing a coding task, call this tool with title "Task Completed", message "I've finished implementing the feature you requested. Please review the changes.", and signature with your name (if proactively notifying) to notify the user on their Dot device.`,
inputSchema: {
title: z
.string()
.optional()
.describe(
"Text title displayed on the screen (max 10 Chinese characters display length)"
),
message: z
.string()
.optional()
.describe(
"Text content displayed on the screen (max 40 Chinese characters display length)"
),
signature: z
.string()
.optional()
.describe("Text signature displayed on the screen"),
icon: z
.string()
.optional()
.describe(
"Base64 encoded PNG icon data (40x40px), displayed in the bottom left corner"
),
link: z
.string()
.optional()
.describe(
"HTTP/HTTPS link or Scheme URL for tap-to-open functionality"
),
refreshNow: z
.boolean()
.optional()
.describe("Whether to display content immediately (default: true)")
.default(true),
},
},
async (params) => {
const result = await sendTextToDot(params);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(result),
},
],
};
}
);
// Start the server with stdio transport
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch((error) => {
console.error("Failed to start MCP server:", error);
process.exit(1);
});