@papyruslabsai/seshat-mcp 0.12.1 → 0.12.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/dist/index.js +194 -79
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,6 +11,47 @@ import path from 'path';
|
|
|
11
11
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
12
12
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
13
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
14
|
+
const TIER_ORDER = ['cartographer', 'analyst', 'architect'];
|
|
15
|
+
const TOOL_TIERS = {
|
|
16
|
+
// Cartographer (free) — explore and navigate
|
|
17
|
+
list_projects: 'cartographer',
|
|
18
|
+
query_entities: 'cartographer',
|
|
19
|
+
get_entity: 'cartographer',
|
|
20
|
+
get_dependencies: 'cartographer',
|
|
21
|
+
get_data_flow: 'cartographer',
|
|
22
|
+
find_by_constraint: 'cartographer',
|
|
23
|
+
get_blast_radius: 'cartographer',
|
|
24
|
+
list_modules: 'cartographer',
|
|
25
|
+
get_topology: 'cartographer',
|
|
26
|
+
get_optimal_context: 'cartographer',
|
|
27
|
+
// Analyst (tier 2) — audit and analyze
|
|
28
|
+
find_dead_code: 'analyst',
|
|
29
|
+
find_layer_violations: 'analyst',
|
|
30
|
+
get_coupling_metrics: 'analyst',
|
|
31
|
+
get_auth_matrix: 'analyst',
|
|
32
|
+
find_error_gaps: 'analyst',
|
|
33
|
+
get_test_coverage: 'analyst',
|
|
34
|
+
find_runtime_violations: 'analyst',
|
|
35
|
+
find_ownership_violations: 'analyst',
|
|
36
|
+
query_traits: 'analyst',
|
|
37
|
+
find_exposure_leaks: 'analyst',
|
|
38
|
+
find_semantic_clones: 'analyst',
|
|
39
|
+
// Architect (tier 3) — simulate, estimate, and act
|
|
40
|
+
estimate_task_cost: 'architect',
|
|
41
|
+
simulate_mutation: 'architect',
|
|
42
|
+
create_symbol: 'architect',
|
|
43
|
+
diff_bundle: 'architect',
|
|
44
|
+
conflict_matrix: 'architect',
|
|
45
|
+
query_data_targets: 'architect',
|
|
46
|
+
};
|
|
47
|
+
const TIER_LABELS = {
|
|
48
|
+
cartographer: 'Cartographer (Free)',
|
|
49
|
+
analyst: 'Analyst (Tier 2)',
|
|
50
|
+
architect: 'Architect (Tier 3)',
|
|
51
|
+
};
|
|
52
|
+
function tierAtLeast(userTier, requiredTier) {
|
|
53
|
+
return TIER_ORDER.indexOf(userTier) >= TIER_ORDER.indexOf(requiredTier);
|
|
54
|
+
}
|
|
14
55
|
// ─── Project param definition ───
|
|
15
56
|
const projectParam = {
|
|
16
57
|
type: 'string',
|
|
@@ -18,6 +59,11 @@ const projectParam = {
|
|
|
18
59
|
};
|
|
19
60
|
// ─── Tool Definitions ─────────────────────────────────────────────
|
|
20
61
|
const TOOLS = [
|
|
62
|
+
{
|
|
63
|
+
name: 'get_account_status',
|
|
64
|
+
description: 'Check your Ptah account: current tier, Ptah Credits balance, and which tools are available or locked. Call this to see what you can do and what upgrades are available.',
|
|
65
|
+
inputSchema: { type: 'object', properties: {} },
|
|
66
|
+
},
|
|
21
67
|
{
|
|
22
68
|
name: 'list_projects',
|
|
23
69
|
description: 'List all loaded projects with entity counts, languages, and metadata. Call this first to see what projects are available, then pass the project name to other tools.',
|
|
@@ -119,7 +165,21 @@ const TOOLS = [
|
|
|
119
165
|
properties: { project: projectParam },
|
|
120
166
|
},
|
|
121
167
|
},
|
|
122
|
-
|
|
168
|
+
{
|
|
169
|
+
name: 'get_optimal_context',
|
|
170
|
+
description: 'Compute the optimal set of related entities to include in an LLM context window for a target entity. Uses greedy knapsack: maximizes relevance per token. Returns entities ranked by relevance with token estimates.',
|
|
171
|
+
inputSchema: {
|
|
172
|
+
type: 'object',
|
|
173
|
+
properties: {
|
|
174
|
+
project: projectParam,
|
|
175
|
+
target_entity: { type: 'string', description: 'Entity ID or name to build context around' },
|
|
176
|
+
max_tokens: { type: 'number', description: 'Token budget for the context window (default: 8000)' },
|
|
177
|
+
strategy: { type: 'string', enum: ['bfs', 'blast_radius'], description: 'Traversal strategy: bfs (faster, local neighborhood) or blast_radius (full affected set)' },
|
|
178
|
+
},
|
|
179
|
+
required: ['target_entity'],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
// ─── Analyst Tools (Tier 2) ───────────────────────────────────────
|
|
123
183
|
{
|
|
124
184
|
name: 'find_dead_code',
|
|
125
185
|
description: 'Find unreachable entities (dead code candidates). BFS from entry points (routes, exported functions, tests, plugins) through the call graph. Entities not reachable from any entry point are flagged.',
|
|
@@ -178,70 +238,55 @@ const TOOLS = [
|
|
|
178
238
|
},
|
|
179
239
|
},
|
|
180
240
|
{
|
|
181
|
-
name: '
|
|
182
|
-
description: '
|
|
183
|
-
inputSchema: {
|
|
184
|
-
type: 'object',
|
|
185
|
-
properties: {
|
|
186
|
-
project: projectParam,
|
|
187
|
-
target_entity: { type: 'string', description: 'Entity ID or name to build context around' },
|
|
188
|
-
max_tokens: { type: 'number', description: 'Token budget for the context window (default: 8000)' },
|
|
189
|
-
strategy: { type: 'string', enum: ['bfs', 'blast_radius'], description: 'Traversal strategy: bfs (faster, local neighborhood) or blast_radius (full affected set)' },
|
|
190
|
-
},
|
|
191
|
-
required: ['target_entity'],
|
|
192
|
-
},
|
|
241
|
+
name: 'find_runtime_violations',
|
|
242
|
+
description: 'Analyze the call graph for runtime environment leaks. Finds architectural boundary issues where framework-agnostic code improperly imports framework-specific code.',
|
|
243
|
+
inputSchema: { type: 'object', properties: { project: projectParam } },
|
|
193
244
|
},
|
|
194
245
|
{
|
|
195
|
-
name: '
|
|
196
|
-
description: '
|
|
246
|
+
name: 'find_ownership_violations',
|
|
247
|
+
description: 'Analyze the codebase for memory and lifecycle constraints. Flags entities with complex ownership rules, unsafe blocks, escaping boundaries, or illegal mutability patterns on borrowed references.',
|
|
248
|
+
inputSchema: { type: 'object', properties: { project: projectParam } },
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: 'query_traits',
|
|
252
|
+
description: 'Search the codebase for specific functional capabilities. Allows you to find entities by their abstract traits (e.g., "fallible", "asyncContext", "generator") regardless of their structural syntax.',
|
|
197
253
|
inputSchema: {
|
|
198
254
|
type: 'object',
|
|
199
255
|
properties: {
|
|
200
256
|
project: projectParam,
|
|
201
|
-
|
|
202
|
-
context_budget: { type: 'number', description: 'LLM context window token budget (default: 200000)' },
|
|
257
|
+
trait: { type: 'string', description: 'The trait or capability to search for (e.g., "fallible", "asyncContext")' },
|
|
203
258
|
},
|
|
204
|
-
required: ['
|
|
259
|
+
required: ['trait'],
|
|
205
260
|
},
|
|
206
261
|
},
|
|
207
262
|
{
|
|
208
|
-
name: '
|
|
209
|
-
description: '
|
|
263
|
+
name: 'find_exposure_leaks',
|
|
264
|
+
description: 'Analyze the call graph for architectural visibility leaks. Flags paths where a "public" or "api" entity directly accesses a "private" internal entity.',
|
|
265
|
+
inputSchema: { type: 'object', properties: { project: projectParam } },
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: 'find_semantic_clones',
|
|
269
|
+
description: 'Analyze the codebase for duplicated logic blocks. Normalizes variables and compares code structure to identify identical algorithms written across different files or even different languages.',
|
|
210
270
|
inputSchema: {
|
|
211
271
|
type: 'object',
|
|
212
272
|
properties: {
|
|
213
|
-
prediction_id: { type: 'string', description: 'The prediction ID returned by estimate_task_cost. Required for complete/abandon actions.' },
|
|
214
|
-
actual_input_tokens: { type: 'number', description: 'Actual input tokens consumed (from LLM usage metadata).' },
|
|
215
|
-
actual_output_tokens: { type: 'number', description: 'Actual output tokens consumed (from LLM usage metadata).' },
|
|
216
|
-
actual_total_tokens: { type: 'number', description: 'Actual total tokens consumed (input + output).' },
|
|
217
|
-
model: { type: 'string', description: 'Model used (e.g. claude-opus-4-6, claude-sonnet-4-6).' },
|
|
218
|
-
action: { type: 'string', enum: ['complete', 'abandon', 'list'], description: 'Action: "complete" reports actuals (default), "abandon" marks prediction as cancelled, "list" shows recent predictions with calibration stats.' },
|
|
219
273
|
project: projectParam,
|
|
220
|
-
|
|
274
|
+
min_complexity: { type: 'number', description: 'Minimum number of logic expressions required to constitute a match (default: 5).' },
|
|
221
275
|
},
|
|
222
276
|
},
|
|
223
277
|
},
|
|
224
|
-
// ───
|
|
225
|
-
{
|
|
226
|
-
name: 'find_runtime_violations',
|
|
227
|
-
description: 'Analyze the call graph for runtime environment leaks. Finds architectural boundary issues where framework-agnostic code improperly imports framework-specific code.',
|
|
228
|
-
inputSchema: { type: 'object', properties: { project: projectParam } },
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
name: 'find_ownership_violations',
|
|
232
|
-
description: 'Analyze the codebase for memory and lifecycle constraints. Flags entities with complex ownership rules, unsafe blocks, escaping boundaries, or illegal mutability patterns on borrowed references.',
|
|
233
|
-
inputSchema: { type: 'object', properties: { project: projectParam } },
|
|
234
|
-
},
|
|
278
|
+
// ─── Architect Tools (Tier 3) ─────────────────────────────────────
|
|
235
279
|
{
|
|
236
|
-
name: '
|
|
237
|
-
description: '
|
|
280
|
+
name: 'estimate_task_cost',
|
|
281
|
+
description: 'Estimate token cost of a code change BEFORE starting work. Computes blast radius, sums source token counts across affected entities, and projects total token burn including iteration cycles. Call this before planning to check if a task fits within your token budget.',
|
|
238
282
|
inputSchema: {
|
|
239
283
|
type: 'object',
|
|
240
284
|
properties: {
|
|
241
285
|
project: projectParam,
|
|
242
|
-
|
|
286
|
+
target_entities: { type: 'array', items: { type: 'string' }, description: 'Entity IDs or names that will be modified' },
|
|
287
|
+
context_budget: { type: 'number', description: 'LLM context window token budget (default: 200000)' },
|
|
243
288
|
},
|
|
244
|
-
required: ['
|
|
289
|
+
required: ['target_entities'],
|
|
245
290
|
},
|
|
246
291
|
},
|
|
247
292
|
{
|
|
@@ -271,34 +316,6 @@ const TOOLS = [
|
|
|
271
316
|
required: ['entity_id', 'mutation'],
|
|
272
317
|
},
|
|
273
318
|
},
|
|
274
|
-
{
|
|
275
|
-
name: 'query_data_targets',
|
|
276
|
-
description: 'Search the codebase for data interactions to find all entities that read or write to a specific database table, state object, or data source.',
|
|
277
|
-
inputSchema: {
|
|
278
|
-
type: 'object',
|
|
279
|
-
properties: {
|
|
280
|
-
project: projectParam,
|
|
281
|
-
target_name: { type: 'string', description: 'The name of the database table, state object, or data source to query (e.g., "users", "auth_token").' },
|
|
282
|
-
},
|
|
283
|
-
required: ['target_name'],
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
name: 'find_exposure_leaks',
|
|
288
|
-
description: 'Analyze the call graph for architectural visibility leaks. Flags paths where a "public" or "api" entity directly accesses a "private" internal entity.',
|
|
289
|
-
inputSchema: { type: 'object', properties: { project: projectParam } },
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
name: 'find_semantic_clones',
|
|
293
|
-
description: 'Analyze the codebase for duplicated logic blocks. Normalizes variables and compares code structure to identify identical algorithms written across different files or even different languages.',
|
|
294
|
-
inputSchema: {
|
|
295
|
-
type: 'object',
|
|
296
|
-
properties: {
|
|
297
|
-
project: projectParam,
|
|
298
|
-
min_complexity: { type: 'number', description: 'Minimum number of logic expressions required to constitute a match (default: 5).' },
|
|
299
|
-
},
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
319
|
{
|
|
303
320
|
name: 'create_symbol',
|
|
304
321
|
description: 'Register a new code symbol in the architectural graph. This does not write to disk, but allows the Impact Simulator and Conflict Matrix to reason about a symbol that is pending creation.',
|
|
@@ -314,7 +331,6 @@ const TOOLS = [
|
|
|
314
331
|
required: ['id', 'source_file'],
|
|
315
332
|
},
|
|
316
333
|
},
|
|
317
|
-
// ─── Diff Tools ─────────────────────────────────────────────────
|
|
318
334
|
{
|
|
319
335
|
name: 'diff_bundle',
|
|
320
336
|
description: 'Compare code structure between a worktree and the loaded project. Shows which symbols were added, removed, or modified — not a line diff, but a structural diff showing changed signatures, dependencies, and implementation logic.',
|
|
@@ -353,6 +369,18 @@ const TOOLS = [
|
|
|
353
369
|
required: ['tasks'],
|
|
354
370
|
},
|
|
355
371
|
},
|
|
372
|
+
{
|
|
373
|
+
name: 'query_data_targets',
|
|
374
|
+
description: 'Search the codebase for data interactions to find all entities that read or write to a specific database table, state object, or data source.',
|
|
375
|
+
inputSchema: {
|
|
376
|
+
type: 'object',
|
|
377
|
+
properties: {
|
|
378
|
+
project: projectParam,
|
|
379
|
+
target_name: { type: 'string', description: 'The name of the database table, state object, or data source to query (e.g., "users", "auth_token").' },
|
|
380
|
+
},
|
|
381
|
+
required: ['target_name'],
|
|
382
|
+
},
|
|
383
|
+
},
|
|
356
384
|
];
|
|
357
385
|
// ─── Project Resolution (Fallback) ────────────────────────────────
|
|
358
386
|
function resolveProjectName() {
|
|
@@ -373,20 +401,61 @@ function resolveProjectName() {
|
|
|
373
401
|
// Ultimate fallback to directory name
|
|
374
402
|
return path.basename(process.cwd());
|
|
375
403
|
}
|
|
404
|
+
// ─── Cloud API helper ─────────────────────────────────────────────
|
|
405
|
+
function getCloudUrl(path) {
|
|
406
|
+
const base = process.env.PTAH_CLOUD_URL || 'https://api.papyruslabs.ai';
|
|
407
|
+
// If PTAH_CLOUD_URL includes a full path (legacy), strip it back to the base
|
|
408
|
+
const baseUrl = base.replace(/\/api\/mcp\/execute\/?$/, '');
|
|
409
|
+
return `${baseUrl}${path}`;
|
|
410
|
+
}
|
|
376
411
|
// ─── Server Setup ─────────────────────────────────────────────────
|
|
377
412
|
async function main() {
|
|
378
413
|
const server = new Server({
|
|
379
414
|
name: 'seshat-mcp-cloud-proxy',
|
|
380
|
-
version: '
|
|
415
|
+
version: '0.12.2',
|
|
381
416
|
}, {
|
|
382
417
|
capabilities: { tools: {} },
|
|
383
418
|
});
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
419
|
+
// ─── #3: Dynamic ListTools with tier annotations ──────────────
|
|
420
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
421
|
+
const apiKey = process.env.SESHAT_API_KEY;
|
|
422
|
+
let userTier = 'cartographer';
|
|
423
|
+
let credits = 0;
|
|
424
|
+
// Attempt to fetch account status from the cloud for tier-aware descriptions
|
|
425
|
+
if (apiKey) {
|
|
426
|
+
try {
|
|
427
|
+
const res = await fetch(getCloudUrl('/api/mcp/account'), {
|
|
428
|
+
method: 'GET',
|
|
429
|
+
headers: { 'x-api-key': apiKey },
|
|
430
|
+
});
|
|
431
|
+
if (res.ok) {
|
|
432
|
+
const account = await res.json();
|
|
433
|
+
userTier = account.tier || 'cartographer';
|
|
434
|
+
credits = account.credits || 0;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
// If the account endpoint is unavailable, fall back to showing all tools unlabeled
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const annotatedTools = TOOLS.map((tool) => {
|
|
442
|
+
const requiredTier = TOOL_TIERS[tool.name];
|
|
443
|
+
if (!requiredTier)
|
|
444
|
+
return tool; // get_account_status — always available
|
|
445
|
+
const hasAccess = tierAtLeast(userTier, requiredTier);
|
|
446
|
+
if (hasAccess)
|
|
447
|
+
return tool;
|
|
448
|
+
// Annotate locked tools with tier requirement
|
|
449
|
+
return {
|
|
450
|
+
...tool,
|
|
451
|
+
description: `[LOCKED — requires ${TIER_LABELS[requiredTier]}] ${tool.description}`,
|
|
452
|
+
};
|
|
453
|
+
});
|
|
454
|
+
return { tools: annotatedTools };
|
|
455
|
+
});
|
|
456
|
+
// ─── CallTool handler with #1 (_meta piggyback) and #2 (get_account_status) ──
|
|
387
457
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
388
458
|
const { name, arguments: args } = request.params;
|
|
389
|
-
// We expect the user to provide an API key for the cloud service
|
|
390
459
|
const apiKey = process.env.SESHAT_API_KEY;
|
|
391
460
|
if (!apiKey) {
|
|
392
461
|
return {
|
|
@@ -394,14 +463,57 @@ async function main() {
|
|
|
394
463
|
isError: true,
|
|
395
464
|
};
|
|
396
465
|
}
|
|
466
|
+
// ─── #2: get_account_status tool ──────────────────────────────
|
|
467
|
+
if (name === 'get_account_status') {
|
|
468
|
+
try {
|
|
469
|
+
const res = await fetch(getCloudUrl('/api/mcp/account'), {
|
|
470
|
+
method: 'GET',
|
|
471
|
+
headers: { 'x-api-key': apiKey },
|
|
472
|
+
});
|
|
473
|
+
if (!res.ok) {
|
|
474
|
+
const errorText = await res.text();
|
|
475
|
+
return {
|
|
476
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Failed to fetch account status (${res.status}): ${errorText}` }, null, 2) }],
|
|
477
|
+
isError: true,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
const account = await res.json();
|
|
481
|
+
const userTier = account.tier || 'cartographer';
|
|
482
|
+
const credits = account.credits || 0;
|
|
483
|
+
// Build tool availability breakdown
|
|
484
|
+
const toolsByTier = {
|
|
485
|
+
cartographer: { available: [], locked: [] },
|
|
486
|
+
analyst: { available: [], locked: [] },
|
|
487
|
+
architect: { available: [], locked: [] },
|
|
488
|
+
};
|
|
489
|
+
for (const [toolName, requiredTier] of Object.entries(TOOL_TIERS)) {
|
|
490
|
+
const bucket = tierAtLeast(userTier, requiredTier) ? 'available' : 'locked';
|
|
491
|
+
toolsByTier[requiredTier][bucket].push(toolName);
|
|
492
|
+
}
|
|
493
|
+
return {
|
|
494
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
495
|
+
tier: userTier,
|
|
496
|
+
tier_label: TIER_LABELS[userTier],
|
|
497
|
+
ptah_credits: credits,
|
|
498
|
+
tools: toolsByTier,
|
|
499
|
+
upgrade_url: 'https://ptah.papyruslabs.ai/settings/billing',
|
|
500
|
+
}, null, 2) }],
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
catch (err) {
|
|
504
|
+
return {
|
|
505
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Account status check failed: ${err.message}` }, null, 2) }],
|
|
506
|
+
isError: true,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
}
|
|
397
510
|
// Determine the project hash for this workspace
|
|
398
511
|
const project_hash = (args && typeof args === 'object' && 'project' in args)
|
|
399
512
|
? String(args.project)
|
|
400
513
|
: resolveProjectName();
|
|
401
|
-
const PTAH_CLOUD_URL = process.env.PTAH_CLOUD_URL || 'https://api.papyruslabs.ai/api/mcp/execute';
|
|
402
514
|
try {
|
|
403
|
-
//
|
|
404
|
-
const res = await fetch(
|
|
515
|
+
// Proxy the tool call to the cloud
|
|
516
|
+
const res = await fetch(getCloudUrl('/api/mcp/execute'), {
|
|
405
517
|
method: 'POST',
|
|
406
518
|
headers: {
|
|
407
519
|
'Content-Type': 'application/json',
|
|
@@ -421,6 +533,9 @@ async function main() {
|
|
|
421
533
|
};
|
|
422
534
|
}
|
|
423
535
|
const result = await res.json();
|
|
536
|
+
// ─── #1: _meta piggyback — append account context to every response ──
|
|
537
|
+
// The cloud API includes _meta in its response when available.
|
|
538
|
+
// If it doesn't, we pass through the result as-is.
|
|
424
539
|
return {
|
|
425
540
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
426
541
|
};
|
package/package.json
CHANGED