@fractary/codex-mcp 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/README.md +277 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +545 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +444 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { createCacheManager, createStorageManager } from "@fractary/codex";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import * as yaml from "js-yaml";
|
|
8
|
+
|
|
9
|
+
// src/server.ts
|
|
10
|
+
import { resolveReference as resolveReference2 } from "@fractary/codex";
|
|
11
|
+
|
|
12
|
+
// src/tools.ts
|
|
13
|
+
import { resolveReference } from "@fractary/codex";
|
|
14
|
+
var CODEX_TOOLS = [
|
|
15
|
+
{
|
|
16
|
+
name: "codex_fetch",
|
|
17
|
+
description: "Fetch a document from the Codex knowledge base by URI. Returns the document content.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
uri: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Codex URI in format: codex://org/project/path/to/file.md"
|
|
24
|
+
},
|
|
25
|
+
branch: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Git branch to fetch from (default: main)"
|
|
28
|
+
},
|
|
29
|
+
noCache: {
|
|
30
|
+
type: "boolean",
|
|
31
|
+
description: "Bypass cache and fetch fresh content"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
required: ["uri"]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "codex_search",
|
|
39
|
+
description: "Search for documents in the Codex knowledge base.",
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: {
|
|
43
|
+
query: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "Search query string"
|
|
46
|
+
},
|
|
47
|
+
org: {
|
|
48
|
+
type: "string",
|
|
49
|
+
description: "Filter by organization"
|
|
50
|
+
},
|
|
51
|
+
project: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "Filter by project"
|
|
54
|
+
},
|
|
55
|
+
limit: {
|
|
56
|
+
type: "number",
|
|
57
|
+
description: "Maximum number of results (default: 10)"
|
|
58
|
+
},
|
|
59
|
+
type: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "Filter by artifact type (e.g., docs, specs, logs)"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
required: ["query"]
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "codex_list",
|
|
69
|
+
description: "List documents in the Codex cache.",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: {
|
|
73
|
+
org: {
|
|
74
|
+
type: "string",
|
|
75
|
+
description: "Filter by organization"
|
|
76
|
+
},
|
|
77
|
+
project: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "Filter by project"
|
|
80
|
+
},
|
|
81
|
+
includeExpired: {
|
|
82
|
+
type: "boolean",
|
|
83
|
+
description: "Include expired cache entries"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "codex_invalidate",
|
|
90
|
+
description: "Invalidate cached documents matching a pattern.",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
type: "object",
|
|
93
|
+
properties: {
|
|
94
|
+
pattern: {
|
|
95
|
+
type: "string",
|
|
96
|
+
description: "URI pattern to invalidate (supports regex)"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
required: ["pattern"]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
function textResult(text, isError = false) {
|
|
104
|
+
return {
|
|
105
|
+
content: [{ type: "text", text }],
|
|
106
|
+
isError
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function resourceResult(uri, content, mimeType) {
|
|
110
|
+
return {
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: "resource",
|
|
114
|
+
resource: {
|
|
115
|
+
uri,
|
|
116
|
+
mimeType,
|
|
117
|
+
text: content
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async function handleFetch(args, ctx) {
|
|
124
|
+
const { uri, branch, noCache } = args;
|
|
125
|
+
if (!uri || typeof uri !== "string") {
|
|
126
|
+
return textResult("URI is required and must be a string", true);
|
|
127
|
+
}
|
|
128
|
+
if (branch && typeof branch !== "string") {
|
|
129
|
+
return textResult("Branch must be a string", true);
|
|
130
|
+
}
|
|
131
|
+
const ref = resolveReference(uri);
|
|
132
|
+
if (!ref) {
|
|
133
|
+
return textResult(`Invalid codex URI: ${uri}`, true);
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
let result;
|
|
137
|
+
if (noCache) {
|
|
138
|
+
result = await ctx.storage.fetch(ref, { branch });
|
|
139
|
+
await ctx.cache.set(uri, result);
|
|
140
|
+
} else {
|
|
141
|
+
result = await ctx.cache.get(ref, { branch });
|
|
142
|
+
}
|
|
143
|
+
const content = result.content.toString("utf-8");
|
|
144
|
+
return resourceResult(uri, content, result.contentType);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
147
|
+
return textResult(`Failed to fetch ${uri}: ${message}`, true);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function handleSearch(args, ctx) {
|
|
151
|
+
const { query, org, project, limit = 10 } = args;
|
|
152
|
+
if (!query || typeof query !== "string") {
|
|
153
|
+
return textResult("Query is required and must be a string", true);
|
|
154
|
+
}
|
|
155
|
+
if (query.length > 500) {
|
|
156
|
+
return textResult("Query too long (max 500 characters)", true);
|
|
157
|
+
}
|
|
158
|
+
if (typeof limit !== "number" || limit < 1 || limit > 100) {
|
|
159
|
+
return textResult("Limit must be a number between 1 and 100", true);
|
|
160
|
+
}
|
|
161
|
+
const stats = await ctx.cache.getStats();
|
|
162
|
+
if (stats.entryCount === 0) {
|
|
163
|
+
return textResult("No documents in cache. Use codex_fetch to load documents first.");
|
|
164
|
+
}
|
|
165
|
+
const message = `Search functionality requires a search index.
|
|
166
|
+
Query: "${query}"
|
|
167
|
+
Filters: org=${org || "any"}, project=${project || "any"}
|
|
168
|
+
Limit: ${limit}
|
|
169
|
+
|
|
170
|
+
To fetch documents, use codex_fetch with a specific URI like:
|
|
171
|
+
codex://org/project/docs/file.md`;
|
|
172
|
+
return textResult(message);
|
|
173
|
+
}
|
|
174
|
+
async function handleList(args, ctx) {
|
|
175
|
+
const { org, project, includeExpired } = args;
|
|
176
|
+
const stats = await ctx.cache.getStats();
|
|
177
|
+
let message = `Cache Statistics:
|
|
178
|
+
- Total entries: ${stats.entryCount}
|
|
179
|
+
- Memory entries: ${stats.memoryEntries}
|
|
180
|
+
- Memory size: ${formatBytes(stats.memorySize)}
|
|
181
|
+
- Total size: ${formatBytes(stats.totalSize)}
|
|
182
|
+
- Fresh: ${stats.freshCount}
|
|
183
|
+
- Stale: ${stats.staleCount}
|
|
184
|
+
- Expired: ${stats.expiredCount}`;
|
|
185
|
+
if (org) {
|
|
186
|
+
message += `
|
|
187
|
+
|
|
188
|
+
Filtered by org: ${org}`;
|
|
189
|
+
}
|
|
190
|
+
if (project) {
|
|
191
|
+
message += `
|
|
192
|
+
Filtered by project: ${project}`;
|
|
193
|
+
}
|
|
194
|
+
if (includeExpired) {
|
|
195
|
+
message += `
|
|
196
|
+
Including expired entries`;
|
|
197
|
+
}
|
|
198
|
+
return textResult(message);
|
|
199
|
+
}
|
|
200
|
+
function validateRegexPattern(pattern) {
|
|
201
|
+
if (pattern.length > 1e3) {
|
|
202
|
+
return { valid: false, error: "Pattern too long (max 1000 characters)" };
|
|
203
|
+
}
|
|
204
|
+
const redosPatterns = [
|
|
205
|
+
/(\.\*){3,}/,
|
|
206
|
+
// Multiple consecutive .*
|
|
207
|
+
/(\+\+|\*\*|\?\?)/,
|
|
208
|
+
// Nested quantifiers
|
|
209
|
+
/(\([^)]*){10,}/,
|
|
210
|
+
// Too many groups
|
|
211
|
+
/(\[[^\]]{100,})/
|
|
212
|
+
// Very long character classes
|
|
213
|
+
];
|
|
214
|
+
for (const redos of redosPatterns) {
|
|
215
|
+
if (redos.test(pattern)) {
|
|
216
|
+
return { valid: false, error: "Pattern contains potentially dangerous constructs" };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
new RegExp(pattern);
|
|
221
|
+
return { valid: true };
|
|
222
|
+
} catch (error) {
|
|
223
|
+
const message = error instanceof Error ? error.message : "Invalid regex";
|
|
224
|
+
return { valid: false, error: message };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async function handleInvalidate(args, ctx) {
|
|
228
|
+
const { pattern } = args;
|
|
229
|
+
if (!pattern || typeof pattern !== "string") {
|
|
230
|
+
return textResult("Pattern is required and must be a string", true);
|
|
231
|
+
}
|
|
232
|
+
const validation = validateRegexPattern(pattern);
|
|
233
|
+
if (!validation.valid) {
|
|
234
|
+
return textResult(`Invalid pattern: ${validation.error}`, true);
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const regex = new RegExp(pattern);
|
|
238
|
+
const count = await ctx.cache.invalidatePattern(regex);
|
|
239
|
+
return textResult(`Invalidated ${count} cache entries matching pattern: ${pattern}`);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
242
|
+
return textResult(`Failed to invalidate cache: ${message}`, true);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function handleToolCall(name, args, ctx) {
|
|
246
|
+
switch (name) {
|
|
247
|
+
case "codex_fetch":
|
|
248
|
+
return handleFetch(args, ctx);
|
|
249
|
+
case "codex_search":
|
|
250
|
+
return handleSearch(args, ctx);
|
|
251
|
+
case "codex_list":
|
|
252
|
+
return handleList(args, ctx);
|
|
253
|
+
case "codex_invalidate":
|
|
254
|
+
return handleInvalidate(args, ctx);
|
|
255
|
+
default:
|
|
256
|
+
return textResult(`Unknown tool: ${name}`, true);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function formatBytes(bytes) {
|
|
260
|
+
if (bytes === 0) return "0 B";
|
|
261
|
+
const k = 1024;
|
|
262
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
263
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
264
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/server.ts
|
|
268
|
+
var McpServer = class {
|
|
269
|
+
config;
|
|
270
|
+
toolContext;
|
|
271
|
+
constructor(config) {
|
|
272
|
+
this.config = {
|
|
273
|
+
name: config.name ?? "codex",
|
|
274
|
+
version: config.version ?? "1.0.0",
|
|
275
|
+
cache: config.cache,
|
|
276
|
+
storage: config.storage
|
|
277
|
+
};
|
|
278
|
+
this.toolContext = {
|
|
279
|
+
cache: config.cache,
|
|
280
|
+
storage: config.storage
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get server info
|
|
285
|
+
*/
|
|
286
|
+
getServerInfo() {
|
|
287
|
+
return {
|
|
288
|
+
name: this.config.name,
|
|
289
|
+
version: this.config.version,
|
|
290
|
+
capabilities: this.getCapabilities()
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get server capabilities
|
|
295
|
+
*/
|
|
296
|
+
getCapabilities() {
|
|
297
|
+
return {
|
|
298
|
+
tools: {
|
|
299
|
+
listChanged: false
|
|
300
|
+
},
|
|
301
|
+
resources: {
|
|
302
|
+
subscribe: false,
|
|
303
|
+
listChanged: false
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* List available tools
|
|
309
|
+
*/
|
|
310
|
+
listTools() {
|
|
311
|
+
return CODEX_TOOLS;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Call a tool
|
|
315
|
+
*/
|
|
316
|
+
async callTool(name, args) {
|
|
317
|
+
return handleToolCall(name, args, this.toolContext);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* List available resources
|
|
321
|
+
*/
|
|
322
|
+
async listResources() {
|
|
323
|
+
const resources = [];
|
|
324
|
+
const stats = await this.config.cache.getStats();
|
|
325
|
+
resources.push({
|
|
326
|
+
uri: "codex://cache/summary",
|
|
327
|
+
name: "Cache Summary",
|
|
328
|
+
description: `${stats.entryCount} cached documents`,
|
|
329
|
+
mimeType: "text/plain"
|
|
330
|
+
});
|
|
331
|
+
return resources;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* List resource templates
|
|
335
|
+
*/
|
|
336
|
+
listResourceTemplates() {
|
|
337
|
+
return [
|
|
338
|
+
{
|
|
339
|
+
uriTemplate: "codex://{org}/{project}/{path}",
|
|
340
|
+
name: "Codex Document",
|
|
341
|
+
description: "Fetch a document from the Codex knowledge base",
|
|
342
|
+
mimeType: "text/markdown"
|
|
343
|
+
}
|
|
344
|
+
];
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Read a resource
|
|
348
|
+
*/
|
|
349
|
+
async readResource(uri) {
|
|
350
|
+
if (uri === "codex://cache/summary") {
|
|
351
|
+
const stats = await this.config.cache.getStats();
|
|
352
|
+
return [
|
|
353
|
+
{
|
|
354
|
+
uri,
|
|
355
|
+
mimeType: "text/plain",
|
|
356
|
+
text: `Cache Statistics:
|
|
357
|
+
- Total entries: ${stats.entryCount}
|
|
358
|
+
- Memory entries: ${stats.memoryEntries}
|
|
359
|
+
- Fresh: ${stats.freshCount}
|
|
360
|
+
- Stale: ${stats.staleCount}
|
|
361
|
+
- Expired: ${stats.expiredCount}`
|
|
362
|
+
}
|
|
363
|
+
];
|
|
364
|
+
}
|
|
365
|
+
const ref = resolveReference2(uri);
|
|
366
|
+
if (!ref) {
|
|
367
|
+
throw new Error(`Invalid codex URI: ${uri}`);
|
|
368
|
+
}
|
|
369
|
+
const result = await this.config.cache.get(ref);
|
|
370
|
+
return [
|
|
371
|
+
{
|
|
372
|
+
uri,
|
|
373
|
+
mimeType: result.contentType,
|
|
374
|
+
text: result.content.toString("utf-8")
|
|
375
|
+
}
|
|
376
|
+
];
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Handle JSON-RPC request
|
|
380
|
+
*
|
|
381
|
+
* This method handles the low-level MCP protocol messages.
|
|
382
|
+
*/
|
|
383
|
+
async handleRequest(method, params) {
|
|
384
|
+
switch (method) {
|
|
385
|
+
case "initialize":
|
|
386
|
+
return {
|
|
387
|
+
protocolVersion: "2024-11-05",
|
|
388
|
+
serverInfo: this.getServerInfo(),
|
|
389
|
+
capabilities: this.getCapabilities()
|
|
390
|
+
};
|
|
391
|
+
case "tools/list":
|
|
392
|
+
return { tools: this.listTools() };
|
|
393
|
+
case "tools/call": {
|
|
394
|
+
const { name, arguments: args } = params;
|
|
395
|
+
return await this.callTool(name, args);
|
|
396
|
+
}
|
|
397
|
+
case "resources/list":
|
|
398
|
+
return { resources: await this.listResources() };
|
|
399
|
+
case "resources/templates/list":
|
|
400
|
+
return { resourceTemplates: this.listResourceTemplates() };
|
|
401
|
+
case "resources/read": {
|
|
402
|
+
const { uri } = params;
|
|
403
|
+
return { contents: await this.readResource(uri) };
|
|
404
|
+
}
|
|
405
|
+
case "prompts/list":
|
|
406
|
+
return { prompts: [] };
|
|
407
|
+
default:
|
|
408
|
+
throw new Error(`Unknown method: ${method}`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Process a JSON-RPC message
|
|
413
|
+
*/
|
|
414
|
+
async processMessage(message) {
|
|
415
|
+
let id = null;
|
|
416
|
+
try {
|
|
417
|
+
const request = JSON.parse(message);
|
|
418
|
+
id = request.id;
|
|
419
|
+
const { method, params } = request;
|
|
420
|
+
const result = await this.handleRequest(method, params);
|
|
421
|
+
return JSON.stringify({
|
|
422
|
+
jsonrpc: "2.0",
|
|
423
|
+
id,
|
|
424
|
+
result
|
|
425
|
+
});
|
|
426
|
+
} catch (error) {
|
|
427
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
428
|
+
return JSON.stringify({
|
|
429
|
+
jsonrpc: "2.0",
|
|
430
|
+
id,
|
|
431
|
+
error: {
|
|
432
|
+
code: -32603,
|
|
433
|
+
message: errorMessage
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// src/cli.ts
|
|
441
|
+
var program = new Command();
|
|
442
|
+
program.name("fractary-codex-mcp").description("MCP server for Fractary Codex knowledge management").version("0.1.0").option("--config <path>", "Path to config file", ".fractary/codex.yaml").action(async (options) => {
|
|
443
|
+
let config = {};
|
|
444
|
+
try {
|
|
445
|
+
const configFile = readFileSync(options.config, "utf-8");
|
|
446
|
+
config = yaml.load(configFile);
|
|
447
|
+
} catch (error) {
|
|
448
|
+
if (options.config !== ".fractary/codex.yaml") {
|
|
449
|
+
console.error(`Warning: Could not load config file: ${options.config}`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const storage = createStorageManager(config.storage);
|
|
453
|
+
const cache = createCacheManager({
|
|
454
|
+
cacheDir: config.cache?.cacheDir || ".fractary/cache",
|
|
455
|
+
...config.cache
|
|
456
|
+
});
|
|
457
|
+
const server = new McpServer({
|
|
458
|
+
name: "fractary-codex",
|
|
459
|
+
version: "0.1.0",
|
|
460
|
+
cache,
|
|
461
|
+
storage
|
|
462
|
+
});
|
|
463
|
+
process.stdin.setEncoding("utf-8");
|
|
464
|
+
let buffer = "";
|
|
465
|
+
process.stdin.on("data", async (chunk) => {
|
|
466
|
+
buffer += chunk;
|
|
467
|
+
const lines = buffer.split("\n");
|
|
468
|
+
buffer = lines.pop() || "";
|
|
469
|
+
for (const line of lines) {
|
|
470
|
+
if (line.trim()) {
|
|
471
|
+
try {
|
|
472
|
+
const message = JSON.parse(line);
|
|
473
|
+
const response = await handleMessage(server, message);
|
|
474
|
+
process.stdout.write(JSON.stringify(response) + "\n");
|
|
475
|
+
} catch (error) {
|
|
476
|
+
const errorResponse = {
|
|
477
|
+
jsonrpc: "2.0",
|
|
478
|
+
error: {
|
|
479
|
+
code: -32700,
|
|
480
|
+
message: "Parse error",
|
|
481
|
+
data: error instanceof Error ? error.message : "Unknown error"
|
|
482
|
+
},
|
|
483
|
+
id: null
|
|
484
|
+
};
|
|
485
|
+
process.stdout.write(JSON.stringify(errorResponse) + "\n");
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
process.stdin.on("end", () => {
|
|
491
|
+
process.exit(0);
|
|
492
|
+
});
|
|
493
|
+
console.error("MCP server running in stdio mode");
|
|
494
|
+
});
|
|
495
|
+
async function handleMessage(server, message) {
|
|
496
|
+
const method = message.method;
|
|
497
|
+
const params = message.params || {};
|
|
498
|
+
const id = message.id;
|
|
499
|
+
try {
|
|
500
|
+
let result;
|
|
501
|
+
switch (method) {
|
|
502
|
+
case "initialize":
|
|
503
|
+
result = server.getServerInfo();
|
|
504
|
+
break;
|
|
505
|
+
case "tools/list":
|
|
506
|
+
result = { tools: server.listTools() };
|
|
507
|
+
break;
|
|
508
|
+
case "tools/call": {
|
|
509
|
+
const toolName = params.name;
|
|
510
|
+
const toolArgs = params.arguments;
|
|
511
|
+
result = await server.callTool(toolName, toolArgs);
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
case "resources/list":
|
|
515
|
+
result = { resources: [] };
|
|
516
|
+
break;
|
|
517
|
+
default:
|
|
518
|
+
return {
|
|
519
|
+
jsonrpc: "2.0",
|
|
520
|
+
error: {
|
|
521
|
+
code: -32601,
|
|
522
|
+
message: `Method not found: ${method}`
|
|
523
|
+
},
|
|
524
|
+
id
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
jsonrpc: "2.0",
|
|
529
|
+
result,
|
|
530
|
+
id
|
|
531
|
+
};
|
|
532
|
+
} catch (error) {
|
|
533
|
+
return {
|
|
534
|
+
jsonrpc: "2.0",
|
|
535
|
+
error: {
|
|
536
|
+
code: -32603,
|
|
537
|
+
message: "Internal error",
|
|
538
|
+
data: error instanceof Error ? error.message : "Unknown error"
|
|
539
|
+
},
|
|
540
|
+
id
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
program.parse(process.argv);
|
|
545
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/server.ts","../src/tools.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI entry point for @fractary/codex-mcp-server\n *\n * Provides MCP server with stdio transport.\n */\n\nimport { Command } from 'commander'\nimport { createCacheManager, createStorageManager } from '@fractary/codex'\nimport { readFileSync } from 'fs'\nimport * as yaml from 'js-yaml'\nimport { McpServer } from './server.js'\n\nconst program = new Command()\n\nprogram\n .name('fractary-codex-mcp')\n .description('MCP server for Fractary Codex knowledge management')\n .version('0.1.0')\n .option('--config <path>', 'Path to config file', '.fractary/codex.yaml')\n .action(async (options) => {\n // Load configuration\n let config: Record<string, unknown> = {}\n try {\n const configFile = readFileSync(options.config, 'utf-8')\n config = yaml.load(configFile) as Record<string, unknown>\n } catch (error) {\n // Config file is optional - continue with defaults\n if (options.config !== '.fractary/codex.yaml') {\n console.error(`Warning: Could not load config file: ${options.config}`)\n }\n }\n\n // Initialize storage and cache managers\n const storage = createStorageManager(config.storage as Record<string, unknown> | undefined)\n const cache = createCacheManager({\n cacheDir: (config.cache as Record<string, unknown>)?.cacheDir as string || '.fractary/cache',\n ...(config.cache as Record<string, unknown>),\n })\n\n // Create MCP server\n const server = new McpServer({\n name: 'fractary-codex',\n version: '0.1.0',\n cache,\n storage,\n })\n\n // Stdio mode\n process.stdin.setEncoding('utf-8')\n\n let buffer = ''\n process.stdin.on('data', async (chunk) => {\n buffer += chunk\n const lines = buffer.split('\\n')\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n const message = JSON.parse(line)\n const response = await handleMessage(server, message)\n process.stdout.write(JSON.stringify(response) + '\\n')\n } catch (error) {\n const errorResponse = {\n jsonrpc: '2.0',\n error: {\n code: -32700,\n message: 'Parse error',\n data: error instanceof Error ? error.message : 'Unknown error',\n },\n id: null,\n }\n process.stdout.write(JSON.stringify(errorResponse) + '\\n')\n }\n }\n }\n })\n\n process.stdin.on('end', () => {\n process.exit(0)\n })\n\n console.error('MCP server running in stdio mode')\n })\n\n/**\n * Handle a JSON-RPC message\n */\nasync function handleMessage(\n server: McpServer,\n message: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const method = message.method as string\n const params = (message.params as Record<string, unknown>) || {}\n const id = message.id\n\n try {\n let result: unknown\n\n switch (method) {\n case 'initialize':\n result = server.getServerInfo()\n break\n\n case 'tools/list':\n result = { tools: server.listTools() }\n break\n\n case 'tools/call': {\n const toolName = params.name as string\n const toolArgs = params.arguments as Record<string, unknown>\n result = await server.callTool(toolName, toolArgs)\n break\n }\n\n case 'resources/list':\n result = { resources: [] }\n break\n\n default:\n return {\n jsonrpc: '2.0',\n error: {\n code: -32601,\n message: `Method not found: ${method}`,\n },\n id,\n }\n }\n\n return {\n jsonrpc: '2.0',\n result,\n id,\n }\n } catch (error) {\n return {\n jsonrpc: '2.0',\n error: {\n code: -32603,\n message: 'Internal error',\n data: error instanceof Error ? error.message : 'Unknown error',\n },\n id,\n }\n }\n}\n\n// Run the program\nprogram.parse(process.argv)\n","/**\n * MCP Server implementation\n *\n * Implements a Model Context Protocol server for the Codex SDK.\n * This server can be used standalone or embedded in other applications.\n */\n\nimport type { CacheManager } from '@fractary/codex'\nimport type { StorageManager } from '@fractary/codex'\nimport { resolveReference } from '@fractary/codex'\nimport type {\n McpServerInfo,\n McpCapabilities,\n McpTool,\n McpResource,\n McpResourceTemplate,\n ResourceContent,\n ToolResult,\n} from './types.js'\nimport { CODEX_TOOLS, handleToolCall, type ToolHandlerContext } from './tools.js'\n\n/**\n * MCP Server configuration\n */\nexport interface McpServerConfig {\n /** Server name */\n name?: string\n /** Server version */\n version?: string\n /** Cache manager instance */\n cache: CacheManager\n /** Storage manager instance */\n storage: StorageManager\n}\n\n/**\n * MCP Server for Codex\n *\n * Provides a Model Context Protocol server implementation that exposes\n * Codex functionality as MCP tools and resources.\n */\nexport class McpServer {\n private config: Required<Omit<McpServerConfig, 'cache' | 'storage'>> & Pick<McpServerConfig, 'cache' | 'storage'>\n private toolContext: ToolHandlerContext\n\n constructor(config: McpServerConfig) {\n this.config = {\n name: config.name ?? 'codex',\n version: config.version ?? '1.0.0',\n cache: config.cache,\n storage: config.storage,\n }\n\n this.toolContext = {\n cache: config.cache,\n storage: config.storage,\n }\n }\n\n /**\n * Get server info\n */\n getServerInfo(): McpServerInfo {\n return {\n name: this.config.name,\n version: this.config.version,\n capabilities: this.getCapabilities(),\n }\n }\n\n /**\n * Get server capabilities\n */\n getCapabilities(): McpCapabilities {\n return {\n tools: {\n listChanged: false,\n },\n resources: {\n subscribe: false,\n listChanged: false,\n },\n }\n }\n\n /**\n * List available tools\n */\n listTools(): McpTool[] {\n return CODEX_TOOLS\n }\n\n /**\n * Call a tool\n */\n async callTool(name: string, args: Record<string, unknown>): Promise<ToolResult> {\n return handleToolCall(name, args, this.toolContext)\n }\n\n /**\n * List available resources\n */\n async listResources(): Promise<McpResource[]> {\n // List cached documents as resources\n const resources: McpResource[] = []\n\n // Get cache stats for info\n const stats = await this.config.cache.getStats()\n\n // Add a summary resource\n resources.push({\n uri: 'codex://cache/summary',\n name: 'Cache Summary',\n description: `${stats.entryCount} cached documents`,\n mimeType: 'text/plain',\n })\n\n return resources\n }\n\n /**\n * List resource templates\n */\n listResourceTemplates(): McpResourceTemplate[] {\n return [\n {\n uriTemplate: 'codex://{org}/{project}/{path}',\n name: 'Codex Document',\n description: 'Fetch a document from the Codex knowledge base',\n mimeType: 'text/markdown',\n },\n ]\n }\n\n /**\n * Read a resource\n */\n async readResource(uri: string): Promise<ResourceContent[]> {\n // Handle special URIs\n if (uri === 'codex://cache/summary') {\n const stats = await this.config.cache.getStats()\n return [\n {\n uri,\n mimeType: 'text/plain',\n text: `Cache Statistics:\n- Total entries: ${stats.entryCount}\n- Memory entries: ${stats.memoryEntries}\n- Fresh: ${stats.freshCount}\n- Stale: ${stats.staleCount}\n- Expired: ${stats.expiredCount}`,\n },\n ]\n }\n\n // Resolve and fetch the reference\n const ref = resolveReference(uri)\n if (!ref) {\n throw new Error(`Invalid codex URI: ${uri}`)\n }\n\n const result = await this.config.cache.get(ref)\n return [\n {\n uri,\n mimeType: result.contentType,\n text: result.content.toString('utf-8'),\n },\n ]\n }\n\n /**\n * Handle JSON-RPC request\n *\n * This method handles the low-level MCP protocol messages.\n */\n async handleRequest(method: string, params?: Record<string, unknown>): Promise<unknown> {\n switch (method) {\n case 'initialize':\n return {\n protocolVersion: '2024-11-05',\n serverInfo: this.getServerInfo(),\n capabilities: this.getCapabilities(),\n }\n\n case 'tools/list':\n return { tools: this.listTools() }\n\n case 'tools/call': {\n const { name, arguments: args } = params as { name: string; arguments: Record<string, unknown> }\n return await this.callTool(name, args)\n }\n\n case 'resources/list':\n return { resources: await this.listResources() }\n\n case 'resources/templates/list':\n return { resourceTemplates: this.listResourceTemplates() }\n\n case 'resources/read': {\n const { uri } = params as { uri: string }\n return { contents: await this.readResource(uri) }\n }\n\n case 'prompts/list':\n return { prompts: [] }\n\n default:\n throw new Error(`Unknown method: ${method}`)\n }\n }\n\n /**\n * Process a JSON-RPC message\n */\n async processMessage(message: string): Promise<string> {\n let id: unknown = null\n\n try {\n const request = JSON.parse(message)\n id = request.id\n const { method, params } = request\n\n const result = await this.handleRequest(method, params)\n\n return JSON.stringify({\n jsonrpc: '2.0',\n id,\n result,\n })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n return JSON.stringify({\n jsonrpc: '2.0',\n id,\n error: {\n code: -32603,\n message: errorMessage,\n },\n })\n }\n }\n}\n\n/**\n * Create an MCP server\n */\nexport function createMcpServer(config: McpServerConfig): McpServer {\n return new McpServer(config)\n}\n","/**\n * MCP Tool definitions and handlers\n *\n * Implements the tools exposed by the Codex MCP server.\n */\n\nimport type { CacheManager } from '@fractary/codex'\nimport type { StorageManager } from '@fractary/codex'\nimport { resolveReference } from '@fractary/codex'\nimport type {\n McpTool,\n ToolResult,\n FetchToolArgs,\n SearchToolArgs,\n ListToolArgs,\n InvalidateToolArgs,\n} from './types.js'\n\n/**\n * Tool definitions for the MCP server\n */\nexport const CODEX_TOOLS: McpTool[] = [\n {\n name: 'codex_fetch',\n description: 'Fetch a document from the Codex knowledge base by URI. Returns the document content.',\n inputSchema: {\n type: 'object',\n properties: {\n uri: {\n type: 'string',\n description: 'Codex URI in format: codex://org/project/path/to/file.md',\n },\n branch: {\n type: 'string',\n description: 'Git branch to fetch from (default: main)',\n },\n noCache: {\n type: 'boolean',\n description: 'Bypass cache and fetch fresh content',\n },\n },\n required: ['uri'],\n },\n },\n {\n name: 'codex_search',\n description: 'Search for documents in the Codex knowledge base.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query string',\n },\n org: {\n type: 'string',\n description: 'Filter by organization',\n },\n project: {\n type: 'string',\n description: 'Filter by project',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 10)',\n },\n type: {\n type: 'string',\n description: 'Filter by artifact type (e.g., docs, specs, logs)',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'codex_list',\n description: 'List documents in the Codex cache.',\n inputSchema: {\n type: 'object',\n properties: {\n org: {\n type: 'string',\n description: 'Filter by organization',\n },\n project: {\n type: 'string',\n description: 'Filter by project',\n },\n includeExpired: {\n type: 'boolean',\n description: 'Include expired cache entries',\n },\n },\n },\n },\n {\n name: 'codex_invalidate',\n description: 'Invalidate cached documents matching a pattern.',\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description: 'URI pattern to invalidate (supports regex)',\n },\n },\n required: ['pattern'],\n },\n },\n]\n\n/**\n * Tool handler context\n */\nexport interface ToolHandlerContext {\n cache: CacheManager\n storage: StorageManager\n}\n\n/**\n * Create a text result\n */\nfunction textResult(text: string, isError = false): ToolResult {\n return {\n content: [{ type: 'text', text }],\n isError,\n }\n}\n\n/**\n * Create a resource result\n */\nfunction resourceResult(uri: string, content: string, mimeType?: string): ToolResult {\n return {\n content: [\n {\n type: 'resource',\n resource: {\n uri,\n mimeType,\n text: content,\n },\n },\n ],\n }\n}\n\n/**\n * Handle codex_fetch tool\n */\nexport async function handleFetch(args: FetchToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { uri, branch, noCache } = args\n\n // Validate input\n if (!uri || typeof uri !== 'string') {\n return textResult('URI is required and must be a string', true)\n }\n\n if (branch && typeof branch !== 'string') {\n return textResult('Branch must be a string', true)\n }\n\n // Resolve the reference\n const ref = resolveReference(uri)\n if (!ref) {\n return textResult(`Invalid codex URI: ${uri}`, true)\n }\n\n try {\n let result\n\n if (noCache) {\n // Bypass cache, fetch directly\n result = await ctx.storage.fetch(ref, { branch })\n // Still cache the result for next time\n await ctx.cache.set(uri, result)\n } else {\n // Use cache\n result = await ctx.cache.get(ref, { branch })\n }\n\n const content = result.content.toString('utf-8')\n return resourceResult(uri, content, result.contentType)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return textResult(`Failed to fetch ${uri}: ${message}`, true)\n }\n}\n\n/**\n * Handle codex_search tool\n *\n * Note: This is a basic implementation that searches cached entries.\n * A more sophisticated implementation might use a search index.\n */\nexport async function handleSearch(args: SearchToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { query, org, project, limit = 10 } = args\n\n // Validate input\n if (!query || typeof query !== 'string') {\n return textResult('Query is required and must be a string', true)\n }\n\n if (query.length > 500) {\n return textResult('Query too long (max 500 characters)', true)\n }\n\n if (typeof limit !== 'number' || limit < 1 || limit > 100) {\n return textResult('Limit must be a number between 1 and 100', true)\n }\n\n // Get all cached entries\n const stats = await ctx.cache.getStats()\n if (stats.entryCount === 0) {\n return textResult('No documents in cache. Use codex_fetch to load documents first.')\n }\n\n // This is a simplified search - in a real implementation,\n // we would use a proper search index\n // For now, we search through the cached URIs and content\n\n // Note: This is a placeholder. The actual search implementation\n // would depend on having access to the cache persistence layer's\n // list of URIs and their content.\n\n const message = `Search functionality requires a search index.\nQuery: \"${query}\"\nFilters: org=${org || 'any'}, project=${project || 'any'}\nLimit: ${limit}\n\nTo fetch documents, use codex_fetch with a specific URI like:\ncodex://org/project/docs/file.md`\n\n return textResult(message)\n}\n\n/**\n * Handle codex_list tool\n */\nexport async function handleList(args: ListToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { org, project, includeExpired } = args\n\n // Get cache stats and any available info\n const stats = await ctx.cache.getStats()\n\n let message = `Cache Statistics:\n- Total entries: ${stats.entryCount}\n- Memory entries: ${stats.memoryEntries}\n- Memory size: ${formatBytes(stats.memorySize)}\n- Total size: ${formatBytes(stats.totalSize)}\n- Fresh: ${stats.freshCount}\n- Stale: ${stats.staleCount}\n- Expired: ${stats.expiredCount}`\n\n if (org) {\n message += `\\n\\nFiltered by org: ${org}`\n }\n if (project) {\n message += `\\nFiltered by project: ${project}`\n }\n if (includeExpired) {\n message += `\\nIncluding expired entries`\n }\n\n return textResult(message)\n}\n\n/**\n * Validate and sanitize regex pattern to prevent ReDoS attacks\n */\nfunction validateRegexPattern(pattern: string): { valid: boolean; error?: string } {\n // Check pattern length (prevent extremely long patterns)\n if (pattern.length > 1000) {\n return { valid: false, error: 'Pattern too long (max 1000 characters)' }\n }\n\n // Check for common ReDoS patterns\n const redosPatterns = [\n /(\\.\\*){3,}/, // Multiple consecutive .*\n /(\\+\\+|\\*\\*|\\?\\?)/, // Nested quantifiers\n /(\\([^)]*){10,}/, // Too many groups\n /(\\[[^\\]]{100,})/, // Very long character classes\n ]\n\n for (const redos of redosPatterns) {\n if (redos.test(pattern)) {\n return { valid: false, error: 'Pattern contains potentially dangerous constructs' }\n }\n }\n\n // Try to compile the regex to check for syntax errors\n try {\n new RegExp(pattern)\n return { valid: true }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid regex'\n return { valid: false, error: message }\n }\n}\n\n/**\n * Handle codex_invalidate tool\n */\nexport async function handleInvalidate(args: InvalidateToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { pattern } = args\n\n if (!pattern || typeof pattern !== 'string') {\n return textResult('Pattern is required and must be a string', true)\n }\n\n // Validate pattern to prevent ReDoS\n const validation = validateRegexPattern(pattern)\n if (!validation.valid) {\n return textResult(`Invalid pattern: ${validation.error}`, true)\n }\n\n try {\n const regex = new RegExp(pattern)\n const count = await ctx.cache.invalidatePattern(regex)\n\n return textResult(`Invalidated ${count} cache entries matching pattern: ${pattern}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return textResult(`Failed to invalidate cache: ${message}`, true)\n }\n}\n\n/**\n * Route a tool call to its handler\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n ctx: ToolHandlerContext\n): Promise<ToolResult> {\n switch (name) {\n case 'codex_fetch':\n return handleFetch(args as unknown as FetchToolArgs, ctx)\n case 'codex_search':\n return handleSearch(args as unknown as SearchToolArgs, ctx)\n case 'codex_list':\n return handleList(args as unknown as ListToolArgs, ctx)\n case 'codex_invalidate':\n return handleInvalidate(args as unknown as InvalidateToolArgs, ctx)\n default:\n return textResult(`Unknown tool: ${name}`, true)\n }\n}\n\n/**\n * Format bytes to human readable string\n */\nfunction formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B'\n const k = 1024\n const sizes = ['B', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`\n}\n"],"mappings":"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","names":["resolveReference","resolveReference"]}
|