Skip to content

Commit bdb2f2c

Browse files
Revert change to index.ts that broke tool descriptions
1 parent b90319b commit bdb2f2c

File tree

2 files changed

+229
-99
lines changed

2 files changed

+229
-99
lines changed

index.ts

Lines changed: 228 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,249 @@
11
#!/usr/bin/env node
22

3-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
43
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5-
import { z } from "zod";
6-
4+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
75
import { TaskManagerServer } from "./src/server/TaskManagerServer.js";
86
import { ALL_TOOLS } from "./src/types/tools.js";
7+
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
98

10-
// Initialize the server
11-
const server = new McpServer({
9+
const server = new Server({
1210
name: "task-manager-server",
13-
version: "1.0.0"
11+
version: "1.0.4"
1412
});
1513

1614
const taskManager = new TaskManagerServer();
1715

18-
// Register all tools with their predefined schemas and descriptions
19-
for (const tool of ALL_TOOLS) {
20-
// Convert JSON schema properties to Zod schema
21-
const zodSchema: { [key: string]: z.ZodType<any> } = {};
22-
23-
if (tool.inputSchema.properties) {
24-
for (const [key, prop] of Object.entries(tool.inputSchema.properties)) {
25-
if (typeof prop === 'object' && prop !== null) {
26-
const schemaProp = prop as { type: string; enum?: string[]; description?: string };
27-
if (schemaProp.type === "string") {
28-
zodSchema[key] = schemaProp.enum
29-
? z.enum(schemaProp.enum as [string, ...string[]])
30-
: z.string();
31-
if (!Array.isArray(tool.inputSchema.required) || !tool.inputSchema.required.includes(key)) {
32-
zodSchema[key] = zodSchema[key].optional();
33-
}
16+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
17+
tools: ALL_TOOLS,
18+
}));
19+
20+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
21+
try {
22+
const { name } = request.params;
23+
const args = request.params.arguments || {};
24+
25+
// For validation, ensure args is an object when expected
26+
if (name !== "list_projects" && name !== "list_tasks" && Object.keys(args).length === 0) {
27+
throw new Error("Invalid arguments: expected object with parameters");
28+
}
29+
30+
switch (name) {
31+
// Project tools
32+
case "list_projects": {
33+
const result = await taskManager.listProjects();
34+
return {
35+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
36+
};
37+
}
38+
39+
case "read_project": {
40+
const projectId = String(args.projectId);
41+
if (!projectId) {
42+
throw new Error("Missing required parameter: projectId");
3443
}
44+
const result = await taskManager.getNextTask(projectId);
45+
return {
46+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
47+
};
3548
}
36-
}
37-
}
3849

39-
server.tool(
40-
tool.name,
41-
zodSchema,
42-
async (params: any) => {
43-
let result;
44-
switch (tool.name) {
45-
case "list_projects":
46-
result = await taskManager.listProjects(params.state);
47-
break;
48-
case "read_project":
49-
result = await taskManager.openTaskDetails(params.projectId);
50-
break;
51-
case "create_project":
52-
result = await taskManager.createProject(params.initialPrompt, params.tasks, params.projectPlan);
53-
break;
54-
case "delete_project":
55-
const projectIndex = taskManager["data"].projects.findIndex(
56-
(p) => p.projectId === params.projectId
57-
);
58-
if (projectIndex === -1) {
59-
return { content: [{ type: "text", text: JSON.stringify({ error: "Project not found" }) }] };
60-
}
61-
taskManager["data"].projects.splice(projectIndex, 1);
62-
await taskManager["saveTasks"]();
63-
result = { message: "Project has been deleted" };
64-
break;
65-
case "add_tasks_to_project":
66-
result = await taskManager.addTasksToProject(params.projectId, params.tasks);
67-
break;
68-
case "finalize_project":
69-
result = await taskManager.approveProjectCompletion(params.projectId);
70-
break;
71-
case "list_tasks":
72-
result = await taskManager.listTasks(params.projectId, params.state);
73-
break;
74-
case "read_task":
75-
result = await taskManager.openTaskDetails(params.taskId);
76-
break;
77-
case "create_task":
78-
result = await taskManager.addTasksToProject(params.projectId, [{
79-
title: params.title,
80-
description: params.description,
81-
toolRecommendations: params.toolRecommendations,
82-
ruleRecommendations: params.ruleRecommendations
83-
}]);
84-
break;
85-
case "update_task":
86-
if (params.status === "done") {
87-
if (!params.completedDetails) {
88-
return { content: [{ type: "text", text: JSON.stringify({ error: "completedDetails is required when setting status to 'done'" }) }] };
50+
case "create_project": {
51+
const initialPrompt = String(args.initialPrompt || "");
52+
if (!initialPrompt || !args.tasks || !Array.isArray(args.tasks)) {
53+
throw new Error("Missing required parameters: initialPrompt and/or tasks");
54+
}
55+
const projectPlan = args.projectPlan ? String(args.projectPlan) : undefined;
56+
57+
const result = await taskManager.createProject(
58+
initialPrompt,
59+
args.tasks,
60+
projectPlan
61+
);
62+
return {
63+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
64+
};
65+
}
66+
67+
case "delete_project": {
68+
const projectId = String(args.projectId);
69+
if (!projectId) {
70+
throw new Error("Missing required parameter: projectId");
71+
}
72+
// Use the private data and saveTasks via indexing since there's no explicit delete method
73+
const projectIndex = taskManager["data"].projects.findIndex((p) => p.projectId === projectId);
74+
if (projectIndex === -1) {
75+
return {
76+
content: [{ type: "text", text: JSON.stringify({ status: "error", message: "Project not found" }, null, 2) }],
77+
};
78+
}
79+
80+
taskManager["data"].projects.splice(projectIndex, 1);
81+
await taskManager["saveTasks"]();
82+
return {
83+
content: [{ type: "text", text: JSON.stringify({
84+
status: "project_deleted",
85+
message: `Project ${projectId} has been deleted.`
86+
}, null, 2) }],
87+
};
88+
}
89+
90+
case "add_tasks_to_project": {
91+
const projectId = String(args.projectId);
92+
if (!projectId || !args.tasks || !Array.isArray(args.tasks)) {
93+
throw new Error("Missing required parameters: projectId and/or tasks");
94+
}
95+
const result = await taskManager.addTasksToProject(projectId, args.tasks);
96+
return {
97+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
98+
};
99+
}
100+
101+
case "finalize_project": {
102+
const projectId = String(args.projectId);
103+
if (!projectId) {
104+
throw new Error("Missing required parameter: projectId");
105+
}
106+
const result = await taskManager.approveProjectCompletion(projectId);
107+
return {
108+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
109+
};
110+
}
111+
112+
// Task tools
113+
case "list_tasks": {
114+
// No explicit list tasks method, so return a message
115+
return {
116+
content: [{ type: "text", text: JSON.stringify({
117+
status: "error",
118+
message: "list_tasks functionality to be implemented in future version"
119+
}, null, 2) }],
120+
};
121+
}
122+
123+
case "read_task": {
124+
const taskId = String(args.taskId);
125+
if (!taskId) {
126+
throw new Error("Missing required parameter: taskId");
127+
}
128+
const result = await taskManager.openTaskDetails(taskId);
129+
return {
130+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
131+
};
132+
}
133+
134+
case "create_task": {
135+
const projectId = String(args.projectId);
136+
const title = String(args.title || "");
137+
const description = String(args.description || "");
138+
139+
if (!projectId || !title || !description) {
140+
throw new Error("Missing required parameters: projectId, title, and/or description");
141+
}
142+
143+
const result = await taskManager.addTasksToProject(projectId, [{
144+
title,
145+
description
146+
}]);
147+
return {
148+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
149+
};
150+
}
151+
152+
case "update_task": {
153+
const projectId = String(args.projectId);
154+
const taskId = String(args.taskId);
155+
156+
if (!projectId || !taskId) {
157+
throw new Error("Missing required parameters: projectId and/or taskId");
158+
}
159+
160+
const updates: { title?: string; description?: string } = {};
161+
if (args.title !== undefined) updates.title = String(args.title);
162+
if (args.description !== undefined) updates.description = String(args.description);
163+
164+
const result = await taskManager.updateTask(projectId, taskId, updates);
165+
166+
// Handle status change separately if needed
167+
if (args.status) {
168+
const status = args.status as "not started" | "in progress" | "done";
169+
const proj = taskManager["data"].projects.find(p => p.projectId === projectId);
170+
if (proj) {
171+
const task = proj.tasks.find(t => t.id === taskId);
172+
if (task) {
173+
if (status === "done") {
174+
if (!args.completedDetails) {
175+
return {
176+
content: [{ type: "text", text: JSON.stringify({
177+
status: "error",
178+
message: "completedDetails is required when setting status to 'done'"
179+
}, null, 2) }],
180+
};
181+
}
182+
183+
// Use markTaskDone for proper transition to done status
184+
await taskManager.markTaskDone(projectId, taskId, String(args.completedDetails));
185+
} else {
186+
// For other status changes
187+
task.status = status;
188+
await taskManager["saveTasks"]();
189+
}
89190
}
90-
await taskManager.markTaskDone(params.projectId, params.taskId, params.completedDetails);
91191
}
92-
const updates: any = {};
93-
if (params.title) updates.title = params.title;
94-
if (params.description) updates.description = params.description;
95-
if (params.toolRecommendations) updates.toolRecommendations = params.toolRecommendations;
96-
if (params.ruleRecommendations) updates.ruleRecommendations = params.ruleRecommendations;
97-
if (Object.keys(updates).length > 0) {
98-
result = await taskManager.updateTask(params.projectId, params.taskId, updates);
99-
} else {
100-
result = { message: "Task updated" };
101-
}
102-
break;
103-
case "delete_task":
104-
result = await taskManager.deleteTask(params.projectId, params.taskId);
105-
break;
106-
case "approve_task":
107-
result = await taskManager.approveTaskCompletion(params.projectId, params.taskId);
108-
break;
109-
case "get_next_task":
110-
result = await taskManager.getNextTask(params.projectId);
111-
break;
192+
}
193+
194+
return {
195+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
196+
};
112197
}
113-
return { content: [{ type: "text", text: JSON.stringify(result) }] };
198+
199+
case "delete_task": {
200+
const projectId = String(args.projectId);
201+
const taskId = String(args.taskId);
202+
203+
if (!projectId || !taskId) {
204+
throw new Error("Missing required parameters: projectId and/or taskId");
205+
}
206+
const result = await taskManager.deleteTask(projectId, taskId);
207+
return {
208+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
209+
};
210+
}
211+
212+
case "approve_task": {
213+
const projectId = String(args.projectId);
214+
const taskId = String(args.taskId);
215+
216+
if (!projectId || !taskId) {
217+
throw new Error("Missing required parameters: projectId and/or taskId");
218+
}
219+
const result = await taskManager.approveTaskCompletion(projectId, taskId);
220+
return {
221+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
222+
};
223+
}
224+
225+
case "get_next_task": {
226+
const projectId = String(args.projectId);
227+
if (!projectId) {
228+
throw new Error("Missing required parameter: projectId");
229+
}
230+
const result = await taskManager.getNextTask(projectId);
231+
return {
232+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
233+
};
234+
}
235+
236+
default:
237+
throw new Error(`Unknown tool: ${name}`);
114238
}
115-
);
116-
}
239+
} catch (error) {
240+
const errorMessage = error instanceof Error ? error.message : String(error);
241+
return {
242+
content: [{ type: "text", text: `Error: ${errorMessage}` }],
243+
isError: true,
244+
};
245+
}
246+
});
117247

118248
// Start the server
119249
const transport = new StdioServerTransport();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "taskqueue-mcp",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"description": "Task Queue MCP Server",
55
"author": "Christopher C. Smith ([email protected])",
66
"main": "dist/index.js",

0 commit comments

Comments
 (0)