docorbit 0.1.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/LICENSE +21 -0
- package/README.md +660 -0
- package/apps/cli/bin/docorbit.js +8 -0
- package/apps/cli/src/commands/add.ts +44 -0
- package/apps/cli/src/commands/api.ts +38 -0
- package/apps/cli/src/commands/context.ts +47 -0
- package/apps/cli/src/commands/dashboard.ts +55 -0
- package/apps/cli/src/commands/diff.ts +30 -0
- package/apps/cli/src/commands/evaluate.ts +133 -0
- package/apps/cli/src/commands/examples.ts +39 -0
- package/apps/cli/src/commands/export.ts +89 -0
- package/apps/cli/src/commands/impact.ts +31 -0
- package/apps/cli/src/commands/init.ts +69 -0
- package/apps/cli/src/commands/inspect.ts +30 -0
- package/apps/cli/src/commands/mcp.ts +72 -0
- package/apps/cli/src/commands/pitfalls.ts +38 -0
- package/apps/cli/src/commands/recipes.ts +35 -0
- package/apps/cli/src/commands/search.ts +48 -0
- package/apps/cli/src/commands/update.ts +73 -0
- package/apps/cli/src/commands/verify.ts +48 -0
- package/apps/cli/src/formatters/colors.ts +23 -0
- package/apps/cli/src/formatters/inspection.ts +102 -0
- package/apps/cli/src/formatters/knowledge.ts +272 -0
- package/apps/cli/src/formatters/retrieval.ts +74 -0
- package/apps/cli/src/formatters/terminal.ts +6 -0
- package/apps/cli/src/formatters/verification.ts +126 -0
- package/apps/cli/src/index.ts +409 -0
- package/bin/docorbit.js +8 -0
- package/package.json +46 -0
- package/packages/core/src/dashboard/server.ts +314 -0
- package/packages/core/src/dashboard/ui.ts +586 -0
- package/packages/core/src/implementation-service.ts +451 -0
- package/packages/core/src/index.ts +7 -0
- package/packages/core/src/inspector.ts +71 -0
- package/packages/core/src/pipeline.ts +331 -0
- package/packages/crawler/src/config.ts +12 -0
- package/packages/crawler/src/fetcher.ts +185 -0
- package/packages/crawler/src/index.ts +2 -0
- package/packages/discovery/src/index.ts +31 -0
- package/packages/discovery/src/provider.ts +47 -0
- package/packages/discovery/src/providers/generic.ts +98 -0
- package/packages/discovery/src/providers/github.ts +61 -0
- package/packages/discovery/src/providers/llms-txt.ts +73 -0
- package/packages/discovery/src/providers/markdown.ts +48 -0
- package/packages/discovery/src/providers/openapi.ts +91 -0
- package/packages/discovery/src/providers/sitemap.ts +62 -0
- package/packages/discovery/src/providers/skill.ts +54 -0
- package/packages/discovery/src/ranker.ts +123 -0
- package/packages/evaluation/src/dataset.ts +963 -0
- package/packages/evaluation/src/index.ts +8 -0
- package/packages/evaluation/src/runner.ts +241 -0
- package/packages/evaluation/src/strategies/context7-runner.ts +269 -0
- package/packages/evaluation/src/strategies/docorbit-runner.ts +228 -0
- package/packages/evaluation/src/strategies/firecrawl-runner.ts +172 -0
- package/packages/evaluation/src/strategies/web-search-runner.ts +194 -0
- package/packages/evaluation/src/types.ts +34 -0
- package/packages/evaluation/src/version-matcher.ts +73 -0
- package/packages/export/src/agents-md.ts +200 -0
- package/packages/export/src/claude-md.ts +141 -0
- package/packages/export/src/docs-map.ts +150 -0
- package/packages/export/src/index.ts +6 -0
- package/packages/export/src/llms-txt.ts +96 -0
- package/packages/export/src/service.ts +250 -0
- package/packages/export/src/skill-md.ts +128 -0
- package/packages/mcp/src/index.ts +46 -0
- package/packages/mcp/src/resources/index.ts +189 -0
- package/packages/mcp/src/server.ts +278 -0
- package/packages/mcp/src/tools/analyze-impact.ts +74 -0
- package/packages/mcp/src/tools/check-api.ts +86 -0
- package/packages/mcp/src/tools/diff-docs.ts +68 -0
- package/packages/mcp/src/tools/export-context.ts +73 -0
- package/packages/mcp/src/tools/find-api.ts +99 -0
- package/packages/mcp/src/tools/find-example.ts +100 -0
- package/packages/mcp/src/tools/find-pitfall.ts +94 -0
- package/packages/mcp/src/tools/find-recipe.ts +98 -0
- package/packages/mcp/src/tools/get-doc.ts +130 -0
- package/packages/mcp/src/tools/get-docs-map.ts +64 -0
- package/packages/mcp/src/tools/get-version.ts +118 -0
- package/packages/mcp/src/tools/implementation-context.ts +88 -0
- package/packages/mcp/src/tools/index.ts +59 -0
- package/packages/mcp/src/tools/list-sources.ts +85 -0
- package/packages/mcp/src/tools/search-docs.ts +123 -0
- package/packages/mcp/src/tools/types.ts +28 -0
- package/packages/mcp/src/transports/http.ts +256 -0
- package/packages/mcp/src/transports/stdio.ts +105 -0
- package/packages/mcp/src/transports/types.ts +6 -0
- package/packages/mcp/src/types.ts +102 -0
- package/packages/normalizer/src/example-indexer.ts +240 -0
- package/packages/normalizer/src/html.ts +253 -0
- package/packages/normalizer/src/index.ts +8 -0
- package/packages/normalizer/src/llms.ts +83 -0
- package/packages/normalizer/src/openapi/endpoint-parser.ts +406 -0
- package/packages/normalizer/src/openapi/schema-resolver.ts +111 -0
- package/packages/normalizer/src/openapi.ts +2 -0
- package/packages/normalizer/src/page.ts +184 -0
- package/packages/normalizer/src/pitfall-extractor.ts +190 -0
- package/packages/normalizer/src/slicer.ts +455 -0
- package/packages/retrieval/src/engine.ts +120 -0
- package/packages/retrieval/src/index.ts +7 -0
- package/packages/retrieval/src/intent.ts +43 -0
- package/packages/retrieval/src/packer.ts +145 -0
- package/packages/retrieval/src/recipe-engine.ts +313 -0
- package/packages/retrieval/src/scorer.ts +139 -0
- package/packages/retrieval/src/weights.ts +31 -0
- package/packages/security/src/annotations.ts +112 -0
- package/packages/security/src/index.ts +2 -0
- package/packages/security/src/ssrf.ts +153 -0
- package/packages/shared/src/errors.ts +53 -0
- package/packages/shared/src/hashing.ts +23 -0
- package/packages/shared/src/index.ts +3 -0
- package/packages/shared/src/types.ts +881 -0
- package/packages/storage/src/db.ts +72 -0
- package/packages/storage/src/index.ts +11 -0
- package/packages/storage/src/interfaces.ts +115 -0
- package/packages/storage/src/repositories/api-repository.ts +219 -0
- package/packages/storage/src/repositories/chunk-repository.ts +316 -0
- package/packages/storage/src/repositories/example-repository.ts +206 -0
- package/packages/storage/src/repositories/page-repository.ts +205 -0
- package/packages/storage/src/repositories/pitfall-repository.ts +188 -0
- package/packages/storage/src/repositories/source-repository.ts +205 -0
- package/packages/storage/src/repository.ts +256 -0
- package/packages/storage/src/schema.ts +269 -0
- package/packages/storage/src/search-tokens.ts +28 -0
- package/packages/verification/src/diff-engine.ts +258 -0
- package/packages/verification/src/extractor.ts +339 -0
- package/packages/verification/src/impact-scanner.ts +203 -0
- package/packages/verification/src/index.ts +5 -0
- package/packages/verification/src/services.ts +238 -0
- package/packages/verification/src/verifier.ts +375 -0
- package/packages/workspace/src/detector.ts +143 -0
- package/packages/workspace/src/ecosystems/cargo.ts +84 -0
- package/packages/workspace/src/ecosystems/composer.ts +42 -0
- package/packages/workspace/src/ecosystems/go.ts +54 -0
- package/packages/workspace/src/ecosystems/index.ts +34 -0
- package/packages/workspace/src/ecosystems/maven.ts +34 -0
- package/packages/workspace/src/ecosystems/npm.ts +83 -0
- package/packages/workspace/src/ecosystems/pub.ts +40 -0
- package/packages/workspace/src/ecosystems/pypi.ts +100 -0
- package/packages/workspace/src/ecosystems/rubygems.ts +30 -0
- package/packages/workspace/src/ecosystems/types.ts +18 -0
- package/packages/workspace/src/index.ts +5 -0
- package/packages/workspace/src/lockfile.ts +194 -0
- package/packages/workspace/src/resolver.ts +234 -0
- package/packages/workspace/src/semver.ts +259 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import type { DocOrbitRepository } from '../../storage/src/index.ts';
|
|
2
|
+
import type { WorkspaceResolver } from '../../workspace/src/index.ts';
|
|
3
|
+
import { ImplementationContextService } from '../../core/src/index.ts';
|
|
4
|
+
import {
|
|
5
|
+
VerificationService,
|
|
6
|
+
DiffService,
|
|
7
|
+
ImpactAnalysisService,
|
|
8
|
+
} from '../../verification/src/index.ts';
|
|
9
|
+
import { ExportService } from '../../export/src/index.ts';
|
|
10
|
+
import type {
|
|
11
|
+
JsonRpcRequest,
|
|
12
|
+
JsonRpcResponse,
|
|
13
|
+
McpTool,
|
|
14
|
+
InitializeResult,
|
|
15
|
+
} from './types.ts';
|
|
16
|
+
import { JSONRPC_ERRORS } from './types.ts';
|
|
17
|
+
import type { McpContext, McpToolHandler } from './tools/types.ts';
|
|
18
|
+
import { createDefaultTools } from './tools/index.ts';
|
|
19
|
+
import { McpResourceManager } from './resources/index.ts';
|
|
20
|
+
|
|
21
|
+
export interface McpServerOptions {
|
|
22
|
+
repo: DocOrbitRepository;
|
|
23
|
+
resolver?: WorkspaceResolver;
|
|
24
|
+
projectDir?: string;
|
|
25
|
+
serverName?: string;
|
|
26
|
+
serverVersion?: string;
|
|
27
|
+
tools?: Map<string, McpToolHandler>;
|
|
28
|
+
maxResourceBytes?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class McpServer {
|
|
32
|
+
private repo: DocOrbitRepository;
|
|
33
|
+
private resolver?: WorkspaceResolver;
|
|
34
|
+
private projectDir?: string;
|
|
35
|
+
private serverName: string;
|
|
36
|
+
private serverVersion: string;
|
|
37
|
+
private tools: Map<string, McpToolHandler>;
|
|
38
|
+
private resourceManager: McpResourceManager;
|
|
39
|
+
private context: McpContext;
|
|
40
|
+
private initialized: boolean = false;
|
|
41
|
+
|
|
42
|
+
constructor(options: McpServerOptions) {
|
|
43
|
+
this.repo = options.repo;
|
|
44
|
+
this.resolver = options.resolver;
|
|
45
|
+
this.projectDir = options.projectDir;
|
|
46
|
+
this.serverName = options.serverName || 'docorbit-mcp';
|
|
47
|
+
this.serverVersion = options.serverVersion || '0.5.0';
|
|
48
|
+
|
|
49
|
+
this.tools = options.tools || createDefaultTools();
|
|
50
|
+
this.resourceManager = new McpResourceManager(this.repo, {
|
|
51
|
+
maxResourceBytes: options.maxResourceBytes,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const implService = new ImplementationContextService(this.repo, this.resolver);
|
|
55
|
+
const verificationService = new VerificationService(this.repo);
|
|
56
|
+
const diffService = new DiffService(this.repo);
|
|
57
|
+
const impactService = new ImpactAnalysisService(this.repo);
|
|
58
|
+
const exportService = new ExportService(this.repo);
|
|
59
|
+
|
|
60
|
+
this.context = {
|
|
61
|
+
repo: this.repo,
|
|
62
|
+
resolver: this.resolver,
|
|
63
|
+
projectDir: this.projectDir,
|
|
64
|
+
workspaceRoot: this.projectDir,
|
|
65
|
+
implService,
|
|
66
|
+
implementationService: implService,
|
|
67
|
+
verificationService,
|
|
68
|
+
diffService,
|
|
69
|
+
impactService,
|
|
70
|
+
exportService,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getContext(): McpContext {
|
|
75
|
+
return this.context;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getResourceManager(): McpResourceManager {
|
|
79
|
+
return this.resourceManager;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getTools(): McpTool[] {
|
|
83
|
+
return Array.from(this.tools.values()).map(h => h.definition);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async handleMessage(raw: unknown): Promise<JsonRpcResponse | null> {
|
|
87
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
88
|
+
return {
|
|
89
|
+
jsonrpc: '2.0',
|
|
90
|
+
id: null,
|
|
91
|
+
error: {
|
|
92
|
+
code: JSONRPC_ERRORS.INVALID_REQUEST,
|
|
93
|
+
message: 'Invalid JSON-RPC request: payload must be an object.',
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const msg = raw as Record<string, unknown>;
|
|
99
|
+
const id = (msg.id !== undefined ? (msg.id as string | number | null) : undefined);
|
|
100
|
+
const isNotification = id === undefined;
|
|
101
|
+
|
|
102
|
+
if (msg.jsonrpc !== '2.0' || typeof msg.method !== 'string') {
|
|
103
|
+
if (isNotification) return null;
|
|
104
|
+
return {
|
|
105
|
+
jsonrpc: '2.0',
|
|
106
|
+
id: id ?? null,
|
|
107
|
+
error: {
|
|
108
|
+
code: JSONRPC_ERRORS.INVALID_REQUEST,
|
|
109
|
+
message: 'Invalid JSON-RPC 2.0 request structure: missing "jsonrpc: 2.0" or "method".',
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const method = msg.method;
|
|
115
|
+
const params = (msg.params && typeof msg.params === 'object' && !Array.isArray(msg.params))
|
|
116
|
+
? (msg.params as Record<string, unknown>)
|
|
117
|
+
: {};
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
switch (method) {
|
|
121
|
+
case 'initialize': {
|
|
122
|
+
this.initialized = true;
|
|
123
|
+
const result: InitializeResult = {
|
|
124
|
+
protocolVersion: '2024-11-05',
|
|
125
|
+
serverInfo: {
|
|
126
|
+
name: this.serverName,
|
|
127
|
+
version: this.serverVersion,
|
|
128
|
+
},
|
|
129
|
+
capabilities: {
|
|
130
|
+
tools: {
|
|
131
|
+
listChanged: false,
|
|
132
|
+
},
|
|
133
|
+
resources: {
|
|
134
|
+
subscribe: false,
|
|
135
|
+
listChanged: false,
|
|
136
|
+
},
|
|
137
|
+
logging: {},
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
return { jsonrpc: '2.0', id: id ?? null, result };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
case 'notifications/initialized': {
|
|
144
|
+
this.initialized = true;
|
|
145
|
+
return null; // Notifications have no response
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
case 'ping': {
|
|
149
|
+
if (isNotification) return null;
|
|
150
|
+
return { jsonrpc: '2.0', id: id ?? null, result: {} };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
case 'tools/list': {
|
|
154
|
+
if (isNotification) return null;
|
|
155
|
+
return {
|
|
156
|
+
jsonrpc: '2.0',
|
|
157
|
+
id: id ?? null,
|
|
158
|
+
result: {
|
|
159
|
+
tools: this.getTools(),
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
case 'tools/call': {
|
|
165
|
+
if (isNotification) return null;
|
|
166
|
+
const toolName = typeof params.name === 'string' ? params.name : '';
|
|
167
|
+
const toolArgs = (params.arguments && typeof params.arguments === 'object' && !Array.isArray(params.arguments))
|
|
168
|
+
? (params.arguments as Record<string, unknown>)
|
|
169
|
+
: {};
|
|
170
|
+
|
|
171
|
+
const handler = this.tools.get(toolName);
|
|
172
|
+
if (!handler) {
|
|
173
|
+
return {
|
|
174
|
+
jsonrpc: '2.0',
|
|
175
|
+
id: id ?? null,
|
|
176
|
+
error: {
|
|
177
|
+
code: JSONRPC_ERRORS.METHOD_NOT_FOUND,
|
|
178
|
+
message: `Tool not found: "${toolName}". Available tools: ${Array.from(this.tools.keys()).join(', ')}`,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const toolResult = await handler.execute(toolArgs, this.context);
|
|
185
|
+
return {
|
|
186
|
+
jsonrpc: '2.0',
|
|
187
|
+
id: id ?? null,
|
|
188
|
+
result: toolResult,
|
|
189
|
+
};
|
|
190
|
+
} catch (toolErr) {
|
|
191
|
+
const message = toolErr instanceof Error ? toolErr.message : String(toolErr);
|
|
192
|
+
return {
|
|
193
|
+
jsonrpc: '2.0',
|
|
194
|
+
id: id ?? null,
|
|
195
|
+
result: {
|
|
196
|
+
isError: true,
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: 'text',
|
|
200
|
+
text: JSON.stringify({ error: message, failure: true }),
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
case 'resources/list': {
|
|
209
|
+
if (isNotification) return null;
|
|
210
|
+
return {
|
|
211
|
+
jsonrpc: '2.0',
|
|
212
|
+
id: id ?? null,
|
|
213
|
+
result: {
|
|
214
|
+
resources: this.resourceManager.listResources(),
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
case 'resources/read': {
|
|
220
|
+
if (isNotification) return null;
|
|
221
|
+
const uri = typeof params.uri === 'string' ? params.uri : '';
|
|
222
|
+
if (!uri) {
|
|
223
|
+
return {
|
|
224
|
+
jsonrpc: '2.0',
|
|
225
|
+
id: id ?? null,
|
|
226
|
+
error: {
|
|
227
|
+
code: JSONRPC_ERRORS.INVALID_PARAMS,
|
|
228
|
+
message: 'Missing or empty "uri" parameter for resources/read.',
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
const readResult = this.resourceManager.readResource(uri);
|
|
235
|
+
return {
|
|
236
|
+
jsonrpc: '2.0',
|
|
237
|
+
id: id ?? null,
|
|
238
|
+
result: readResult,
|
|
239
|
+
};
|
|
240
|
+
} catch (resErr) {
|
|
241
|
+
const message = resErr instanceof Error ? resErr.message : String(resErr);
|
|
242
|
+
return {
|
|
243
|
+
jsonrpc: '2.0',
|
|
244
|
+
id: id ?? null,
|
|
245
|
+
error: {
|
|
246
|
+
code: JSONRPC_ERRORS.INVALID_PARAMS,
|
|
247
|
+
message,
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
default: {
|
|
254
|
+
if (isNotification) return null;
|
|
255
|
+
return {
|
|
256
|
+
jsonrpc: '2.0',
|
|
257
|
+
id: id ?? null,
|
|
258
|
+
error: {
|
|
259
|
+
code: JSONRPC_ERRORS.METHOD_NOT_FOUND,
|
|
260
|
+
message: `Unknown or unhandled method: "${method}".`,
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
} catch (err) {
|
|
266
|
+
if (isNotification) return null;
|
|
267
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
268
|
+
return {
|
|
269
|
+
jsonrpc: '2.0',
|
|
270
|
+
id: id ?? null,
|
|
271
|
+
error: {
|
|
272
|
+
code: JSONRPC_ERRORS.INTERNAL_ERROR,
|
|
273
|
+
message: `Internal server error: ${message}`,
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { CallToolResult, McpTool } from '../types.ts';
|
|
2
|
+
import type { McpContext, McpToolHandler } from './types.ts';
|
|
3
|
+
import { ImpactAnalysisService } from '../../../verification/src/index.ts';
|
|
4
|
+
|
|
5
|
+
export class AnalyzeImpactTool implements McpToolHandler {
|
|
6
|
+
readonly definition: McpTool = {
|
|
7
|
+
name: 'analyze_impact',
|
|
8
|
+
description: 'Compare detected documentation and API changes against current project workspace files. Identifies affected files, exact line numbers, code snippets, matched patterns, and traceable reasons with certainty rankings (high, medium, heuristic).',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
project: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'Workspace root directory containing code files to analyze.',
|
|
15
|
+
},
|
|
16
|
+
fromVersion: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
description: 'Current or base documentation version (e.g. "v14").',
|
|
19
|
+
},
|
|
20
|
+
toVersion: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Target or upgraded documentation version (e.g. "v15").',
|
|
23
|
+
},
|
|
24
|
+
fromSnapshotId: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Optional base snapshot ID.',
|
|
27
|
+
},
|
|
28
|
+
toSnapshotId: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Optional target snapshot ID.',
|
|
31
|
+
},
|
|
32
|
+
sourceId: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'Optional documentation source ID filter.',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
async execute(args: Record<string, unknown>, ctx: McpContext): Promise<CallToolResult> {
|
|
41
|
+
const projectDir = typeof args.project === 'string' ? args.project : (ctx.projectDir || ctx.workspaceRoot || process.cwd());
|
|
42
|
+
const fromVersion = typeof args.fromVersion === 'string' ? args.fromVersion : undefined;
|
|
43
|
+
const toVersion = typeof args.toVersion === 'string' ? args.toVersion : undefined;
|
|
44
|
+
const fromSnapshotId = typeof args.fromSnapshotId === 'string' ? args.fromSnapshotId : undefined;
|
|
45
|
+
const toSnapshotId = typeof args.toSnapshotId === 'string' ? args.toSnapshotId : undefined;
|
|
46
|
+
const sourceId = typeof args.sourceId === 'string' ? args.sourceId : undefined;
|
|
47
|
+
|
|
48
|
+
const impactService = ctx.impactService || new ImpactAnalysisService(ctx.repo);
|
|
49
|
+
const { result, markdown } = impactService.analyzeImpact({
|
|
50
|
+
projectDir,
|
|
51
|
+
fromVersion,
|
|
52
|
+
toVersion,
|
|
53
|
+
fromSnapshotId,
|
|
54
|
+
toSnapshotId,
|
|
55
|
+
sourceId,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: JSON.stringify(
|
|
63
|
+
{
|
|
64
|
+
markdown,
|
|
65
|
+
data: result,
|
|
66
|
+
},
|
|
67
|
+
null,
|
|
68
|
+
2
|
|
69
|
+
),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { CallToolResult, McpTool } from '../types.ts';
|
|
2
|
+
import type { McpContext, McpToolHandler } from './types.ts';
|
|
3
|
+
import { VerificationService } from '../../../verification/src/index.ts';
|
|
4
|
+
|
|
5
|
+
export class CheckApiTool implements McpToolHandler {
|
|
6
|
+
readonly definition: McpTool = {
|
|
7
|
+
name: 'check_api',
|
|
8
|
+
description: 'Verify agent/generated code against indexed OpenAPI schemas and documentation. Detects invalid endpoints, wrong HTTP methods, missing required parameters, deprecations, removed APIs, version syntax conflicts, and response assumptions. Distinguishes verified, warning, mismatch, and insufficient_evidence.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
code: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'The generated code snippet, route handler, or API client call to verify.',
|
|
15
|
+
},
|
|
16
|
+
language: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
description: 'Programming language of the code (e.g. "typescript", "javascript", "python", "curl").',
|
|
19
|
+
},
|
|
20
|
+
library: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Target library or SDK name (e.g. "stripe", "next").',
|
|
23
|
+
},
|
|
24
|
+
version: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Target documentation/API version (e.g. "v14", "v15", "1.0"). If omitted, project version is auto-detected.',
|
|
27
|
+
},
|
|
28
|
+
project: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Workspace root directory to auto-resolve project dependencies and versions.',
|
|
31
|
+
},
|
|
32
|
+
filePath: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'Optional path of the file being verified for context.',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: ['code'],
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
async execute(args: Record<string, unknown>, ctx: McpContext): Promise<CallToolResult> {
|
|
42
|
+
const code = typeof args.code === 'string' ? args.code : '';
|
|
43
|
+
if (!code) {
|
|
44
|
+
return {
|
|
45
|
+
isError: true,
|
|
46
|
+
content: [{ type: 'text', text: JSON.stringify({ error: 'Missing required argument: code' }) }],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const language = typeof args.language === 'string' ? args.language : undefined;
|
|
51
|
+
const library = typeof args.library === 'string' ? args.library : undefined;
|
|
52
|
+
const version = typeof args.version === 'string' ? args.version : undefined;
|
|
53
|
+
const filePath = typeof args.filePath === 'string' ? args.filePath : undefined;
|
|
54
|
+
const projectDir =
|
|
55
|
+
(typeof args.projectDir === 'string' ? args.projectDir : undefined) ||
|
|
56
|
+
(typeof args.project === 'string' ? args.project : undefined) ||
|
|
57
|
+
ctx.projectDir ||
|
|
58
|
+
ctx.workspaceRoot;
|
|
59
|
+
|
|
60
|
+
const service = ctx.verificationService || new VerificationService(ctx.repo);
|
|
61
|
+
const { result, markdown } = service.verifyCode({
|
|
62
|
+
code,
|
|
63
|
+
language,
|
|
64
|
+
library,
|
|
65
|
+
version,
|
|
66
|
+
projectDir,
|
|
67
|
+
filePath,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: 'text',
|
|
74
|
+
text: JSON.stringify(
|
|
75
|
+
{
|
|
76
|
+
markdown,
|
|
77
|
+
data: result,
|
|
78
|
+
},
|
|
79
|
+
null,
|
|
80
|
+
2
|
|
81
|
+
),
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { CallToolResult, McpTool } from '../types.ts';
|
|
2
|
+
import type { McpContext, McpToolHandler } from './types.ts';
|
|
3
|
+
import { DiffService } from '../../../verification/src/index.ts';
|
|
4
|
+
|
|
5
|
+
export class DiffDocsTool implements McpToolHandler {
|
|
6
|
+
readonly definition: McpTool = {
|
|
7
|
+
name: 'diff_docs',
|
|
8
|
+
description: 'Compare documentation snapshots and versions to detect added, removed, modified, and deprecated API endpoints, parameters, pitfalls, and content sections. Produces deterministic diffs ignoring formatting-only changes.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
fromVersion: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'Base documentation version (e.g. "v14", "1.0").',
|
|
15
|
+
},
|
|
16
|
+
toVersion: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
description: 'Target documentation version to compare against (e.g. "v15", "2.0").',
|
|
19
|
+
},
|
|
20
|
+
fromSnapshotId: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Base snapshot ID to compare.',
|
|
23
|
+
},
|
|
24
|
+
toSnapshotId: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Target snapshot ID to compare.',
|
|
27
|
+
},
|
|
28
|
+
sourceId: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Optional documentation source ID filter.',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
async execute(args: Record<string, unknown>, ctx: McpContext): Promise<CallToolResult> {
|
|
37
|
+
const fromVersion = typeof args.fromVersion === 'string' ? args.fromVersion : undefined;
|
|
38
|
+
const toVersion = typeof args.toVersion === 'string' ? args.toVersion : undefined;
|
|
39
|
+
const fromSnapshotId = typeof args.fromSnapshotId === 'string' ? args.fromSnapshotId : undefined;
|
|
40
|
+
const toSnapshotId = typeof args.toSnapshotId === 'string' ? args.toSnapshotId : undefined;
|
|
41
|
+
const sourceId = typeof args.sourceId === 'string' ? args.sourceId : undefined;
|
|
42
|
+
|
|
43
|
+
const diffService = ctx.diffService || new DiffService(ctx.repo);
|
|
44
|
+
const { result, markdown } = diffService.diffDocs({
|
|
45
|
+
fromVersion,
|
|
46
|
+
toVersion,
|
|
47
|
+
fromSnapshotId,
|
|
48
|
+
toSnapshotId,
|
|
49
|
+
sourceId,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: 'text',
|
|
56
|
+
text: JSON.stringify(
|
|
57
|
+
{
|
|
58
|
+
markdown,
|
|
59
|
+
data: result,
|
|
60
|
+
},
|
|
61
|
+
null,
|
|
62
|
+
2
|
|
63
|
+
),
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { CallToolResult, McpTool } from '../types.ts';
|
|
2
|
+
import type { McpContext, McpToolHandler } from './types.ts';
|
|
3
|
+
import { ExportService } from '../../../export/src/index.ts';
|
|
4
|
+
import type { ExportFormat } from '../../../shared/src/index.ts';
|
|
5
|
+
|
|
6
|
+
export class ExportAgentContextTool implements McpToolHandler {
|
|
7
|
+
readonly definition: McpTool = {
|
|
8
|
+
name: 'export_agent_context',
|
|
9
|
+
description: 'Deterministically generate and export agent-native documentation context files (AGENTS.md, CLAUDE.md, skill.md, llms.txt, docs-map.md) grounded in project dependency versions and authoritative documentation.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
format: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
enum: ['agents.md', 'claude.md', 'skill.md', 'llms.txt', 'docs-map.md'],
|
|
16
|
+
description: 'Target agent file format to generate (default: "agents.md").',
|
|
17
|
+
},
|
|
18
|
+
docVersion: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Optional target documentation version (e.g. "v14", "v15").',
|
|
21
|
+
},
|
|
22
|
+
projectDir: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Optional project directory for resolving workspace dependency versions.',
|
|
25
|
+
},
|
|
26
|
+
targetSource: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Optional library or skill name label.',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ['format'],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
async execute(args: Record<string, unknown>, ctx: McpContext): Promise<CallToolResult> {
|
|
36
|
+
const rawFormat = typeof args.format === 'string' ? args.format.toLowerCase() : 'agents.md';
|
|
37
|
+
const validFormats: ExportFormat[] = ['agents.md', 'claude.md', 'skill.md', 'llms.txt', 'docs-map.md'];
|
|
38
|
+
const format = validFormats.includes(rawFormat as ExportFormat) ? (rawFormat as ExportFormat) : 'agents.md';
|
|
39
|
+
|
|
40
|
+
const docVersion = typeof args.docVersion === 'string' ? args.docVersion : undefined;
|
|
41
|
+
const projectDir = typeof args.projectDir === 'string' ? args.projectDir : ctx.projectDir || ctx.workspaceRoot;
|
|
42
|
+
const targetSource = typeof args.targetSource === 'string' ? args.targetSource : undefined;
|
|
43
|
+
|
|
44
|
+
const exportService = ctx.exportService || new ExportService(ctx.repo);
|
|
45
|
+
const result = await exportService.generateExport({
|
|
46
|
+
format,
|
|
47
|
+
docVersion,
|
|
48
|
+
projectDir,
|
|
49
|
+
targetSource,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: 'text',
|
|
56
|
+
text: JSON.stringify(
|
|
57
|
+
{
|
|
58
|
+
markdown: result.content,
|
|
59
|
+
data: {
|
|
60
|
+
format: result.format,
|
|
61
|
+
metadata: result.metadata,
|
|
62
|
+
tokenEstimate: result.metadata.tokenEstimate,
|
|
63
|
+
untrusted: true,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
null,
|
|
67
|
+
2
|
|
68
|
+
),
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { CallToolResult, McpTool } from '../types.ts';
|
|
2
|
+
import type { McpContext, McpToolHandler } from './types.ts';
|
|
3
|
+
|
|
4
|
+
export class FindApiTool implements McpToolHandler {
|
|
5
|
+
readonly definition: McpTool = {
|
|
6
|
+
name: 'find_api',
|
|
7
|
+
description: 'Lookup structured OpenAPI endpoints by path, operation ID, or keyword with exact parameters, schemas, auth, and error responses.',
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
query: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
description: 'API path or keyword search (e.g. "/v1/webhook_endpoints", "create subscription").',
|
|
14
|
+
},
|
|
15
|
+
method: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
description: 'HTTP method filter (e.g. "get", "post", "delete").',
|
|
18
|
+
enum: ['get', 'post', 'put', 'delete', 'patch', 'head', 'options'],
|
|
19
|
+
},
|
|
20
|
+
version: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Target API / documentation version filter.',
|
|
23
|
+
},
|
|
24
|
+
limit: {
|
|
25
|
+
type: 'number',
|
|
26
|
+
description: 'Maximum number of endpoints to return (default: 5).',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
required: ['query'],
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
async execute(args: Record<string, unknown>, ctx: McpContext): Promise<CallToolResult> {
|
|
34
|
+
const query = typeof args.query === 'string' ? args.query.trim() : '';
|
|
35
|
+
if (!query) {
|
|
36
|
+
return {
|
|
37
|
+
isError: true,
|
|
38
|
+
content: [{ type: 'text', text: JSON.stringify({ error: 'Missing required parameter: query' }) }],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const method = typeof args.method === 'string' ? args.method.toLowerCase() : undefined;
|
|
43
|
+
const version = typeof args.version === 'string' ? args.version : undefined;
|
|
44
|
+
const limit = typeof args.limit === 'number' && args.limit > 0 ? args.limit : 5;
|
|
45
|
+
|
|
46
|
+
const endpoints = ctx.repo.searchApiEndpoints(query, {
|
|
47
|
+
method,
|
|
48
|
+
docVersion: version,
|
|
49
|
+
limit,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (endpoints.length === 0) {
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: 'text',
|
|
57
|
+
text: JSON.stringify({
|
|
58
|
+
markdown: `### API Search for "${query}"\n\nNo matching API endpoints found.`,
|
|
59
|
+
data: { query, count: 0, endpoints: [] },
|
|
60
|
+
}, null, 2),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const lines: string[] = [`### API Intelligence for "${query}" (${endpoints.length} found)\n`];
|
|
67
|
+
for (const ep of endpoints) {
|
|
68
|
+
lines.push(`#### \`${ep.method.toUpperCase()} ${ep.path}\`${ep.deprecated ? ' [DEPRECATED]' : ''}`);
|
|
69
|
+
if (ep.summary) lines.push(`*${ep.summary}*`);
|
|
70
|
+
if (ep.parameters.length > 0) {
|
|
71
|
+
const pList = ep.parameters.map(p => `${p.name}${p.required ? '*' : ''} (${p.in}:${p.type || 'any'})`).join(', ');
|
|
72
|
+
lines.push(`- **Parameters**: ${pList}`);
|
|
73
|
+
}
|
|
74
|
+
if (ep.auth.length > 0) {
|
|
75
|
+
lines.push(`- **Auth**: ${ep.auth.map(a => `${a.type}${a.scheme ? `:${a.scheme}` : ''}`).join(', ')}`);
|
|
76
|
+
}
|
|
77
|
+
if (ep.pagination) {
|
|
78
|
+
lines.push(`- **Pagination**: ${ep.pagination.type} (${ep.pagination.parameters.join(', ')})`);
|
|
79
|
+
}
|
|
80
|
+
lines.push('');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: 'text',
|
|
87
|
+
text: JSON.stringify({
|
|
88
|
+
markdown: lines.join('\n'),
|
|
89
|
+
data: {
|
|
90
|
+
query,
|
|
91
|
+
count: endpoints.length,
|
|
92
|
+
endpoints,
|
|
93
|
+
},
|
|
94
|
+
}, null, 2),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|