@evomap/gep-mcp-server 1.0.0 → 1.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evomap/gep-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "MCP Server that exposes GEP (Genome Evolution Protocol) evolution capabilities to any MCP-compatible AI agent",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -23,7 +23,7 @@ const HUB_URL = process.env.EVOMAP_HUB_URL || 'https://evomap.ai';
23
23
  const runtime = new GepRuntime({ assetsDir: ASSETS_DIR, memoryDir: MEMORY_DIR });
24
24
 
25
25
  const server = new Server(
26
- { name: 'gep-mcp-server', version: '1.0.0' },
26
+ { name: 'gep-mcp-server', version: '1.0.2' },
27
27
  { capabilities: { tools: {}, resources: {} } }
28
28
  );
29
29
 
@@ -208,7 +208,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
208
208
  params.set('q', args.query.trim().slice(0, 500));
209
209
  if (args.type && ['Gene', 'Capsule'].includes(args.type)) params.set('type', args.type);
210
210
  if (args.outcome && ['success', 'failed'].includes(args.outcome)) params.set('outcome', args.outcome);
211
- params.set('limit', String(args.limit || 10));
211
+ params.set('limit', String(Math.min(Math.max(1, parseInt(args.limit, 10) || 10), 50)));
212
212
  params.set('include_context', 'true');
213
213
  const url = `${HUB_URL}/a2a/assets/semantic-search?${params.toString()}`;
214
214
  const res = await fetch(url, { signal: AbortSignal.timeout(15000) });
@@ -251,8 +251,14 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
251
251
  const { uri } = request.params;
