@ai-setting/roy-task-plugin 0.6.0 → 0.7.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/claude-plugin/hooks/stop-check.mjs +23 -19
- package/dist/claude-plugin/mcp/bridge.mjs +64 -443
- package/dist/claude-plugin/mcp/roy-task-mcp-server.mjs +75 -50
- package/dist/claude-plugin/mcp/tools.mjs +39 -225
- package/dist/cli.js +100 -78
- package/dist/index.js +525 -524
- package/dist/index.js.map +22 -21
- package/package.json +2 -2
|
@@ -3,14 +3,25 @@
|
|
|
3
3
|
* roy-task MCP server — exposes the task lifecycle to Claude Code as native
|
|
4
4
|
* MCP tools.
|
|
5
5
|
*
|
|
6
|
-
* ##
|
|
6
|
+
* ## What this file is
|
|
7
|
+
*
|
|
8
|
+
* A **transport**: newline-delimited JSON-RPC 2.0 over stdin/stdout, and
|
|
9
|
+
* nothing else. The protocol handling, the tool catalogue, the tool
|
|
10
|
+
* execution and every task semantic live in
|
|
11
|
+
* `@ai-setting/roy-agent-core/env/task/mcp`.
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
13
|
+
* Before Task #4619 this file (281 lines) plus `bridge.mjs` (482 lines) plus
|
|
14
|
+
* `tools.mjs` (240 lines) re-implemented the whole task surface: the tool
|
|
15
|
+
* catalogue was hand-copied, and the tools were raw SQL against roy's own
|
|
16
|
+
* database. Now the plugin contributes **transport + wiring** and nothing
|
|
17
|
+
* else.
|
|
18
|
+
*
|
|
19
|
+
* ## Protocol
|
|
10
20
|
*
|
|
11
21
|
* | method | direction | notes |
|
|
12
22
|
* |-------------------------|-----------------|----------------------------------|
|
|
13
23
|
* | `initialize` | client -> server | we negotiate the protocol version |
|
|
24
|
+
* | `server/discover` | client -> server | Claude Code 2.1.285's pre-handshake probe |
|
|
14
25
|
* | `notifications/initialized` | client -> server | acknowledged by doing nothing |
|
|
15
26
|
* | `tools/list` | client -> server | the tool catalogue |
|
|
16
27
|
* | `tools/call` | client -> server | run one tool |
|
|
@@ -36,16 +47,25 @@
|
|
|
36
47
|
|
|
37
48
|
import { createInterface } from "node:readline";
|
|
38
49
|
|
|
39
|
-
import {
|
|
50
|
+
import { createServer, BridgeError, defaultTaskDbPath } from "./bridge.mjs";
|
|
40
51
|
import {
|
|
41
|
-
|
|
52
|
+
JSON_RPC_ERRORS,
|
|
42
53
|
SUPPORTED_PROTOCOL_VERSIONS,
|
|
43
54
|
DEFAULT_PROTOCOL_VERSION,
|
|
44
|
-
JSON_RPC_ERRORS,
|
|
45
55
|
} from "./tools.mjs";
|
|
56
|
+
import { setStdoutStrictMode } from "@ai-setting/roy-agent-core/env/log-trace";
|
|
46
57
|
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
59
|
+
// stdout 归协议,stderr 归诊断(Task #4619)
|
|
60
|
+
//
|
|
61
|
+
// MCP 的 stdio 传输是「按行分隔的 JSON-RPC」,跑在 stdout 上。core 的 logger
|
|
62
|
+
// 原本把 `info` 打到 stdout,task store 的 migration 也用 `console.log` 打印
|
|
63
|
+
// 横幅 —— 实测本 server **26 行 stdout 里有 24 行不是 JSON**,客户端会因此
|
|
64
|
+
// 丢弃整个 server(Claude Code 报 `status: "failed"`)。
|
|
65
|
+
//
|
|
66
|
+
// 所以这里开 core 的 stdout-strict 模式:日志全走 stderr,stdout 只留给协议。
|
|
67
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
68
|
+
setStdoutStrictMode(true);
|
|
49
69
|
|
|
50
70
|
/**
|
|
51
71
|
* Write one JSON-RPC message to stdout.
|
|
@@ -71,23 +91,7 @@ function sendResult(id, result) {
|
|
|
71
91
|
}
|
|
72
92
|
|
|
73
93
|
function sendError(id, code, message, data) {
|
|
74
|
-
|
|
75
|
-
if (data !== undefined) error.data = data;
|
|
76
|
-
send({ jsonrpc: "2.0", id, error });
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Pick the protocol version to answer with.
|
|
81
|
-
*
|
|
82
|
-
* Echo the client's version when we know it; otherwise offer ours. This is
|
|
83
|
-
* what the official SDK does, and it is what lets an older Claude Code talk to
|
|
84
|
-
* a newer server without a hard failure.
|
|
85
|
-
*/
|
|
86
|
-
export function negotiateProtocolVersion(requested) {
|
|
87
|
-
if (typeof requested === "string" && SUPPORTED_PROTOCOL_VERSIONS.includes(requested)) {
|
|
88
|
-
return requested;
|
|
89
|
-
}
|
|
90
|
-
return DEFAULT_PROTOCOL_VERSION;
|
|
94
|
+
send({ jsonrpc: "2.0", id, error: { code, message, ...(data ? { data } : {}) } });
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
/** Turn a thrown error into an MCP tool result with `isError: true`. */
|
|
@@ -98,23 +102,17 @@ function toolError(message) {
|
|
|
98
102
|
};
|
|
99
103
|
}
|
|
100
104
|
|
|
101
|
-
/**
|
|
102
|
-
* The server's identity, shared by `initialize` and `server/discover`.
|
|
103
|
-
*/
|
|
104
|
-
const SERVER_INFO = { name: SERVER_NAME, version: SERVER_VERSION };
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* The capabilities we advertise.
|
|
108
|
-
*/
|
|
109
|
-
const SERVER_CAPABILITIES = { tools: { listChanged: false } };
|
|
110
|
-
|
|
111
105
|
/**
|
|
112
106
|
* Handle one parsed JSON-RPC request.
|
|
113
107
|
*
|
|
108
|
+
* The dispatch is delegated to core's MCP server; this function only adapts
|
|
109
|
+
* the **shape** (core returns `result` / `error` objects, this module writes
|
|
110
|
+
* them with the `jsonrpc` envelope).
|
|
111
|
+
*
|
|
114
112
|
* Exported for tests: the pure part (dispatch) is separated from the I/O
|
|
115
113
|
* part (stdin/stdout) so the protocol can be exercised without a pipe.
|
|
116
114
|
*/
|
|
117
|
-
export function handleRequest(request,
|
|
115
|
+
export async function handleRequest(request, server) {
|
|
118
116
|
const { id, method, params } = request;
|
|
119
117
|
|
|
120
118
|
// Notifications have no id and must not be answered.
|
|
@@ -155,9 +153,6 @@ export function handleRequest(request, db) {
|
|
|
155
153
|
* `{"name":"plugin:roy-task:roy-task","status":"failed"}`; with it
|
|
156
154
|
* handled the same event reported `status:"connected"`.)
|
|
157
155
|
*
|
|
158
|
-
* The response shape mirrors `initialize` — the server describes itself
|
|
159
|
-
* — so the two handlers share `SERVER_INFO` / `SERVER_CAPABILITIES`.
|
|
160
|
-
*
|
|
161
156
|
* This method is **not** in @modelcontextprotocol/sdk 1.32.1, which is why
|
|
162
157
|
* an SDK-based client never exercises it and a hand-rolled server can
|
|
163
158
|
* pass its own tests while failing inside Claude Code.
|
|
@@ -182,7 +177,7 @@ export function handleRequest(request, db) {
|
|
|
182
177
|
return { id, result: {} };
|
|
183
178
|
|
|
184
179
|
case "tools/list":
|
|
185
|
-
return { id, result: { tools:
|
|
180
|
+
return { id, result: { tools: server.listTools() } };
|
|
186
181
|
|
|
187
182
|
case "tools/call": {
|
|
188
183
|
const toolName = params && params.name;
|
|
@@ -197,7 +192,7 @@ export function handleRequest(request, db) {
|
|
|
197
192
|
};
|
|
198
193
|
}
|
|
199
194
|
try {
|
|
200
|
-
const value = callTool(
|
|
195
|
+
const value = await server.callTool(toolName, args);
|
|
201
196
|
return {
|
|
202
197
|
id,
|
|
203
198
|
result: {
|
|
@@ -224,12 +219,38 @@ export function handleRequest(request, db) {
|
|
|
224
219
|
}
|
|
225
220
|
}
|
|
226
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Pick the protocol version to answer with.
|
|
224
|
+
*
|
|
225
|
+
* Echo the client's version when we know it; otherwise offer ours. This is
|
|
226
|
+
* what the official SDK does, and it is what lets an older Claude Code talk to
|
|
227
|
+
* a newer server without a hard failure.
|
|
228
|
+
*/
|
|
229
|
+
export function negotiateProtocolVersion(requested) {
|
|
230
|
+
if (typeof requested === "string" && SUPPORTED_PROTOCOL_VERSIONS.includes(requested)) {
|
|
231
|
+
return requested;
|
|
232
|
+
}
|
|
233
|
+
return DEFAULT_PROTOCOL_VERSION;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* The server's identity, shared by `initialize` and `server/discover`.
|
|
238
|
+
*/
|
|
239
|
+
const SERVER_NAME = "roy-task";
|
|
240
|
+
const SERVER_VERSION = "1.0.0";
|
|
241
|
+
const SERVER_INFO = { name: SERVER_NAME, version: SERVER_VERSION };
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* The capabilities we advertise.
|
|
245
|
+
*/
|
|
246
|
+
const SERVER_CAPABILITIES = { tools: { listChanged: false } };
|
|
247
|
+
|
|
227
248
|
/** Read newline-delimited JSON-RPC from stdin and answer on stdout. */
|
|
228
249
|
export function main() {
|
|
229
250
|
const dbPath = process.env.ROY_TASK_DB_PATH || defaultTaskDbPath();
|
|
230
|
-
let
|
|
251
|
+
let server;
|
|
231
252
|
try {
|
|
232
|
-
|
|
253
|
+
server = createServer(dbPath);
|
|
233
254
|
} catch (err) {
|
|
234
255
|
process.stderr.write(
|
|
235
256
|
`roy-task mcp server: cannot open task store at ${dbPath}: ${err && err.message}\n`,
|
|
@@ -256,16 +277,20 @@ export function main() {
|
|
|
256
277
|
return;
|
|
257
278
|
}
|
|
258
279
|
|
|
259
|
-
|
|
260
|
-
|
|
280
|
+
Promise.resolve(handleRequest(request, server))
|
|
281
|
+
.then((response) => {
|
|
282
|
+
if (response) send(response);
|
|
283
|
+
})
|
|
284
|
+
.catch((err) => {
|
|
285
|
+
sendError(
|
|
286
|
+
request.id ?? null,
|
|
287
|
+
JSON_RPC_ERRORS.INTERNAL_ERROR,
|
|
288
|
+
err && err.message ? err.message : String(err),
|
|
289
|
+
);
|
|
290
|
+
});
|
|
261
291
|
});
|
|
262
292
|
|
|
263
293
|
rl.on("close", () => {
|
|
264
|
-
try {
|
|
265
|
-
db.close();
|
|
266
|
-
} catch {
|
|
267
|
-
// already closed
|
|
268
|
-
}
|
|
269
294
|
process.exit(0);
|
|
270
295
|
});
|
|
271
296
|
}
|
|
@@ -1,240 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The MCP tool catalogue — **derived from roy-agent's core**.
|
|
3
3
|
*
|
|
4
|
-
* ##
|
|
4
|
+
* ## What this file used to be
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Before Task #4619 it was a hand-written catalogue: 240 lines of
|
|
7
|
+
* hand-copied tool names, descriptions and JSON Schemas for the eight task
|
|
8
|
+
* tools. It was a **second copy** of core's tool definitions, so it drifted:
|
|
9
|
+
* core's `task_create` gained a `context` field, a `type` enum and a
|
|
10
|
+
* `project_path` field, and the plugin's copy did not — so a Claude Code
|
|
11
|
+
* client could not pass the arguments the real tool accepted.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
* - `initialize` / `tools/list` / `tools/call` (plus `notifications/initialized`)
|
|
13
|
+
* ## What it is now
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* A ~20-line re-export of core's own tool definitions. The names,
|
|
16
|
+
* descriptions and JSON Schema come from the **same factories** the tool
|
|
17
|
+
* execution uses, so they cannot drift.
|
|
17
18
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* The task store is **roy-agent's** store (`~/.local/share/roy-agent/tasks.db`),
|
|
21
|
-
* not the plugin's own `~/.roy-task-plugin/tasks.db`. The reason is
|
|
22
|
-
* interoperability: the roy agent inside opencode/claude creates tasks through
|
|
23
|
-
* `roy-agent`'s own task tools, and the progress card the daemon sends is
|
|
24
|
-
* rendered from the *same* rows. If this MCP server wrote to a different
|
|
25
|
-
* database, Claude would create tasks the card can never see.
|
|
26
|
-
*
|
|
27
|
-
* So the tools shell out to the `roy-agent tasks …` CLI, which is the stable,
|
|
28
|
-
* already-migrated, already-schema-validated way to reach that store. We do
|
|
29
|
-
* not re-implement the store, and we do not open the SQLite file ourselves.
|
|
30
|
-
*
|
|
31
|
-
* ## stdio hygiene
|
|
32
|
-
*
|
|
33
|
-
* This process is spawned by Claude Code as an MCP server. It must:
|
|
34
|
-
*
|
|
35
|
-
* - **read** stdin (that is the transport) — obviously not `ignore` here;
|
|
36
|
-
* - **never** write anything but protocol messages to stdout. A stray
|
|
37
|
-
* `console.log` would corrupt the stream, so every log line goes to stderr.
|
|
38
|
-
*
|
|
39
|
-
* The "stdin must be ignore" rule from the daemon's spawn adapter applies to
|
|
40
|
-
* *agent* subprocesses, not to an MCP server — an MCP server whose stdin is
|
|
41
|
-
* closed can never receive a single request.
|
|
19
|
+
* The MCP wire protocol constants (protocol versions, JSON-RPC error codes)
|
|
20
|
+
* also come from core now — they are part of the same contract.
|
|
42
21
|
*/
|
|
43
22
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
23
|
+
import {
|
|
24
|
+
createTaskMcpToolDefinitions,
|
|
25
|
+
TASK_MCP_SUPPORTED_PROTOCOL_VERSIONS,
|
|
26
|
+
TASK_MCP_DEFAULT_PROTOCOL_VERSION,
|
|
27
|
+
TASK_MCP_JSON_RPC_ERRORS,
|
|
28
|
+
} from "@ai-setting/roy-agent-core/env/task/mcp";
|
|
29
|
+
import { TaskStoreBackend, createSQLiteTaskPort } from "@ai-setting/roy-agent-core/env/task/backend";
|
|
30
|
+
import { SQLiteTaskStore } from "@ai-setting/roy-agent-core/env/task/storage";
|
|
31
|
+
|
|
32
|
+
/** The MCP protocol versions we accept. */
|
|
33
|
+
export const SUPPORTED_PROTOCOL_VERSIONS = TASK_MCP_SUPPORTED_PROTOCOL_VERSIONS;
|
|
51
34
|
|
|
52
|
-
|
|
35
|
+
/** The protocol version we answer with when the client's is unknown. */
|
|
36
|
+
export const DEFAULT_PROTOCOL_VERSION = TASK_MCP_DEFAULT_PROTOCOL_VERSION;
|
|
53
37
|
|
|
54
38
|
/** The JSON-RPC error codes we use. */
|
|
55
|
-
export const JSON_RPC_ERRORS =
|
|
56
|
-
PARSE_ERROR: -32700,
|
|
57
|
-
INVALID_REQUEST: -32600,
|
|
58
|
-
METHOD_NOT_FOUND: -32601,
|
|
59
|
-
INVALID_PARAMS: -32602,
|
|
60
|
-
INTERNAL_ERROR: -32603,
|
|
61
|
-
});
|
|
39
|
+
export const JSON_RPC_ERRORS = TASK_MCP_JSON_RPC_ERRORS;
|
|
62
40
|
|
|
63
41
|
/**
|
|
64
|
-
* The task tools we expose.
|
|
42
|
+
* The task tools we expose — derived from core's own tool factories.
|
|
65
43
|
*
|
|
66
|
-
* The
|
|
67
|
-
*
|
|
44
|
+
* The factories never touch the store while building a definition, so an
|
|
45
|
+
* **in-memory** store is enough here. Using the real path would create the
|
|
46
|
+
* database file as a side effect of *importing* this module — a surprising
|
|
47
|
+
* side effect for a module that is only supposed to describe the tool
|
|
48
|
+
* catalogue.
|
|
68
49
|
*/
|
|
69
|
-
export const MCP_TOOLS = Object.freeze(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
inputSchema: {
|
|
75
|
-
type: "object",
|
|
76
|
-
properties: {
|
|
77
|
-
depth: {
|
|
78
|
-
type: "number",
|
|
79
|
-
description: "Tree depth. 1 = roots + their direct children. -1 = unlimited.",
|
|
80
|
-
},
|
|
81
|
-
parent_task_id: {
|
|
82
|
-
type: "number",
|
|
83
|
-
description: "Only show the subtree under this task id.",
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: "task_create",
|
|
90
|
-
description:
|
|
91
|
-
"Create a tracked task. Task is a first-class citizen: create the task BEFORE doing the work, then update it as you go and complete it when done.",
|
|
92
|
-
inputSchema: {
|
|
93
|
-
type: "object",
|
|
94
|
-
properties: {
|
|
95
|
-
title: { type: "string", description: "Imperative, specific one-line title." },
|
|
96
|
-
description: { type: "string", description: "What needs to be done and why." },
|
|
97
|
-
goals_and_expected_deliverables: {
|
|
98
|
-
type: "string",
|
|
99
|
-
description: "Success criteria and expected outputs.",
|
|
100
|
-
},
|
|
101
|
-
priority: {
|
|
102
|
-
type: "string",
|
|
103
|
-
enum: ["low", "medium", "high"],
|
|
104
|
-
description: "Task priority.",
|
|
105
|
-
},
|
|
106
|
-
type: {
|
|
107
|
-
type: "string",
|
|
108
|
-
enum: ["normal", "cycle", "longterm"],
|
|
109
|
-
description: "normal = one-off; cycle = periodic; longterm = ongoing goal.",
|
|
110
|
-
},
|
|
111
|
-
parent_task_id: {
|
|
112
|
-
type: "number",
|
|
113
|
-
description: "Parent task id. Omit to create a root task.",
|
|
114
|
-
},
|
|
115
|
-
project_path: { type: "string", description: "Project root path." },
|
|
116
|
-
context: {
|
|
117
|
-
type: "string",
|
|
118
|
-
description: "JSON string with worktree_path / branch / type etc.",
|
|
119
|
-
},
|
|
120
|
-
tags: {
|
|
121
|
-
type: "array",
|
|
122
|
-
items: { type: "string" },
|
|
123
|
-
description: "Task tags.",
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
required: ["title"],
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
name: "task_get",
|
|
131
|
-
description: "Get one task's full detail, including its operation records.",
|
|
132
|
-
inputSchema: {
|
|
133
|
-
type: "object",
|
|
134
|
-
properties: { id: { type: "number", description: "Task id." } },
|
|
135
|
-
required: ["id"],
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: "task_list",
|
|
140
|
-
description: "List tasks. Supports filtering by status / priority / type.",
|
|
141
|
-
inputSchema: {
|
|
142
|
-
type: "object",
|
|
143
|
-
properties: {
|
|
144
|
-
status: {
|
|
145
|
-
type: "string",
|
|
146
|
-
enum: ["todo", "active", "completed", "paused", "cancelled", "archived"],
|
|
147
|
-
},
|
|
148
|
-
priority: { type: "string", enum: ["low", "medium", "high"] },
|
|
149
|
-
type: { type: "string", enum: ["normal", "cycle", "longterm"] },
|
|
150
|
-
limit: { type: "number", description: "Max rows (default 20)." },
|
|
151
|
-
offset: { type: "number", description: "Row offset." },
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
name: "task_update",
|
|
157
|
-
description:
|
|
158
|
-
"Update a task's status, progress or description. Report progress as you go, not only at the end.",
|
|
159
|
-
inputSchema: {
|
|
160
|
-
type: "object",
|
|
161
|
-
properties: {
|
|
162
|
-
id: { type: "number", description: "Task id." },
|
|
163
|
-
status: {
|
|
164
|
-
type: "string",
|
|
165
|
-
enum: ["todo", "active", "completed", "paused", "cancelled", "archived"],
|
|
166
|
-
},
|
|
167
|
-
progress: { type: "number", description: "0-100." },
|
|
168
|
-
current_status: { type: "string", description: "One sentence: where you are right now." },
|
|
169
|
-
description: { type: "string", description: "Replace the description." },
|
|
170
|
-
goals_and_expected_deliverables: { type: "string", description: "Replace the goals." },
|
|
171
|
-
priority: { type: "string", enum: ["low", "medium", "high"] },
|
|
172
|
-
},
|
|
173
|
-
required: ["id"],
|
|
174
|
-
},
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
name: "task_operation_create",
|
|
178
|
-
description:
|
|
179
|
-
"Record a milestone (what was reached) and, optionally, a process summary (how you got there, 100-150 chars). Milestones mark state transitions: RED->GREEN, blocker found, decision made.",
|
|
180
|
-
inputSchema: {
|
|
181
|
-
type: "object",
|
|
182
|
-
properties: {
|
|
183
|
-
task_id: { type: "number", description: "Task id." },
|
|
184
|
-
milestone_type: {
|
|
185
|
-
type: "string",
|
|
186
|
-
enum: [
|
|
187
|
-
"create",
|
|
188
|
-
"progress",
|
|
189
|
-
"milestone",
|
|
190
|
-
"problem",
|
|
191
|
-
"solution",
|
|
192
|
-
"decision",
|
|
193
|
-
"review",
|
|
194
|
-
"completed",
|
|
195
|
-
],
|
|
196
|
-
},
|
|
197
|
-
milestone_title: { type: "string", description: "One-line milestone title." },
|
|
198
|
-
milestone_description: { type: "string", description: "What was reached." },
|
|
199
|
-
process_description: {
|
|
200
|
-
type: "string",
|
|
201
|
-
description: "How you got there. 100-150 characters, strictly.",
|
|
202
|
-
},
|
|
203
|
-
},
|
|
204
|
-
required: ["task_id", "milestone_type", "milestone_title"],
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
name: "task_complete",
|
|
209
|
-
description:
|
|
210
|
-
"Close out a task. Provide deliverable_storage_path so the outcome is traceable.",
|
|
211
|
-
inputSchema: {
|
|
212
|
-
type: "object",
|
|
213
|
-
properties: {
|
|
214
|
-
id: { type: "number", description: "Task id." },
|
|
215
|
-
deliverable_storage_path: {
|
|
216
|
-
type: "string",
|
|
217
|
-
description: "Where the work product lives (path / URL / branch).",
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
required: ["id"],
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
name: "task_search",
|
|
225
|
-
description:
|
|
226
|
-
"Search tasks by keywords across title, description, goals, tags and operation records.",
|
|
227
|
-
inputSchema: {
|
|
228
|
-
type: "object",
|
|
229
|
-
properties: {
|
|
230
|
-
keywords: {
|
|
231
|
-
type: "array",
|
|
232
|
-
items: { type: "string" },
|
|
233
|
-
description: "Keywords (AND logic).",
|
|
234
|
-
},
|
|
235
|
-
limit: { type: "number" },
|
|
236
|
-
},
|
|
237
|
-
required: ["keywords"],
|
|
238
|
-
},
|
|
239
|
-
},
|
|
240
|
-
]);
|
|
50
|
+
export const MCP_TOOLS = Object.freeze(
|
|
51
|
+
createTaskMcpToolDefinitions(
|
|
52
|
+
new TaskStoreBackend(createSQLiteTaskPort(new SQLiteTaskStore(":memory:"))),
|
|
53
|
+
),
|
|
54
|
+
);
|