@papyruslabsai/seshat-mcp 0.13.2 → 0.13.3

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 CHANGED
@@ -33,7 +33,7 @@ Use Seshat tools instead of grep/Read when you need to understand code structure
33
33
  All tools are read-only and safe to call speculatively — there is no cost to trying them.
34
34
 
35
35
  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.`;
36
- const TIER_ORDER = ['cartographer', 'analyst', 'architect'];
36
+ const TIER_ORDER = ['cartographer', 'analyst', 'architect', 'founder'];
37
37
  const TOOL_TIERS = {
38
38
  // Cartographer (free) — explore, navigate, and assess security surface
39
39
  list_projects: 'cartographer',
@@ -70,6 +70,7 @@ const TIER_LABELS = {
70
70
  cartographer: 'Cartographer (Free)',
71
71
  analyst: 'Analyst (Tier 2)',
72
72
  architect: 'Architect (Tier 3)',
73
+ founder: 'Founder (All Access)',
73
74
  };
74
75
  function tierAtLeast(userTier, requiredTier) {
75
76
  return TIER_ORDER.indexOf(userTier) >= TIER_ORDER.indexOf(requiredTier);
@@ -159,7 +160,7 @@ const TOOLS = [
159
160
  },
160
161
  {
161
162
  name: 'find_by_constraint',
162
- description: 'Find every function with a specific behavior tag — AUTH (requires authentication), DB_ACCESS (touches database), THROWS (can throw), PURE (no side effects), NETWORK_IO (makes HTTP calls), VALIDATED (has input validation). Use this when you need to answer questions like "which functions write to the database?" or "what endpoints lack auth?"',
163
+ description: 'Find every function with a specific syntactic constraint tag — AUTH (requires authentication), DB_ACCESS (touches database), THROWS (explicit throw statement), PURE (no side effects), NETWORK_IO (makes HTTP calls), VALIDATED (has input validation). Constraints are extracted from source syntax, not inferred. Use this when you need to answer "which functions write to the database?" or "what endpoints lack auth?" For semantic/behavioral properties (e.g., "can fail transitively"), use query_traits instead.',
163
164
  inputSchema: {
164
165
  type: 'object',
165
166
  properties: {
@@ -243,7 +244,7 @@ const TOOLS = [
243
244
  },
244
245
  {
245
246
  name: 'get_coupling_metrics',
246
- description: 'Measure how tangled modules are. Returns coupling (cross-module dependencies), cohesion (within-module dependencies), and instability scores. High coupling + low cohesion = refactoring candidates. Use this when planning a refactor to find the worst offenders.',
247
+ description: 'Measure how tangled your code is. Returns coupling (cross-boundary dependencies), cohesion (within-group dependencies), and instability scores. High coupling + low cohesion = refactoring candidates. Start with group_by: "layer" for the architectural health view ("are my controllers more coupled than my services?"), then drill into group_by: "module" for specific hotspots.',
247
248
  inputSchema: {
248
249
  type: 'object',
249
250
  properties: {
@@ -285,19 +286,19 @@ const TOOLS = [
285
286
  },
286
287
  {
287
288
  name: 'find_runtime_violations',
288
- description: 'Find architectural boundary leaks where framework-agnostic code imports framework-specific code. Use this when separating core logic from framework dependencies.',
289
+ description: 'Find architectural boundary leaks where framework-agnostic code imports framework-specific code. Use this when separating core logic from framework dependencies. Returns 0 for most JS/Python codebases — a non-zero result indicates a serious boundary violation worth investigating.',
289
290
  inputSchema: { type: 'object', properties: { project: projectParam } },
290
291
  annotations: READ_ONLY_OPEN,
291
292
  },
292
293
  {
293
294
  name: 'find_ownership_violations',
294
- description: 'Find memory and lifecycle issues — entities with complex ownership, unsafe blocks, escaping references, or illegal mutability on borrowed data. Most useful for Rust and C++ codebases.',
295
+ description: 'Find memory and lifecycle issues — entities with complex ownership, unsafe blocks, escaping references, or illegal mutability on borrowed data. Returns 0 for most JS/Python codebases — a non-zero result in those languages indicates a serious boundary violation worth investigating. Most detailed results for Rust and C++.',
295
296
  inputSchema: { type: 'object', properties: { project: projectParam } },
296
297
  annotations: READ_ONLY_OPEN,
297
298
  },
298
299
  {
299
300
  name: 'query_traits',
300
- description: 'Find functions by abstract capability regardless of syntax — "fallible" (can fail), "asyncContext" (carries async state), "generator" (yields values). Use this when you need to find all code with a specific behavioral trait across the entire codebase.',
301
+ description: 'Find functions by inferred behavioral trait — "fallible" (can fail, including transitively via callees that throw), "asyncContext" (carries async state), "generator" (yields values). Traits are semantic properties inferred from the call graph, not just syntax. Use this when you need to find all code with a specific capability. For syntactic tags (explicit throw statements, DB access), use find_by_constraint instead.',
301
302
  inputSchema: {
302
303
  type: 'object',
303
304
  properties: {
@@ -469,7 +470,7 @@ function getCloudUrl(path) {
469
470
  async function main() {
470
471
  const server = new Server({
471
472
  name: 'seshat',
472
- version: '0.13.2',
473
+ version: '0.13.3',
473
474
  }, {
474
475
  capabilities: { tools: {} },
475
476
  instructions: SERVER_INSTRUCTIONS,
@@ -135,6 +135,15 @@ export function findDeadCode(args, loader) {
135
135
  if (!include_tests) {
136
136
  deadEntities = deadEntities.filter((e) => entityLayer(e) !== 'test');
137
137
  }
138
+ // Separate schemas — they're often registered dynamically (e.g., fastify.addSchema())
139
+ // and appear "dead" from a static call graph but are alive at runtime.
140
+ const SCHEMA_TYPES = new Set(['schema', 'typealias', 'interface', 'type']);
141
+ const schemaEntities = deadEntities.filter((e) => {
142
+ const type = (typeof e.struct === 'string' ? e.struct : e.struct?.type || '').toLowerCase();
143
+ const layer = entityLayer(e);
144
+ return SCHEMA_TYPES.has(type) || layer === 'schema';
145
+ });
146
+ deadEntities = deadEntities.filter((e) => !schemaEntities.includes(e));
138
147
  // Group by layer for overview
139
148
  const byLayer = new Map();
140
149
  for (const e of deadEntities) {
@@ -148,6 +157,10 @@ export function findDeadCode(args, loader) {
148
157
  deadCount: deadEntities.length,
149
158
  deadByLayer: Object.fromEntries([...byLayer.entries()].sort((a, b) => b[1] - a[1])),
150
159
  dead: deadEntities.slice(0, 100).map(entitySummary),
160
+ ...(schemaEntities.length > 0 ? {
161
+ schemas_excluded: schemaEntities.length,
162
+ _note_schemas: `${schemaEntities.length} schema/type definitions excluded — no static references found, but schemas are often registered dynamically (e.g., fastify.addSchema()) and may be alive at runtime.`,
163
+ } : {}),
151
164
  };
152
165
  }
153
166
  // ─── Tool: find_layer_violations ─────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@papyruslabsai/seshat-mcp",
3
- "version": "0.13.2",
3
+ "version": "0.13.3",
4
4
  "description": "Semantic MCP server — exposes a codebase's structure, dependencies, and constraints as queryable tools",
5
5
  "type": "module",
6
6
  "bin": {