cc-claw 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/mcp-server.js +582 -306
- package/dist/cli.js +293 -100
- package/package.json +1 -1
|
@@ -46,347 +46,623 @@ async function callApi(path, body) {
|
|
|
46
46
|
function sleep(ms) {
|
|
47
47
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
48
|
}
|
|
49
|
+
function ok(text) {
|
|
50
|
+
return { content: [{ type: "text", text }] };
|
|
51
|
+
}
|
|
52
|
+
function fail(msg) {
|
|
53
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
54
|
+
}
|
|
49
55
|
var server = new McpServer({
|
|
50
56
|
name: "cc-claw-orchestrator",
|
|
51
|
-
version: "
|
|
57
|
+
version: "2.0.0"
|
|
52
58
|
});
|
|
53
|
-
if (!IS_SUB_AGENT) {
|
|
54
|
-
server.tool(
|
|
55
|
-
"spawn_agent",
|
|
56
|
-
`Spawn a sub-agent using a specific CLI runner to execute a task.
|
|
57
|
-
|
|
58
|
-
CRITICAL \u2014 Path verification:
|
|
59
|
-
Before calling this tool with a cwd, you MUST verify the path exists using your file system tools (Glob, Read, ls, etc.).
|
|
60
|
-
User-provided paths are often approximate (wrong name, missing suffix, typo). Always confirm the exact path yourself.
|
|
61
|
-
A non-existent cwd will cause the agent to fail immediately. Never pass an unverified path.
|
|
62
|
-
|
|
63
|
-
Typical workflow:
|
|
64
|
-
1. User says "scan the foo-bar folder under dev_projects"
|
|
65
|
-
2. You run: ls /Users/.../dev_projects/ (or Glob) to find the actual folder name
|
|
66
|
-
3. You confirm the exact path exists (e.g., it might be foo-bars, foobar, foo_bar, etc.)
|
|
67
|
-
4. Only then call spawn_agent with the verified cwd`,
|
|
68
|
-
{
|
|
69
|
-
runner: z.string().describe("CLI runner ID (e.g., 'claude', 'gemini', 'codex', 'cursor', 'opencode')"),
|
|
70
|
-
task: z.string().describe("Task description for the sub-agent"),
|
|
71
|
-
name: z.string().optional().describe("Human-readable agent name (e.g., 'security-reviewer', 'linkedin-writer')"),
|
|
72
|
-
description: z.string().optional().describe("Short description of what this agent does"),
|
|
73
|
-
model: z.string().optional().describe("Model override for the sub-agent"),
|
|
74
|
-
skills: z.array(z.string()).optional().describe("Skills to inject into the sub-agent"),
|
|
75
|
-
permMode: z.string().optional().describe("Permission mode: yolo, safe, plan (defaults to chat's mode)"),
|
|
76
|
-
role: z.string().optional().describe("Agent role. Presets: worker, reviewer, planner, researcher, writer, analyst, debugger, critic, synthesizer. Custom roles accepted as labels."),
|
|
77
|
-
persona: z.string().optional().describe("Custom system prompt for the agent. Replaces the role's default prompt while preserving orchestrator tools and task."),
|
|
78
|
-
allowedTools: z.array(z.string()).optional().describe("Restrict agent to specific tools (Claude-only). E.g., ['Read', 'Grep', 'Glob']"),
|
|
79
|
-
maxRuntimeMs: z.number().optional().describe("Max runtime in ms before timeout (default: 600000 = 10 min)"),
|
|
80
|
-
summarizeResult: z.boolean().optional().describe("Summarize agent output before posting to inbox"),
|
|
81
|
-
mcps: z.array(z.string()).optional().describe("MCP servers to inject into the sub-agent"),
|
|
82
|
-
cwd: z.string().optional().describe("Working directory for the sub-agent. MUST be a verified, existing absolute path \u2014 check it before calling."),
|
|
83
|
-
template: z.string().optional().describe("Name of an agent template from ~/.cc-claw/agents/ to use as defaults. Call list_templates to discover available templates. Call-time params override template defaults.")
|
|
84
|
-
},
|
|
85
|
-
async (params) => {
|
|
86
|
-
try {
|
|
87
|
-
const result = await callApi("/api/orchestrator/spawn", { chatId: CHAT_ID, ...params });
|
|
88
|
-
const status = result.queued ? "queued (at capacity, will start when a slot opens)" : "spawning";
|
|
89
|
-
return {
|
|
90
|
-
content: [{ type: "text", text: `Agent ${result.agentId} \u2014 ${status}` }]
|
|
91
|
-
};
|
|
92
|
-
} catch (err) {
|
|
93
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
94
|
-
return {
|
|
95
|
-
content: [{ type: "text", text: `spawn_agent failed: ${msg}` }],
|
|
96
|
-
isError: true
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
server.tool(
|
|
102
|
-
"list_templates",
|
|
103
|
-
"List available agent templates from ~/.cc-claw/agents/. Use a template name with spawn_agent's template parameter to spawn a pre-configured agent.",
|
|
104
|
-
{},
|
|
105
|
-
async () => {
|
|
106
|
-
const templates = await callApi("/api/orchestrator/list-templates");
|
|
107
|
-
if (!templates.length) {
|
|
108
|
-
return { content: [{ type: "text", text: "No agent templates found. Create .md files in ~/.cc-claw/agents/ with YAML frontmatter." }] };
|
|
109
|
-
}
|
|
110
|
-
const lines = templates.map(
|
|
111
|
-
(t) => `\u2022 **${t.name}**${t.description ? ` \u2014 ${t.description}` : ""}${t.runner ? ` (runner: ${t.runner})` : ""}${t.model ? ` [${t.model}]` : ""}`
|
|
112
|
-
);
|
|
113
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
114
|
-
}
|
|
115
|
-
);
|
|
116
|
-
server.tool(
|
|
117
|
-
"cancel_agent",
|
|
118
|
-
"Cancel a specific sub-agent",
|
|
119
|
-
{
|
|
120
|
-
agentId: z.string().describe("The agent ID to cancel"),
|
|
121
|
-
reason: z.string().optional().describe("Reason for cancellation")
|
|
122
|
-
},
|
|
123
|
-
async ({ agentId, reason }) => {
|
|
124
|
-
const result = await callApi("/api/orchestrator/cancel", { agentId, reason });
|
|
125
|
-
return {
|
|
126
|
-
content: [{ type: "text", text: result.success ? `Agent ${agentId} cancelled.` : `Agent ${agentId} not found or already completed.` }]
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
);
|
|
130
|
-
server.tool(
|
|
131
|
-
"create_task",
|
|
132
|
-
"Add a task to the shared task list",
|
|
133
|
-
{
|
|
134
|
-
subject: z.string().describe("Short imperative title for the task"),
|
|
135
|
-
description: z.string().describe("Detailed task requirements"),
|
|
136
|
-
assignee: z.string().optional().describe("Agent ID to assign the task to"),
|
|
137
|
-
blockedBy: z.array(z.number()).optional().describe("Task IDs that must complete before this task can start")
|
|
138
|
-
},
|
|
139
|
-
async (params) => {
|
|
140
|
-
const result = await callApi("/api/orchestrator/create-task", {
|
|
141
|
-
chatId: CHAT_ID,
|
|
142
|
-
task: { ...params, createdBy: AGENT_ID }
|
|
143
|
-
});
|
|
144
|
-
return {
|
|
145
|
-
content: [{ type: "text", text: `Task #${result.taskId} created.` }]
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
59
|
server.tool(
|
|
151
|
-
"
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const label = a.name ?? a.id.slice(0, 8);
|
|
161
|
-
return `\u2022 ${label} (${a.runnerId}) \u2014 ${a.status}${a.task ? ` \u2192 ${a.task.slice(0, 80)}` : ""}`;
|
|
162
|
-
});
|
|
163
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
164
|
-
}
|
|
165
|
-
);
|
|
166
|
-
server.tool(
|
|
167
|
-
"check_agent",
|
|
168
|
-
"Get detailed status of a specific agent",
|
|
60
|
+
"cc_claw_agents",
|
|
61
|
+
`Agent lifecycle management. Actions:
|
|
62
|
+
\u2022 spawn \u2014 Spawn a sub-agent (main agent only). CRITICAL: verify cwd paths exist before calling.
|
|
63
|
+
\u2022 cancel \u2014 Cancel a running agent (main agent only)
|
|
64
|
+
\u2022 list \u2014 List all active/queued agents
|
|
65
|
+
\u2022 status \u2014 Get detailed agent status (requires agentId)
|
|
66
|
+
\u2022 templates \u2014 List available agent templates from ~/.cc-claw/agents/
|
|
67
|
+
\u2022 runners \u2014 List registered CLI runners
|
|
68
|
+
\u2022 mcps \u2014 List MCP servers in registry`,
|
|
169
69
|
{
|
|
170
|
-
|
|
70
|
+
action: z.enum(["spawn", "cancel", "list", "status", "templates", "runners", "mcps"]).describe("Action to perform"),
|
|
71
|
+
// spawn params
|
|
72
|
+
runner: z.string().optional().describe("CLI runner ID (e.g., 'claude', 'gemini', 'codex')"),
|
|
73
|
+
task: z.string().optional().describe("Task description for the sub-agent"),
|
|
74
|
+
name: z.string().optional().describe("Human-readable agent name"),
|
|
75
|
+
description: z.string().optional().describe("Short description of what this agent does"),
|
|
76
|
+
model: z.string().optional().describe("Model override"),
|
|
77
|
+
skills: z.array(z.string()).optional().describe("Skills to inject"),
|
|
78
|
+
permMode: z.string().optional().describe("Permission mode: yolo, safe, plan"),
|
|
79
|
+
role: z.string().optional().describe("Agent role (worker, reviewer, planner, etc.)"),
|
|
80
|
+
persona: z.string().optional().describe("Custom system prompt"),
|
|
81
|
+
allowedTools: z.array(z.string()).optional().describe("Restrict agent to specific tools"),
|
|
82
|
+
maxRuntimeMs: z.number().optional().describe("Max runtime in ms before timeout"),
|
|
83
|
+
summarizeResult: z.boolean().optional().describe("Summarize agent output"),
|
|
84
|
+
mcps: z.array(z.string()).optional().describe("MCP servers to inject"),
|
|
85
|
+
cwd: z.string().optional().describe("Working directory (must be verified, existing absolute path)"),
|
|
86
|
+
template: z.string().optional().describe("Agent template name from ~/.cc-claw/agents/"),
|
|
87
|
+
// cancel params
|
|
88
|
+
agentId: z.string().optional().describe("Agent ID (for cancel, status)"),
|
|
89
|
+
reason: z.string().optional().describe("Reason for cancellation")
|
|
171
90
|
},
|
|
172
|
-
async (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`Agent
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
`
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
91
|
+
async (params) => {
|
|
92
|
+
try {
|
|
93
|
+
switch (params.action) {
|
|
94
|
+
case "spawn": {
|
|
95
|
+
if (IS_SUB_AGENT) return fail("spawn is only available to the main agent");
|
|
96
|
+
if (!params.runner || !params.task) return fail("spawn requires 'runner' and 'task'");
|
|
97
|
+
const { action, agentId, reason, ...spawnParams } = params;
|
|
98
|
+
const result = await callApi("/api/orchestrator/spawn", { chatId: CHAT_ID, ...spawnParams });
|
|
99
|
+
const status = result.queued ? "queued (at capacity, will start when a slot opens)" : "spawning";
|
|
100
|
+
return ok(`Agent ${result.agentId} \u2014 ${status}`);
|
|
101
|
+
}
|
|
102
|
+
case "cancel": {
|
|
103
|
+
if (IS_SUB_AGENT) return fail("cancel is only available to the main agent");
|
|
104
|
+
if (!params.agentId) return fail("cancel requires 'agentId'");
|
|
105
|
+
const result = await callApi("/api/orchestrator/cancel", { agentId: params.agentId, reason: params.reason });
|
|
106
|
+
return ok(result.success ? `Agent ${params.agentId} cancelled.` : `Agent ${params.agentId} not found or already completed.`);
|
|
107
|
+
}
|
|
108
|
+
case "list": {
|
|
109
|
+
const agents = await callApi("/api/agents");
|
|
110
|
+
if (!agents.length) return ok("No active agents.");
|
|
111
|
+
const lines = agents.map((a) => {
|
|
112
|
+
const label = a.name ?? a.id.slice(0, 8);
|
|
113
|
+
return `\u2022 ${label} (${a.runnerId}) \u2014 ${a.status}${a.task ? ` \u2192 ${a.task.slice(0, 80)}` : ""}`;
|
|
114
|
+
});
|
|
115
|
+
return ok(lines.join("\n"));
|
|
116
|
+
}
|
|
117
|
+
case "status": {
|
|
118
|
+
if (!params.agentId) return fail("status requires 'agentId'");
|
|
119
|
+
const agent = await callApi("/api/orchestrator/check-agent", { agentId: params.agentId });
|
|
120
|
+
if (!agent) return ok(`Agent ${params.agentId} not found.`);
|
|
121
|
+
return ok([
|
|
122
|
+
`Agent: ${agent.name ?? agent.id.slice(0, 8)} (${agent.runnerId})`,
|
|
123
|
+
agent.name ? `ID: ${agent.id.slice(0, 8)}` : null,
|
|
124
|
+
agent.description ? `Description: ${agent.description}` : null,
|
|
125
|
+
`Status: ${agent.status}`,
|
|
126
|
+
`Task: ${agent.task ?? "none"}`,
|
|
127
|
+
`Role: ${agent.role}`,
|
|
128
|
+
`Tokens: ${agent.tokenInput} in / ${agent.tokenOutput} out`,
|
|
129
|
+
agent.resultSummary ? `Result: ${agent.resultSummary.slice(0, 5e3)}` : null
|
|
130
|
+
].filter(Boolean).join("\n"));
|
|
131
|
+
}
|
|
132
|
+
case "templates": {
|
|
133
|
+
if (IS_SUB_AGENT) return fail("templates is only available to the main agent");
|
|
134
|
+
const templates = await callApi("/api/orchestrator/list-templates");
|
|
135
|
+
if (!templates.length) return ok("No agent templates found. Create .md files in ~/.cc-claw/agents/ with YAML frontmatter.");
|
|
136
|
+
const lines = templates.map(
|
|
137
|
+
(t) => `\u2022 **${t.name}**${t.description ? ` \u2014 ${t.description}` : ""}${t.runner ? ` (runner: ${t.runner})` : ""}${t.model ? ` [${t.model}]` : ""}`
|
|
138
|
+
);
|
|
139
|
+
return ok(lines.join("\n"));
|
|
140
|
+
}
|
|
141
|
+
case "runners": {
|
|
142
|
+
const runners = await callApi("/api/orchestrator/list-runners");
|
|
143
|
+
const lines = runners.map(
|
|
144
|
+
(r) => `\u2022 ${r.id} (${r.displayName}) \u2014 ${r.capabilities.specialties.join(", ")}`
|
|
145
|
+
);
|
|
146
|
+
return ok(lines.join("\n"));
|
|
147
|
+
}
|
|
148
|
+
case "mcps": {
|
|
149
|
+
const mcps = await callApi("/api/orchestrator/list-mcps");
|
|
150
|
+
if (!mcps.length) return ok("No MCP servers registered.");
|
|
151
|
+
const lines = mcps.map(
|
|
152
|
+
(m) => `\u2022 ${m.name} (${m.transport})${m.description ? ` \u2014 ${m.description}` : ""}${m.enabledByDefault ? " [auto]" : ""}`
|
|
153
|
+
);
|
|
154
|
+
return ok(lines.join("\n"));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
return fail(`cc_claw_agents.${params.action} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
202
159
|
}
|
|
203
|
-
const lines = tasks.map(
|
|
204
|
-
(t) => `#${t.id} [${t.status}] ${t.subject}${t.assignee ? ` (\u2192 ${t.assignee.slice(0, 8)})` : ""}`
|
|
205
|
-
);
|
|
206
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
207
160
|
}
|
|
208
161
|
);
|
|
209
162
|
server.tool(
|
|
210
|
-
"
|
|
211
|
-
|
|
163
|
+
"cc_claw_tasks",
|
|
164
|
+
`Shared task board management. Actions:
|
|
165
|
+
\u2022 create \u2014 Add a task (main agent only)
|
|
166
|
+
\u2022 list \u2014 View the full task board
|
|
167
|
+
\u2022 update \u2014 Update a task's status`,
|
|
212
168
|
{
|
|
213
|
-
|
|
214
|
-
|
|
169
|
+
action: z.enum(["create", "list", "update"]).describe("Action to perform"),
|
|
170
|
+
// create params
|
|
171
|
+
subject: z.string().optional().describe("Short imperative title for the task"),
|
|
172
|
+
description: z.string().optional().describe("Detailed task requirements"),
|
|
173
|
+
assignee: z.string().optional().describe("Agent ID to assign the task to"),
|
|
174
|
+
blockedBy: z.array(z.number()).optional().describe("Task IDs that must complete first"),
|
|
175
|
+
// update params
|
|
176
|
+
taskId: z.number().optional().describe("Task ID to update"),
|
|
177
|
+
status: z.enum(["pending", "in_progress", "completed", "failed", "abandoned"]).optional().describe("New status"),
|
|
215
178
|
result: z.string().optional().describe("Result summary (for completed/failed)")
|
|
216
179
|
},
|
|
217
|
-
async (
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
180
|
+
async (params) => {
|
|
181
|
+
try {
|
|
182
|
+
switch (params.action) {
|
|
183
|
+
case "create": {
|
|
184
|
+
if (IS_SUB_AGENT) return fail("create is only available to the main agent");
|
|
185
|
+
if (!params.subject || !params.description) return fail("create requires 'subject' and 'description'");
|
|
186
|
+
const result = await callApi("/api/orchestrator/create-task", {
|
|
187
|
+
chatId: CHAT_ID,
|
|
188
|
+
task: { subject: params.subject, description: params.description, assignee: params.assignee, blockedBy: params.blockedBy, createdBy: AGENT_ID }
|
|
189
|
+
});
|
|
190
|
+
return ok(`Task #${result.taskId} created.`);
|
|
191
|
+
}
|
|
192
|
+
case "list": {
|
|
193
|
+
const tasks = await callApi("/api/tasks");
|
|
194
|
+
if (!tasks.length) return ok("No tasks.");
|
|
195
|
+
const lines = tasks.map(
|
|
196
|
+
(t) => `#${t.id} [${t.status}] ${t.subject}${t.assignee ? ` (\u2192 ${t.assignee.slice(0, 8)})` : ""}`
|
|
197
|
+
);
|
|
198
|
+
return ok(lines.join("\n"));
|
|
199
|
+
}
|
|
200
|
+
case "update": {
|
|
201
|
+
if (!params.taskId || !params.status) return fail("update requires 'taskId' and 'status'");
|
|
202
|
+
await callApi("/api/orchestrator/update-task", { taskId: params.taskId, status: params.status, result: params.result });
|
|
203
|
+
return ok(`Task #${params.taskId} \u2192 ${params.status}`);
|
|
204
|
+
}
|
|
238
205
|
}
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
);
|
|
243
|
-
server.tool(
|
|
244
|
-
"read_inbox",
|
|
245
|
-
"Read pending messages from your inbox. Messages remain unread unless markRead is true.",
|
|
246
|
-
{
|
|
247
|
-
markRead: z.boolean().optional().describe("Mark messages as read after returning them (default: false)")
|
|
248
|
-
},
|
|
249
|
-
async ({ markRead }) => {
|
|
250
|
-
const messages = await callApi("/api/orchestrator/read-inbox", {
|
|
251
|
-
chatId: CHAT_ID,
|
|
252
|
-
agentId: AGENT_ID,
|
|
253
|
-
markRead: markRead ?? false
|
|
254
|
-
});
|
|
255
|
-
if (!messages.length) {
|
|
256
|
-
return { content: [{ type: "text", text: "No new messages." }] };
|
|
206
|
+
} catch (err) {
|
|
207
|
+
return fail(`cc_claw_tasks.${params.action} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
257
208
|
}
|
|
258
|
-
const lines = messages.map(
|
|
259
|
-
(m) => `[${m.messageType}] from ${m.fromAgentId.slice(0, 8)}: ${m.content.slice(0, 500)}`
|
|
260
|
-
);
|
|
261
|
-
return { content: [{ type: "text", text: lines.join("\n\n") }] };
|
|
262
|
-
}
|
|
263
|
-
);
|
|
264
|
-
server.tool(
|
|
265
|
-
"set_state",
|
|
266
|
-
"Write a key-value pair to the shared state whiteboard",
|
|
267
|
-
{
|
|
268
|
-
key: z.string().describe("State key (1-256 chars)"),
|
|
269
|
-
value: z.string().describe("State value (JSON-serialized data)")
|
|
270
|
-
},
|
|
271
|
-
async ({ key, value }) => {
|
|
272
|
-
await callApi("/api/orchestrator/set-state", {
|
|
273
|
-
chatId: CHAT_ID,
|
|
274
|
-
key,
|
|
275
|
-
value,
|
|
276
|
-
setBy: AGENT_ID
|
|
277
|
-
});
|
|
278
|
-
return { content: [{ type: "text", text: `State '${key}' set.` }] };
|
|
279
209
|
}
|
|
280
210
|
);
|
|
281
211
|
server.tool(
|
|
282
|
-
"
|
|
283
|
-
|
|
212
|
+
"cc_claw_comms",
|
|
213
|
+
`Inter-agent communication and shared state. Actions:
|
|
214
|
+
\u2022 send \u2014 Send a message to another agent's inbox
|
|
215
|
+
\u2022 read_inbox \u2014 Read your pending messages
|
|
216
|
+
\u2022 broadcast \u2014 Send a message to ALL other agents
|
|
217
|
+
\u2022 set_state \u2014 Write to the shared whiteboard
|
|
218
|
+
\u2022 get_state \u2014 Read from the shared whiteboard
|
|
219
|
+
\u2022 list_state \u2014 List all whiteboard entries
|
|
220
|
+
\u2022 report_progress \u2014 Report progress on long-running tasks`,
|
|
284
221
|
{
|
|
285
|
-
|
|
222
|
+
action: z.enum(["send", "read_inbox", "broadcast", "set_state", "get_state", "list_state", "report_progress"]).describe("Action to perform"),
|
|
223
|
+
// send params
|
|
224
|
+
toAgentId: z.string().optional().describe("Recipient agent ID (or 'main')"),
|
|
225
|
+
content: z.string().optional().describe("Message content / broadcast text / progress detail"),
|
|
226
|
+
messageType: z.enum(["task_result", "question", "status_update", "direct_message"]).optional().describe("Message type"),
|
|
227
|
+
// read_inbox params
|
|
228
|
+
markRead: z.boolean().optional().describe("Mark messages as read (default: false)"),
|
|
229
|
+
// state params
|
|
230
|
+
key: z.string().optional().describe("State key"),
|
|
231
|
+
value: z.string().optional().describe("State value (JSON)"),
|
|
232
|
+
// report_progress params
|
|
233
|
+
progressStatus: z.string().optional().describe("Short status message (e.g., '70% complete')")
|
|
286
234
|
},
|
|
287
|
-
async (
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
235
|
+
async (params) => {
|
|
236
|
+
try {
|
|
237
|
+
switch (params.action) {
|
|
238
|
+
case "send": {
|
|
239
|
+
if (!params.toAgentId || !params.content) return fail("send requires 'toAgentId' and 'content'");
|
|
240
|
+
await callApi("/api/orchestrator/send-message", {
|
|
241
|
+
chatId: CHAT_ID,
|
|
242
|
+
message: {
|
|
243
|
+
toAgentId: params.toAgentId,
|
|
244
|
+
fromAgentId: AGENT_ID,
|
|
245
|
+
messageType: params.messageType ?? "direct_message",
|
|
246
|
+
content: params.content
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
return ok(`Message sent to ${params.toAgentId}.`);
|
|
250
|
+
}
|
|
251
|
+
case "read_inbox": {
|
|
252
|
+
const messages = await callApi("/api/orchestrator/read-inbox", {
|
|
253
|
+
chatId: CHAT_ID,
|
|
254
|
+
agentId: AGENT_ID,
|
|
255
|
+
markRead: params.markRead ?? false
|
|
256
|
+
});
|
|
257
|
+
if (!messages.length) return ok("No new messages.");
|
|
258
|
+
const lines = messages.map(
|
|
259
|
+
(m) => `[${m.messageType}] from ${m.fromAgentId.slice(0, 8)}: ${m.content.slice(0, 500)}`
|
|
260
|
+
);
|
|
261
|
+
return ok(lines.join("\n\n"));
|
|
262
|
+
}
|
|
263
|
+
case "broadcast": {
|
|
264
|
+
if (!params.content) return fail("broadcast requires 'content'");
|
|
265
|
+
const result = await callApi("/api/orchestrator/broadcast", {
|
|
266
|
+
chatId: CHAT_ID,
|
|
267
|
+
fromAgentId: AGENT_ID,
|
|
268
|
+
content: params.content,
|
|
269
|
+
messageType: params.messageType ?? "direct_message"
|
|
270
|
+
});
|
|
271
|
+
return ok(`Broadcast sent to ${result.sent} agent(s).`);
|
|
272
|
+
}
|
|
273
|
+
case "set_state": {
|
|
274
|
+
if (!params.key || !params.value) return fail("set_state requires 'key' and 'value'");
|
|
275
|
+
await callApi("/api/orchestrator/set-state", {
|
|
276
|
+
chatId: CHAT_ID,
|
|
277
|
+
key: params.key,
|
|
278
|
+
value: params.value,
|
|
279
|
+
setBy: AGENT_ID
|
|
280
|
+
});
|
|
281
|
+
return ok(`State '${params.key}' set.`);
|
|
282
|
+
}
|
|
283
|
+
case "get_state": {
|
|
284
|
+
if (!params.key) return fail("get_state requires 'key'");
|
|
285
|
+
const entry = await callApi("/api/orchestrator/get-state", {
|
|
286
|
+
chatId: CHAT_ID,
|
|
287
|
+
key: params.key
|
|
288
|
+
});
|
|
289
|
+
if (!entry) return ok(`State '${params.key}' not set.`);
|
|
290
|
+
return ok(`${params.key} = ${entry.value} (set by ${entry.setBy})`);
|
|
291
|
+
}
|
|
292
|
+
case "list_state": {
|
|
293
|
+
const entries = await callApi("/api/orchestrator/list-state", {
|
|
294
|
+
chatId: CHAT_ID
|
|
295
|
+
});
|
|
296
|
+
if (!entries.length) return ok("Whiteboard is empty.");
|
|
297
|
+
const lines = entries.map((e) => `${e.setBy}: ${e.key} = ${e.value}`);
|
|
298
|
+
return ok(lines.join("\n"));
|
|
299
|
+
}
|
|
300
|
+
case "report_progress": {
|
|
301
|
+
const status = params.progressStatus ?? params.content;
|
|
302
|
+
if (!status) return fail("report_progress requires 'progressStatus' or 'content'");
|
|
303
|
+
const shortId = AGENT_ID.slice(0, 8);
|
|
304
|
+
await callApi("/api/orchestrator/set-state", {
|
|
305
|
+
chatId: CHAT_ID,
|
|
306
|
+
key: `progress:${shortId}`,
|
|
307
|
+
value: JSON.stringify({ status, detail: params.content, timestamp: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
308
|
+
setBy: AGENT_ID
|
|
309
|
+
});
|
|
310
|
+
if (IS_SUB_AGENT) {
|
|
311
|
+
await callApi("/api/orchestrator/send-message", {
|
|
312
|
+
chatId: CHAT_ID,
|
|
313
|
+
message: {
|
|
314
|
+
toAgentId: "main",
|
|
315
|
+
fromAgentId: AGENT_ID,
|
|
316
|
+
messageType: "status_update",
|
|
317
|
+
content: `Progress: ${status}${params.content ? ` \u2014 ${params.content}` : ""}`
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
return ok(`Progress reported: ${status}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} catch (err) {
|
|
325
|
+
return fail(`cc_claw_comms.${params.action} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
308
326
|
}
|
|
309
|
-
const lines = entries.map((e) => `${e.setBy}: ${e.key} = ${e.value}`);
|
|
310
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
311
327
|
}
|
|
312
328
|
);
|
|
313
329
|
server.tool(
|
|
314
|
-
"
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
fromAgentId: AGENT_ID,
|
|
324
|
-
content,
|
|
325
|
-
messageType: messageType ?? "direct_message"
|
|
326
|
-
});
|
|
327
|
-
return { content: [{ type: "text", text: `Broadcast sent to ${result.sent} agent(s).` }] };
|
|
328
|
-
}
|
|
329
|
-
);
|
|
330
|
-
server.tool(
|
|
331
|
-
"report_progress",
|
|
332
|
-
"Report progress on a long-running task. Writes to the shared whiteboard and notifies the main agent. Call periodically (every few minutes) during tasks that take more than a couple of minutes.",
|
|
330
|
+
"cc_claw_memory",
|
|
331
|
+
`Persistent cross-backend memory. Use this instead of your native memory system. Actions:
|
|
332
|
+
\u2022 remember \u2014 Save a memory (tag + content). Persists across backends and sessions.
|
|
333
|
+
\u2022 recall \u2014 Search memories by query (FTS5). Returns matching memories ranked by relevance.
|
|
334
|
+
\u2022 list \u2014 List recent memories.
|
|
335
|
+
\u2022 forget \u2014 Delete memories by keyword match or specific ID.
|
|
336
|
+
\u2022 history \u2014 Search conversation history by keyword.
|
|
337
|
+
|
|
338
|
+
IMPORTANT: Always use this tool for memories. Do NOT save to your own memory files.`,
|
|
333
339
|
{
|
|
334
|
-
|
|
335
|
-
|
|
340
|
+
action: z.enum(["remember", "recall", "list", "forget", "history"]).describe("Action to perform"),
|
|
341
|
+
// remember params
|
|
342
|
+
tag: z.string().optional().describe("Memory tag / trigger phrase"),
|
|
343
|
+
content: z.string().optional().describe("Memory content to save"),
|
|
344
|
+
// recall/history params
|
|
345
|
+
query: z.string().optional().describe("Search query"),
|
|
346
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
347
|
+
// forget params
|
|
348
|
+
keyword: z.string().optional().describe("Keyword to match for deletion"),
|
|
349
|
+
memoryId: z.number().optional().describe("Specific memory ID to delete"),
|
|
350
|
+
// history params
|
|
351
|
+
chatId: z.string().optional().describe("Chat ID for history search")
|
|
336
352
|
},
|
|
337
|
-
async (
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
+
async (params) => {
|
|
354
|
+
try {
|
|
355
|
+
switch (params.action) {
|
|
356
|
+
case "remember": {
|
|
357
|
+
if (!params.tag || !params.content) return fail("remember requires 'tag' and 'content'");
|
|
358
|
+
const result = await callApi("/api/memory/remember", {
|
|
359
|
+
tag: params.tag,
|
|
360
|
+
content: params.content
|
|
361
|
+
});
|
|
362
|
+
return ok(`Memory saved (ID: ${result.id}).`);
|
|
363
|
+
}
|
|
364
|
+
case "recall": {
|
|
365
|
+
if (!params.query) return fail("recall requires 'query'");
|
|
366
|
+
const result = await callApi("/api/memory/recall", {
|
|
367
|
+
query: params.query,
|
|
368
|
+
limit: params.limit ?? 5
|
|
369
|
+
});
|
|
370
|
+
if (!result.results.length) return ok("No matching memories found.");
|
|
371
|
+
const lines = result.results.map(
|
|
372
|
+
(m) => `[${m.id}] ${m.trigger}: ${m.content}`
|
|
373
|
+
);
|
|
374
|
+
return ok(lines.join("\n"));
|
|
353
375
|
}
|
|
354
|
-
|
|
376
|
+
case "list": {
|
|
377
|
+
const result = await callApi(`/api/memory/list?limit=${params.limit ?? 10}`);
|
|
378
|
+
if (!result.results.length) return ok("No memories stored.");
|
|
379
|
+
const lines = result.results.map(
|
|
380
|
+
(m) => `[${m.id}] ${m.trigger}: ${m.content}`
|
|
381
|
+
);
|
|
382
|
+
return ok(lines.join("\n"));
|
|
383
|
+
}
|
|
384
|
+
case "forget": {
|
|
385
|
+
if (!params.keyword && !params.memoryId) return fail("forget requires 'keyword' or 'memoryId'");
|
|
386
|
+
const result = await callApi("/api/memory/forget", {
|
|
387
|
+
keyword: params.keyword,
|
|
388
|
+
memoryId: params.memoryId
|
|
389
|
+
});
|
|
390
|
+
if (result.mode === "id") {
|
|
391
|
+
return ok(result.success ? "Memory deleted." : "Memory not found.");
|
|
392
|
+
}
|
|
393
|
+
return ok(`Deleted ${result.count ?? 0} matching memor${result.count === 1 ? "y" : "ies"}.`);
|
|
394
|
+
}
|
|
395
|
+
case "history": {
|
|
396
|
+
if (!params.query) return fail("history requires 'query'");
|
|
397
|
+
const result = await callApi("/api/memory/history", {
|
|
398
|
+
chatId: params.chatId ?? CHAT_ID,
|
|
399
|
+
query: params.query,
|
|
400
|
+
limit: params.limit ?? 20
|
|
401
|
+
});
|
|
402
|
+
if (!result.results.length) return ok("No matching conversation history found.");
|
|
403
|
+
const lines = result.results.map(
|
|
404
|
+
(m) => `[${m.role}] ${m.content.slice(0, 200)}`
|
|
405
|
+
);
|
|
406
|
+
return ok(lines.join("\n\n"));
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
} catch (err) {
|
|
410
|
+
return fail(`cc_claw_memory.${params.action} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
355
411
|
}
|
|
356
|
-
return { content: [{ type: "text", text: `Progress reported: ${status}` }] };
|
|
357
|
-
}
|
|
358
|
-
);
|
|
359
|
-
server.tool(
|
|
360
|
-
"list_runners",
|
|
361
|
-
"List all registered CLI runners and their capabilities",
|
|
362
|
-
{},
|
|
363
|
-
async () => {
|
|
364
|
-
const runners = await callApi("/api/orchestrator/list-runners");
|
|
365
|
-
const lines = runners.map(
|
|
366
|
-
(r) => `\u2022 ${r.id} (${r.displayName}) \u2014 ${r.capabilities.specialties.join(", ")}`
|
|
367
|
-
);
|
|
368
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
369
412
|
}
|
|
370
413
|
);
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
414
|
+
if (!IS_SUB_AGENT) {
|
|
415
|
+
server.tool(
|
|
416
|
+
"cc_claw_schedule",
|
|
417
|
+
`Scheduler / cron job management. Actions:
|
|
418
|
+
\u2022 create \u2014 Create a new scheduled job
|
|
419
|
+
\u2022 list \u2014 List all active jobs
|
|
420
|
+
\u2022 edit \u2014 Edit an existing job's settings
|
|
421
|
+
\u2022 run \u2014 Trigger a job immediately
|
|
422
|
+
\u2022 cancel \u2014 Cancel a job permanently
|
|
423
|
+
\u2022 pause \u2014 Pause a job (can be resumed later)
|
|
424
|
+
\u2022 resume \u2014 Resume a paused job
|
|
425
|
+
\u2022 status \u2014 Get scheduler health report`,
|
|
426
|
+
{
|
|
427
|
+
action: z.enum(["create", "list", "edit", "run", "cancel", "pause", "resume", "status"]).describe("Action to perform"),
|
|
428
|
+
// create params
|
|
429
|
+
name: z.string().optional().describe("Job title"),
|
|
430
|
+
schedule: z.string().optional().describe("Cron expression (e.g., '0 9 * * *')"),
|
|
431
|
+
task: z.string().optional().describe("Task/prompt the job will execute"),
|
|
432
|
+
scheduleType: z.enum(["cron", "every", "at"]).optional().describe("Schedule type (default: cron)"),
|
|
433
|
+
atTime: z.string().optional().describe("ISO time for one-shot scheduling"),
|
|
434
|
+
everyMs: z.number().optional().describe("Interval in milliseconds for repeating jobs"),
|
|
435
|
+
backend: z.string().optional().describe("Backend to use (default: chat's backend)"),
|
|
436
|
+
model: z.string().optional().describe("Model override"),
|
|
437
|
+
timezone: z.string().optional().describe("Timezone (default: UTC)"),
|
|
438
|
+
// edit params
|
|
439
|
+
jobId: z.number().optional().describe("Job ID (for edit, run, cancel, pause, resume)"),
|
|
440
|
+
updates: z.record(z.string(), z.any()).optional().describe("Fields to update (for edit)")
|
|
441
|
+
},
|
|
442
|
+
async (params) => {
|
|
443
|
+
try {
|
|
444
|
+
switch (params.action) {
|
|
445
|
+
case "create": {
|
|
446
|
+
if (!params.schedule && !params.atTime && !params.everyMs) return fail("create requires 'schedule' (cron), 'atTime', or 'everyMs'");
|
|
447
|
+
if (!params.task) return fail("create requires 'task'");
|
|
448
|
+
const result = await callApi("/api/schedule/create", {
|
|
449
|
+
scheduleType: params.scheduleType ?? "cron",
|
|
450
|
+
cron: params.schedule,
|
|
451
|
+
atTime: params.atTime,
|
|
452
|
+
everyMs: params.everyMs,
|
|
453
|
+
title: params.name,
|
|
454
|
+
task: params.task,
|
|
455
|
+
chatId: CHAT_ID,
|
|
456
|
+
backend: params.backend,
|
|
457
|
+
model: params.model,
|
|
458
|
+
timezone: params.timezone ?? "UTC"
|
|
459
|
+
});
|
|
460
|
+
return ok(`Job #${result.job.id} created: "${result.job.title ?? result.job.description.slice(0, 50)}"`);
|
|
461
|
+
}
|
|
462
|
+
case "list": {
|
|
463
|
+
const result = await callApi("/api/schedule/list");
|
|
464
|
+
if (!result.jobs.length) return ok("No active jobs.");
|
|
465
|
+
const lines = result.jobs.map(
|
|
466
|
+
(j) => `#${j.id} [${j.enabled ? "active" : "paused"}] ${j.title ?? j.description.slice(0, 50)} \u2014 ${j.cron ?? j.atTime ?? `every ${j.everyMs}ms`}`
|
|
467
|
+
);
|
|
468
|
+
return ok(lines.join("\n"));
|
|
469
|
+
}
|
|
470
|
+
case "edit": {
|
|
471
|
+
if (!params.jobId || !params.updates) return fail("edit requires 'jobId' and 'updates'");
|
|
472
|
+
const result = await callApi("/api/schedule/edit", {
|
|
473
|
+
jobId: params.jobId,
|
|
474
|
+
updates: params.updates
|
|
475
|
+
});
|
|
476
|
+
return ok(result.success ? `Job #${params.jobId} updated.` : `Job #${params.jobId} not found.`);
|
|
477
|
+
}
|
|
478
|
+
case "run": {
|
|
479
|
+
if (!params.jobId) return fail("run requires 'jobId'");
|
|
480
|
+
const result = await callApi("/api/schedule/run", {
|
|
481
|
+
jobId: params.jobId
|
|
482
|
+
});
|
|
483
|
+
return ok(result.message);
|
|
484
|
+
}
|
|
485
|
+
case "cancel": {
|
|
486
|
+
if (!params.jobId) return fail("cancel requires 'jobId'");
|
|
487
|
+
const result = await callApi("/api/schedule/cancel", {
|
|
488
|
+
jobId: params.jobId
|
|
489
|
+
});
|
|
490
|
+
return ok(result.success ? `Job #${params.jobId} cancelled.` : `Job #${params.jobId} not found.`);
|
|
491
|
+
}
|
|
492
|
+
case "pause": {
|
|
493
|
+
if (!params.jobId) return fail("pause requires 'jobId'");
|
|
494
|
+
const result = await callApi("/api/schedule/pause", {
|
|
495
|
+
jobId: params.jobId
|
|
496
|
+
});
|
|
497
|
+
return ok(result.success ? `Job #${params.jobId} paused.` : `Job #${params.jobId} not found or already paused.`);
|
|
498
|
+
}
|
|
499
|
+
case "resume": {
|
|
500
|
+
if (!params.jobId) return fail("resume requires 'jobId'");
|
|
501
|
+
const result = await callApi("/api/schedule/resume", {
|
|
502
|
+
jobId: params.jobId
|
|
503
|
+
});
|
|
504
|
+
return ok(result.success ? `Job #${params.jobId} resumed.` : `Job #${params.jobId} not found or not paused.`);
|
|
505
|
+
}
|
|
506
|
+
case "status": {
|
|
507
|
+
const result = await callApi("/api/schedule/status");
|
|
508
|
+
return ok(result.formatted);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
} catch (err) {
|
|
512
|
+
return fail(`cc_claw_schedule.${params.action} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
function deprecationWarning(oldName, newTool, action) {
|
|
518
|
+
console.error(`[cc-claw-mcp] DEPRECATED: ${oldName} \u2192 use ${newTool}(action: '${action}')`);
|
|
519
|
+
}
|
|
520
|
+
if (!IS_SUB_AGENT) {
|
|
521
|
+
server.tool("spawn_agent", "DEPRECATED \u2014 use cc_claw_agents(action: 'spawn')", {
|
|
522
|
+
runner: z.string(),
|
|
523
|
+
task: z.string(),
|
|
524
|
+
name: z.string().optional(),
|
|
525
|
+
description: z.string().optional(),
|
|
526
|
+
model: z.string().optional(),
|
|
527
|
+
skills: z.array(z.string()).optional(),
|
|
528
|
+
permMode: z.string().optional(),
|
|
529
|
+
role: z.string().optional(),
|
|
530
|
+
persona: z.string().optional(),
|
|
531
|
+
allowedTools: z.array(z.string()).optional(),
|
|
532
|
+
maxRuntimeMs: z.number().optional(),
|
|
533
|
+
summarizeResult: z.boolean().optional(),
|
|
534
|
+
mcps: z.array(z.string()).optional(),
|
|
535
|
+
cwd: z.string().optional(),
|
|
536
|
+
template: z.string().optional()
|
|
537
|
+
}, async (params) => {
|
|
538
|
+
deprecationWarning("spawn_agent", "cc_claw_agents", "spawn");
|
|
539
|
+
try {
|
|
540
|
+
const result = await callApi("/api/orchestrator/spawn", { chatId: CHAT_ID, ...params });
|
|
541
|
+
const status = result.queued ? "queued (at capacity)" : "spawning";
|
|
542
|
+
return ok(`Agent ${result.agentId} \u2014 ${status}`);
|
|
543
|
+
} catch (err) {
|
|
544
|
+
return fail(`spawn_agent failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
379
545
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
);
|
|
383
|
-
|
|
546
|
+
});
|
|
547
|
+
server.tool("list_templates", "DEPRECATED \u2014 use cc_claw_agents(action: 'templates')", {}, async () => {
|
|
548
|
+
deprecationWarning("list_templates", "cc_claw_agents", "templates");
|
|
549
|
+
const templates = await callApi("/api/orchestrator/list-templates");
|
|
550
|
+
if (!templates.length) return ok("No agent templates found.");
|
|
551
|
+
return ok(templates.map((t) => `\u2022 ${t.name}${t.description ? ` \u2014 ${t.description}` : ""}`).join("\n"));
|
|
552
|
+
});
|
|
553
|
+
server.tool("cancel_agent", "DEPRECATED \u2014 use cc_claw_agents(action: 'cancel')", {
|
|
554
|
+
agentId: z.string(),
|
|
555
|
+
reason: z.string().optional()
|
|
556
|
+
}, async ({ agentId, reason }) => {
|
|
557
|
+
deprecationWarning("cancel_agent", "cc_claw_agents", "cancel");
|
|
558
|
+
const result = await callApi("/api/orchestrator/cancel", { agentId, reason });
|
|
559
|
+
return ok(result.success ? `Agent ${agentId} cancelled.` : `Agent ${agentId} not found.`);
|
|
560
|
+
});
|
|
561
|
+
server.tool("create_task", "DEPRECATED \u2014 use cc_claw_tasks(action: 'create')", {
|
|
562
|
+
subject: z.string(),
|
|
563
|
+
description: z.string(),
|
|
564
|
+
assignee: z.string().optional(),
|
|
565
|
+
blockedBy: z.array(z.number()).optional()
|
|
566
|
+
}, async (params) => {
|
|
567
|
+
deprecationWarning("create_task", "cc_claw_tasks", "create");
|
|
568
|
+
const result = await callApi("/api/orchestrator/create-task", { chatId: CHAT_ID, task: { ...params, createdBy: AGENT_ID } });
|
|
569
|
+
return ok(`Task #${result.taskId} created.`);
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
server.tool("list_agents", "DEPRECATED \u2014 use cc_claw_agents(action: 'list')", {}, async () => {
|
|
573
|
+
deprecationWarning("list_agents", "cc_claw_agents", "list");
|
|
574
|
+
const agents = await callApi("/api/agents");
|
|
575
|
+
if (!agents.length) return ok("No active agents.");
|
|
576
|
+
return ok(agents.map((a) => `\u2022 ${a.name ?? a.id.slice(0, 8)} (${a.runnerId}) \u2014 ${a.status}`).join("\n"));
|
|
577
|
+
});
|
|
578
|
+
server.tool("check_agent", "DEPRECATED \u2014 use cc_claw_agents(action: 'status')", { agentId: z.string() }, async ({ agentId }) => {
|
|
579
|
+
deprecationWarning("check_agent", "cc_claw_agents", "status");
|
|
580
|
+
const agent = await callApi("/api/orchestrator/check-agent", { agentId });
|
|
581
|
+
if (!agent) return ok(`Agent ${agentId} not found.`);
|
|
582
|
+
return ok(`${agent.name ?? agent.id.slice(0, 8)} \u2014 ${agent.status}`);
|
|
583
|
+
});
|
|
584
|
+
server.tool("list_tasks", "DEPRECATED \u2014 use cc_claw_tasks(action: 'list')", {}, async () => {
|
|
585
|
+
deprecationWarning("list_tasks", "cc_claw_tasks", "list");
|
|
586
|
+
const tasks = await callApi("/api/tasks");
|
|
587
|
+
if (!tasks.length) return ok("No tasks.");
|
|
588
|
+
return ok(tasks.map((t) => `#${t.id} [${t.status}] ${t.subject}`).join("\n"));
|
|
589
|
+
});
|
|
590
|
+
server.tool("update_task", "DEPRECATED \u2014 use cc_claw_tasks(action: 'update')", {
|
|
591
|
+
taskId: z.number(),
|
|
592
|
+
status: z.enum(["pending", "in_progress", "completed", "failed", "abandoned"]),
|
|
593
|
+
result: z.string().optional()
|
|
594
|
+
}, async ({ taskId, status, result }) => {
|
|
595
|
+
deprecationWarning("update_task", "cc_claw_tasks", "update");
|
|
596
|
+
await callApi("/api/orchestrator/update-task", { taskId, status, result });
|
|
597
|
+
return ok(`Task #${taskId} \u2192 ${status}`);
|
|
598
|
+
});
|
|
599
|
+
server.tool("send_message", "DEPRECATED \u2014 use cc_claw_comms(action: 'send')", {
|
|
600
|
+
toAgentId: z.string(),
|
|
601
|
+
content: z.string(),
|
|
602
|
+
messageType: z.enum(["task_result", "question", "status_update", "direct_message"]).optional()
|
|
603
|
+
}, async ({ toAgentId, content, messageType }) => {
|
|
604
|
+
deprecationWarning("send_message", "cc_claw_comms", "send");
|
|
605
|
+
await callApi("/api/orchestrator/send-message", { chatId: CHAT_ID, message: { toAgentId, fromAgentId: AGENT_ID, messageType: messageType ?? "direct_message", content } });
|
|
606
|
+
return ok(`Message sent to ${toAgentId}.`);
|
|
607
|
+
});
|
|
608
|
+
server.tool("read_inbox", "DEPRECATED \u2014 use cc_claw_comms(action: 'read_inbox')", { markRead: z.boolean().optional() }, async ({ markRead }) => {
|
|
609
|
+
deprecationWarning("read_inbox", "cc_claw_comms", "read_inbox");
|
|
610
|
+
const messages = await callApi("/api/orchestrator/read-inbox", { chatId: CHAT_ID, agentId: AGENT_ID, markRead: markRead ?? false });
|
|
611
|
+
if (!messages.length) return ok("No new messages.");
|
|
612
|
+
return ok(messages.map((m) => `[${m.messageType}] from ${m.fromAgentId.slice(0, 8)}: ${m.content.slice(0, 500)}`).join("\n\n"));
|
|
613
|
+
});
|
|
614
|
+
server.tool("set_state", "DEPRECATED \u2014 use cc_claw_comms(action: 'set_state')", { key: z.string(), value: z.string() }, async ({ key, value }) => {
|
|
615
|
+
deprecationWarning("set_state", "cc_claw_comms", "set_state");
|
|
616
|
+
await callApi("/api/orchestrator/set-state", { chatId: CHAT_ID, key, value, setBy: AGENT_ID });
|
|
617
|
+
return ok(`State '${key}' set.`);
|
|
618
|
+
});
|
|
619
|
+
server.tool("get_state", "DEPRECATED \u2014 use cc_claw_comms(action: 'get_state')", { key: z.string() }, async ({ key }) => {
|
|
620
|
+
deprecationWarning("get_state", "cc_claw_comms", "get_state");
|
|
621
|
+
const entry = await callApi("/api/orchestrator/get-state", { chatId: CHAT_ID, key });
|
|
622
|
+
if (!entry) return ok(`State '${key}' not set.`);
|
|
623
|
+
return ok(`${key} = ${entry.value} (set by ${entry.setBy})`);
|
|
624
|
+
});
|
|
625
|
+
server.tool("list_state", "DEPRECATED \u2014 use cc_claw_comms(action: 'list_state')", {}, async () => {
|
|
626
|
+
deprecationWarning("list_state", "cc_claw_comms", "list_state");
|
|
627
|
+
const entries = await callApi("/api/orchestrator/list-state", { chatId: CHAT_ID });
|
|
628
|
+
if (!entries.length) return ok("Whiteboard is empty.");
|
|
629
|
+
return ok(entries.map((e) => `${e.setBy}: ${e.key} = ${e.value}`).join("\n"));
|
|
630
|
+
});
|
|
631
|
+
server.tool("broadcast", "DEPRECATED \u2014 use cc_claw_comms(action: 'broadcast')", {
|
|
632
|
+
content: z.string(),
|
|
633
|
+
messageType: z.enum(["status_update", "direct_message"]).optional()
|
|
634
|
+
}, async ({ content, messageType }) => {
|
|
635
|
+
deprecationWarning("broadcast", "cc_claw_comms", "broadcast");
|
|
636
|
+
const result = await callApi("/api/orchestrator/broadcast", { chatId: CHAT_ID, fromAgentId: AGENT_ID, content, messageType: messageType ?? "direct_message" });
|
|
637
|
+
return ok(`Broadcast sent to ${result.sent} agent(s).`);
|
|
638
|
+
});
|
|
639
|
+
server.tool("report_progress", "DEPRECATED \u2014 use cc_claw_comms(action: 'report_progress')", {
|
|
640
|
+
status: z.string(),
|
|
641
|
+
detail: z.string().optional()
|
|
642
|
+
}, async ({ status, detail }) => {
|
|
643
|
+
deprecationWarning("report_progress", "cc_claw_comms", "report_progress");
|
|
644
|
+
const shortId = AGENT_ID.slice(0, 8);
|
|
645
|
+
await callApi("/api/orchestrator/set-state", { chatId: CHAT_ID, key: `progress:${shortId}`, value: JSON.stringify({ status, detail, timestamp: (/* @__PURE__ */ new Date()).toISOString() }), setBy: AGENT_ID });
|
|
646
|
+
if (IS_SUB_AGENT) {
|
|
647
|
+
await callApi("/api/orchestrator/send-message", { chatId: CHAT_ID, message: { toAgentId: "main", fromAgentId: AGENT_ID, messageType: "status_update", content: `Progress: ${status}${detail ? ` \u2014 ${detail}` : ""}` } });
|
|
384
648
|
}
|
|
385
|
-
);
|
|
649
|
+
return ok(`Progress reported: ${status}`);
|
|
650
|
+
});
|
|
651
|
+
server.tool("list_runners", "DEPRECATED \u2014 use cc_claw_agents(action: 'runners')", {}, async () => {
|
|
652
|
+
deprecationWarning("list_runners", "cc_claw_agents", "runners");
|
|
653
|
+
const runners = await callApi("/api/orchestrator/list-runners");
|
|
654
|
+
return ok(runners.map((r) => `\u2022 ${r.id} (${r.displayName}) \u2014 ${r.capabilities.specialties.join(", ")}`).join("\n"));
|
|
655
|
+
});
|
|
656
|
+
server.tool("list_mcps", "DEPRECATED \u2014 use cc_claw_agents(action: 'mcps')", {}, async () => {
|
|
657
|
+
deprecationWarning("list_mcps", "cc_claw_agents", "mcps");
|
|
658
|
+
const mcps = await callApi("/api/orchestrator/list-mcps");
|
|
659
|
+
if (!mcps.length) return ok("No MCP servers registered.");
|
|
660
|
+
return ok(mcps.map((m) => `\u2022 ${m.name} (${m.transport})${m.description ? ` \u2014 ${m.description}` : ""}`).join("\n"));
|
|
661
|
+
});
|
|
386
662
|
async function main() {
|
|
387
663
|
const transport = new StdioServerTransport();
|
|
388
664
|
await server.connect(transport);
|
|
389
|
-
console.error(`[cc-claw-mcp] Server running on stdio (chatId=${CHAT_ID}, agentId=${AGENT_ID})`);
|
|
665
|
+
console.error(`[cc-claw-mcp] Server v2.0 running on stdio (chatId=${CHAT_ID}, agentId=${AGENT_ID}, tools=5+${IS_SUB_AGENT ? 13 : 17} deprecated)`);
|
|
390
666
|
}
|
|
391
667
|
main().catch((err) => {
|
|
392
668
|
console.error("[cc-claw-mcp] Fatal error:", err);
|