@agentskit/doc-bridge 1.2.4 → 1.2.6
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/CHANGELOG.md +13 -0
- package/CONTRIBUTING.md +6 -0
- package/PRIVACY.md +38 -0
- package/README.md +21 -0
- package/SECURITY.md +7 -2
- package/action.yml +1 -1
- package/dist/cli/program.js +57 -27
- package/dist/cli/program.js.map +1 -1
- package/dist/index.d.ts +41 -9
- package/dist/index.js +57 -27
- package/dist/index.js.map +1 -1
- package/docs/mcp.md +16 -0
- package/mcpb/.mcpbignore +8 -0
- package/mcpb/icon.png +0 -0
- package/mcpb/manifest.json +96 -0
- package/package.json +11 -10
- package/src/mcp/server.ts +58 -26
- package/src/version.ts +1 -1
package/docs/mcp.md
CHANGED
|
@@ -43,6 +43,19 @@ Or with a global/local bin:
|
|
|
43
43
|
|
|
44
44
|
Run from the repo root (or pass config discovery that resolves to it). Always `ak-docs index` after doc changes (or gate in CI).
|
|
45
45
|
|
|
46
|
+
## Claude Desktop MCP Bundle
|
|
47
|
+
|
|
48
|
+
Maintainers can build the local desktop extension from a clean checkout:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pnpm install --frozen-lockfile
|
|
52
|
+
pnpm mcpb:pack
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The bundle asks the user to select the repository's `doc-bridge.config.json` and uses that file's directory as the project boundary. It contains a self-contained MCP runtime rather than the optional RAG, chat, or model-provider packages. The build validates the manifest, checks the archive inventory, and exercises all eight tools from the staged runtime.
|
|
56
|
+
|
|
57
|
+
The stdio server accepts the newline-delimited JSON transport used by current MCP clients and the legacy `Content-Length` framing used by older integrations. Responses use the same framing as each request.
|
|
58
|
+
|
|
46
59
|
## Tools
|
|
47
60
|
|
|
48
61
|
| Tool | Purpose |
|
|
@@ -53,6 +66,9 @@ Run from the repo root (or pass config discovery that resolves to it). Always `a
|
|
|
53
66
|
| `gate.status` | Freshness / configured gates |
|
|
54
67
|
| `retriever.query` | Local retriever chunks |
|
|
55
68
|
| `memory.classify` / `memory.promoteDraft` | Memory pipeline |
|
|
69
|
+
| `registry.topology` | Static curator and delegate topology |
|
|
70
|
+
|
|
71
|
+
Every tool is annotated read-only. None of these MCP calls writes project files or publishes a memory promotion.
|
|
56
72
|
|
|
57
73
|
## Agent guidance (paste into AGENTS.md)
|
|
58
74
|
|
package/mcpb/.mcpbignore
ADDED
package/mcpb/icon.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": "0.3",
|
|
3
|
+
"name": "doc-bridge",
|
|
4
|
+
"display_name": "Doc Bridge",
|
|
5
|
+
"version": "1.2.6",
|
|
6
|
+
"description": "Deterministic repository handoffs for coding agents, running locally without an LLM or API key.",
|
|
7
|
+
"long_description": "Doc Bridge turns a repository's own documentation and ownership metadata into deterministic handoffs: where an agent should start, which paths it may edit, which checks it must run, and when a human must take over. The local connector exposes the same read-only contract available through Doc Bridge CLI and CI.",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "AgentsKit",
|
|
10
|
+
"url": "https://agentskit.io"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/AgentsKit-io/doc-bridge.git"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://doc-bridge.agentskit.io/",
|
|
17
|
+
"documentation": "https://doc-bridge.agentskit.io/docs/mcp",
|
|
18
|
+
"support": "https://github.com/AgentsKit-io/doc-bridge/issues",
|
|
19
|
+
"icon": "icon.png",
|
|
20
|
+
"server": {
|
|
21
|
+
"type": "node",
|
|
22
|
+
"entry_point": "server/ak-docs.js",
|
|
23
|
+
"mcp_config": {
|
|
24
|
+
"command": "node",
|
|
25
|
+
"args": [
|
|
26
|
+
"${__dirname}/server/ak-docs.js",
|
|
27
|
+
"mcp",
|
|
28
|
+
"--config",
|
|
29
|
+
"${user_config.project_config}"
|
|
30
|
+
],
|
|
31
|
+
"env": {}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"tools": [
|
|
35
|
+
{
|
|
36
|
+
"name": "handoff.resolve",
|
|
37
|
+
"description": "Resolve a package or ownership id to its deterministic AgentHandoff."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "doc.search",
|
|
41
|
+
"description": "Search the deterministic Doc Bridge index for repository documentation."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "doc.get",
|
|
45
|
+
"description": "Read one indexed agent documentation file by id or indexed path."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "gate.status",
|
|
49
|
+
"description": "Evaluate documentation gates without writing files."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "retriever.query",
|
|
53
|
+
"description": "Return relevant local Doc Bridge index chunks for a query."
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "memory.classify",
|
|
57
|
+
"description": "Classify local memory candidates into agent, human, playbook, or discard routes."
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "memory.promoteDraft",
|
|
61
|
+
"description": "Build a reviewable draft promotion body from local memory candidates without publishing it."
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "registry.topology",
|
|
65
|
+
"description": "Return the static Doc Bridge curator and delegate topology."
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"tools_generated": false,
|
|
69
|
+
"keywords": [
|
|
70
|
+
"coding-agents",
|
|
71
|
+
"documentation",
|
|
72
|
+
"handoff",
|
|
73
|
+
"repository",
|
|
74
|
+
"developer-tools"
|
|
75
|
+
],
|
|
76
|
+
"license": "MIT",
|
|
77
|
+
"privacy_policies": [
|
|
78
|
+
"https://github.com/AgentsKit-io/doc-bridge/blob/master/PRIVACY.md"
|
|
79
|
+
],
|
|
80
|
+
"compatibility": {
|
|
81
|
+
"platforms": [
|
|
82
|
+
"darwin"
|
|
83
|
+
],
|
|
84
|
+
"runtimes": {
|
|
85
|
+
"node": ">=22"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"user_config": {
|
|
89
|
+
"project_config": {
|
|
90
|
+
"type": "file",
|
|
91
|
+
"title": "Doc Bridge configuration",
|
|
92
|
+
"description": "Select the doc-bridge.config.json file at the root of the repository Doc Bridge may read.",
|
|
93
|
+
"required": true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentskit/doc-bridge",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"mcpName": "io.github.AgentsKit-io/doc-bridge",
|
|
5
5
|
"description": "Human↔agent documentation bridge — deterministic handoffs, doc-site links, memory→docs, optional AgentsKit RAG/chat.",
|
|
6
6
|
"type": "module",
|
|
@@ -31,11 +31,13 @@
|
|
|
31
31
|
"docs",
|
|
32
32
|
"examples",
|
|
33
33
|
"README.md",
|
|
34
|
+
"PRIVACY.md",
|
|
34
35
|
"CONTRIBUTING.md",
|
|
35
36
|
"SECURITY.md",
|
|
36
37
|
"CODE_OF_CONDUCT.md",
|
|
37
38
|
"CHANGELOG.md",
|
|
38
39
|
"LICENSE",
|
|
40
|
+
"mcpb",
|
|
39
41
|
"tsup.config.ts",
|
|
40
42
|
"tsconfig.json",
|
|
41
43
|
"src"
|
|
@@ -53,6 +55,11 @@
|
|
|
53
55
|
"smoke:docsites": "node scripts/smoke-docsites.mjs",
|
|
54
56
|
"smoke:real-docsites": "node scripts/smoke-real-docsites.mjs",
|
|
55
57
|
"smoke:ollama": "node scripts/smoke-ollama.mjs",
|
|
58
|
+
"mcpb:stage": "npm run build && node scripts/build-mcpb.mjs stage",
|
|
59
|
+
"mcpb:validate": "node scripts/build-mcpb.mjs validate",
|
|
60
|
+
"mcpb:smoke": "node scripts/smoke-mcpb.mjs",
|
|
61
|
+
"mcpb:pack": "npm run mcpb:stage && npm run mcpb:smoke && node scripts/build-mcpb.mjs pack",
|
|
62
|
+
"test:mcpb": "node --test scripts/mcpb-contract.test.mjs",
|
|
56
63
|
"coverage:badge": "node scripts/update-coverage-badge.mjs",
|
|
57
64
|
"changeset": "changeset",
|
|
58
65
|
"version-packages": "changeset version && node scripts/sync-version.mjs",
|
|
@@ -132,6 +139,7 @@
|
|
|
132
139
|
"@agentskit/core": "1.12.3",
|
|
133
140
|
"@agentskit/ink": "0.10.4",
|
|
134
141
|
"@agentskit/react": "0.7.4",
|
|
142
|
+
"@anthropic-ai/mcpb": "2.1.2",
|
|
135
143
|
"@changesets/cli": "^2.31.0",
|
|
136
144
|
"@lhci/cli": "^0.15.1",
|
|
137
145
|
"@playwright/test": "1.61.1",
|
|
@@ -140,11 +148,12 @@
|
|
|
140
148
|
"@types/react": "19.2.17",
|
|
141
149
|
"@types/react-dom": "19.2.3",
|
|
142
150
|
"@vitest/coverage-v8": "4.1.10",
|
|
151
|
+
"esbuild": "^0.28.1",
|
|
143
152
|
"fumadocs-core": "15.6.5",
|
|
144
153
|
"fumadocs-mdx": "11.6.4",
|
|
145
154
|
"fumadocs-ui": "15.6.5",
|
|
146
155
|
"lucide-react": "0.460.0",
|
|
147
|
-
"next": "15.5.
|
|
156
|
+
"next": "15.5.21",
|
|
148
157
|
"react": "19.2.0",
|
|
149
158
|
"react-dom": "19.2.0",
|
|
150
159
|
"tailwindcss": "4.3.2",
|
|
@@ -152,14 +161,6 @@
|
|
|
152
161
|
"typescript": "^6.0.3",
|
|
153
162
|
"vitest": "^4.1.9"
|
|
154
163
|
},
|
|
155
|
-
"pnpm": {
|
|
156
|
-
"overrides": {
|
|
157
|
-
"esbuild": "^0.28.1",
|
|
158
|
-
"postcss": "8.5.19",
|
|
159
|
-
"tmp": "0.2.7",
|
|
160
|
-
"uuid": "11.1.1"
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
164
|
"directories": {
|
|
164
165
|
"doc": "docs",
|
|
165
166
|
"example": "examples",
|
package/src/mcp/server.ts
CHANGED
|
@@ -30,7 +30,9 @@ type McpContext = {
|
|
|
30
30
|
export const MCP_TOOLS = [
|
|
31
31
|
{
|
|
32
32
|
name: 'handoff.resolve',
|
|
33
|
-
|
|
33
|
+
title: 'Resolve repository handoff',
|
|
34
|
+
description: 'Resolve a package or ownership id to its deterministic AgentHandoff.',
|
|
35
|
+
annotations: { readOnlyHint: true },
|
|
34
36
|
inputSchema: {
|
|
35
37
|
type: 'object',
|
|
36
38
|
properties: { id: { type: 'string' }, kind: { type: 'string', enum: ['package', 'ownership'] } },
|
|
@@ -39,7 +41,9 @@ export const MCP_TOOLS = [
|
|
|
39
41
|
},
|
|
40
42
|
{
|
|
41
43
|
name: 'doc.search',
|
|
42
|
-
|
|
44
|
+
title: 'Search repository documentation',
|
|
45
|
+
description: 'Search the deterministic Doc Bridge index for repository documentation.',
|
|
46
|
+
annotations: { readOnlyHint: true },
|
|
43
47
|
inputSchema: {
|
|
44
48
|
type: 'object',
|
|
45
49
|
properties: { term: { type: 'string' }, limit: { type: 'number' } },
|
|
@@ -48,7 +52,9 @@ export const MCP_TOOLS = [
|
|
|
48
52
|
},
|
|
49
53
|
{
|
|
50
54
|
name: 'doc.get',
|
|
51
|
-
|
|
55
|
+
title: 'Read indexed documentation',
|
|
56
|
+
description: 'Read one indexed agent documentation file by id or indexed path.',
|
|
57
|
+
annotations: { readOnlyHint: true },
|
|
52
58
|
inputSchema: {
|
|
53
59
|
type: 'object',
|
|
54
60
|
properties: { id: { type: 'string' }, path: { type: 'string' } },
|
|
@@ -56,12 +62,16 @@ export const MCP_TOOLS = [
|
|
|
56
62
|
},
|
|
57
63
|
{
|
|
58
64
|
name: 'gate.status',
|
|
59
|
-
|
|
65
|
+
title: 'Check documentation gates',
|
|
66
|
+
description: 'Evaluate documentation gates without writing files.',
|
|
67
|
+
annotations: { readOnlyHint: true },
|
|
60
68
|
inputSchema: { type: 'object', properties: {} },
|
|
61
69
|
},
|
|
62
70
|
{
|
|
63
71
|
name: 'retriever.query',
|
|
64
|
-
|
|
72
|
+
title: 'Retrieve documentation context',
|
|
73
|
+
description: 'Return relevant local Doc Bridge index chunks for a query.',
|
|
74
|
+
annotations: { readOnlyHint: true },
|
|
65
75
|
inputSchema: {
|
|
66
76
|
type: 'object',
|
|
67
77
|
properties: { query: { type: 'string' }, limit: { type: 'number' } },
|
|
@@ -70,17 +80,23 @@ export const MCP_TOOLS = [
|
|
|
70
80
|
},
|
|
71
81
|
{
|
|
72
82
|
name: 'memory.classify',
|
|
73
|
-
|
|
83
|
+
title: 'Classify memory candidates',
|
|
84
|
+
description: 'Classify local memory candidates into agent, human, playbook, or discard routes.',
|
|
85
|
+
annotations: { readOnlyHint: true },
|
|
74
86
|
inputSchema: { type: 'object', properties: {} },
|
|
75
87
|
},
|
|
76
88
|
{
|
|
77
89
|
name: 'memory.promoteDraft',
|
|
78
|
-
|
|
90
|
+
title: 'Draft memory promotion',
|
|
91
|
+
description: 'Build a reviewable draft promotion body from local memory candidates without publishing it.',
|
|
92
|
+
annotations: { readOnlyHint: true },
|
|
79
93
|
inputSchema: { type: 'object', properties: {} },
|
|
80
94
|
},
|
|
81
95
|
{
|
|
82
96
|
name: 'registry.topology',
|
|
83
|
-
|
|
97
|
+
title: 'Inspect registry topology',
|
|
98
|
+
description: 'Return the static Doc Bridge curator and delegate topology.',
|
|
99
|
+
annotations: { readOnlyHint: true },
|
|
84
100
|
inputSchema: { type: 'object', properties: {} },
|
|
85
101
|
},
|
|
86
102
|
] as const
|
|
@@ -223,12 +239,14 @@ export const handleMcpRequest = (ctx: McpContext, request: JsonRpcRequest): unkn
|
|
|
223
239
|
throw new Error(`Unsupported MCP method "${request.method ?? ''}"`)
|
|
224
240
|
}
|
|
225
241
|
|
|
226
|
-
|
|
242
|
+
type StdioFraming = 'content-length' | 'json-line'
|
|
243
|
+
|
|
244
|
+
const writeFrame = (payload: unknown, framing: StdioFraming): void => {
|
|
227
245
|
const body = JSON.stringify(payload)
|
|
228
|
-
process.stdout.write(`Content-Length: ${Buffer.byteLength(body)}\r\n\r\n${body}`)
|
|
246
|
+
process.stdout.write(framing === 'json-line' ? `${body}\n` : `Content-Length: ${Buffer.byteLength(body)}\r\n\r\n${body}`)
|
|
229
247
|
}
|
|
230
248
|
|
|
231
|
-
const respond = (ctx: McpContext, request: JsonRpcRequest): void => {
|
|
249
|
+
const respond = (ctx: McpContext, request: JsonRpcRequest, framing: StdioFraming): void => {
|
|
232
250
|
if (request.id === undefined) {
|
|
233
251
|
try {
|
|
234
252
|
handleMcpRequest(ctx, request)
|
|
@@ -240,13 +258,13 @@ const respond = (ctx: McpContext, request: JsonRpcRequest): void => {
|
|
|
240
258
|
|
|
241
259
|
try {
|
|
242
260
|
const result = handleMcpRequest(ctx, request)
|
|
243
|
-
writeFrame({ jsonrpc: '2.0', id: request.id, result: result ?? {} })
|
|
261
|
+
writeFrame({ jsonrpc: '2.0', id: request.id, result: result ?? {} }, framing)
|
|
244
262
|
} catch (error) {
|
|
245
263
|
writeFrame({
|
|
246
264
|
jsonrpc: '2.0',
|
|
247
265
|
id: request.id,
|
|
248
266
|
error: { code: -32000, message: error instanceof Error ? error.message : String(error) },
|
|
249
|
-
})
|
|
267
|
+
}, framing)
|
|
250
268
|
}
|
|
251
269
|
}
|
|
252
270
|
|
|
@@ -255,21 +273,35 @@ export const startMcpStdioServer = (ctx: McpContext): void => {
|
|
|
255
273
|
process.stdin.on('data', (chunk: Buffer) => {
|
|
256
274
|
buffer = Buffer.concat([buffer, chunk])
|
|
257
275
|
while (true) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
276
|
+
if (/^content-length:/i.test(buffer.subarray(0, Math.min(buffer.length, 32)).toString('utf8'))) {
|
|
277
|
+
const headerEnd = buffer.indexOf('\r\n\r\n')
|
|
278
|
+
if (headerEnd === -1) return
|
|
279
|
+
const header = buffer.subarray(0, headerEnd).toString('utf8')
|
|
280
|
+
const match = /content-length:\s*(\d+)/i.exec(header)
|
|
281
|
+
if (!match?.[1]) {
|
|
282
|
+
buffer = buffer.subarray(headerEnd + 4)
|
|
283
|
+
continue
|
|
284
|
+
}
|
|
285
|
+
const length = Number(match[1])
|
|
286
|
+
const bodyStart = headerEnd + 4
|
|
287
|
+
const bodyEnd = bodyStart + length
|
|
288
|
+
if (buffer.length < bodyEnd) return
|
|
289
|
+
const raw = buffer.subarray(bodyStart, bodyEnd).toString('utf8')
|
|
290
|
+
buffer = buffer.subarray(bodyEnd)
|
|
291
|
+
respond(ctx, JSON.parse(raw) as JsonRpcRequest, 'content-length')
|
|
264
292
|
continue
|
|
265
293
|
}
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
294
|
+
|
|
295
|
+
const lineEnd = buffer.indexOf('\n')
|
|
296
|
+
if (lineEnd === -1) return
|
|
297
|
+
const raw = buffer.subarray(0, lineEnd).toString('utf8').trim()
|
|
298
|
+
buffer = buffer.subarray(lineEnd + 1)
|
|
299
|
+
if (!raw) continue
|
|
300
|
+
try {
|
|
301
|
+
respond(ctx, JSON.parse(raw) as JsonRpcRequest, 'json-line')
|
|
302
|
+
} catch {
|
|
303
|
+
writeFrame({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } }, 'json-line')
|
|
304
|
+
}
|
|
273
305
|
}
|
|
274
306
|
})
|
|
275
307
|
process.stdin.resume()
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '1.2.
|
|
1
|
+
export const PACKAGE_VERSION = '1.2.6'
|