@papyruslabsai/seshat-mcp 0.12.0 → 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.d.ts +8 -0
- package/dist/index.js +275 -530
- package/dist/tools/diff.d.ts +1 -0
- package/dist/tools/functors.d.ts +15 -15
- package/dist/tools/functors.js +7 -7
- package/dist/tools/index.d.ts +1 -1
- package/package.json +8 -1
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @papyruslabs/seshat-mcp — Semantic Code Analysis MCP Server (Cloud Proxy)
|
|
4
|
+
*
|
|
5
|
+
* This CLI server declares the full suite of Seshat tools to Claude/AI clients,
|
|
6
|
+
* but executes all logic remotely on the Ptah Cloud API for zero-conflict
|
|
7
|
+
* collaboration and deep analytics.
|
|
8
|
+
*/
|
|
1
9
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,97 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
node;
|
|
1
|
+
#!/usr/bin/env node
|
|
3
2
|
/**
|
|
4
|
-
* @papyruslabs/seshat-mcp — Semantic Code Analysis MCP Server
|
|
3
|
+
* @papyruslabs/seshat-mcp — Semantic Code Analysis MCP Server (Cloud Proxy)
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Multi-project mode:
|
|
10
|
-
* Set SESHAT_PROJECTS env var to comma-separated paths or a glob pattern.
|
|
11
|
-
* In multi-project mode, all tools require a `project` parameter.
|
|
12
|
-
* Use `list_projects` to see available projects.
|
|
13
|
-
*
|
|
14
|
-
* Single-project mode (default):
|
|
15
|
-
* When SESHAT_PROJECTS is not set, loads from CWD. No `project` param needed.
|
|
16
|
-
*
|
|
17
|
-
* 20 tools across 4 categories:
|
|
18
|
-
* Discovery: list_projects, query_entities, get_entity, list_modules, get_topology
|
|
19
|
-
* Graph: get_dependencies, get_data_flow, find_by_constraint, get_blast_radius
|
|
20
|
-
* Analysis: find_dead_code, find_layer_violations, get_coupling_metrics,
|
|
21
|
-
* get_auth_matrix, find_error_gaps, get_test_coverage,
|
|
22
|
-
* get_optimal_context, estimate_task_cost, report_actual_burn
|
|
23
|
-
* Diff: diff_bundle, conflict_matrix
|
|
24
|
-
*
|
|
25
|
-
* Usage:
|
|
26
|
-
* npx @papyruslabs/seshat-mcp # single project (CWD)
|
|
27
|
-
* SESHAT_PROJECTS=/path/a,/path/b npx @papyruslabs/seshat-mcp # multi-project
|
|
28
|
-
* SESHAT_PROJECTS="/home/user/projects/*" npx @papyruslabs/seshat-mcp # glob
|
|
5
|
+
* This CLI server declares the full suite of Seshat tools to Claude/AI clients,
|
|
6
|
+
* but executes all logic remotely on the Ptah Cloud API for zero-conflict
|
|
7
|
+
* collaboration and deep analytics.
|
|
29
8
|
*/
|
|
30
9
|
import fs from 'fs';
|
|
31
10
|
import path from 'path';
|
|
32
11
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
33
12
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
34
13
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
return dirs;
|
|
77
|
-
}
|
|
78
|
-
// Comma-separated paths
|
|
79
|
-
return trimmed.split(',').map(p => path.resolve(p.trim())).filter(p => p.length > 0);
|
|
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);
|
|
80
54
|
}
|
|
81
|
-
// ─── Project param definition
|
|
55
|
+
// ─── Project param definition ───
|
|
82
56
|
const projectParam = {
|
|
83
57
|
type: 'string',
|
|
84
58
|
description: 'Project name (required in multi-project mode). Use list_projects to see available projects.',
|
|
85
59
|
};
|
|
86
60
|
// ─── Tool Definitions ─────────────────────────────────────────────
|
|
87
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
|
+
},
|
|
88
67
|
{
|
|
89
68
|
name: 'list_projects',
|
|
90
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.',
|
|
91
|
-
inputSchema: {
|
|
92
|
-
type: 'object',
|
|
93
|
-
properties: {},
|
|
94
|
-
},
|
|
70
|
+
inputSchema: { type: 'object', properties: {} },
|
|
95
71
|
},
|
|
96
72
|
{
|
|
97
73
|
name: 'query_entities',
|
|
@@ -100,26 +76,11 @@ const TOOLS = [
|
|
|
100
76
|
type: 'object',
|
|
101
77
|
properties: {
|
|
102
78
|
project: projectParam,
|
|
103
|
-
query: {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
type: 'string',
|
|
109
|
-
description: 'Filter by architectural layer: route, controller, service, repository, utility, hook, component, schema',
|
|
110
|
-
},
|
|
111
|
-
module: {
|
|
112
|
-
type: 'string',
|
|
113
|
-
description: 'Filter by module (partial match)',
|
|
114
|
-
},
|
|
115
|
-
language: {
|
|
116
|
-
type: 'string',
|
|
117
|
-
description: 'Filter by source language: javascript, typescript, python, go, rust, etc.',
|
|
118
|
-
},
|
|
119
|
-
limit: {
|
|
120
|
-
type: 'number',
|
|
121
|
-
description: 'Max results to return (default: 50)',
|
|
122
|
-
},
|
|
79
|
+
query: { type: 'string', description: 'Search term — matches against entity name, ID, source file, and module' },
|
|
80
|
+
layer: { type: 'string', description: 'Filter by architectural layer: route, controller, service, repository, utility, hook, component, schema' },
|
|
81
|
+
module: { type: 'string', description: 'Filter by module (partial match)' },
|
|
82
|
+
language: { type: 'string', description: 'Filter by source language: javascript, typescript, python, go, rust, etc.' },
|
|
83
|
+
limit: { type: 'number', description: 'Max results to return (default: 50)' },
|
|
123
84
|
},
|
|
124
85
|
},
|
|
125
86
|
},
|
|
@@ -130,10 +91,7 @@ const TOOLS = [
|
|
|
130
91
|
type: 'object',
|
|
131
92
|
properties: {
|
|
132
93
|
project: projectParam,
|
|
133
|
-
id: {
|
|
134
|
-
type: 'string',
|
|
135
|
-
description: 'Entity ID or name',
|
|
136
|
-
},
|
|
94
|
+
id: { type: 'string', description: 'Entity ID or name' },
|
|
137
95
|
},
|
|
138
96
|
required: ['id'],
|
|
139
97
|
},
|
|
@@ -145,19 +103,9 @@ const TOOLS = [
|
|
|
145
103
|
type: 'object',
|
|
146
104
|
properties: {
|
|
147
105
|
project: projectParam,
|
|
148
|
-
entity_id: {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
},
|
|
152
|
-
direction: {
|
|
153
|
-
type: 'string',
|
|
154
|
-
enum: ['callers', 'callees', 'both'],
|
|
155
|
-
description: 'Which direction to traverse (default: both)',
|
|
156
|
-
},
|
|
157
|
-
depth: {
|
|
158
|
-
type: 'number',
|
|
159
|
-
description: 'How many levels deep to traverse (default: 2)',
|
|
160
|
-
},
|
|
106
|
+
entity_id: { type: 'string', description: 'Entity ID or name' },
|
|
107
|
+
direction: { type: 'string', enum: ['callers', 'callees', 'both'], description: 'Which direction to traverse (default: both)' },
|
|
108
|
+
depth: { type: 'number', description: 'How many levels deep to traverse (default: 2)' },
|
|
161
109
|
},
|
|
162
110
|
required: ['entity_id'],
|
|
163
111
|
},
|
|
@@ -169,10 +117,7 @@ const TOOLS = [
|
|
|
169
117
|
type: 'object',
|
|
170
118
|
properties: {
|
|
171
119
|
project: projectParam,
|
|
172
|
-
entity_id: {
|
|
173
|
-
type: 'string',
|
|
174
|
-
description: 'Entity ID or name',
|
|
175
|
-
},
|
|
120
|
+
entity_id: { type: 'string', description: 'Entity ID or name' },
|
|
176
121
|
},
|
|
177
122
|
required: ['entity_id'],
|
|
178
123
|
},
|
|
@@ -184,10 +129,7 @@ const TOOLS = [
|
|
|
184
129
|
type: 'object',
|
|
185
130
|
properties: {
|
|
186
131
|
project: projectParam,
|
|
187
|
-
constraint: {
|
|
188
|
-
type: 'string',
|
|
189
|
-
description: 'Constraint tag to search for: AUTH, VALIDATED, PURE, THROWS, DB_ACCESS, NETWORK_IO, IMP, etc.',
|
|
190
|
-
},
|
|
132
|
+
constraint: { type: 'string', description: 'Constraint tag to search for: AUTH, VALIDATED, PURE, THROWS, DB_ACCESS, NETWORK_IO, IMP, etc.' },
|
|
191
133
|
},
|
|
192
134
|
required: ['constraint'],
|
|
193
135
|
},
|
|
@@ -199,11 +141,7 @@ const TOOLS = [
|
|
|
199
141
|
type: 'object',
|
|
200
142
|
properties: {
|
|
201
143
|
project: projectParam,
|
|
202
|
-
entity_ids: {
|
|
203
|
-
type: 'array',
|
|
204
|
-
items: { type: 'string' },
|
|
205
|
-
description: 'Array of entity IDs or names to compute blast radius for',
|
|
206
|
-
},
|
|
144
|
+
entity_ids: { type: 'array', items: { type: 'string' }, description: 'Array of entity IDs or names to compute blast radius for' },
|
|
207
145
|
},
|
|
208
146
|
required: ['entity_ids'],
|
|
209
147
|
},
|
|
@@ -215,25 +153,33 @@ const TOOLS = [
|
|
|
215
153
|
type: 'object',
|
|
216
154
|
properties: {
|
|
217
155
|
project: projectParam,
|
|
218
|
-
group_by: {
|
|
219
|
-
type: 'string',
|
|
220
|
-
enum: ['layer', 'module', 'file', 'language'],
|
|
221
|
-
description: 'How to group entities (default: layer)',
|
|
222
|
-
},
|
|
156
|
+
group_by: { type: 'string', enum: ['layer', 'module', 'file', 'language'], description: 'How to group entities (default: layer)' },
|
|
223
157
|
},
|
|
224
158
|
},
|
|
225
159
|
},
|
|
226
160
|
{
|
|
227
161
|
name: 'get_topology',
|
|
228
162
|
description: 'Get the API topology: routes, plugins, auth patterns, and database tables. Built from architectural context and dependency analysis across all entities.',
|
|
163
|
+
inputSchema: {
|
|
164
|
+
type: 'object',
|
|
165
|
+
properties: { project: projectParam },
|
|
166
|
+
},
|
|
167
|
+
},
|
|
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.',
|
|
229
171
|
inputSchema: {
|
|
230
172
|
type: 'object',
|
|
231
173
|
properties: {
|
|
232
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)' },
|
|
233
178
|
},
|
|
179
|
+
required: ['target_entity'],
|
|
234
180
|
},
|
|
235
181
|
},
|
|
236
|
-
// ───
|
|
182
|
+
// ─── Analyst Tools (Tier 2) ───────────────────────────────────────
|
|
237
183
|
{
|
|
238
184
|
name: 'find_dead_code',
|
|
239
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.',
|
|
@@ -241,21 +187,16 @@ const TOOLS = [
|
|
|
241
187
|
type: 'object',
|
|
242
188
|
properties: {
|
|
243
189
|
project: projectParam,
|
|
244
|
-
include_tests: {
|
|
245
|
-
type: 'boolean',
|
|
246
|
-
description: 'Include test entities in dead code results (default: false)',
|
|
247
|
-
},
|
|
190
|
+
include_tests: { type: 'boolean', description: 'Include test entities in dead code results (default: false)' },
|
|
248
191
|
},
|
|
249
192
|
},
|
|
250
193
|
},
|
|
251
194
|
{
|
|
252
195
|
name: 'find_layer_violations',
|
|
253
|
-
description: 'Detect architectural layer violations in the call graph. Finds backward calls (lower layer calling higher layer, e.g. repository → route) and skip-layer calls (jumping over multiple layers).
|
|
196
|
+
description: 'Detect architectural layer violations in the call graph. Finds backward calls (lower layer calling higher layer, e.g. repository → route) and skip-layer calls (jumping over multiple layers).',
|
|
254
197
|
inputSchema: {
|
|
255
198
|
type: 'object',
|
|
256
|
-
properties: {
|
|
257
|
-
project: projectParam,
|
|
258
|
-
},
|
|
199
|
+
properties: { project: projectParam },
|
|
259
200
|
},
|
|
260
201
|
},
|
|
261
202
|
{
|
|
@@ -265,11 +206,7 @@ const TOOLS = [
|
|
|
265
206
|
type: 'object',
|
|
266
207
|
properties: {
|
|
267
208
|
project: projectParam,
|
|
268
|
-
group_by: {
|
|
269
|
-
type: 'string',
|
|
270
|
-
enum: ['module', 'layer'],
|
|
271
|
-
description: 'Group entities by module or layer (default: module)',
|
|
272
|
-
},
|
|
209
|
+
group_by: { type: 'string', enum: ['module', 'layer'], description: 'Group entities by module or layer (default: module)' },
|
|
273
210
|
},
|
|
274
211
|
},
|
|
275
212
|
},
|
|
@@ -278,9 +215,7 @@ const TOOLS = [
|
|
|
278
215
|
description: 'Analyze authentication coverage across all API-facing entities. Shows which routes/controllers have auth requirements and which don\'t. Detects inconsistencies like DB access without auth.',
|
|
279
216
|
inputSchema: {
|
|
280
217
|
type: 'object',
|
|
281
|
-
properties: {
|
|
282
|
-
project: projectParam,
|
|
283
|
-
},
|
|
218
|
+
properties: { project: projectParam },
|
|
284
219
|
},
|
|
285
220
|
},
|
|
286
221
|
{
|
|
@@ -288,9 +223,7 @@ const TOOLS = [
|
|
|
288
223
|
description: 'Find error handling gaps: entities that throw or have network/db side effects whose callers lack try/catch. These are crash risk points where exceptions can propagate unhandled.',
|
|
289
224
|
inputSchema: {
|
|
290
225
|
type: 'object',
|
|
291
|
-
properties: {
|
|
292
|
-
project: projectParam,
|
|
293
|
-
},
|
|
226
|
+
properties: { project: projectParam },
|
|
294
227
|
},
|
|
295
228
|
},
|
|
296
229
|
{
|
|
@@ -300,143 +233,70 @@ const TOOLS = [
|
|
|
300
233
|
type: 'object',
|
|
301
234
|
properties: {
|
|
302
235
|
project: projectParam,
|
|
303
|
-
weight_by_blast_radius: {
|
|
304
|
-
type: 'boolean',
|
|
305
|
-
description: 'Rank uncovered entities by blast radius to prioritize testing (default: false, slower)',
|
|
306
|
-
},
|
|
236
|
+
weight_by_blast_radius: { type: 'boolean', description: 'Rank uncovered entities by blast radius to prioritize testing (default: false, slower)' },
|
|
307
237
|
},
|
|
308
238
|
},
|
|
309
239
|
},
|
|
310
240
|
{
|
|
311
|
-
name: '
|
|
312
|
-
description: '
|
|
313
|
-
inputSchema: {
|
|
314
|
-
type: 'object',
|
|
315
|
-
properties: {
|
|
316
|
-
project: projectParam,
|
|
317
|
-
target_entity: {
|
|
318
|
-
type: 'string',
|
|
319
|
-
description: 'Entity ID or name to build context around',
|
|
320
|
-
},
|
|
321
|
-
max_tokens: {
|
|
322
|
-
type: 'number',
|
|
323
|
-
description: 'Token budget for the context window (default: 8000)',
|
|
324
|
-
},
|
|
325
|
-
strategy: {
|
|
326
|
-
type: 'string',
|
|
327
|
-
enum: ['bfs', 'blast_radius'],
|
|
328
|
-
description: 'Traversal strategy: bfs (faster, local neighborhood) or blast_radius (full affected set)',
|
|
329
|
-
},
|
|
330
|
-
},
|
|
331
|
-
required: ['target_entity'],
|
|
332
|
-
},
|
|
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 } },
|
|
333
244
|
},
|
|
334
245
|
{
|
|
335
|
-
name: '
|
|
336
|
-
description: '
|
|
337
|
-
inputSchema: {
|
|
338
|
-
type: 'object',
|
|
339
|
-
properties: {
|
|
340
|
-
project: projectParam,
|
|
341
|
-
target_entities: {
|
|
342
|
-
type: 'array',
|
|
343
|
-
items: { type: 'string' },
|
|
344
|
-
description: 'Entity IDs or names that will be modified',
|
|
345
|
-
},
|
|
346
|
-
context_budget: {
|
|
347
|
-
type: 'number',
|
|
348
|
-
description: 'LLM context window token budget (default: 200000)',
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
required: ['target_entities'],
|
|
352
|
-
},
|
|
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 } },
|
|
353
249
|
},
|
|
354
250
|
{
|
|
355
|
-
name: '
|
|
356
|
-
description: '
|
|
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.',
|
|
357
253
|
inputSchema: {
|
|
358
254
|
type: 'object',
|
|
359
255
|
properties: {
|
|
360
|
-
prediction_id: {
|
|
361
|
-
type: 'string',
|
|
362
|
-
description: 'The prediction ID returned by estimate_task_cost. Required for complete/abandon actions.',
|
|
363
|
-
},
|
|
364
|
-
actual_input_tokens: {
|
|
365
|
-
type: 'number',
|
|
366
|
-
description: 'Actual input tokens consumed (from LLM usage metadata).',
|
|
367
|
-
},
|
|
368
|
-
actual_output_tokens: {
|
|
369
|
-
type: 'number',
|
|
370
|
-
description: 'Actual output tokens consumed (from LLM usage metadata).',
|
|
371
|
-
},
|
|
372
|
-
actual_total_tokens: {
|
|
373
|
-
type: 'number',
|
|
374
|
-
description: 'Actual total tokens consumed (input + output).',
|
|
375
|
-
},
|
|
376
|
-
model: {
|
|
377
|
-
type: 'string',
|
|
378
|
-
description: 'Model used (e.g. claude-opus-4-6, claude-sonnet-4-6).',
|
|
379
|
-
},
|
|
380
|
-
action: {
|
|
381
|
-
type: 'string',
|
|
382
|
-
enum: ['complete', 'abandon', 'list'],
|
|
383
|
-
description: 'Action: "complete" reports actuals (default), "abandon" marks prediction as cancelled, "list" shows recent predictions with calibration stats.',
|
|
384
|
-
},
|
|
385
256
|
project: projectParam,
|
|
386
|
-
|
|
387
|
-
type: 'string',
|
|
388
|
-
description: 'Optional notes about the task outcome.',
|
|
389
|
-
},
|
|
257
|
+
trait: { type: 'string', description: 'The trait or capability to search for (e.g., "fallible", "asyncContext")' },
|
|
390
258
|
},
|
|
259
|
+
required: ['trait'],
|
|
391
260
|
},
|
|
392
261
|
},
|
|
393
|
-
// ─── Analysis & Impact Tools ───────────────────────────────────
|
|
394
262
|
{
|
|
395
|
-
name: '
|
|
396
|
-
description: 'Analyze the call graph for
|
|
397
|
-
inputSchema: {
|
|
398
|
-
type: 'object',
|
|
399
|
-
properties: {
|
|
400
|
-
project: projectParam,
|
|
401
|
-
},
|
|
402
|
-
},
|
|
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 } },
|
|
403
266
|
},
|
|
404
267
|
{
|
|
405
|
-
name: '
|
|
406
|
-
description: 'Analyze the codebase for
|
|
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.',
|
|
407
270
|
inputSchema: {
|
|
408
271
|
type: 'object',
|
|
409
272
|
properties: {
|
|
410
273
|
project: projectParam,
|
|
274
|
+
min_complexity: { type: 'number', description: 'Minimum number of logic expressions required to constitute a match (default: 5).' },
|
|
411
275
|
},
|
|
412
276
|
},
|
|
413
277
|
},
|
|
278
|
+
// ─── Architect Tools (Tier 3) ─────────────────────────────────────
|
|
414
279
|
{
|
|
415
|
-
name: '
|
|
416
|
-
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.',
|
|
417
282
|
inputSchema: {
|
|
418
283
|
type: 'object',
|
|
419
284
|
properties: {
|
|
420
285
|
project: projectParam,
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
description: 'The trait or capability to search for (e.g., "fallible", "asyncContext")',
|
|
424
|
-
},
|
|
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)' },
|
|
425
288
|
},
|
|
426
|
-
required: ['
|
|
289
|
+
required: ['target_entities'],
|
|
427
290
|
},
|
|
428
291
|
},
|
|
429
292
|
{
|
|
430
293
|
name: 'simulate_mutation',
|
|
431
|
-
description: 'The Impact Simulator. Proposes a hypothetical change to an entity
|
|
294
|
+
description: 'The Impact Simulator. Proposes a hypothetical change to an entity and simulates the architectural fallout upstream and downstream. Returns a blueprint of exactly which other entities will break and what fixes they require.',
|
|
432
295
|
inputSchema: {
|
|
433
296
|
type: 'object',
|
|
434
297
|
properties: {
|
|
435
298
|
project: projectParam,
|
|
436
|
-
entity_id: {
|
|
437
|
-
type: 'string',
|
|
438
|
-
description: 'The target entity to analyze.',
|
|
439
|
-
},
|
|
299
|
+
entity_id: { type: 'string', description: 'The target entity to analyze.' },
|
|
440
300
|
mutation: {
|
|
441
301
|
type: 'object',
|
|
442
302
|
description: 'The hypothetical change to apply.',
|
|
@@ -456,73 +316,21 @@ const TOOLS = [
|
|
|
456
316
|
required: ['entity_id', 'mutation'],
|
|
457
317
|
},
|
|
458
318
|
},
|
|
459
|
-
{
|
|
460
|
-
name: 'query_data_targets',
|
|
461
|
-
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. This acts as a reverse-index for data flow, essential for planning migrations or state refactors.',
|
|
462
|
-
inputSchema: {
|
|
463
|
-
type: 'object',
|
|
464
|
-
properties: {
|
|
465
|
-
project: projectParam,
|
|
466
|
-
target_name: {
|
|
467
|
-
type: 'string',
|
|
468
|
-
description: 'The name of the database table, state object, or data source to query (e.g., "users", "auth_token").',
|
|
469
|
-
},
|
|
470
|
-
},
|
|
471
|
-
required: ['target_name'],
|
|
472
|
-
},
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
name: 'find_exposure_leaks',
|
|
476
|
-
description: 'Analyze the call graph for architectural visibility leaks. Flags paths where a "public" or "api" entity directly accesses a "private" internal entity, potentially leaking sensitive data or bypassing internal service boundaries.',
|
|
477
|
-
inputSchema: {
|
|
478
|
-
type: 'object',
|
|
479
|
-
properties: {
|
|
480
|
-
project: projectParam,
|
|
481
|
-
},
|
|
482
|
-
},
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
name: 'find_semantic_clones',
|
|
486
|
-
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.',
|
|
487
|
-
inputSchema: {
|
|
488
|
-
type: 'object',
|
|
489
|
-
properties: {
|
|
490
|
-
project: projectParam,
|
|
491
|
-
min_complexity: {
|
|
492
|
-
type: 'number',
|
|
493
|
-
description: 'Minimum number of logic expressions required to constitute a match (default: 5).',
|
|
494
|
-
},
|
|
495
|
-
},
|
|
496
|
-
},
|
|
497
|
-
},
|
|
498
319
|
{
|
|
499
320
|
name: 'create_symbol',
|
|
500
|
-
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.
|
|
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.',
|
|
501
322
|
inputSchema: {
|
|
502
323
|
type: 'object',
|
|
503
324
|
properties: {
|
|
504
325
|
project: projectParam,
|
|
505
|
-
id: {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
},
|
|
509
|
-
source_file: {
|
|
510
|
-
type: 'string',
|
|
511
|
-
description: 'The relative path to the file where this symbol will be created.',
|
|
512
|
-
},
|
|
513
|
-
layer: {
|
|
514
|
-
type: 'string',
|
|
515
|
-
description: 'The architectural layer (e.g., "service", "route", "component").',
|
|
516
|
-
},
|
|
517
|
-
description: {
|
|
518
|
-
type: 'string',
|
|
519
|
-
description: 'Brief description of the symbol\'s purpose.',
|
|
520
|
-
},
|
|
326
|
+
id: { type: 'string', description: 'The unique ID or name for the new symbol.' },
|
|
327
|
+
source_file: { type: 'string', description: 'The relative path to the file where this symbol will be created.' },
|
|
328
|
+
layer: { type: 'string', description: 'The architectural layer (e.g., "service", "route", "component").' },
|
|
329
|
+
description: { type: 'string', description: 'Brief description of the symbol\'s purpose.' },
|
|
521
330
|
},
|
|
522
331
|
required: ['id', 'source_file'],
|
|
523
332
|
},
|
|
524
333
|
},
|
|
525
|
-
// ─── Diff Tools ─────────────────────────────────────────────────
|
|
526
334
|
{
|
|
527
335
|
name: 'diff_bundle',
|
|
528
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.',
|
|
@@ -530,14 +338,8 @@ const TOOLS = [
|
|
|
530
338
|
type: 'object',
|
|
531
339
|
properties: {
|
|
532
340
|
project: projectParam,
|
|
533
|
-
worktree_path: {
|
|
534
|
-
|
|
535
|
-
description: 'Absolute path to the worktree or branch checkout to compare against the loaded project',
|
|
536
|
-
},
|
|
537
|
-
include_unchanged: {
|
|
538
|
-
type: 'boolean',
|
|
539
|
-
description: 'Include unchanged entities in the output (default: false)',
|
|
540
|
-
},
|
|
341
|
+
worktree_path: { type: 'string', description: 'Absolute path to the worktree or branch checkout to compare against the loaded project' },
|
|
342
|
+
include_unchanged: { type: 'boolean', description: 'Include unchanged entities in the output (default: false)' },
|
|
541
343
|
},
|
|
542
344
|
required: ['worktree_path'],
|
|
543
345
|
},
|
|
@@ -554,24 +356,10 @@ const TOOLS = [
|
|
|
554
356
|
items: {
|
|
555
357
|
type: 'object',
|
|
556
358
|
properties: {
|
|
557
|
-
id: {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
},
|
|
561
|
-
entity_ids: {
|
|
562
|
-
type: 'array',
|
|
563
|
-
items: { type: 'string' },
|
|
564
|
-
description: 'Symbol names or IDs that this task will modify',
|
|
565
|
-
},
|
|
566
|
-
dimensions: {
|
|
567
|
-
type: 'array',
|
|
568
|
-
items: { type: 'string' },
|
|
569
|
-
description: 'Optional: Code scopes this task will modify. (Legacy support, no longer required for Tier 2 safety).',
|
|
570
|
-
},
|
|
571
|
-
expand_blast_radius: {
|
|
572
|
-
type: 'boolean',
|
|
573
|
-
description: 'Include transitively affected symbols in the conflict check (default: false)',
|
|
574
|
-
},
|
|
359
|
+
id: { type: 'string', description: 'Unique task identifier (e.g. "add-dark-mode")' },
|
|
360
|
+
entity_ids: { type: 'array', items: { type: 'string' }, description: 'Symbol names or IDs that this task will modify' },
|
|
361
|
+
dimensions: { type: 'array', items: { type: 'string' }, description: 'Optional: Code scopes this task will modify.' },
|
|
362
|
+
expand_blast_radius: { type: 'boolean', description: 'Include transitively affected symbols in the conflict check (default: false)' },
|
|
575
363
|
},
|
|
576
364
|
required: ['id', 'entity_ids'],
|
|
577
365
|
},
|
|
@@ -581,230 +369,187 @@ const TOOLS = [
|
|
|
581
369
|
required: ['tasks'],
|
|
582
370
|
},
|
|
583
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
|
+
},
|
|
584
384
|
];
|
|
585
|
-
// ───
|
|
586
|
-
|
|
587
|
-
//
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
try {
|
|
591
|
-
loader.load();
|
|
385
|
+
// ─── Project Resolution (Fallback) ────────────────────────────────
|
|
386
|
+
function resolveProjectName() {
|
|
387
|
+
// If SESHAT_PROJECTS is set to a single name, use it
|
|
388
|
+
if (process.env.SESHAT_PROJECTS && !process.env.SESHAT_PROJECTS.includes(',') && !process.env.SESHAT_PROJECTS.includes('*')) {
|
|
389
|
+
return path.basename(process.env.SESHAT_PROJECTS);
|
|
592
390
|
}
|
|
593
|
-
|
|
594
|
-
|
|
391
|
+
// Fallback to reading local manifest if it exists
|
|
392
|
+
const manifestPath = path.join(process.cwd(), '.seshat', 'manifest.json');
|
|
393
|
+
if (fs.existsSync(manifestPath)) {
|
|
394
|
+
try {
|
|
395
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
396
|
+
if (manifest.projectName)
|
|
397
|
+
return manifest.projectName;
|
|
398
|
+
}
|
|
399
|
+
catch { }
|
|
595
400
|
}
|
|
596
|
-
//
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
401
|
+
// Ultimate fallback to directory name
|
|
402
|
+
return path.basename(process.cwd());
|
|
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
|
+
}
|
|
411
|
+
// ─── Server Setup ─────────────────────────────────────────────────
|
|
412
|
+
async function main() {
|
|
413
|
+
const server = new Server({
|
|
414
|
+
name: 'seshat-mcp-cloud-proxy',
|
|
415
|
+
version: '0.12.2',
|
|
416
|
+
}, {
|
|
417
|
+
capabilities: { tools: {} },
|
|
418
|
+
});
|
|
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;
|
|
613
435
|
}
|
|
614
436
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
process.stderr.write(`[seshat-mcp] Starting with 0 entities. Run extraction manually or push to trigger CI.\n`);
|
|
437
|
+
catch {
|
|
438
|
+
// If the account endpoint is unavailable, fall back to showing all tools unlabeled
|
|
618
439
|
}
|
|
619
440
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const manifest = loader.getManifest();
|
|
635
|
-
serverLabel = `seshat-mcp (${manifest?.projectName || projectNames[0] || 'unknown'})`;
|
|
636
|
-
}
|
|
637
|
-
const server = new Server({
|
|
638
|
-
name: serverLabel,
|
|
639
|
-
version: '0.5.0',
|
|
640
|
-
}, {
|
|
641
|
-
capabilities: {
|
|
642
|
-
tools: {},
|
|
643
|
-
},
|
|
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 };
|
|
644
455
|
});
|
|
645
|
-
//
|
|
646
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
647
|
-
tools: TOOLS,
|
|
648
|
-
}));
|
|
649
|
-
// Handle tool calls
|
|
456
|
+
// ─── CallTool handler with #1 (_meta piggyback) and #2 (get_account_status) ──
|
|
650
457
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
651
458
|
const { name, arguments: args } = request.params;
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
|
|
459
|
+
const apiKey = process.env.SESHAT_API_KEY;
|
|
460
|
+
if (!apiKey) {
|
|
461
|
+
return {
|
|
462
|
+
content: [{ type: 'text', text: JSON.stringify({ error: 'SESHAT_API_KEY environment variable is required to use Ptah Cloud tools.' }, null, 2) }],
|
|
463
|
+
isError: true,
|
|
464
|
+
};
|
|
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
|
+
}
|
|
655
493
|
return {
|
|
656
|
-
content: [{
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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) }],
|
|
662
501
|
};
|
|
663
502
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
projects: loader.getProjectInfo(),
|
|
670
|
-
totalEntities,
|
|
671
|
-
hint: isMulti
|
|
672
|
-
? 'Pass the project name as the "project" parameter to all other tools.'
|
|
673
|
-
: 'Single project mode — the "project" parameter is optional.',
|
|
674
|
-
};
|
|
675
|
-
break;
|
|
676
|
-
// Core tools
|
|
677
|
-
case 'query_entities':
|
|
678
|
-
result = queryEntities(args);
|
|
679
|
-
break;
|
|
680
|
-
case 'get_entity':
|
|
681
|
-
result = getEntity(args);
|
|
682
|
-
break;
|
|
683
|
-
case 'get_dependencies':
|
|
684
|
-
result = getDependencies(args);
|
|
685
|
-
break;
|
|
686
|
-
case 'get_data_flow':
|
|
687
|
-
result = getDataFlow(args);
|
|
688
|
-
break;
|
|
689
|
-
case 'find_by_constraint':
|
|
690
|
-
result = findByConstraint(args);
|
|
691
|
-
break;
|
|
692
|
-
case 'get_blast_radius':
|
|
693
|
-
result = getBlastRadius(args);
|
|
694
|
-
break;
|
|
695
|
-
case 'list_modules':
|
|
696
|
-
result = listModules(args);
|
|
697
|
-
break;
|
|
698
|
-
case 'get_topology':
|
|
699
|
-
result = getTopology(args);
|
|
700
|
-
break;
|
|
701
|
-
// Analysis Tools
|
|
702
|
-
case 'find_dead_code':
|
|
703
|
-
result = findDeadCode(args);
|
|
704
|
-
break;
|
|
705
|
-
case 'find_layer_violations':
|
|
706
|
-
result = findLayerViolations(args);
|
|
707
|
-
break;
|
|
708
|
-
case 'get_coupling_metrics':
|
|
709
|
-
result = getCouplingMetrics(args);
|
|
710
|
-
break;
|
|
711
|
-
case 'get_auth_matrix':
|
|
712
|
-
result = getAuthMatrix(args);
|
|
713
|
-
break;
|
|
714
|
-
case 'find_error_gaps':
|
|
715
|
-
result = findErrorGaps(args);
|
|
716
|
-
break;
|
|
717
|
-
case 'get_test_coverage':
|
|
718
|
-
result = getTestCoverage(args);
|
|
719
|
-
break;
|
|
720
|
-
case 'get_optimal_context':
|
|
721
|
-
result = getOptimalContext(args);
|
|
722
|
-
break;
|
|
723
|
-
case 'estimate_task_cost':
|
|
724
|
-
result = await estimateTaskCost(args);
|
|
725
|
-
break;
|
|
726
|
-
case 'report_actual_burn':
|
|
727
|
-
result = await reportActualBurn(args);
|
|
728
|
-
break;
|
|
729
|
-
// Analysis & Impact Tools
|
|
730
|
-
case 'find_runtime_violations':
|
|
731
|
-
result = find_runtime_violations(args);
|
|
732
|
-
break;
|
|
733
|
-
case 'find_ownership_violations':
|
|
734
|
-
result = find_ownership_violations(args);
|
|
735
|
-
break;
|
|
736
|
-
case 'query_traits':
|
|
737
|
-
result = query_traits(args);
|
|
738
|
-
break;
|
|
739
|
-
case 'simulate_mutation':
|
|
740
|
-
result = simulate_mutation(args);
|
|
741
|
-
break;
|
|
742
|
-
case 'query_data_targets':
|
|
743
|
-
result = query_data_targets(args);
|
|
744
|
-
break;
|
|
745
|
-
case 'find_exposure_leaks':
|
|
746
|
-
result = find_exposure_leaks(args);
|
|
747
|
-
break;
|
|
748
|
-
case 'find_semantic_clones':
|
|
749
|
-
result = find_semantic_clones(args);
|
|
750
|
-
break;
|
|
751
|
-
case 'create_symbol':
|
|
752
|
-
result = create_symbol(args);
|
|
753
|
-
break;
|
|
754
|
-
// Diff Tools
|
|
755
|
-
case 'diff_bundle':
|
|
756
|
-
result = await diffBundle(args);
|
|
757
|
-
break;
|
|
758
|
-
case 'conflict_matrix':
|
|
759
|
-
result = conflictMatrix(args);
|
|
760
|
-
break;
|
|
761
|
-
default:
|
|
762
|
-
result = { error: `Unknown tool: ${name}` };
|
|
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
|
+
};
|
|
763
508
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
509
|
+
}
|
|
510
|
+
// Determine the project hash for this workspace
|
|
511
|
+
const project_hash = (args && typeof args === 'object' && 'project' in args)
|
|
512
|
+
? String(args.project)
|
|
513
|
+
: resolveProjectName();
|
|
514
|
+
try {
|
|
515
|
+
// Proxy the tool call to the cloud
|
|
516
|
+
const res = await fetch(getCloudUrl('/api/mcp/execute'), {
|
|
517
|
+
method: 'POST',
|
|
518
|
+
headers: {
|
|
519
|
+
'Content-Type': 'application/json',
|
|
520
|
+
'x-api-key': apiKey
|
|
521
|
+
},
|
|
522
|
+
body: JSON.stringify({
|
|
523
|
+
tool: name,
|
|
524
|
+
project_hash,
|
|
525
|
+
args
|
|
526
|
+
})
|
|
527
|
+
});
|
|
528
|
+
if (!res.ok) {
|
|
529
|
+
const errorText = await res.text();
|
|
530
|
+
return {
|
|
531
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Cloud API Error (${res.status}): ${errorText}` }, null, 2) }],
|
|
532
|
+
isError: true
|
|
533
|
+
};
|
|
778
534
|
}
|
|
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.
|
|
779
539
|
return {
|
|
780
|
-
content: [{
|
|
781
|
-
type: 'text',
|
|
782
|
-
text: JSON.stringify(result, null, 2),
|
|
783
|
-
}],
|
|
540
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
784
541
|
};
|
|
785
542
|
}
|
|
786
543
|
catch (err) {
|
|
787
544
|
return {
|
|
788
|
-
content: [{
|
|
789
|
-
type: 'text',
|
|
790
|
-
text: JSON.stringify({
|
|
791
|
-
error: `Tool ${name} failed: ${err.message}`,
|
|
792
|
-
}, null, 2),
|
|
793
|
-
}],
|
|
545
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Cloud proxy failed: ${err.message}` }, null, 2) }],
|
|
794
546
|
isError: true,
|
|
795
547
|
};
|
|
796
548
|
}
|
|
797
549
|
});
|
|
798
|
-
// Start stdio transport
|
|
799
550
|
const transport = new StdioServerTransport();
|
|
800
551
|
await server.connect(transport);
|
|
801
|
-
|
|
802
|
-
process.stderr.write(`Seshat MCP server started: ${projectNames.length} projects (${totalEntities} entities) — ${projectNames.join(', ')}\n`);
|
|
803
|
-
}
|
|
804
|
-
else {
|
|
805
|
-
const manifest = loader.getManifest();
|
|
806
|
-
process.stderr.write(`Seshat MCP server started: ${manifest?.projectName || 'unknown'} (${totalEntities} entities)\n`);
|
|
807
|
-
}
|
|
552
|
+
process.stderr.write(`Seshat Cloud Proxy started. Routing requests to Ptah API...\n`);
|
|
808
553
|
}
|
|
809
554
|
main().catch((err) => {
|
|
810
555
|
process.stderr.write(`Fatal: ${err.message}\n`);
|
package/dist/tools/diff.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* These tools compare TWO entity sets (base vs branch, or task vs task),
|
|
8
8
|
* unlike the single-bundle queries in index.ts and functors.ts.
|
|
9
9
|
*/
|
|
10
|
+
import type { ProjectLoader } from '../types.js';
|
|
10
11
|
export declare function diffBundle(args: {
|
|
11
12
|
worktree_path: string;
|
|
12
13
|
project?: string;
|
package/dist/tools/functors.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Each tool computes derived insights (dead code, layer violations,
|
|
6
6
|
* coupling metrics, auth coverage, etc.) from the entity data.
|
|
7
7
|
*/
|
|
8
|
-
import type { JstfEntity } from '../types.js';
|
|
8
|
+
import type { JstfEntity, ProjectLoader } from '../types.js';
|
|
9
9
|
/**
|
|
10
10
|
* Estimate the token cost of loading an entity's source code into an LLM context.
|
|
11
11
|
* Uses real sourceTokens from the extraction pipeline when available (v0.3.2+),
|
|
@@ -16,19 +16,19 @@ export declare function findDeadCode(args: {
|
|
|
16
16
|
include_tests?: boolean;
|
|
17
17
|
project?: string;
|
|
18
18
|
}, loader: ProjectLoader): unknown;
|
|
19
|
-
export declare function findLayerViolations(args
|
|
19
|
+
export declare function findLayerViolations(args: {
|
|
20
20
|
project?: string;
|
|
21
|
-
}): unknown;
|
|
21
|
+
}, loader: ProjectLoader): unknown;
|
|
22
22
|
export declare function getCouplingMetrics(args: {
|
|
23
23
|
group_by?: 'module' | 'layer';
|
|
24
24
|
project?: string;
|
|
25
25
|
}, loader: ProjectLoader): unknown;
|
|
26
|
-
export declare function getAuthMatrix(args
|
|
26
|
+
export declare function getAuthMatrix(args: {
|
|
27
27
|
project?: string;
|
|
28
|
-
}): unknown;
|
|
29
|
-
export declare function findErrorGaps(args
|
|
28
|
+
}, loader: ProjectLoader): unknown;
|
|
29
|
+
export declare function findErrorGaps(args: {
|
|
30
30
|
project?: string;
|
|
31
|
-
}): unknown;
|
|
31
|
+
}, loader: ProjectLoader): unknown;
|
|
32
32
|
export declare function getTestCoverage(args: {
|
|
33
33
|
weight_by_blast_radius?: boolean;
|
|
34
34
|
project?: string;
|
|
@@ -66,12 +66,12 @@ export declare function reportActualBurn(args: {
|
|
|
66
66
|
project?: string;
|
|
67
67
|
notes?: string;
|
|
68
68
|
}, loader: ProjectLoader): Promise<unknown>;
|
|
69
|
-
export declare function find_runtime_violations(args
|
|
69
|
+
export declare function find_runtime_violations(args: {
|
|
70
70
|
project?: string;
|
|
71
|
-
}): unknown;
|
|
72
|
-
export declare function find_ownership_violations(args
|
|
71
|
+
}, loader: ProjectLoader): unknown;
|
|
72
|
+
export declare function find_ownership_violations(args: {
|
|
73
73
|
project?: string;
|
|
74
|
-
}): unknown;
|
|
74
|
+
}, loader: ProjectLoader): unknown;
|
|
75
75
|
export declare function query_traits(args: {
|
|
76
76
|
trait: string;
|
|
77
77
|
project?: string;
|
|
@@ -91,13 +91,13 @@ export declare function query_data_targets(args: {
|
|
|
91
91
|
target_name: string;
|
|
92
92
|
project?: string;
|
|
93
93
|
}, loader: ProjectLoader): unknown;
|
|
94
|
-
export declare function find_exposure_leaks(args
|
|
94
|
+
export declare function find_exposure_leaks(args: {
|
|
95
95
|
project?: string;
|
|
96
|
-
}): unknown;
|
|
97
|
-
export declare function find_semantic_clones(args
|
|
96
|
+
}, loader: ProjectLoader): unknown;
|
|
97
|
+
export declare function find_semantic_clones(args: {
|
|
98
98
|
project?: string;
|
|
99
99
|
min_complexity?: number;
|
|
100
|
-
}): unknown;
|
|
100
|
+
}, loader: ProjectLoader): unknown;
|
|
101
101
|
export declare function create_symbol(args: {
|
|
102
102
|
id: string;
|
|
103
103
|
source_file: string;
|
package/dist/tools/functors.js
CHANGED
|
@@ -151,7 +151,7 @@ export function findDeadCode(args, loader) {
|
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
// ─── Tool: find_layer_violations ─────────────────────────────────
|
|
154
|
-
export function findLayerViolations(args) {
|
|
154
|
+
export function findLayerViolations(args, loader) {
|
|
155
155
|
const projErr = validateProject(args?.project, loader);
|
|
156
156
|
if (projErr)
|
|
157
157
|
return { error: projErr };
|
|
@@ -278,7 +278,7 @@ export function getCouplingMetrics(args, loader) {
|
|
|
278
278
|
};
|
|
279
279
|
}
|
|
280
280
|
// ─── Tool: get_auth_matrix ───────────────────────────────────────
|
|
281
|
-
export function getAuthMatrix(args) {
|
|
281
|
+
export function getAuthMatrix(args, loader) {
|
|
282
282
|
const projErr = validateProject(args?.project, loader);
|
|
283
283
|
if (projErr)
|
|
284
284
|
return { error: projErr };
|
|
@@ -335,7 +335,7 @@ export function getAuthMatrix(args) {
|
|
|
335
335
|
};
|
|
336
336
|
}
|
|
337
337
|
// ─── Tool: find_error_gaps ───────────────────────────────────────
|
|
338
|
-
export function findErrorGaps(args) {
|
|
338
|
+
export function findErrorGaps(args, loader) {
|
|
339
339
|
const projErr = validateProject(args?.project, loader);
|
|
340
340
|
if (projErr)
|
|
341
341
|
return { error: projErr };
|
|
@@ -822,7 +822,7 @@ export async function reportActualBurn(args, loader) {
|
|
|
822
822
|
};
|
|
823
823
|
}
|
|
824
824
|
// ─── Tool: find_runtime_violations (Runtime Context) ────────────
|
|
825
|
-
export function find_runtime_violations(args) {
|
|
825
|
+
export function find_runtime_violations(args, loader) {
|
|
826
826
|
const projErr = validateProject(args?.project, loader);
|
|
827
827
|
if (projErr)
|
|
828
828
|
return { error: projErr };
|
|
@@ -863,7 +863,7 @@ export function find_runtime_violations(args) {
|
|
|
863
863
|
};
|
|
864
864
|
}
|
|
865
865
|
// ─── Tool: find_ownership_violations (Ownership & Lifetimes) ─────
|
|
866
|
-
export function find_ownership_violations(args) {
|
|
866
|
+
export function find_ownership_violations(args, loader) {
|
|
867
867
|
const projErr = validateProject(args?.project, loader);
|
|
868
868
|
if (projErr)
|
|
869
869
|
return { error: projErr };
|
|
@@ -1079,7 +1079,7 @@ export function query_data_targets(args, loader) {
|
|
|
1079
1079
|
};
|
|
1080
1080
|
}
|
|
1081
1081
|
// ─── Tool: find_exposure_leaks (Architectural Visibility) ───────
|
|
1082
|
-
export function find_exposure_leaks(args) {
|
|
1082
|
+
export function find_exposure_leaks(args, loader) {
|
|
1083
1083
|
const projErr = validateProject(args?.project, loader);
|
|
1084
1084
|
if (projErr)
|
|
1085
1085
|
return { error: projErr };
|
|
@@ -1114,7 +1114,7 @@ export function find_exposure_leaks(args) {
|
|
|
1114
1114
|
}
|
|
1115
1115
|
// ─── Tool: find_semantic_clones (Logic Analysis) ────────────────
|
|
1116
1116
|
import { createHash } from 'crypto';
|
|
1117
|
-
export function find_semantic_clones(args) {
|
|
1117
|
+
export function find_semantic_clones(args, loader) {
|
|
1118
1118
|
const projErr = validateProject(args?.project, loader);
|
|
1119
1119
|
if (projErr)
|
|
1120
1120
|
return { error: projErr };
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Multi-project: when multiple projects are loaded, each tool accepts an optional
|
|
8
8
|
* `project` parameter. In multi-project mode, `project` is required.
|
|
9
9
|
*/
|
|
10
|
-
import type { JstfEntity } from '../types.js';
|
|
10
|
+
import type { JstfEntity, ProjectLoader } from '../types.js';
|
|
11
11
|
import { type CallGraph } from '../graph.js';
|
|
12
12
|
export declare function getGraph(project: string | undefined, loader: ProjectLoader): CallGraph;
|
|
13
13
|
/**
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papyruslabsai/seshat-mcp",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"description": "Semantic MCP server — exposes a codebase's structure, dependencies, and constraints as queryable tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"seshat-mcp": "./dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/index.js",
|
|
12
|
+
"./tools": "./dist/tools/index.js",
|
|
13
|
+
"./functors": "./dist/tools/functors.js",
|
|
14
|
+
"./diff": "./dist/tools/diff.js",
|
|
15
|
+
"./types": "./dist/types.js"
|
|
16
|
+
},
|
|
10
17
|
"scripts": {
|
|
11
18
|
"build": "tsc",
|
|
12
19
|
"dev": "tsc --watch",
|