@papyruslabsai/seshat-mcp 0.14.2 → 0.15.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/dist/index.js +41 -180
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,117 +34,17 @@ Use Seshat tools instead of grep/Read when you need to understand code structure
|
|
|
34
34
|
All tools are read-only and safe to call speculatively — there is no cost to trying them.
|
|
35
35
|
|
|
36
36
|
get_blast_radius and get_optimal_context are designed to be called iteratively. Start with any entity, then feed discovered entities back in to expand your understanding. Each round reveals new structure that informs where to look next. When answering "what does this system do?" questions, a few rounds of blast_radius → get_entity → blast_radius on the newly discovered symbols will build a complete picture faster than reading files.`;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
get_optimal_context: 'core',
|
|
49
|
-
// Navigation — after agent starts exploring (revealed after ~3 queries)
|
|
50
|
-
query_entities: 'navigate',
|
|
51
|
-
list_modules: 'navigate',
|
|
52
|
-
get_topology: 'navigate',
|
|
53
|
-
get_data_flow: 'navigate',
|
|
54
|
-
find_by_constraint: 'navigate',
|
|
55
|
-
// Security surface — after architecture is understood (~8 queries)
|
|
56
|
-
get_auth_matrix: 'security',
|
|
57
|
-
find_exposure_leaks: 'security',
|
|
58
|
-
// Quality & audit — after deep exploration (~15 queries)
|
|
59
|
-
find_dead_code: 'quality',
|
|
60
|
-
find_layer_violations: 'quality',
|
|
61
|
-
get_coupling_metrics: 'quality',
|
|
62
|
-
find_error_gaps: 'quality',
|
|
63
|
-
get_test_coverage: 'quality',
|
|
64
|
-
find_runtime_violations: 'quality',
|
|
65
|
-
find_ownership_violations: 'quality',
|
|
66
|
-
query_traits: 'quality',
|
|
67
|
-
find_semantic_clones: 'quality',
|
|
68
|
-
// Architect — always gated by tier, shown when quality is visible
|
|
69
|
-
estimate_task_cost: 'full',
|
|
70
|
-
simulate_mutation: 'full',
|
|
71
|
-
create_symbol: 'full',
|
|
72
|
-
diff_bundle: 'full',
|
|
73
|
-
conflict_matrix: 'full',
|
|
74
|
-
query_data_targets: 'full',
|
|
75
|
-
};
|
|
76
|
-
// Query thresholds for each stage transition
|
|
77
|
-
const REVELATION_THRESHOLDS = {
|
|
78
|
-
core: 0, // Immediate
|
|
79
|
-
navigate: 3, // After a few core loop calls
|
|
80
|
-
security: 8, // After architecture is understood
|
|
81
|
-
quality: 15, // After deep exploration
|
|
82
|
-
full: 25, // Power user territory
|
|
83
|
-
};
|
|
84
|
-
// Session state for progressive revelation
|
|
85
|
-
let _sessionQueryCount = 0;
|
|
86
|
-
let _currentStage = 'core';
|
|
87
|
-
let _serverRef = null; // Stored so we can send notifications
|
|
88
|
-
function stageAtLeast(current, required) {
|
|
89
|
-
return REVELATION_ORDER.indexOf(current) >= REVELATION_ORDER.indexOf(required);
|
|
90
|
-
}
|
|
91
|
-
function checkRevelation() {
|
|
92
|
-
for (const stage of REVELATION_ORDER) {
|
|
93
|
-
if (_sessionQueryCount >= REVELATION_THRESHOLDS[stage]) {
|
|
94
|
-
if (REVELATION_ORDER.indexOf(stage) > REVELATION_ORDER.indexOf(_currentStage)) {
|
|
95
|
-
const previousStage = _currentStage;
|
|
96
|
-
_currentStage = stage;
|
|
97
|
-
// Notify client that tool list has changed
|
|
98
|
-
if (_serverRef) {
|
|
99
|
-
_serverRef.notification({ method: 'notifications/tools/list_changed' });
|
|
100
|
-
process.stderr.write(`[Seshat] Revelation: ${previousStage} → ${stage} (${_sessionQueryCount} queries). Notified client.\n`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
const TOOL_TIERS = {
|
|
107
|
-
// Cartographer (free) — explore, navigate, and assess security surface
|
|
108
|
-
list_projects: 'cartographer',
|
|
109
|
-
query_entities: 'cartographer',
|
|
110
|
-
get_entity: 'cartographer',
|
|
111
|
-
get_dependencies: 'cartographer',
|
|
112
|
-
get_data_flow: 'cartographer',
|
|
113
|
-
find_by_constraint: 'cartographer',
|
|
114
|
-
get_blast_radius: 'cartographer',
|
|
115
|
-
list_modules: 'cartographer',
|
|
116
|
-
get_topology: 'cartographer',
|
|
117
|
-
get_optimal_context: 'cartographer',
|
|
118
|
-
get_auth_matrix: 'cartographer',
|
|
119
|
-
find_exposure_leaks: 'cartographer',
|
|
120
|
-
// Analyst (tier 2) — audit and diagnose
|
|
121
|
-
find_dead_code: 'analyst',
|
|
122
|
-
find_layer_violations: 'analyst',
|
|
123
|
-
get_coupling_metrics: 'analyst',
|
|
124
|
-
find_error_gaps: 'analyst',
|
|
125
|
-
get_test_coverage: 'analyst',
|
|
126
|
-
find_runtime_violations: 'analyst',
|
|
127
|
-
find_ownership_violations: 'analyst',
|
|
128
|
-
query_traits: 'analyst',
|
|
129
|
-
find_semantic_clones: 'analyst',
|
|
130
|
-
// Architect (tier 3) — simulate, estimate, and act
|
|
131
|
-
estimate_task_cost: 'architect',
|
|
132
|
-
simulate_mutation: 'architect',
|
|
133
|
-
create_symbol: 'architect',
|
|
134
|
-
diff_bundle: 'architect',
|
|
135
|
-
conflict_matrix: 'architect',
|
|
136
|
-
query_data_targets: 'architect',
|
|
137
|
-
};
|
|
138
|
-
const TIER_LABELS = {
|
|
139
|
-
cartographer: 'Cartographer (Free)',
|
|
140
|
-
pro: 'Seshat Pro',
|
|
141
|
-
analyst: 'Seshat Shield',
|
|
142
|
-
architect: 'Architect',
|
|
143
|
-
founder: 'Founder (All Access)',
|
|
144
|
-
};
|
|
145
|
-
function tierAtLeast(userTier, requiredTier) {
|
|
146
|
-
return TIER_ORDER.indexOf(userTier) >= TIER_ORDER.indexOf(requiredTier);
|
|
147
|
-
}
|
|
37
|
+
// ─── Private Tools (Ptah IP — never exposed publicly) ────────────
|
|
38
|
+
// These tools are reserved for the Ptah write layer. They exist in
|
|
39
|
+
// the codebase but are never listed, never hinted at, never mentioned.
|
|
40
|
+
const PRIVATE_TOOLS = new Set([
|
|
41
|
+
'estimate_task_cost',
|
|
42
|
+
'simulate_mutation',
|
|
43
|
+
'create_symbol',
|
|
44
|
+
'diff_bundle',
|
|
45
|
+
'conflict_matrix',
|
|
46
|
+
'query_data_targets',
|
|
47
|
+
]);
|
|
148
48
|
// ─── Shared Definitions ──────────────────────────────────────────
|
|
149
49
|
const projectParam = {
|
|
150
50
|
type: 'string',
|
|
@@ -511,6 +411,11 @@ const TOOLS = [
|
|
|
511
411
|
annotations: READ_ONLY_OPEN,
|
|
512
412
|
},
|
|
513
413
|
];
|
|
414
|
+
// ─── _meta Steering Hints ────────────────────────────────────────
|
|
415
|
+
// After each tool call, suggest the next logical tool based on what
|
|
416
|
+
// the agent has been doing. This replaces progressive revelation —
|
|
417
|
+
// all tools are visible, but hints guide the agent toward the right
|
|
418
|
+
// tool at the right time.
|
|
514
419
|
// ─── Project Resolution (Fallback) ────────────────────────────────
|
|
515
420
|
// Cache for the last project used — so tools auto-scope after list_projects
|
|
516
421
|
let _lastKnownProject;
|
|
@@ -551,46 +456,15 @@ function getCloudUrl(path) {
|
|
|
551
456
|
async function main() {
|
|
552
457
|
const server = new Server({
|
|
553
458
|
name: 'seshat',
|
|
554
|
-
version: '0.14.
|
|
459
|
+
version: '0.14.2',
|
|
555
460
|
}, {
|
|
556
|
-
capabilities: { tools: {
|
|
461
|
+
capabilities: { tools: {} },
|
|
557
462
|
instructions: SERVER_INSTRUCTIONS,
|
|
558
463
|
});
|
|
559
|
-
//
|
|
560
|
-
_serverRef = server;
|
|
561
|
-
// ─── Dynamic ListTools — only expose tools the user can access ──
|
|
464
|
+
// ─── ListTools — all public tools, Architect tools hidden (Ptah IP) ──
|
|
562
465
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
// Fetch account status to determine which tools to expose
|
|
566
|
-
if (apiKey) {
|
|
567
|
-
try {
|
|
568
|
-
const res = await fetch(getCloudUrl('/api/mcp/account'), {
|
|
569
|
-
method: 'GET',
|
|
570
|
-
headers: { 'x-api-key': apiKey },
|
|
571
|
-
});
|
|
572
|
-
if (res.ok) {
|
|
573
|
-
const account = await res.json();
|
|
574
|
-
userTier = account.tier || 'cartographer';
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
catch {
|
|
578
|
-
// If unavailable, default to cartographer (free tier tools only)
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
// Filter tools by BOTH tier access AND revelation stage
|
|
582
|
-
const visibleTools = TOOLS.filter((tool) => {
|
|
583
|
-
// Tier gate: user must have access
|
|
584
|
-
const requiredTier = TOOL_TIERS[tool.name];
|
|
585
|
-
if (requiredTier && !tierAtLeast(userTier, requiredTier))
|
|
586
|
-
return false;
|
|
587
|
-
// Revelation gate: tool must be revealed at current stage
|
|
588
|
-
const requiredStage = TOOL_REVELATION[tool.name];
|
|
589
|
-
if (requiredStage && !stageAtLeast(_currentStage, requiredStage))
|
|
590
|
-
return false;
|
|
591
|
-
return true;
|
|
592
|
-
});
|
|
593
|
-
process.stderr.write(`[Seshat] ListTools: stage=${_currentStage}, queries=${_sessionQueryCount}, tools=${visibleTools.length}/${TOOLS.length}\n`);
|
|
466
|
+
const visibleTools = TOOLS.filter((tool) => !PRIVATE_TOOLS.has(tool.name));
|
|
467
|
+
process.stderr.write(`[Seshat] ListTools: ${visibleTools.length} tools (${PRIVATE_TOOLS.size} private)\n`);
|
|
594
468
|
return { tools: visibleTools };
|
|
595
469
|
});
|
|
596
470
|
// ─── CallTool handler ──────────────────────────────────────────
|
|
@@ -603,6 +477,13 @@ async function main() {
|
|
|
603
477
|
isError: true,
|
|
604
478
|
};
|
|
605
479
|
}
|
|
480
|
+
// Block private Ptah tools from being called
|
|
481
|
+
if (PRIVATE_TOOLS.has(name)) {
|
|
482
|
+
return {
|
|
483
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Unknown tool: ${name}` }, null, 2) }],
|
|
484
|
+
isError: true,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
606
487
|
// ─── get_account_status ──────────────────────────────────────
|
|
607
488
|
if (name === 'get_account_status') {
|
|
608
489
|
try {
|
|
@@ -618,37 +499,16 @@ async function main() {
|
|
|
618
499
|
};
|
|
619
500
|
}
|
|
620
501
|
const account = await res.json();
|
|
621
|
-
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
const upgradeTeaser = {};
|
|
626
|
-
for (const [toolName, requiredTier] of Object.entries(TOOL_TIERS)) {
|
|
627
|
-
if (tierAtLeast(userTier, requiredTier)) {
|
|
628
|
-
availableTools.push(toolName);
|
|
629
|
-
}
|
|
630
|
-
else {
|
|
631
|
-
if (!upgradeTeaser[TIER_LABELS[requiredTier]]) {
|
|
632
|
-
upgradeTeaser[TIER_LABELS[requiredTier]] = [];
|
|
633
|
-
}
|
|
634
|
-
upgradeTeaser[TIER_LABELS[requiredTier]].push(toolName);
|
|
635
|
-
}
|
|
636
|
-
}
|
|
502
|
+
// List all public tools
|
|
503
|
+
const publicTools = TOOLS
|
|
504
|
+
.filter(t => !PRIVATE_TOOLS.has(t.name))
|
|
505
|
+
.map(t => t.name);
|
|
637
506
|
const response = {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
tool_count: `${availableTools.length} tools available`,
|
|
507
|
+
status: 'active',
|
|
508
|
+
tools_available: publicTools.length,
|
|
509
|
+
your_tools: publicTools,
|
|
510
|
+
dashboard: 'https://ptah.papyruslabs.ai/dashboard',
|
|
643
511
|
};
|
|
644
|
-
// Only mention upgrades if there are locked tools, and frame positively
|
|
645
|
-
if (Object.keys(upgradeTeaser).length > 0) {
|
|
646
|
-
const totalLocked = Object.values(upgradeTeaser).reduce((sum, t) => sum + t.length, 0);
|
|
647
|
-
response.upgrades_available = {
|
|
648
|
-
summary: `${totalLocked} additional diagnostic and simulation tools available with a tier upgrade — find dead code, coupling hotspots, test gaps, layer violations, and simulate changes before making them.`,
|
|
649
|
-
url: 'https://ptah.papyruslabs.ai/settings/billing',
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
512
|
return {
|
|
653
513
|
content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
|
|
654
514
|
};
|
|
@@ -702,12 +562,10 @@ async function main() {
|
|
|
702
562
|
if (name === 'list_projects' && result.projects && result.projects.length > 0) {
|
|
703
563
|
_lastKnownProject = result.projects[0].name;
|
|
704
564
|
}
|
|
705
|
-
// Progressive revelation: count queries and check for stage transitions
|
|
706
|
-
_sessionQueryCount++;
|
|
707
|
-
checkRevelation();
|
|
708
565
|
// Separate _meta into assistant-only content so it doesn't clutter
|
|
709
566
|
// the user-visible response. The LLM still sees it for context.
|
|
710
|
-
|
|
567
|
+
// Server-side _meta now includes cross-tool recommendations.
|
|
568
|
+
if (result._meta && Object.keys(result._meta).length > 0) {
|
|
711
569
|
const meta = result._meta;
|
|
712
570
|
delete result._meta;
|
|
713
571
|
return {
|
|
@@ -717,6 +575,9 @@ async function main() {
|
|
|
717
575
|
],
|
|
718
576
|
};
|
|
719
577
|
}
|
|
578
|
+
// Strip empty _meta
|
|
579
|
+
if (result._meta)
|
|
580
|
+
delete result._meta;
|
|
720
581
|
return {
|
|
721
582
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
722
583
|
};
|
package/package.json
CHANGED