252
252
  switch (uri) {
253
253
  case 'gep://spec': {
254
- const specPath = resolve(__dirname, '../../gep-protocol/spec/gep-spec-v1.md');
255
- const content = existsSync(specPath) ? readFileSync(specPath, 'utf8') : 'GEP spec not found at ' + specPath;
254
+ const candidates = [
255
+ resolve(ASSETS_DIR, 'gep-spec-v1.md'),
256
+ resolve(__dirname, '../../gep-protocol/spec/gep-spec-v1.md'),
257
+ ];
258
+ const specPath = candidates.find(p => existsSync(p));
259
+ const content = specPath
260
+ ? readFileSync(specPath, 'utf8')
261
+ : 'GEP spec not found. Place gep-spec-v1.md in your GEP_ASSETS_DIR or install gep-protocol alongside this package.';
256
262
  return { contents: [{ uri, mimeType: 'text/markdown', text: content }] };
257
263
  }
258
264
  case 'gep://genes':
package/src/runtime.js CHANGED
@@ -16,7 +16,8 @@ export class GepRuntime {
16
16
  this.store.ensureFiles();
17
17
  }
18
18
 
19
- evolve({ context, intent }) {
19
+ evolve(args) {
20
+ const { context, intent } = args || {};
20
21
  const signals = this._extractSignals(context);
21
22
 
22
23
  if (intent) {
@@ -96,7 +97,8 @@ export class GepRuntime {
96
97
  };
97
98
  }
98
99
 
99
- recall({ query, signals }) {
100
+ recall(args) {
101
+ const { query, signals } = args || {};
100
102
  const events = this._readGraphEvents(500);
101
103
  const querySignals = signals || this._extractSignals(query);
102
104
  const queryKey = this._computeSignalKey(querySignals);
@@ -130,7 +132,8 @@ export class GepRuntime {
130
132
  };
131
133
  }
132
134
 
133
- recordOutcome({ geneId, signals, status, score, summary }) {
135
+ recordOutcome(args) {
136
+ const { geneId, signals, status, score, summary } = args || {};
134
137
  const signalKey = this._computeSignalKey(signals);
135
138
  const ev = {
136
139
  type: 'MemoryGraphEvent',
@@ -178,7 +181,8 @@ export class GepRuntime {
178
181
  };
179
182
  }
180
183
 
181
- installGene({ gene }) {
184
+ installGene(args) {
185
+ const { gene } = args || {};
182
186
  if (!gene || gene.type !== 'Gene' || !gene.id) {
183
187
  return { ok: false, error: 'Invalid gene: must have type="Gene" and a non-empty id' };
184
188
  }
@@ -188,7 +192,13 @@ export class GepRuntime {
188
192
  return { ok: true, installed: gene.id };
189
193
  }
190
194
 
191
- exportEvolution({ outputPath, agentName }) {
195
+ exportEvolution(args) {
196
+ let { outputPath, agentName } = args || {};
197
+ const resolvedOutput = resolve(outputPath);
198
+ const allowedRoots = [resolve(this.assetsDir), resolve(this.memoryDir, '..')];
199
+ if (!allowedRoots.some(root => resolvedOutput.startsWith(root + '/'))) {
200
+ outputPath = join(this.assetsDir, 'export.gepx');
201
+ }
192
202
  const tmpDir = `${outputPath}.tmp`;
193
203
  mkdirSync(join(tmpDir, 'genes'), { recursive: true });
194
204
  mkdirSync(join(tmpDir, 'capsules'), { recursive: true });
@@ -212,11 +222,16 @@ export class GepRuntime {
212
222
  created_at: new Date().toISOString(),
213
223
  agent_name: agentName || 'unknown',
214
224
  statistics: this.getStatus().statistics,
215
- source: { platform: 'gep-mcp-server', version: '1.0.0' },
225
+ source: { platform: 'gep-mcp-server', version: '1.0.2' },
216
226
  };
217
227
  writeFileSync(join(tmpDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
218
228
 
219
- execFileSync('tar', ['-czf', outputPath, '-C', tmpDir, '.'], { timeout: 30000 });
229
+ try {
230
+ execFileSync('tar', ['-czf', outputPath, '-C', tmpDir, '.'], { timeout: 30000 });
231
+ } catch (err) {
232
+ rmSync(tmpDir, { recursive: true, force: true });
233
+ return { ok: false, error: `tar failed: ${err.message}. Ensure tar is available on your system.` };
234
+ }
220
235
  rmSync(tmpDir, { recursive: true, force: true });
221
236
 
222
237
  return { ok: true, outputPath, manifest };
@@ -226,7 +241,7 @@ export class GepRuntime {
226
241
  const genes = this.store.loadGenes();
227
242
  const capsules = this.store.loadCapsules();
228
243
  const events = this.store.readAllEvents();
229
- const graphEvents = this._readGraphEvents(100);
244
+ const graphEntryCount = this._countGraphEntries();
230
245
 
231
246
  const recentEvents = events.slice(-5).map(e => ({
232
247
  id: e.id,
@@ -243,7 +258,7 @@ export class GepRuntime {
243
258
  total_genes: genes.length,
244
259
  total_capsules: capsules.length,
245
260
  total_events: events.length,
246
- memory_graph_entries: graphEvents.length,
261
+ memory_graph_entries: graphEntryCount,
247
262
  success_rate: events.length > 0 ? Math.round((successCount / events.length) * 100) / 100 : 0,
248
263
  },
249
264
  recent_events: recentEvents,
@@ -362,6 +377,14 @@ export class GepRuntime {
362
377
  return 'improve success rate and efficiency';
363
378
  }
364
379
 
380
+ _countGraphEntries() {
381
+ try {
382
+ if (!existsSync(this.memoryGraphPath)) return 0;
383
+ const raw = readFileSync(this.memoryGraphPath, 'utf8');
384
+ return raw.split('\n').filter(l => l.trim()).length;
385
+ } catch { return 0; }
386
+ }
387
+
365
388
  _readGraphEvents(limit = 1000) {
366
389
  try {
367
390
  if (!existsSync(this.memoryGraphPath)) return [];
@@ -376,6 +399,19 @@ export class GepRuntime {
376
399
  _appendToGraph(event) {
377
400
  mkdirSync(this.memoryDir, { recursive: true });
378
401
  appendFileSync(this.memoryGraphPath, JSON.stringify(event) + '\n', 'utf8');
402
+ this._maybeTruncateGraph();
403
+ }
404
+
405
+ _maybeTruncateGraph() {
406
+ const MAX_ENTRIES = 5000;
407
+ try {
408
+ if (!existsSync(this.memoryGraphPath)) return;
409
+ const raw = readFileSync(this.memoryGraphPath, 'utf8');
410
+ const lines = raw.split('\n').filter(l => l.trim());
411
+ if (lines.length <= MAX_ENTRIES) return;
412
+ const kept = lines.slice(lines.length - MAX_ENTRIES);
413
+ writeFileSync(this.memoryGraphPath, kept.join('\n') + '\n', 'utf8');
414
+ } catch { /* best effort */ }
379
415
  }
380
416
 
381
417
  _recordToGraph({ kind, signals, gene, mutation }) {