@supermodeltools/mcp-server 0.5.3 → 0.6.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/README.md +311 -26
- package/dist/server.js +14 -1
- package/dist/tools/create-supermodel-graph.js +231 -87
- package/dist/types.js +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,45 @@ MCP server that provides deep codebase analysis to AI agents via the [Supermodel
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
+
### Quick Setup (Recommended)
|
|
12
|
+
|
|
13
|
+
Run the setup script to configure the recommended timeout settings:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
curl -sSL https://raw.githubusercontent.com/supermodeltools/mcp/main/setup.sh | bash
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
<details>
|
|
20
|
+
<summary>Prefer to inspect before running? (Click to expand)</summary>
|
|
21
|
+
|
|
22
|
+
Download, review, then execute:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Download the script
|
|
26
|
+
curl -sSL https://raw.githubusercontent.com/supermodeltools/mcp/main/setup.sh -o setup.sh
|
|
27
|
+
|
|
28
|
+
# Review the contents
|
|
29
|
+
cat setup.sh
|
|
30
|
+
|
|
31
|
+
# Make executable and run
|
|
32
|
+
chmod +x setup.sh
|
|
33
|
+
./setup.sh
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or clone the entire repo:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git clone https://github.com/supermodeltools/mcp.git
|
|
40
|
+
cd mcp
|
|
41
|
+
./setup.sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
</details>
|
|
45
|
+
|
|
46
|
+
This will configure `MCP_TOOL_TIMEOUT=900000` for optimal performance with large codebases.
|
|
47
|
+
|
|
48
|
+
### Manual Install
|
|
49
|
+
|
|
11
50
|
```bash
|
|
12
51
|
npm install -g @supermodeltools/mcp-server
|
|
13
52
|
```
|
|
@@ -18,6 +57,45 @@ Or run directly:
|
|
|
18
57
|
npx @supermodeltools/mcp-server
|
|
19
58
|
```
|
|
20
59
|
|
|
60
|
+
## ⚠️ Important: Configure Timeout for Large Codebase Analysis
|
|
61
|
+
|
|
62
|
+
The `explore_codebase` tool can take **5-15 minutes** to analyze large repositories. Most MCP clients have a default timeout of 60-120 seconds, which will cause the operation to fail prematurely.
|
|
63
|
+
|
|
64
|
+
**Quick Setup:**
|
|
65
|
+
|
|
66
|
+
Add this to your shell profile to set a 15-minute timeout:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
export MCP_TOOL_TIMEOUT=900000
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Installation by Client:**
|
|
73
|
+
|
|
74
|
+
<details>
|
|
75
|
+
<summary><strong>Claude Code CLI</strong></summary>
|
|
76
|
+
|
|
77
|
+
Add to your shell profile (`~/.zshrc` for macOS or `~/.bashrc` for Linux):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
export MCP_TOOL_TIMEOUT=900000
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then reload your shell:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
source ~/.zshrc # or ~/.bashrc
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Verify it's set:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
echo $MCP_TOOL_TIMEOUT
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
</details>
|
|
96
|
+
|
|
97
|
+
**Note:** Timeout configuration via `MCP_TOOL_TIMEOUT` is only supported in Claude Code CLI. For more details, see the [official Claude Code documentation](https://code.claude.com/docs/en/settings.md).
|
|
98
|
+
|
|
21
99
|
## Configuration
|
|
22
100
|
|
|
23
101
|
Get your API key from the [Supermodel Dashboard](https://dashboard.supermodeltools.com).
|
|
@@ -114,25 +192,7 @@ Add to `~/.cursor/mcp.json`:
|
|
|
114
192
|
}
|
|
115
193
|
```
|
|
116
194
|
|
|
117
|
-
### Claude
|
|
118
|
-
|
|
119
|
-
Add to `claude_desktop_config.json`:
|
|
120
|
-
|
|
121
|
-
```json
|
|
122
|
-
{
|
|
123
|
-
"mcpServers": {
|
|
124
|
-
"supermodel": {
|
|
125
|
-
"command": "npx",
|
|
126
|
-
"args": ["-y", "@supermodeltools/mcp-server"],
|
|
127
|
-
"env": {
|
|
128
|
-
"SUPERMODEL_API_KEY": "your-api-key"
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Claude Code
|
|
195
|
+
### Claude Code CLI
|
|
136
196
|
|
|
137
197
|
Add the MCP server with your API key:
|
|
138
198
|
|
|
@@ -152,6 +212,44 @@ Verify installation:
|
|
|
152
212
|
claude mcp list
|
|
153
213
|
```
|
|
154
214
|
|
|
215
|
+
## Health Checks
|
|
216
|
+
|
|
217
|
+
This MCP server implements the [MCP ping utility](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping) for connection health monitoring. The ping mechanism allows clients to verify that the server is responsive and the connection remains alive.
|
|
218
|
+
|
|
219
|
+
### How It Works
|
|
220
|
+
|
|
221
|
+
- **Request**: Client sends a `ping` JSON-RPC request with no parameters
|
|
222
|
+
- **Response**: Server responds promptly with an empty result object `{}`
|
|
223
|
+
- **Automatic**: Handled automatically by the MCP SDK - no additional configuration needed
|
|
224
|
+
|
|
225
|
+
### Use Cases
|
|
226
|
+
|
|
227
|
+
- **Pre-flight checks**: Verify server is accessible before starting work
|
|
228
|
+
- **Connection monitoring**: Detect stale connections during long-running sessions
|
|
229
|
+
- **Periodic health checks**: Confirm server remains responsive
|
|
230
|
+
|
|
231
|
+
### Example
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
// Request
|
|
235
|
+
{
|
|
236
|
+
"jsonrpc": "2.0",
|
|
237
|
+
"id": "123",
|
|
238
|
+
"method": "ping"
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Response
|
|
242
|
+
{
|
|
243
|
+
"jsonrpc": "2.0",
|
|
244
|
+
"id": "123",
|
|
245
|
+
"result": {}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
If the server doesn't respond within a reasonable timeout (typically 5-10 seconds), the connection should be considered stale.
|
|
250
|
+
|
|
251
|
+
For more details, see the [MCP specification for ping/health checks](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping).
|
|
252
|
+
|
|
155
253
|
## Tools
|
|
156
254
|
|
|
157
255
|
### `explore_codebase`
|
|
@@ -196,9 +294,176 @@ Analyzes code structure, dependencies, and relationships across a repository. Us
|
|
|
196
294
|
- Cleans up temporary files automatically
|
|
197
295
|
- Cross-platform compatible
|
|
198
296
|
|
|
297
|
+
## Tool Performance & Timeout Requirements
|
|
298
|
+
|
|
299
|
+
The `explore_codebase` tool analyzes your entire repository to build a comprehensive code graph. Analysis time scales with repository size and complexity.
|
|
300
|
+
|
|
301
|
+
| Tool | Typical Duration | Recommended Timeout | Repository Size |
|
|
302
|
+
|------|------------------|---------------------|--------------------|
|
|
303
|
+
| `explore_codebase` | 2-5 min | 600000ms (10 min) | Small (<1k files) |
|
|
304
|
+
| `explore_codebase` | 5-10 min | 900000ms (15 min) | Medium (1k-10k files) |
|
|
305
|
+
| `explore_codebase` | 10-15 min | 1200000ms (20 min) | Large (10k+ files) |
|
|
306
|
+
|
|
307
|
+
**Default recommendation**: The server uses a 15-minute timeout (`900000ms`) by default, which works well for most medium-sized repositories.
|
|
308
|
+
|
|
309
|
+
**Caching behavior**: The first run analyzes your codebase and caches the results. Subsequent queries on the same repository are typically much faster (seconds instead of minutes) as they use the cached graph.
|
|
310
|
+
|
|
311
|
+
**Setting custom timeouts**: If you need to adjust the timeout for larger repositories, you can set the `SUPERMODEL_TIMEOUT_MS` environment variable:
|
|
312
|
+
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"mcpServers": {
|
|
316
|
+
"supermodel": {
|
|
317
|
+
"command": "npx",
|
|
318
|
+
"args": ["-y", "@supermodeltools/mcp-server"],
|
|
319
|
+
"env": {
|
|
320
|
+
"SUPERMODEL_API_KEY": "your-api-key",
|
|
321
|
+
"SUPERMODEL_TIMEOUT_MS": "1200000"
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
199
328
|
## Troubleshooting
|
|
200
329
|
|
|
201
|
-
|
|
330
|
+
### Timeout Errors
|
|
331
|
+
|
|
332
|
+
#### "Request timeout"
|
|
333
|
+
|
|
334
|
+
**Cause:** The analysis is taking longer than your MCP client's timeout allows (varies by client—Claude Code CLI defaults to ~2 minutes, Claude Desktop enforces 5 minutes). Large repositories or complex codebases may require more time to analyze.
|
|
335
|
+
|
|
336
|
+
**Solutions:**
|
|
337
|
+
|
|
338
|
+
1. **Analyze a subdirectory instead** - Target specific parts of your codebase:
|
|
339
|
+
```bash
|
|
340
|
+
# Instead of analyzing the entire repo
|
|
341
|
+
explore_codebase(directory="/path/to/repo")
|
|
342
|
+
|
|
343
|
+
# Analyze just the core module
|
|
344
|
+
explore_codebase(directory="/path/to/repo/src/core")
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
2. **Increase your MCP client timeout** - For Claude Code CLI, set the `MCP_TOOL_TIMEOUT` environment variable:
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
# Set timeout to 15 minutes (900000ms) for large codebase analysis
|
|
351
|
+
export MCP_TOOL_TIMEOUT=900000
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Then reload your shell or start a new terminal session. This timeout applies to all MCP tool executions.
|
|
355
|
+
|
|
356
|
+
**Note:** Timeout configuration is currently only supported in Claude Code CLI.
|
|
357
|
+
|
|
358
|
+
3. **Verify `.gitignore` excludes build artifacts** - Ensure your repository excludes:
|
|
359
|
+
- `node_modules/`, `vendor/`, `venv/`
|
|
360
|
+
- `dist/`, `build/`, `out/`
|
|
361
|
+
- `.next/`, `.nuxt/`, `.cache/`
|
|
362
|
+
|
|
363
|
+
The MCP server automatically excludes these patterns when zipping, but `.gitignore` prevents them from being in your working directory in the first place—both improve performance and reduce analysis size.
|
|
364
|
+
|
|
365
|
+
#### "Analysis interrupted mid-way"
|
|
366
|
+
|
|
367
|
+
**Cause:** Network interruption or the MCP server process was terminated before completion.
|
|
368
|
+
|
|
369
|
+
**Solutions:**
|
|
370
|
+
|
|
371
|
+
1. **Check MCP server logs** - Logs location varies by client:
|
|
372
|
+
|
|
373
|
+
> **Note:** Log filenames match your MCP server name from the config. If you named it differently (e.g., `my-server`), look for `mcp-server-my-server.log` instead of `mcp-server-supermodel.log`.
|
|
374
|
+
|
|
375
|
+
**Claude Desktop (macOS):**
|
|
376
|
+
```bash
|
|
377
|
+
tail -f ~/Library/Logs/Claude/mcp-server-supermodel.log
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Claude Desktop (Windows):**
|
|
381
|
+
```powershell
|
|
382
|
+
Get-Content "$env:APPDATA\Claude\Logs\mcp-server-supermodel.log" -Wait
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Claude Desktop (Linux):**
|
|
386
|
+
```bash
|
|
387
|
+
tail -f ~/.config/Claude/logs/mcp-server-supermodel.log
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Cursor:**
|
|
391
|
+
```bash
|
|
392
|
+
# Check the Cursor logs directory
|
|
393
|
+
tail -f ~/Library/Application\ Support/Cursor/logs/mcp-server-supermodel.log
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Claude Code:**
|
|
397
|
+
```bash
|
|
398
|
+
# Logs are shown in the terminal when running with verbose mode
|
|
399
|
+
claude --verbose
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
2. **Retry the analysis** - Temporary network issues often resolve on retry
|
|
403
|
+
|
|
404
|
+
3. **Check your internet connection** - The analysis requires a stable connection to the Supermodel API
|
|
405
|
+
|
|
406
|
+
4. **Verify the API is accessible:**
|
|
407
|
+
```bash
|
|
408
|
+
curl -H "Authorization: Bearer YOUR_API_KEY" https://api.supermodeltools.com/health
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
#### "ERROR Request failed. Check the MCP server logs"
|
|
412
|
+
|
|
413
|
+
**Multiple possible causes:**
|
|
414
|
+
|
|
415
|
+
##### 1. Missing or invalid API key
|
|
416
|
+
|
|
417
|
+
Check if your API key is set:
|
|
418
|
+
```bash
|
|
419
|
+
echo $SUPERMODEL_API_KEY
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Verify it's valid at [Supermodel Dashboard](https://dashboard.supermodeltools.com).
|
|
423
|
+
|
|
424
|
+
**Solution:**
|
|
425
|
+
```bash
|
|
426
|
+
# Set in your shell profile (~/.zshrc or ~/.bashrc)
|
|
427
|
+
export SUPERMODEL_API_KEY="your-api-key"
|
|
428
|
+
source ~/.zshrc
|
|
429
|
+
|
|
430
|
+
# Or update your MCP client config with the correct key
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
##### 2. API service outage or rate limiting
|
|
434
|
+
|
|
435
|
+
Check the error details in logs (see log locations above).
|
|
436
|
+
|
|
437
|
+
**Solution:**
|
|
438
|
+
- Visit [Supermodel Status](https://status.supermodeltools.com) for service status
|
|
439
|
+
- If rate limited, wait a few minutes before retrying
|
|
440
|
+
- Consider upgrading your API plan if hitting rate limits frequently
|
|
441
|
+
|
|
442
|
+
##### 3. Repository too large
|
|
443
|
+
|
|
444
|
+
The API has size limits for analysis. Check the [Supermodel documentation](https://docs.supermodeltools.com) for current limits.
|
|
445
|
+
|
|
446
|
+
**Solution:**
|
|
447
|
+
```bash
|
|
448
|
+
# Check your repo size
|
|
449
|
+
du -sh /path/to/repo
|
|
450
|
+
|
|
451
|
+
# If too large, analyze subdirectories instead
|
|
452
|
+
explore_codebase(directory="/path/to/repo/src")
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
##### 4. Network or firewall issues
|
|
456
|
+
|
|
457
|
+
Corporate firewalls may block outbound requests to the Supermodel API.
|
|
458
|
+
|
|
459
|
+
**Solution:**
|
|
460
|
+
- Test connectivity: `curl https://api.supermodeltools.com/health`
|
|
461
|
+
- Check firewall rules allow HTTPS to `api.supermodeltools.com`
|
|
462
|
+
- Contact your IT department if behind a corporate proxy
|
|
463
|
+
|
|
464
|
+
### Debug Logging
|
|
465
|
+
|
|
466
|
+
Debug logs go to stderr and include:
|
|
202
467
|
|
|
203
468
|
- `[DEBUG] Server configuration:` - Startup config
|
|
204
469
|
- `[DEBUG] Auto-zipping directory:` - Starting zip creation
|
|
@@ -206,12 +471,32 @@ Debug logs go to stderr:
|
|
|
206
471
|
- `[DEBUG] Making API request` - Request details
|
|
207
472
|
- `[ERROR] API call failed:` - Error details with HTTP status
|
|
208
473
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
474
|
+
To enable verbose logging, set the `DEBUG` environment variable:
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
# In your MCP config
|
|
478
|
+
{
|
|
479
|
+
"mcpServers": {
|
|
480
|
+
"supermodel": {
|
|
481
|
+
"command": "npx",
|
|
482
|
+
"args": ["-y", "@supermodeltools/mcp-server"],
|
|
483
|
+
"env": {
|
|
484
|
+
"SUPERMODEL_API_KEY": "your-api-key",
|
|
485
|
+
"DEBUG": "supermodel:*"
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Common Issues
|
|
493
|
+
|
|
494
|
+
- **401 Unauthorized:** Check `SUPERMODEL_API_KEY` is set correctly
|
|
495
|
+
- **ZIP too large:** Directory contains too many files/dependencies. Ensure `.gitignore` is configured properly
|
|
496
|
+
- **Permission denied:** Check read permissions on the directory
|
|
497
|
+
- **Insufficient disk space:** Free up space in your system's temp directory
|
|
498
|
+
- **Directory does not exist:** Verify the path is correct and absolute
|
|
499
|
+
- **ENOTFOUND or connection errors:** Check your internet connection and firewall settings
|
|
215
500
|
|
|
216
501
|
## Benchmarking
|
|
217
502
|
|
package/dist/server.js
CHANGED
|
@@ -110,7 +110,20 @@ For localized bugs:
|
|
|
110
110
|
|
|
111
111
|
Example:
|
|
112
112
|
- Full repo: directory="/repo" → 180MB, 50k nodes
|
|
113
|
-
- Subsystem: directory="/repo/django/db" → 15MB, 3k nodes
|
|
113
|
+
- Subsystem: directory="/repo/django/db" → 15MB, 3k nodes
|
|
114
|
+
|
|
115
|
+
## Error Handling
|
|
116
|
+
|
|
117
|
+
When a tool call returns an error, check the structured error fields:
|
|
118
|
+
- \`error.recoverable: true\` → wait briefly and retry the request
|
|
119
|
+
- \`error.reportable: true\` → this is a server-side bug, not your fault
|
|
120
|
+
|
|
121
|
+
If you receive a reportable error and have GitHub access:
|
|
122
|
+
1. Search the \`error.repo\` issues for the \`error.code\` to avoid duplicates
|
|
123
|
+
2. If no existing issue, open one with the error code, message, and any reproduction context
|
|
124
|
+
3. If you can identify and fix the root cause, fork the repo and open a PR
|
|
125
|
+
|
|
126
|
+
This helps the maintainers fix bugs faster and avoids wasting your iteration budget on issues you cannot work around locally.`,
|
|
114
127
|
});
|
|
115
128
|
const config = new sdk_1.Configuration({
|
|
116
129
|
basePath: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com',
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.handler = exports.tool = exports.metadata = void 0;
|
|
37
|
+
exports.classifyApiError = classifyApiError;
|
|
37
38
|
const promises_1 = require("fs/promises");
|
|
38
39
|
const child_process_1 = require("child_process");
|
|
39
40
|
const crypto_1 = require("crypto");
|
|
@@ -43,6 +44,8 @@ const filtering_1 = require("../filtering");
|
|
|
43
44
|
const queries_1 = require("../queries");
|
|
44
45
|
const zip_repository_1 = require("../utils/zip-repository");
|
|
45
46
|
const logger = __importStar(require("../utils/logger"));
|
|
47
|
+
const REPORT_REPO = 'https://github.com/supermodeltools/mcp.git';
|
|
48
|
+
const REPORT_SUGGESTION = 'This may be a bug in the MCP server. You can help by opening an issue at https://github.com/supermodeltools/mcp/issues with the error details, or fork the repo and open a PR with a fix.';
|
|
46
49
|
exports.metadata = {
|
|
47
50
|
resource: 'graphs',
|
|
48
51
|
operation: 'write',
|
|
@@ -53,7 +56,9 @@ exports.metadata = {
|
|
|
53
56
|
};
|
|
54
57
|
exports.tool = {
|
|
55
58
|
name: 'explore_codebase',
|
|
56
|
-
description: `
|
|
59
|
+
description: `Comprehensive codebase analysis using Supermodel API. ⚠️ This operation takes 5-15 minutes for large repositories. Ensure your Claude CLI timeout is configured (MCP_TOOL_TIMEOUT=900000). Analyzes code structure, dependencies, and patterns while respecting .gitignore.
|
|
60
|
+
|
|
61
|
+
Analyzes code within the target directory to produce a graph that can be used to navigate the codebase when solving bugs, planning or analyzing code changes.
|
|
57
62
|
|
|
58
63
|
## Example Output
|
|
59
64
|
|
|
@@ -243,12 +248,24 @@ const handler = async (client, args, defaultWorkdir) => {
|
|
|
243
248
|
// Validate directory - check if explicitly invalid first
|
|
244
249
|
if (providedDirectory !== undefined && typeof providedDirectory !== 'string') {
|
|
245
250
|
logger.error('Invalid directory parameter:', providedDirectory);
|
|
246
|
-
return (0, types_1.asErrorResult)(
|
|
251
|
+
return (0, types_1.asErrorResult)({
|
|
252
|
+
type: 'validation_error',
|
|
253
|
+
message: 'Invalid "directory" parameter. Provide a valid directory path as a string.',
|
|
254
|
+
code: 'INVALID_DIRECTORY',
|
|
255
|
+
recoverable: false,
|
|
256
|
+
suggestion: 'Pass directory as a string path, e.g. directory="/workspace/my-repo"',
|
|
257
|
+
});
|
|
247
258
|
}
|
|
248
259
|
// Check if we have any directory at all
|
|
249
260
|
if (!directory || typeof directory !== 'string') {
|
|
250
261
|
logger.error('Invalid directory parameter:', directory);
|
|
251
|
-
return (0, types_1.asErrorResult)(
|
|
262
|
+
return (0, types_1.asErrorResult)({
|
|
263
|
+
type: 'validation_error',
|
|
264
|
+
message: 'No "directory" parameter provided and no default workdir configured.',
|
|
265
|
+
code: 'MISSING_DIRECTORY',
|
|
266
|
+
recoverable: false,
|
|
267
|
+
suggestion: 'Provide a directory path or start the MCP server with a workdir argument (e.g. npx @anthropic-ai/supermodel-mcp /path/to/repo).',
|
|
268
|
+
});
|
|
252
269
|
}
|
|
253
270
|
if (providedDirectory) {
|
|
254
271
|
logger.debug('Using provided directory:', directory);
|
|
@@ -301,20 +318,58 @@ const handler = async (client, args, defaultWorkdir) => {
|
|
|
301
318
|
if (error.stack) {
|
|
302
319
|
logger.error('Stack trace:', error.stack);
|
|
303
320
|
}
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
|
|
321
|
+
// Normalize: guard against non-Error throws (string, object, undefined)
|
|
322
|
+
const message = typeof error?.message === 'string' ? error.message : String(error);
|
|
323
|
+
// Return structured, actionable error messages
|
|
324
|
+
if (message.includes('does not exist')) {
|
|
325
|
+
return (0, types_1.asErrorResult)({
|
|
326
|
+
type: 'not_found_error',
|
|
327
|
+
message: `Directory not found: ${directory}`,
|
|
328
|
+
code: 'DIRECTORY_NOT_FOUND',
|
|
329
|
+
recoverable: false,
|
|
330
|
+
suggestion: 'Verify the path exists. Use an absolute path to the repository root or subdirectory.',
|
|
331
|
+
details: { directory },
|
|
332
|
+
});
|
|
307
333
|
}
|
|
308
|
-
if (
|
|
309
|
-
return (0, types_1.asErrorResult)(
|
|
334
|
+
if (message.includes('Permission denied')) {
|
|
335
|
+
return (0, types_1.asErrorResult)({
|
|
336
|
+
type: 'resource_error',
|
|
337
|
+
message: `Permission denied accessing directory: ${directory}`,
|
|
338
|
+
code: 'PERMISSION_DENIED',
|
|
339
|
+
recoverable: false,
|
|
340
|
+
suggestion: 'Check that the MCP server process has read access to this directory.',
|
|
341
|
+
details: { directory },
|
|
342
|
+
});
|
|
310
343
|
}
|
|
311
|
-
if (
|
|
312
|
-
return (0, types_1.asErrorResult)(
|
|
344
|
+
if (message.includes('exceeds limit')) {
|
|
345
|
+
return (0, types_1.asErrorResult)({
|
|
346
|
+
type: 'resource_error',
|
|
347
|
+
message,
|
|
348
|
+
code: 'ZIP_TOO_LARGE',
|
|
349
|
+
recoverable: true,
|
|
350
|
+
suggestion: 'Analyze a subdirectory instead of the full repository (e.g. directory="/repo/src/core"). This reduces ZIP size and processing time.',
|
|
351
|
+
details: { directory },
|
|
352
|
+
});
|
|
313
353
|
}
|
|
314
|
-
if (
|
|
315
|
-
return (0, types_1.asErrorResult)(
|
|
354
|
+
if (message.includes('ENOSPC')) {
|
|
355
|
+
return (0, types_1.asErrorResult)({
|
|
356
|
+
type: 'resource_error',
|
|
357
|
+
message: 'Insufficient disk space to create ZIP archive.',
|
|
358
|
+
code: 'DISK_FULL',
|
|
359
|
+
recoverable: false,
|
|
360
|
+
suggestion: 'Free up disk space or analyze a smaller subdirectory.',
|
|
361
|
+
});
|
|
316
362
|
}
|
|
317
|
-
return (0, types_1.asErrorResult)(
|
|
363
|
+
return (0, types_1.asErrorResult)({
|
|
364
|
+
type: 'internal_error',
|
|
365
|
+
message: `Failed to create ZIP archive: ${message}`,
|
|
366
|
+
code: 'ZIP_CREATION_FAILED',
|
|
367
|
+
recoverable: false,
|
|
368
|
+
reportable: true,
|
|
369
|
+
repo: REPORT_REPO,
|
|
370
|
+
suggestion: REPORT_SUGGESTION,
|
|
371
|
+
details: { directory: (0, path_1.basename)(directory), errorType: error.name || 'Error' },
|
|
372
|
+
});
|
|
318
373
|
}
|
|
319
374
|
// Execute query with cleanup handling
|
|
320
375
|
try {
|
|
@@ -429,40 +484,7 @@ async function handleQueryMode(client, params) {
|
|
|
429
484
|
}
|
|
430
485
|
catch (error) {
|
|
431
486
|
// Error details are already logged by fetchFromApi and logErrorResponse
|
|
432
|
-
|
|
433
|
-
let errorMessage = '';
|
|
434
|
-
if (error.response) {
|
|
435
|
-
const status = error.response.status;
|
|
436
|
-
switch (status) {
|
|
437
|
-
case 401:
|
|
438
|
-
errorMessage = 'Authentication failed. Set your SUPERMODEL_API_KEY environment variable and restart the MCP server.';
|
|
439
|
-
break;
|
|
440
|
-
case 403:
|
|
441
|
-
errorMessage = 'Access forbidden. Your API key does not have permission for this operation. Contact support if this is unexpected.';
|
|
442
|
-
break;
|
|
443
|
-
case 404:
|
|
444
|
-
errorMessage = 'API endpoint not found. The service URL may be incorrect. Check your SUPERMODEL_BASE_URL configuration.';
|
|
445
|
-
break;
|
|
446
|
-
case 429:
|
|
447
|
-
errorMessage = 'Rate limit exceeded. Wait a few minutes and try again.';
|
|
448
|
-
break;
|
|
449
|
-
case 500:
|
|
450
|
-
case 502:
|
|
451
|
-
case 503:
|
|
452
|
-
case 504:
|
|
453
|
-
errorMessage = 'Server error. The Supermodel API is temporarily unavailable. Try again in a few minutes.';
|
|
454
|
-
break;
|
|
455
|
-
default:
|
|
456
|
-
errorMessage = `API error (HTTP ${status}). Check the MCP server logs for details.`;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
else if (error.request) {
|
|
460
|
-
errorMessage = 'No response from server. Check your network connection and verify the API is reachable.';
|
|
461
|
-
}
|
|
462
|
-
else {
|
|
463
|
-
errorMessage = 'Request failed. Check the MCP server logs for details.';
|
|
464
|
-
}
|
|
465
|
-
return (0, types_1.asErrorResult)(errorMessage);
|
|
487
|
+
return (0, types_1.asErrorResult)(classifyApiError(error));
|
|
466
488
|
}
|
|
467
489
|
}
|
|
468
490
|
// Handle query errors
|
|
@@ -625,7 +647,7 @@ async function logErrorResponse(error) {
|
|
|
625
647
|
}
|
|
626
648
|
}
|
|
627
649
|
/**
|
|
628
|
-
* Fetch graph from API with comprehensive logging
|
|
650
|
+
* Fetch graph from API with comprehensive logging and progress updates
|
|
629
651
|
*/
|
|
630
652
|
async function fetchFromApi(client, file, idempotencyKey) {
|
|
631
653
|
const startTime = Date.now();
|
|
@@ -643,33 +665,182 @@ async function fetchFromApi(client, file, idempotencyKey) {
|
|
|
643
665
|
file: fileBlob,
|
|
644
666
|
idempotencyKey: idempotencyKey,
|
|
645
667
|
};
|
|
668
|
+
// Start progress logging
|
|
669
|
+
console.error('[Supermodel] Starting codebase analysis...');
|
|
670
|
+
// Set up periodic progress updates every 15 seconds
|
|
671
|
+
let progressInterval = null;
|
|
672
|
+
let elapsedSeconds = 0;
|
|
673
|
+
progressInterval = setInterval(() => {
|
|
674
|
+
elapsedSeconds += 15;
|
|
675
|
+
console.error(`[Supermodel] Analysis in progress... (${elapsedSeconds}s elapsed)`);
|
|
676
|
+
}, 15000);
|
|
646
677
|
try {
|
|
647
678
|
const response = await client.graphs.generateSupermodelGraph(requestParams);
|
|
648
679
|
const duration = Date.now() - startTime;
|
|
680
|
+
// Clear progress interval
|
|
681
|
+
if (progressInterval) {
|
|
682
|
+
clearInterval(progressInterval);
|
|
683
|
+
progressInterval = null;
|
|
684
|
+
}
|
|
649
685
|
// Calculate approximate response size
|
|
650
686
|
const responseSize = JSON.stringify(response).length;
|
|
651
687
|
logResponse(200, 'OK', responseSize, duration);
|
|
688
|
+
// Log completion with summary
|
|
689
|
+
const summary = response.summary;
|
|
690
|
+
if (summary) {
|
|
691
|
+
console.error(`[Supermodel] Analysis complete, retrieving results... (${summary.filesProcessed || 0} files processed)`);
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
console.error('[Supermodel] Analysis complete, retrieving results...');
|
|
695
|
+
}
|
|
652
696
|
logger.debug(`[${getTimestamp()}] [API SUCCESS] Request completed successfully`);
|
|
653
697
|
return response;
|
|
654
698
|
}
|
|
655
699
|
catch (error) {
|
|
656
700
|
const duration = Date.now() - startTime;
|
|
701
|
+
// Clear progress interval on error
|
|
702
|
+
if (progressInterval) {
|
|
703
|
+
clearInterval(progressInterval);
|
|
704
|
+
progressInterval = null;
|
|
705
|
+
}
|
|
657
706
|
logger.error(`[${getTimestamp()}] [API FAILURE] Request failed after ${duration}ms`);
|
|
658
707
|
// Log detailed error information
|
|
659
708
|
await logErrorResponse(error);
|
|
660
|
-
//
|
|
709
|
+
// Preserve error.response so classifyApiError can read the status code (#75)
|
|
661
710
|
if (error.response?.status === 401) {
|
|
662
|
-
|
|
711
|
+
error.message = 'API authentication failed (401 Unauthorized). Please check your SUPERMODEL_API_KEY environment variable.';
|
|
663
712
|
}
|
|
664
713
|
else if (error.response?.status === 403) {
|
|
665
|
-
|
|
714
|
+
error.message = 'API access forbidden (403 Forbidden). Your API key may not have permission to access this resource.';
|
|
666
715
|
}
|
|
667
716
|
else if (error.response?.status >= 500) {
|
|
668
|
-
|
|
717
|
+
error.message = `Supermodel API server error (${error.response.status}). The service may be temporarily unavailable.`;
|
|
669
718
|
}
|
|
670
719
|
throw error;
|
|
671
720
|
}
|
|
672
721
|
}
|
|
722
|
+
/**
|
|
723
|
+
* Classify an API error into a structured error response.
|
|
724
|
+
* Extracts HTTP status, network conditions, and timeout signals
|
|
725
|
+
* to produce an agent-actionable error with recovery guidance.
|
|
726
|
+
*/
|
|
727
|
+
function classifyApiError(error) {
|
|
728
|
+
// Guard against non-Error throws (strings, nulls, plain objects)
|
|
729
|
+
if (!error || typeof error !== 'object') {
|
|
730
|
+
return {
|
|
731
|
+
type: 'internal_error',
|
|
732
|
+
message: typeof error === 'string' ? error : 'An unexpected error occurred.',
|
|
733
|
+
code: 'UNKNOWN_ERROR',
|
|
734
|
+
recoverable: false,
|
|
735
|
+
reportable: true,
|
|
736
|
+
repo: REPORT_REPO,
|
|
737
|
+
suggestion: REPORT_SUGGESTION,
|
|
738
|
+
details: { errorType: typeof error },
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
if (error.response) {
|
|
742
|
+
const status = error.response.status;
|
|
743
|
+
switch (status) {
|
|
744
|
+
case 401:
|
|
745
|
+
return {
|
|
746
|
+
type: 'authentication_error',
|
|
747
|
+
message: 'Invalid or missing API key.',
|
|
748
|
+
code: 'INVALID_API_KEY',
|
|
749
|
+
recoverable: false,
|
|
750
|
+
suggestion: 'Set the SUPERMODEL_API_KEY environment variable and restart the MCP server.',
|
|
751
|
+
details: { apiKeySet: !!process.env.SUPERMODEL_API_KEY, httpStatus: 401 },
|
|
752
|
+
};
|
|
753
|
+
case 403:
|
|
754
|
+
return {
|
|
755
|
+
type: 'authorization_error',
|
|
756
|
+
message: 'API key does not have permission for this operation.',
|
|
757
|
+
code: 'FORBIDDEN',
|
|
758
|
+
recoverable: false,
|
|
759
|
+
suggestion: 'Verify your API key has the correct permissions. Contact support if unexpected.',
|
|
760
|
+
details: { httpStatus: 403 },
|
|
761
|
+
};
|
|
762
|
+
case 404:
|
|
763
|
+
return {
|
|
764
|
+
type: 'not_found_error',
|
|
765
|
+
message: 'API endpoint not found.',
|
|
766
|
+
code: 'ENDPOINT_NOT_FOUND',
|
|
767
|
+
recoverable: false,
|
|
768
|
+
suggestion: 'Check SUPERMODEL_BASE_URL environment variable. Default: https://api.supermodeltools.com',
|
|
769
|
+
details: { baseUrl: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com', httpStatus: 404 },
|
|
770
|
+
};
|
|
771
|
+
case 429:
|
|
772
|
+
return {
|
|
773
|
+
type: 'rate_limit_error',
|
|
774
|
+
message: 'API rate limit exceeded.',
|
|
775
|
+
code: 'RATE_LIMITED',
|
|
776
|
+
recoverable: true,
|
|
777
|
+
suggestion: 'Wait 30-60 seconds and retry. Consider analyzing smaller subdirectories to reduce API calls.',
|
|
778
|
+
details: { httpStatus: 429 },
|
|
779
|
+
};
|
|
780
|
+
case 500:
|
|
781
|
+
case 502:
|
|
782
|
+
case 503:
|
|
783
|
+
case 504:
|
|
784
|
+
return {
|
|
785
|
+
type: 'internal_error',
|
|
786
|
+
message: `Supermodel API server error (HTTP ${status}).`,
|
|
787
|
+
code: 'SERVER_ERROR',
|
|
788
|
+
recoverable: true,
|
|
789
|
+
reportable: true,
|
|
790
|
+
repo: REPORT_REPO,
|
|
791
|
+
suggestion: 'The API may be temporarily unavailable. Wait a few minutes and retry. If persistent, open an issue at https://github.com/supermodeltools/mcp/issues with the error details, or fork the repo and open a PR with a fix.',
|
|
792
|
+
details: { httpStatus: status },
|
|
793
|
+
};
|
|
794
|
+
default: {
|
|
795
|
+
const isServerError = status >= 500;
|
|
796
|
+
return {
|
|
797
|
+
type: isServerError ? 'internal_error' : 'validation_error',
|
|
798
|
+
message: `API request failed with HTTP ${status}.`,
|
|
799
|
+
code: 'API_ERROR',
|
|
800
|
+
recoverable: isServerError,
|
|
801
|
+
...(isServerError && {
|
|
802
|
+
reportable: true,
|
|
803
|
+
repo: REPORT_REPO,
|
|
804
|
+
suggestion: 'The API may be temporarily unavailable. Wait a few minutes and retry. If persistent, open an issue at https://github.com/supermodeltools/mcp/issues with the error details, or fork the repo and open a PR with a fix.',
|
|
805
|
+
}),
|
|
806
|
+
...(!isServerError && { suggestion: 'Check the request parameters and base URL configuration.' }),
|
|
807
|
+
details: { httpStatus: status },
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
if (error.request) {
|
|
813
|
+
// Distinguish timeout from general network failure
|
|
814
|
+
if (error.code === 'UND_ERR_HEADERS_TIMEOUT' || error.code === 'UND_ERR_BODY_TIMEOUT' || error.message?.includes('timeout')) {
|
|
815
|
+
return {
|
|
816
|
+
type: 'timeout_error',
|
|
817
|
+
message: 'API request timed out. The codebase may be too large for a single analysis.',
|
|
818
|
+
code: 'REQUEST_TIMEOUT',
|
|
819
|
+
recoverable: true,
|
|
820
|
+
suggestion: 'Analyze a smaller subdirectory (e.g. directory="/repo/src/core") or increase SUPERMODEL_TIMEOUT_MS.',
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
return {
|
|
824
|
+
type: 'network_error',
|
|
825
|
+
message: 'No response from Supermodel API server.',
|
|
826
|
+
code: 'NO_RESPONSE',
|
|
827
|
+
recoverable: true,
|
|
828
|
+
suggestion: 'Check network connectivity. Verify the API is reachable at the configured base URL.',
|
|
829
|
+
details: { baseUrl: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com' },
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
// Catch-all for unexpected errors - include the actual message
|
|
833
|
+
return {
|
|
834
|
+
type: 'internal_error',
|
|
835
|
+
message: error.message || 'An unexpected error occurred.',
|
|
836
|
+
code: 'UNKNOWN_ERROR',
|
|
837
|
+
recoverable: false,
|
|
838
|
+
reportable: true,
|
|
839
|
+
repo: REPORT_REPO,
|
|
840
|
+
suggestion: REPORT_SUGGESTION,
|
|
841
|
+
details: { errorType: error.name || 'Error' },
|
|
842
|
+
};
|
|
843
|
+
}
|
|
673
844
|
/**
|
|
674
845
|
* Legacy mode: direct jq filtering on API response
|
|
675
846
|
*/
|
|
@@ -681,43 +852,16 @@ async function handleLegacyMode(client, file, idempotencyKey, jq_filter) {
|
|
|
681
852
|
catch (error) {
|
|
682
853
|
if ((0, filtering_1.isJqError)(error)) {
|
|
683
854
|
logger.error('jq filter error:', error.message);
|
|
684
|
-
return (0, types_1.asErrorResult)(
|
|
855
|
+
return (0, types_1.asErrorResult)({
|
|
856
|
+
type: 'validation_error',
|
|
857
|
+
message: `Invalid jq filter syntax: ${error.message}`,
|
|
858
|
+
code: 'INVALID_JQ_FILTER',
|
|
859
|
+
recoverable: false,
|
|
860
|
+
suggestion: 'Check jq filter syntax. Use the query parameter instead for structured queries (e.g. query="summary").',
|
|
861
|
+
});
|
|
685
862
|
}
|
|
686
863
|
// Error details are already logged by fetchFromApi and logErrorResponse
|
|
687
|
-
|
|
688
|
-
let errorMessage = '';
|
|
689
|
-
if (error.response) {
|
|
690
|
-
const status = error.response.status;
|
|
691
|
-
switch (status) {
|
|
692
|
-
case 401:
|
|
693
|
-
errorMessage = 'Authentication failed. Set your SUPERMODEL_API_KEY environment variable and restart the MCP server.';
|
|
694
|
-
break;
|
|
695
|
-
case 403:
|
|
696
|
-
errorMessage = 'Access forbidden. Your API key does not have permission for this operation. Contact support if this is unexpected.';
|
|
697
|
-
break;
|
|
698
|
-
case 404:
|
|
699
|
-
errorMessage = 'API endpoint not found. The service URL may be incorrect. Check your SUPERMODEL_BASE_URL configuration.';
|
|
700
|
-
break;
|
|
701
|
-
case 429:
|
|
702
|
-
errorMessage = 'Rate limit exceeded. Wait a few minutes and try again.';
|
|
703
|
-
break;
|
|
704
|
-
case 500:
|
|
705
|
-
case 502:
|
|
706
|
-
case 503:
|
|
707
|
-
case 504:
|
|
708
|
-
errorMessage = 'Server error. The Supermodel API is temporarily unavailable. Try again in a few minutes.';
|
|
709
|
-
break;
|
|
710
|
-
default:
|
|
711
|
-
errorMessage = `API error (HTTP ${status}). Check the MCP server logs for details.`;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
else if (error.request) {
|
|
715
|
-
errorMessage = 'No response from server. Check your network connection and verify the API is reachable.';
|
|
716
|
-
}
|
|
717
|
-
else {
|
|
718
|
-
errorMessage = 'Request failed. Check the MCP server logs for details.';
|
|
719
|
-
}
|
|
720
|
-
return (0, types_1.asErrorResult)(errorMessage);
|
|
864
|
+
return (0, types_1.asErrorResult)(classifyApiError(error));
|
|
721
865
|
}
|
|
722
866
|
}
|
|
723
867
|
exports.default = { metadata: exports.metadata, tool: exports.tool, handler: exports.handler };
|
package/dist/types.js
CHANGED
|
@@ -13,12 +13,15 @@ function asTextContentResult(result) {
|
|
|
13
13
|
isError: false
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
function asErrorResult(
|
|
16
|
+
function asErrorResult(error) {
|
|
17
|
+
const text = typeof error === 'string'
|
|
18
|
+
? error
|
|
19
|
+
: JSON.stringify({ error }, null, 2);
|
|
17
20
|
return {
|
|
18
21
|
content: [
|
|
19
22
|
{
|
|
20
23
|
type: 'text',
|
|
21
|
-
text
|
|
24
|
+
text,
|
|
22
25
|
},
|
|
23
26
|
],
|
|
24
27
|
isError: true,
|