godspeed-mcp
by AliNagy
Verified
- godspeed-mcp
- src
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { GodspeedAPI } from "./godspeed.js";
// Parse command line arguments
let tokenArg: string | undefined;
let emptyListIdArg: string | undefined;
for (let i = 2; i < process.argv.length; i++) {
if (process.argv[i] === '--token' || process.argv[i] === '-t') {
tokenArg = process.argv[i + 1];
i++;
} else if (process.argv[i].startsWith('--token=')) {
tokenArg = process.argv[i].substring(8);
} else if (process.argv[i] === '--empty-list-id' || process.argv[i] === '-e') {
emptyListIdArg = process.argv[i + 1];
i++;
} else if (process.argv[i].startsWith('--empty-list-id=')) {
emptyListIdArg = process.argv[i].substring(15);
}
}
// Get token and empty list ID from environment variables or command line arguments
const token = tokenArg || process.env.GODSPEED_TOKEN;
const emptyListId = emptyListIdArg || process.env.GODSPEED_EMPTY_LIST_ID;
if (!token) {
console.error('Error: GODSPEED_TOKEN environment variable or --token argument is required');
console.error('Usage: godspeed-mcp --token=YOUR_TOKEN or -t YOUR_TOKEN');
process.exit(1);
}
const server = new McpServer({
name: "godspeed-mcp",
version: "1.0.0",
});
// Initialize Godspeed API client
const godspeedApi = new GodspeedAPI();
godspeedApi.setAuthToken(token);
// Add tools for Godspeed API operations
server.tool(
"listTasks",
{
status: z.enum(["incomplete", "complete"]).optional(),
list_id: z.string().optional(),
updated_before: z.string().optional(),
updated_after: z.string().optional()
},
async (params) => {
try {
const result = await godspeedApi.listTasks(params);
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)}` }]
};
}
}
);
server.tool(
"getTask",
{
id: z.string()
},
async ({ id }) => {
try {
const result = await godspeedApi.getTask(id);
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)}` }]
};
}
}
);
server.tool(
"createTask",
{
title: z.string(),
list_id: z.string().optional(),
location: z.enum(["start", "end"]).optional(),
notes: z.string().optional(),
due_at: z.date().optional(),
timeless_due_at: z.string().optional(),
starts_at: z.date().optional(),
timeless_starts_at: z.string().optional(),
duration_minutes: z.number().int().nonnegative().optional(),
label_names: z.array(z.string()).optional(),
label_ids: z.array(z.string()).optional(),
metadata: z.record(z.any()).optional()
},
async (params) => {
try {
const result = await godspeedApi.createTask(params);
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)}` }]
};
}
}
);
server.tool(
"updateTask",
{
id: z.string(),
title: z.string().optional(),
notes: z.string().optional(),
due_at: z.date().optional(),
timeless_due_at: z.string().optional(),
snoozed_until: z.date().optional(),
timeless_snoozed_until: z.string().optional(),
starts_at: z.date().optional(),
timeless_starts_at: z.string().optional(),
duration_minutes: z.number().int().nonnegative().optional(),
is_complete: z.boolean().optional(),
is_cleared: z.boolean().optional(),
add_label_names: z.array(z.string()).optional(),
add_label_ids: z.array(z.string()).optional(),
remove_label_names: z.array(z.string()).optional(),
remove_label_ids: z.array(z.string()).optional(),
metadata: z.record(z.any()).optional()
},
async (params) => {
try {
const result = await godspeedApi.updateTask(params);
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)}` }]
};
}
}
);
server.tool(
"deleteTask",
{
id: z.string()
},
async ({ id }) => {
try {
const result = await godspeedApi.deleteTask(id);
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)}` }]
};
}
}
);
server.tool(
"completeTask",
{
id: z.string()
},
async ({ id }) => {
try {
const result = await godspeedApi.completeTask(id);
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)}` }]
};
}
}
);
server.tool(
"uncompleteTask",
{
id: z.string()
},
async ({ id }) => {
try {
const result = await godspeedApi.uncompleteTask(id);
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)}` }]
};
}
}
);
server.tool(
"getTaskLists",
{
random_string: z.string()
},
async () => {
try {
const result = await godspeedApi.getTaskLists();
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)}` }]
};
}
}
);
server.tool(
"duplicateList",
{
list_id: z.string(),
name: z.string().optional()
},
async (params) => {
try {
const { list_id, name } = params;
const result = await godspeedApi.duplicateList(list_id, name ? { name } : undefined);
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)}` }]
};
}
}
);
server.tool(
"bulkCreateTask",
{
tasks: z.array(z.object({
title: z.string(),
list_id: z.string().optional(),
location: z.enum(["start", "end"]).optional(),
notes: z.string().optional(),
due_at: z.date().optional(),
timeless_due_at: z.string().optional(),
starts_at: z.date().optional(),
timeless_starts_at: z.string().optional(),
duration_minutes: z.number().int().nonnegative().optional(),
label_names: z.array(z.string()).optional(),
label_ids: z.array(z.string()).optional(),
metadata: z.record(z.any()).optional()
})).max(60)
},
async ({ tasks }) => {
try {
const results = await Promise.all(
tasks.map(taskParams => godspeedApi.createTask(taskParams))
);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
};
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }]
};
}
}
);
server.tool(
"createTaskList",
{
name: z.string(),
empty_list_id: emptyListId ? z.string().default(emptyListId) : z.string()
},
async ({ name, empty_list_id }) => {
try {
const result = await godspeedApi.duplicateList(empty_list_id, { name });
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)}` }]
};
}
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);