@supermodeltools/mcp-server 0.4.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 ADDED
@@ -0,0 +1,109 @@
1
+ # Supermodel MCP Server
2
+
3
+ [![npm](https://img.shields.io/npm/v/@supermodeltools/mcp-server)](https://www.npmjs.com/package/@supermodeltools/mcp-server)
4
+ [![MCP](https://img.shields.io/badge/MCP-compatible-blue)](https://modelcontextprotocol.io)
5
+
6
+ MCP server that exposes [Supermodel API](https://docs.supermodeltools.com) graph generation to AI agents. Generates dependency graphs, call graphs, domain models, and full Supermodel IR from code repositories.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install -g @supermodeltools/mcp-server
12
+ ```
13
+
14
+ Or run directly:
15
+
16
+ ```bash
17
+ npx @supermodeltools/mcp-server
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ Get your API key from the [Supermodel Dashboard](https://supermodeltools.com/dashboard).
23
+
24
+ | Variable | Description |
25
+ |----------|-------------|
26
+ | `SUPERMODEL_API_KEY` | Your Supermodel API key (required) |
27
+ | `SUPERMODEL_BASE_URL` | Override API base URL (optional) |
28
+
29
+ ## Usage
30
+
31
+ ### Cursor
32
+
33
+ Add to `~/.cursor/mcp.json`:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "supermodel": {
39
+ "command": "npx",
40
+ "args": ["-y", "@supermodeltools/mcp-server"],
41
+ "env": {
42
+ "SUPERMODEL_API_KEY": "your-api-key"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Claude Desktop
50
+
51
+ Add to `claude_desktop_config.json`:
52
+
53
+ ```json
54
+ {
55
+ "mcpServers": {
56
+ "supermodel": {
57
+ "command": "npx",
58
+ "args": ["-y", "@supermodeltools/mcp-server"],
59
+ "env": {
60
+ "SUPERMODEL_API_KEY": "your-api-key"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ ### Claude Code
68
+
69
+ ```bash
70
+ claude mcp add supermodel -- npx -y @supermodeltools/mcp-server
71
+ ```
72
+
73
+ ## Tools
74
+
75
+ ### `create_supermodel_graph_graphs`
76
+
77
+ Generates Supermodel IR from a zipped repository.
78
+
79
+ | Argument | Type | Description |
80
+ |----------|------|-------------|
81
+ | `file` | string | Path to repository ZIP file |
82
+ | `Idempotency-Key` | string | Unique request key for caching |
83
+ | `jq_filter` | string | Optional jq filter to reduce response size |
84
+
85
+ **Prepare your repo:**
86
+
87
+ ```bash
88
+ git archive -o /tmp/repo.zip HEAD
89
+ ```
90
+
91
+ **Example prompt:**
92
+ > Generate a supermodel graph for `/tmp/repo.zip`
93
+
94
+ ## Troubleshooting
95
+
96
+ Debug logs go to stderr:
97
+
98
+ - `[DEBUG] Server configuration:` - Startup config
99
+ - `[DEBUG] Making API request` - Request details
100
+ - `[ERROR] API call failed:` - Error details with HTTP status
101
+
102
+ **Common issues:**
103
+ - 401: Check `SUPERMODEL_API_KEY` is set
104
+ - ZIP too large: Exclude node_modules/dist (use `git archive`)
105
+
106
+ ## Links
107
+
108
+ - [API Documentation](https://docs.supermodeltools.com)
109
+ - [Supermodel SDK](https://www.npmjs.com/package/@supermodeltools/sdk)
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.maybeFilter = maybeFilter;
7
+ exports.isJqError = isJqError;
8
+ // @ts-nocheck
9
+ const jq_web_1 = __importDefault(require("jq-web"));
10
+ async function maybeFilter(jqFilter, response) {
11
+ if (jqFilter && typeof jqFilter === 'string') {
12
+ return await jq(response, jqFilter);
13
+ }
14
+ else {
15
+ return response;
16
+ }
17
+ }
18
+ async function jq(json, jqFilter) {
19
+ return (await jq_web_1.default).json(json, jqFilter);
20
+ }
21
+ function isJqError(error) {
22
+ return error instanceof Error && 'stderr' in error;
23
+ }
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const server_1 = require("./server");
5
+ async function main() {
6
+ const server = new server_1.Server();
7
+ await server.start();
8
+ }
9
+ main().catch((error) => {
10
+ console.error('Fatal error:', error);
11
+ process.exit(1);
12
+ });
package/dist/server.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Server = void 0;
7
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const sdk_1 = require("@supermodeltools/sdk");
10
+ const create_supermodel_graph_1 = __importDefault(require("./tools/create-supermodel-graph"));
11
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
12
+ class Server {
13
+ server;
14
+ client;
15
+ constructor() {
16
+ this.server = new mcp_js_1.McpServer({
17
+ name: 'supermodel_api',
18
+ version: '0.0.1',
19
+ }, {
20
+ capabilities: { tools: {}, logging: {} },
21
+ instructions: 'This MCP server provides tools for analyzing code repositories. Before using the graph generation tools, follow these instructions.\n\nPREPARING REPOSITORY ZIP FILES:\nAll graph generation tools require a ZIP archive of your repository.\n\nFor Git Repositories (Recommended):\nRun: cd /path/to/your/repo && git archive -o /tmp/repo.zip HEAD\nThis method automatically respects .gitignore, only includes tracked files, creates cleaner smaller archives, and produces reproducible results.\n\nFor Any Directory:\nRun: cd /path/to/your/repo && zip -r /tmp/repo.zip . -x "node_modules/*" -x ".git/*" -x "dist/*" -x "build/*" -x "target/*" -x "*.pyc" -x "__pycache__/*" -x "venv/*" -x ".venv/*" -x "vendor/*" -x ".idea/*" -x ".vscode/*"\n\nINCLUDE: Source code files (.py, .js, .ts, .tsx, .java, .go, .rs, .rb, .kt, .scala, .c, .cpp, .h, .hpp), configuration files (package.json, tsconfig.json, pyproject.toml, Cargo.toml, go.mod, pom.xml), and type definitions (.d.ts, .pyi).\n\nEXCLUDE: Dependencies (node_modules/, vendor/, venv/, .venv/, target/), build outputs (dist/, build/, out/, .next/, __pycache__/), version control (.git/), IDE files (.idea/, .vscode/), and large binaries/images/datasets.\n\nIf ZIP exceeds 50MB, ensure dependencies are excluded, consider analyzing a subdirectory, or check for accidentally committed binary files.\n\nGRAPH CACHING STRATEGY:\nGraph generation is expensive. NEVER re-upload the same repository state twice.\n\nIdempotency Keys: Every graph tool requires an Idempotency-Key parameter. Use format: {repo_identifier}:{graph_type}:{content_hash} Example: myproject:supermodel:abc123def\n\nGenerate content hash via: git rev-parse --short HEAD (for git repos) or shasum -a 256 /tmp/repo.zip | cut -d\' \' -f1 | head -c 12 (for ZIP hash).\n\nREGENERATE when: source code files changed, new files added affecting analysis scope, files deleted from graph, or dependencies changed (for dependency graph only).\n\nDO NOT regenerate when: only documentation/comments changed, only formatting changed, only non-code files changed, or switching between analysis tasks on same code state.\n\nSESSION MANAGEMENT:\nWithin a session: keep graph results in memory/context, reference previous results instead of re-calling APIs, use jq_filter to extract specific parts.\n\nAcross sessions: store the idempotency key used, store a summary of the graph (node count, key relationships), on resume check if code state matches before regenerating.\n\nGRAPH TYPE SELECTION:\ncreate_supermodel_graph_graphs - Best for comprehensive analysis, includes all graph types. Use jq_filter to extract specific data.\ncreate_call_graph_graphs - Function-level call relationships. Invalidate when function signatures change.\ncreate_dependency_graph_graphs - Module/package dependencies. Invalidate when imports or package manifests change.\ncreate_domain_graph_graphs - High-level domain model. Most stable, only invalidate for structural changes.\ncreate_parse_graph_graphs - AST-level relationships. Most sensitive, invalidate for any syntax changes.\n\nOPTIMIZATION: Call create_supermodel_graph_graphs ONCE (includes all types), use jq_filter to extract needed data, track last idempotency key, last commit/ZIP hash, generation timestamp, and summary stats.\n\nEXAMPLE WORKFLOW:\n1. Create ZIP: git archive -o /tmp/repo.zip HEAD\n2. Get hash: git rev-parse --short HEAD (e.g. abc123)\n3. Call create_supermodel_graph_graphs with file=/tmp/repo.zip and Idempotency-Key=myproject:supermodel:abc123\n4. Store result. Later queries use same key or extract from cached result.\n5. After code changes, check new hash. If different, regenerate with new key. If same, use cached result.',
22
+ });
23
+ const config = new sdk_1.Configuration({
24
+ basePath: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com',
25
+ apiKey: process.env.SUPERMODEL_API_KEY,
26
+ });
27
+ console.error('[DEBUG] Server configuration:');
28
+ console.error('[DEBUG] Base URL:', config.basePath);
29
+ console.error('[DEBUG] API Key set:', !!process.env.SUPERMODEL_API_KEY);
30
+ this.client = {
31
+ graphs: new sdk_1.DefaultApi(config),
32
+ };
33
+ this.setupHandlers();
34
+ }
35
+ setupHandlers() {
36
+ this.server.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
37
+ return {
38
+ tools: [create_supermodel_graph_1.default.tool],
39
+ };
40
+ });
41
+ this.server.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
42
+ const { name, arguments: args } = request.params;
43
+ if (name === create_supermodel_graph_1.default.tool.name) {
44
+ return create_supermodel_graph_1.default.handler(this.client, args);
45
+ }
46
+ throw new Error(`Unknown tool: ${name}`);
47
+ });
48
+ }
49
+ async start() {
50
+ const transport = new stdio_js_1.StdioServerTransport();
51
+ await this.server.connect(transport);
52
+ console.error('Supermodel MCP Server running on stdio');
53
+ }
54
+ }
55
+ exports.Server = Server;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handler = exports.tool = exports.metadata = void 0;
4
+ const promises_1 = require("fs/promises");
5
+ const types_1 = require("../types");
6
+ const filtering_1 = require("../filtering");
7
+ exports.metadata = {
8
+ resource: 'graphs',
9
+ operation: 'write',
10
+ tags: [],
11
+ httpMethod: 'post',
12
+ httpPath: '/v1/graphs/supermodel',
13
+ operationId: 'generateSupermodelGraph',
14
+ };
15
+ exports.tool = {
16
+ name: 'create_supermodel_graph_graphs',
17
+ description: "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nUpload a zipped repository snapshot to generate the Supermodel Intermediate Representation (SIR) artifact bundle.\n\n# Response Schema\n(Refer to the schema in the existing documentation)\n",
18
+ inputSchema: {
19
+ type: 'object',
20
+ properties: {
21
+ file: {
22
+ type: 'string',
23
+ description: 'Path to the zipped repository archive containing the code to analyze.',
24
+ },
25
+ 'Idempotency-Key': {
26
+ type: 'string',
27
+ },
28
+ jq_filter: {
29
+ type: 'string',
30
+ title: 'jq Filter',
31
+ description: 'A jq filter to apply to the response to include certain fields.',
32
+ },
33
+ },
34
+ required: ['file', 'Idempotency-Key'],
35
+ },
36
+ };
37
+ const handler = async (client, args) => {
38
+ if (!args) {
39
+ return (0, types_1.asErrorResult)('No arguments provided');
40
+ }
41
+ const { jq_filter, file, 'Idempotency-Key': idempotencyKey } = args;
42
+ if (!file || typeof file !== 'string') {
43
+ return (0, types_1.asErrorResult)('File argument is required and must be a string path');
44
+ }
45
+ if (!idempotencyKey || typeof idempotencyKey !== 'string') {
46
+ return (0, types_1.asErrorResult)('Idempotency-Key argument is required');
47
+ }
48
+ try {
49
+ // Read the file into a Buffer and convert to Blob
50
+ // The SDK expects a Blob type, not a stream
51
+ console.error('[DEBUG] Reading file:', file);
52
+ const fileBuffer = await (0, promises_1.readFile)(file);
53
+ // Create a Blob from the buffer
54
+ // In Node.js 18+, Blob is available globally
55
+ const fileBlob = new Blob([fileBuffer], { type: 'application/zip' });
56
+ console.error('[DEBUG] File size:', fileBuffer.length, 'bytes');
57
+ console.error('[DEBUG] Making API request with idempotency key:', idempotencyKey);
58
+ // Construct the request object
59
+ const requestParams = {
60
+ file: fileBlob,
61
+ idempotencyKey: idempotencyKey
62
+ };
63
+ const response = await client.graphs.generateSupermodelGraph(requestParams);
64
+ console.error('[DEBUG] API request successful');
65
+ return (0, types_1.asTextContentResult)(await (0, filtering_1.maybeFilter)(jq_filter, response));
66
+ }
67
+ catch (error) {
68
+ if ((0, filtering_1.isJqError)(error)) {
69
+ return (0, types_1.asErrorResult)(error.message);
70
+ }
71
+ // Enhanced error logging
72
+ console.error('[ERROR] API call failed:', error);
73
+ console.error('[ERROR] Error name:', error.name);
74
+ console.error('[ERROR] Error message:', error.message);
75
+ console.error('[ERROR] Error stack:', error.stack);
76
+ if (error.response) {
77
+ console.error('[ERROR] Response status:', error.response.status);
78
+ console.error('[ERROR] Response statusText:', error.response.statusText);
79
+ console.error('[ERROR] Response headers:', error.response.headers);
80
+ try {
81
+ const responseText = await error.response.text();
82
+ console.error('[ERROR] Response body:', responseText);
83
+ }
84
+ catch (e) {
85
+ console.error('[ERROR] Could not read response body');
86
+ }
87
+ }
88
+ if (error.request) {
89
+ console.error('[ERROR] Request was made but no response received');
90
+ }
91
+ return (0, types_1.asErrorResult)(`API call failed: ${error.message || String(error)}. Check server logs for details.`);
92
+ }
93
+ };
94
+ exports.handler = handler;
95
+ exports.default = { metadata: exports.metadata, tool: exports.tool, handler: exports.handler };
package/dist/types.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.asTextContentResult = asTextContentResult;
4
+ exports.asErrorResult = asErrorResult;
5
+ function asTextContentResult(result) {
6
+ return {
7
+ content: [
8
+ {
9
+ type: 'text',
10
+ text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
11
+ },
12
+ ],
13
+ isError: false
14
+ };
15
+ }
16
+ function asErrorResult(message) {
17
+ return {
18
+ content: [
19
+ {
20
+ type: 'text',
21
+ text: message,
22
+ },
23
+ ],
24
+ isError: true,
25
+ };
26
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@supermodeltools/mcp-server",
3
+ "version": "0.4.0",
4
+ "description": "MCP server for Supermodel API - code graph generation for AI agents",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "supermodel-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "start": "node dist/index.js",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/supermodeltools/mcp.git"
21
+ },
22
+ "homepage": "https://docs.supermodeltools.com",
23
+ "bugs": {
24
+ "url": "https://github.com/supermodeltools/mcp/issues"
25
+ },
26
+ "license": "UNLICENSED",
27
+ "keywords": [
28
+ "mcp",
29
+ "model-context-protocol",
30
+ "supermodel",
31
+ "ai-agent",
32
+ "code-analysis",
33
+ "cursor",
34
+ "claude"
35
+ ],
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.0.1",
38
+ "@supermodeltools/sdk": "^0.3.8",
39
+ "jq-web": "^0.6.2",
40
+ "zod": "^3.22.4"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.11.0",
44
+ "typescript": "^5.3.3"
45
+ }
46
+ }