@supermodeltools/mcp-server 0.9.1 → 0.9.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/constants.js +2 -1
- package/dist/index.js +7 -0
- package/dist/server.js +23 -22
- package/dist/tools/overview.js +3 -2
- package/dist/tools/symbol-context.js +137 -13
- package/dist/utils/api-helpers.js +10 -0
- package/package.json +2 -2
package/dist/constants.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Single source of truth for configuration values
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.MAX_SYMBOL_RELATED = exports.MAX_SYMBOL_CALLEES = exports.MAX_SYMBOL_CALLERS = exports.MAX_OVERVIEW_HUB_FUNCTIONS = exports.MAX_OVERVIEW_DOMAINS = exports.DEFAULT_CACHE_TTL_MS = exports.DEFAULT_MAX_NODES = exports.DEFAULT_MAX_GRAPHS = exports.MAX_ZIP_SIZE_BYTES = exports.ZIP_CLEANUP_AGE_MS = exports.CONNECTION_TIMEOUT_MS = exports.DEFAULT_API_TIMEOUT_MS = void 0;
|
|
7
|
+
exports.MAX_SOURCE_LINES = exports.MAX_SYMBOL_RELATED = exports.MAX_SYMBOL_CALLEES = exports.MAX_SYMBOL_CALLERS = exports.MAX_OVERVIEW_HUB_FUNCTIONS = exports.MAX_OVERVIEW_DOMAINS = exports.DEFAULT_CACHE_TTL_MS = exports.DEFAULT_MAX_NODES = exports.DEFAULT_MAX_GRAPHS = exports.MAX_ZIP_SIZE_BYTES = exports.ZIP_CLEANUP_AGE_MS = exports.CONNECTION_TIMEOUT_MS = exports.DEFAULT_API_TIMEOUT_MS = void 0;
|
|
8
8
|
// HTTP timeout configuration
|
|
9
9
|
exports.DEFAULT_API_TIMEOUT_MS = 900_000; // 15 minutes (complex repos can take 10+ min)
|
|
10
10
|
exports.CONNECTION_TIMEOUT_MS = 30_000; // 30 seconds to establish connection
|
|
@@ -22,3 +22,4 @@ exports.MAX_OVERVIEW_HUB_FUNCTIONS = 10; // Top N hub functions to show
|
|
|
22
22
|
exports.MAX_SYMBOL_CALLERS = 10; // Top N callers to show
|
|
23
23
|
exports.MAX_SYMBOL_CALLEES = 10; // Top N callees to show
|
|
24
24
|
exports.MAX_SYMBOL_RELATED = 8; // Related symbols in same file
|
|
25
|
+
exports.MAX_SOURCE_LINES = 50; // Max lines of source code to include inline
|
package/dist/index.js
CHANGED
|
@@ -214,6 +214,13 @@ async function handlePrecache(args) {
|
|
|
214
214
|
console.error('');
|
|
215
215
|
console.error('Done! To use this cache, set SUPERMODEL_CACHE_DIR=' + outputDir);
|
|
216
216
|
}
|
|
217
|
+
// Graceful shutdown on signals (e.g., container stop, SSH drop)
|
|
218
|
+
for (const signal of ['SIGTERM', 'SIGINT']) {
|
|
219
|
+
process.on(signal, () => {
|
|
220
|
+
logger.debug(`Received ${signal}, shutting down`);
|
|
221
|
+
process.exit(0);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
217
224
|
main().catch((error) => {
|
|
218
225
|
logger.error('Fatal error:', error);
|
|
219
226
|
process.exit(1);
|
package/dist/server.js
CHANGED
|
@@ -91,21 +91,21 @@ class Server {
|
|
|
91
91
|
|
|
92
92
|
Two tools for instant codebase understanding. Pre-computed graphs enable sub-second responses.
|
|
93
93
|
|
|
94
|
-
##
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
## Recommended workflow
|
|
95
|
+
1. \`overview\` first to learn architecture and key symbols (1 call)
|
|
96
|
+
2. \`symbol_context\` on 1-2 symbols from the issue to see source, callers, callees (1-2 calls)
|
|
97
|
+
3. Stop calling MCP tools. Use the results to make your fix.
|
|
97
98
|
|
|
98
|
-
##
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
Supports partial matching and "ClassName.method" syntax.
|
|
99
|
+
## Anti-patterns
|
|
100
|
+
- >3 MCP calls total = diminishing returns. Aim for 1 overview + 1-2 symbol lookups.
|
|
101
|
+
- Chasing callers-of-callers burns iterations without helping.
|
|
102
102
|
|
|
103
|
-
##
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
## After fixing
|
|
104
|
+
Run the project's existing test suite (e.g. pytest). Do NOT write standalone test scripts.
|
|
105
|
+
|
|
106
|
+
## Tool reference
|
|
107
|
+
- \`overview\`: Architecture map, domains, hub functions, file counts. Zero-arg, sub-second.
|
|
108
|
+
- \`symbol_context\`: Source, callers, callees, domain for any function/class/method. Supports "Class.method" and partial matching.`,
|
|
109
109
|
});
|
|
110
110
|
const config = new sdk_1.Configuration({
|
|
111
111
|
basePath: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com',
|
|
@@ -167,26 +167,27 @@ Supports partial matching and "ClassName.method" syntax.
|
|
|
167
167
|
logger.warn('Failed to load cache directory:', err.message || err);
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
+
// Connect transport FIRST so the MCP handshake completes immediately.
|
|
171
|
+
// This prevents Claude Code from timing out the server (MCP_TIMEOUT=60s)
|
|
172
|
+
// when precaching requires a slow API call.
|
|
173
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
174
|
+
await this.server.connect(transport);
|
|
175
|
+
logger.info('Supermodel MCP Server running on stdio');
|
|
170
176
|
// Precache the workdir's repo if --precache flag is set.
|
|
171
|
-
// Runs BEFORE noApiFallback
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
// with the same repo+commit return instantly. Results are saved to
|
|
175
|
-
// cacheDir for cross-container persistence.
|
|
177
|
+
// Runs AFTER connect but BEFORE noApiFallback so the API is available.
|
|
178
|
+
// This is fire-and-forget from the MCP client's perspective — tools
|
|
179
|
+
// that arrive before precaching finishes will use on-demand API calls.
|
|
176
180
|
if (this.options?.precache && this.defaultWorkdir) {
|
|
177
181
|
try {
|
|
178
182
|
await (0, graph_cache_1.precacheForDirectory)(this.client, this.defaultWorkdir, cacheDir);
|
|
179
183
|
}
|
|
180
184
|
catch (err) {
|
|
181
|
-
// Non-fatal: if precaching fails, tools fall back to
|
|
185
|
+
// Non-fatal: if precaching fails, tools fall back to on-demand API
|
|
182
186
|
logger.warn('Startup precache failed:', err.message || err);
|
|
183
187
|
}
|
|
184
188
|
}
|
|
185
189
|
// NOW enable no-api-fallback (after precaching had its chance)
|
|
186
190
|
(0, graph_cache_1.setNoApiFallback)(!!this.options?.noApiFallback);
|
|
187
|
-
const transport = new stdio_js_1.StdioServerTransport();
|
|
188
|
-
await this.server.connect(transport);
|
|
189
|
-
logger.info('Supermodel MCP Server running on stdio');
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
exports.Server = Server;
|
package/dist/tools/overview.js
CHANGED
|
@@ -17,7 +17,7 @@ const api_helpers_1 = require("../utils/api-helpers");
|
|
|
17
17
|
const constants_1 = require("../constants");
|
|
18
18
|
exports.tool = {
|
|
19
19
|
name: 'overview',
|
|
20
|
-
description: `
|
|
20
|
+
description: `Returns a pre-computed architectural map of the entire codebase: which domains own which files, the most-called hub functions (call graph centrality), file/function/class counts. Sub-second, zero cost. Useful when you need to understand the overall structure before diving in. Skip this if you already know what file or symbol to investigate — use symbol_context or file reading instead.`,
|
|
21
21
|
inputSchema: {
|
|
22
22
|
type: 'object',
|
|
23
23
|
properties: {
|
|
@@ -30,7 +30,8 @@ exports.tool = {
|
|
|
30
30
|
},
|
|
31
31
|
};
|
|
32
32
|
const handler = async (client, args, defaultWorkdir) => {
|
|
33
|
-
const
|
|
33
|
+
const rawDir = args?.directory;
|
|
34
|
+
const directory = (rawDir && rawDir.trim()) || defaultWorkdir || process.cwd();
|
|
34
35
|
if (!directory || typeof directory !== 'string') {
|
|
35
36
|
return (0, types_1.asErrorResult)({
|
|
36
37
|
type: 'validation_error',
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* `symbol_context` tool -- deep dive on a specific symbol.
|
|
4
4
|
*
|
|
5
|
-
* Given a function, class, or method name, returns (<
|
|
5
|
+
* Given a function, class, or method name, returns (<10KB markdown):
|
|
6
6
|
* - Definition location (file, line)
|
|
7
|
+
* - Source code (up to MAX_SOURCE_LINES)
|
|
7
8
|
* - Callers (who calls this)
|
|
8
9
|
* - Callees (what this calls)
|
|
9
10
|
* - Domain membership
|
|
@@ -11,15 +12,53 @@
|
|
|
11
12
|
*
|
|
12
13
|
* Backed by pre-computed graphs (sub-second) with on-demand API fallback.
|
|
13
14
|
*/
|
|
15
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
+
}
|
|
21
|
+
Object.defineProperty(o, k2, desc);
|
|
22
|
+
}) : (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
o[k2] = m[k];
|
|
25
|
+
}));
|
|
26
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
27
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
28
|
+
}) : function(o, v) {
|
|
29
|
+
o["default"] = v;
|
|
30
|
+
});
|
|
31
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
32
|
+
var ownKeys = function(o) {
|
|
33
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
34
|
+
var ar = [];
|
|
35
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
36
|
+
return ar;
|
|
37
|
+
};
|
|
38
|
+
return ownKeys(o);
|
|
39
|
+
};
|
|
40
|
+
return function (mod) {
|
|
41
|
+
if (mod && mod.__esModule) return mod;
|
|
42
|
+
var result = {};
|
|
43
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
44
|
+
__setModuleDefault(result, mod);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
})();
|
|
14
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
49
|
exports.handler = exports.tool = void 0;
|
|
50
|
+
exports.findSymbol = findSymbol;
|
|
51
|
+
exports.renderSymbolContext = renderSymbolContext;
|
|
52
|
+
exports.languageFromExtension = languageFromExtension;
|
|
53
|
+
const fs_1 = require("fs");
|
|
54
|
+
const path = __importStar(require("path"));
|
|
16
55
|
const types_1 = require("../types");
|
|
17
56
|
const graph_cache_1 = require("../cache/graph-cache");
|
|
18
57
|
const api_helpers_1 = require("../utils/api-helpers");
|
|
19
58
|
const constants_1 = require("../constants");
|
|
20
59
|
exports.tool = {
|
|
21
60
|
name: 'symbol_context',
|
|
22
|
-
description: `Strictly better than grep for understanding a function, class, or method. Given a symbol name, instantly returns its definition location, all callers, all callees, architectural domain, and related symbols in the same file -- structural context that grep cannot reconstruct. Sub-second, zero cost. Supports partial matching ("filter" finds "QuerySet.filter", "filter_queryset", etc.) and "ClassName.method" syntax. Use this whenever you have a symbol name from a stack trace, issue, or search result and need to understand how it connects to the rest of the codebase.`,
|
|
61
|
+
description: `Strictly better than grep for understanding a function, class, or method. Given a symbol name, instantly returns its source code, definition location, all callers, all callees, architectural domain, and related symbols in the same file -- structural context that grep cannot reconstruct. Sub-second, zero cost. Supports partial matching ("filter" finds "QuerySet.filter", "filter_queryset", etc.) and "ClassName.method" syntax. Use this whenever you have a symbol name from a stack trace, issue, or search result and need to understand how it connects to the rest of the codebase.`,
|
|
23
62
|
inputSchema: {
|
|
24
63
|
type: 'object',
|
|
25
64
|
properties: {
|
|
@@ -37,7 +76,8 @@ exports.tool = {
|
|
|
37
76
|
};
|
|
38
77
|
const handler = async (client, args, defaultWorkdir) => {
|
|
39
78
|
const symbol = typeof args?.symbol === 'string' ? args.symbol.trim() : '';
|
|
40
|
-
const
|
|
79
|
+
const rawDir = args?.directory;
|
|
80
|
+
const directory = (rawDir && rawDir.trim()) || defaultWorkdir || process.cwd();
|
|
41
81
|
if (!symbol) {
|
|
42
82
|
return (0, types_1.asErrorResult)({
|
|
43
83
|
type: 'validation_error',
|
|
@@ -73,10 +113,8 @@ const handler = async (client, args, defaultWorkdir) => {
|
|
|
73
113
|
`- Use the \`overview\` tool to see available domains and key functions`);
|
|
74
114
|
}
|
|
75
115
|
// Render results for top matches (usually 1, sometimes a few)
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
.map(node => renderSymbolContext(graph, node))
|
|
79
|
-
.join('\n---\n\n');
|
|
116
|
+
const renderedParts = await Promise.all(matches.slice(0, 3).map(node => renderSymbolContext(graph, node, directory)));
|
|
117
|
+
const rendered = renderedParts.join('\n---\n\n');
|
|
80
118
|
if (matches.length > 3) {
|
|
81
119
|
return (0, types_1.asTextContentResult)(rendered + `\n\n*... and ${matches.length - 3} more matches. Use a more specific name to narrow results.*`);
|
|
82
120
|
}
|
|
@@ -100,7 +138,12 @@ function findSymbol(graph, query) {
|
|
|
100
138
|
return exactIds
|
|
101
139
|
.map(id => graph.nodeById.get(id))
|
|
102
140
|
.filter(n => n && isCodeSymbol(n))
|
|
103
|
-
.sort((a, b) =>
|
|
141
|
+
.sort((a, b) => {
|
|
142
|
+
const pDiff = symbolPriority(a) - symbolPriority(b);
|
|
143
|
+
if (pDiff !== 0)
|
|
144
|
+
return pDiff;
|
|
145
|
+
return callerCount(graph, b) - callerCount(graph, a);
|
|
146
|
+
});
|
|
104
147
|
}
|
|
105
148
|
// Strategy 2: ClassName.method match
|
|
106
149
|
if (className && methodName) {
|
|
@@ -116,13 +159,21 @@ function findSymbol(graph, query) {
|
|
|
116
159
|
return fp && classFilePaths.has(fp);
|
|
117
160
|
});
|
|
118
161
|
if (matched.length > 0) {
|
|
119
|
-
return matched.sort((a, b) =>
|
|
162
|
+
return matched.sort((a, b) => {
|
|
163
|
+
const pDiff = symbolPriority(a) - symbolPriority(b);
|
|
164
|
+
if (pDiff !== 0)
|
|
165
|
+
return pDiff;
|
|
166
|
+
return callerCount(graph, b) - callerCount(graph, a);
|
|
167
|
+
});
|
|
120
168
|
}
|
|
121
169
|
}
|
|
122
170
|
// Strategy 3: Substring match (for partial names)
|
|
171
|
+
if (lowerQuery.length < 2) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
123
174
|
const substringMatches = [];
|
|
124
175
|
for (const [name, ids] of graph.nameIndex) {
|
|
125
|
-
if (name.includes(lowerQuery)
|
|
176
|
+
if (name.includes(lowerQuery)) {
|
|
126
177
|
for (const id of ids) {
|
|
127
178
|
const node = graph.nodeById.get(id);
|
|
128
179
|
if (node && isCodeSymbol(node)) {
|
|
@@ -131,7 +182,7 @@ function findSymbol(graph, query) {
|
|
|
131
182
|
}
|
|
132
183
|
}
|
|
133
184
|
}
|
|
134
|
-
// Sort by relevance: exact prefix > contains
|
|
185
|
+
// Sort by relevance: exact prefix > contains, then symbol priority, then caller count
|
|
135
186
|
substringMatches.sort((a, b) => {
|
|
136
187
|
const aName = (a.properties?.name || '').toLowerCase();
|
|
137
188
|
const bName = (b.properties?.name || '').toLowerCase();
|
|
@@ -139,7 +190,10 @@ function findSymbol(graph, query) {
|
|
|
139
190
|
const bPrefix = bName.startsWith(lowerQuery) ? 0 : 1;
|
|
140
191
|
if (aPrefix !== bPrefix)
|
|
141
192
|
return aPrefix - bPrefix;
|
|
142
|
-
|
|
193
|
+
const pDiff = symbolPriority(a) - symbolPriority(b);
|
|
194
|
+
if (pDiff !== 0)
|
|
195
|
+
return pDiff;
|
|
196
|
+
return callerCount(graph, b) - callerCount(graph, a);
|
|
143
197
|
});
|
|
144
198
|
return substringMatches.slice(0, 10);
|
|
145
199
|
}
|
|
@@ -157,8 +211,11 @@ function symbolPriority(node) {
|
|
|
157
211
|
return 2;
|
|
158
212
|
return 3;
|
|
159
213
|
}
|
|
214
|
+
function callerCount(graph, node) {
|
|
215
|
+
return graph.callAdj.get(node.id)?.in.length || 0;
|
|
216
|
+
}
|
|
160
217
|
// ── Rendering ──
|
|
161
|
-
function renderSymbolContext(graph, node) {
|
|
218
|
+
async function renderSymbolContext(graph, node, directory) {
|
|
162
219
|
const name = node.properties?.name || '(unknown)';
|
|
163
220
|
const rawFilePath = node.properties?.filePath || '';
|
|
164
221
|
const filePath = (0, graph_cache_1.normalizePath)(rawFilePath);
|
|
@@ -178,6 +235,31 @@ function renderSymbolContext(graph, node) {
|
|
|
178
235
|
lines.push(`**Domain:** ${domain}`);
|
|
179
236
|
}
|
|
180
237
|
lines.push('');
|
|
238
|
+
// Source code
|
|
239
|
+
if (filePath && startLine > 0) {
|
|
240
|
+
try {
|
|
241
|
+
const absPath = path.resolve(directory, filePath);
|
|
242
|
+
const content = await fs_1.promises.readFile(absPath, 'utf-8');
|
|
243
|
+
const fileLines = content.split('\n');
|
|
244
|
+
const end = endLine > 0 ? Math.min(endLine, startLine + constants_1.MAX_SOURCE_LINES - 1) : startLine + constants_1.MAX_SOURCE_LINES - 1;
|
|
245
|
+
const sourceSlice = fileLines.slice(startLine - 1, end);
|
|
246
|
+
if (sourceSlice.length > 0) {
|
|
247
|
+
const lang = languageFromExtension(filePath);
|
|
248
|
+
lines.push(`### Source`);
|
|
249
|
+
lines.push('');
|
|
250
|
+
lines.push(`\`\`\`${lang}`);
|
|
251
|
+
lines.push(sourceSlice.join('\n'));
|
|
252
|
+
lines.push('```');
|
|
253
|
+
if (endLine > 0 && endLine > startLine + constants_1.MAX_SOURCE_LINES - 1) {
|
|
254
|
+
lines.push(`*... truncated (showing ${constants_1.MAX_SOURCE_LINES} of ${endLine - startLine + 1} lines)*`);
|
|
255
|
+
}
|
|
256
|
+
lines.push('');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// File unreadable — skip source section silently
|
|
261
|
+
}
|
|
262
|
+
}
|
|
181
263
|
// Callers
|
|
182
264
|
const adj = graph.callAdj.get(node.id);
|
|
183
265
|
if (adj && adj.in.length > 0) {
|
|
@@ -274,6 +356,48 @@ function renderSymbolContext(graph, node) {
|
|
|
274
356
|
}
|
|
275
357
|
return lines.join('\n');
|
|
276
358
|
}
|
|
359
|
+
function languageFromExtension(filePath) {
|
|
360
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
361
|
+
const map = {
|
|
362
|
+
'.ts': 'typescript',
|
|
363
|
+
'.tsx': 'typescript',
|
|
364
|
+
'.js': 'javascript',
|
|
365
|
+
'.jsx': 'javascript',
|
|
366
|
+
'.py': 'python',
|
|
367
|
+
'.rb': 'ruby',
|
|
368
|
+
'.go': 'go',
|
|
369
|
+
'.rs': 'rust',
|
|
370
|
+
'.java': 'java',
|
|
371
|
+
'.kt': 'kotlin',
|
|
372
|
+
'.cs': 'csharp',
|
|
373
|
+
'.cpp': 'cpp',
|
|
374
|
+
'.c': 'c',
|
|
375
|
+
'.h': 'c',
|
|
376
|
+
'.hpp': 'cpp',
|
|
377
|
+
'.swift': 'swift',
|
|
378
|
+
'.php': 'php',
|
|
379
|
+
'.scala': 'scala',
|
|
380
|
+
'.sh': 'bash',
|
|
381
|
+
'.bash': 'bash',
|
|
382
|
+
'.yaml': 'yaml',
|
|
383
|
+
'.yml': 'yaml',
|
|
384
|
+
'.json': 'json',
|
|
385
|
+
'.xml': 'xml',
|
|
386
|
+
'.html': 'html',
|
|
387
|
+
'.css': 'css',
|
|
388
|
+
'.sql': 'sql',
|
|
389
|
+
'.r': 'r',
|
|
390
|
+
'.lua': 'lua',
|
|
391
|
+
'.dart': 'dart',
|
|
392
|
+
'.ex': 'elixir',
|
|
393
|
+
'.exs': 'elixir',
|
|
394
|
+
'.erl': 'erlang',
|
|
395
|
+
'.hs': 'haskell',
|
|
396
|
+
'.ml': 'ocaml',
|
|
397
|
+
'.clj': 'clojure',
|
|
398
|
+
};
|
|
399
|
+
return map[ext] || '';
|
|
400
|
+
}
|
|
277
401
|
function findDomain(graph, nodeId) {
|
|
278
402
|
for (const [domainName, data] of graph.domainIndex) {
|
|
279
403
|
if (data.memberIds.includes(nodeId)) {
|
|
@@ -66,6 +66,16 @@ function classifyApiError(error) {
|
|
|
66
66
|
details: { errorType: typeof error },
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
// Fast-fail: no pre-computed cache and API fallback disabled
|
|
70
|
+
if (error.code === 'NO_CACHE') {
|
|
71
|
+
return {
|
|
72
|
+
type: 'cache_error',
|
|
73
|
+
message: error.message || 'No pre-computed graph available for this repository.',
|
|
74
|
+
code: 'NO_CACHE',
|
|
75
|
+
recoverable: false,
|
|
76
|
+
suggestion: 'Use grep, find, and file reading to explore the codebase instead. Or run the precache command and set SUPERMODEL_CACHE_DIR.',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
69
79
|
if (error.response) {
|
|
70
80
|
const status = error.response.status;
|
|
71
81
|
switch (status) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supermodeltools/mcp-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "MCP server for Supermodel API - code graph generation for AI agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.0.1",
|
|
41
|
-
"@supermodeltools/sdk": "0.9.
|
|
41
|
+
"@supermodeltools/sdk": "0.9.3",
|
|
42
42
|
"archiver": "^7.0.1",
|
|
43
43
|
"ignore": "^7.0.5",
|
|
44
44
|
"jq-web": "^0.6.2",
|