@supermodeltools/mcp-server 0.8.0 → 0.9.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/cache/graph-cache.js +328 -16
- package/dist/cache/graph-types.js +2 -2
- package/dist/constants.js +8 -4
- package/dist/index.js +167 -9
- package/dist/server.js +61 -98
- package/dist/tools/overview.js +144 -0
- package/dist/tools/symbol-context.js +285 -0
- package/dist/utils/api-helpers.js +8 -22
- package/package.json +2 -2
- package/dist/cache/index.js +0 -21
- package/dist/filtering.js +0 -45
- package/dist/queries/discovery.js +0 -163
- package/dist/queries/index.js +0 -252
- package/dist/queries/summary.js +0 -36
- package/dist/queries/traversal.js +0 -445
- package/dist/queries/types.js +0 -38
- package/dist/tools/create-supermodel-graph.js +0 -691
- package/dist/tools/feature-request.js +0 -84
- package/dist/tools/find-call-sites.js +0 -140
- package/dist/tools/find-definition.js +0 -160
- package/dist/tools/graph-tools.js +0 -277
- package/dist/tools/report-bug.js +0 -133
- package/dist/tools/task-query-tools.js +0 -81
- package/dist/tools/trace-call-chain.js +0 -178
- package/dist/tools/trace-data-flow.js +0 -232
- package/dist/utils/github.js +0 -253
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Tool for agents to submit feature requests as GitHub issues.
|
|
4
|
-
* Creates issues on the supermodeltools/mcp repository.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.handler = exports.tool = exports.metadata = void 0;
|
|
8
|
-
const types_1 = require("../types");
|
|
9
|
-
const github_1 = require("../utils/github");
|
|
10
|
-
exports.metadata = {
|
|
11
|
-
resource: 'issues',
|
|
12
|
-
operation: 'write',
|
|
13
|
-
tags: ['feature-request', 'github'],
|
|
14
|
-
httpMethod: 'post',
|
|
15
|
-
httpPath: '/repos/supermodeltools/mcp/issues',
|
|
16
|
-
operationId: 'createFeatureRequest',
|
|
17
|
-
};
|
|
18
|
-
exports.tool = {
|
|
19
|
-
name: 'request_feature',
|
|
20
|
-
description: `Submit a feature request to the Supermodel MCP server GitHub repository (${github_1.GITHUB_REPO}).
|
|
21
|
-
|
|
22
|
-
Creates a GitHub issue on behalf of the agent. The Supermodel team actively monitors and responds to all submitted issues.
|
|
23
|
-
|
|
24
|
-
Use this tool whenever you believe a new feature, improvement, or enhancement would be helpful for the Supermodel MCP server or its underlying API. Examples include:
|
|
25
|
-
- Suggesting a new tool, query type, or graph capability
|
|
26
|
-
- Requesting improvements to an existing tool (e.g. better filtering, new parameters, improved output format)
|
|
27
|
-
- Proposing changes to error messages, documentation, or developer experience
|
|
28
|
-
- Identifying a missing capability you needed while working on a task
|
|
29
|
-
|
|
30
|
-
This tool requires a GITHUB_TOKEN environment variable. To set it up:
|
|
31
|
-
1. Create a GitHub personal access token at https://github.com/settings/tokens with the "public_repo" scope
|
|
32
|
-
2. Set it in your environment: export GITHUB_TOKEN=ghp_your_token_here
|
|
33
|
-
3. Restart the MCP server`,
|
|
34
|
-
inputSchema: {
|
|
35
|
-
type: 'object',
|
|
36
|
-
properties: {
|
|
37
|
-
title: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
description: 'Short, descriptive title for the feature request.',
|
|
40
|
-
},
|
|
41
|
-
description: {
|
|
42
|
-
type: 'string',
|
|
43
|
-
description: 'Detailed description of the feature. Include context, use cases, and expected behavior.',
|
|
44
|
-
},
|
|
45
|
-
labels: {
|
|
46
|
-
type: 'array',
|
|
47
|
-
items: { type: 'string' },
|
|
48
|
-
description: 'Optional labels to categorize the issue (e.g. ["enhancement"]).',
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
required: ['title', 'description'],
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
const handler = async (_client, args) => {
|
|
55
|
-
const tokenError = (0, github_1.validateGitHubToken)();
|
|
56
|
-
if (tokenError)
|
|
57
|
-
return (0, types_1.asErrorResult)(tokenError);
|
|
58
|
-
if (!args) {
|
|
59
|
-
return (0, types_1.asErrorResult)({
|
|
60
|
-
type: 'validation_error',
|
|
61
|
-
message: 'Missing required parameters: title and description.',
|
|
62
|
-
code: 'MISSING_PARAMETERS',
|
|
63
|
-
recoverable: false,
|
|
64
|
-
suggestion: 'Provide both "title" and "description" parameters.',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
const { title, description, labels } = args;
|
|
68
|
-
const titleError = (0, github_1.validateRequiredString)(title, 'title', 'INVALID_TITLE', 'Provide a short, descriptive title as a string.');
|
|
69
|
-
if (titleError)
|
|
70
|
-
return (0, types_1.asErrorResult)(titleError);
|
|
71
|
-
const descError = (0, github_1.validateRequiredString)(description, 'description', 'INVALID_DESCRIPTION', 'Provide a detailed description as a string.');
|
|
72
|
-
if (descError)
|
|
73
|
-
return (0, types_1.asErrorResult)(descError);
|
|
74
|
-
const labelsError = (0, github_1.validateLabels)(labels);
|
|
75
|
-
if (labelsError)
|
|
76
|
-
return (0, types_1.asErrorResult)(labelsError);
|
|
77
|
-
return (0, github_1.createGitHubIssue)('request_feature', {
|
|
78
|
-
title: title,
|
|
79
|
-
body: description,
|
|
80
|
-
labels: labels,
|
|
81
|
-
}, 'Feature request created successfully.');
|
|
82
|
-
};
|
|
83
|
-
exports.handler = handler;
|
|
84
|
-
exports.default = { metadata: exports.metadata, tool: exports.tool, handler: exports.handler };
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Task-specific tool: Find call sites for a function
|
|
4
|
-
* Lightweight, focused query without full graph overhead
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.findCallSitesTool = void 0;
|
|
8
|
-
exports.findCallSites = findCallSites;
|
|
9
|
-
const zod_1 = require("zod");
|
|
10
|
-
const cache_1 = require("../cache");
|
|
11
|
-
const FindCallSitesArgsSchema = zod_1.z.object({
|
|
12
|
-
path: zod_1.z.string().describe('Repository path'),
|
|
13
|
-
function_name: zod_1.z.string().describe('Name of function to find call sites for'),
|
|
14
|
-
include_context: zod_1.z.boolean().optional().describe('Include surrounding code context'),
|
|
15
|
-
max_results: zod_1.z.number().optional().describe('Maximum number of results to return'),
|
|
16
|
-
});
|
|
17
|
-
/**
|
|
18
|
-
* Find all places where a function is called
|
|
19
|
-
*/
|
|
20
|
-
async function findCallSites(args) {
|
|
21
|
-
const { path, function_name, include_context = true, max_results = 10 } = args;
|
|
22
|
-
// Get cached graph
|
|
23
|
-
const cacheKey = getCacheKey(path);
|
|
24
|
-
const graph = cache_1.graphCache.get(cacheKey);
|
|
25
|
-
if (!graph) {
|
|
26
|
-
throw new Error('Graph not cached. Run explore_codebase first to analyze the repository.');
|
|
27
|
-
}
|
|
28
|
-
// Find function node by name (case-insensitive)
|
|
29
|
-
const functionNodes = findFunctionsByName(graph, function_name);
|
|
30
|
-
if (functionNodes.length === 0) {
|
|
31
|
-
return {
|
|
32
|
-
function_name,
|
|
33
|
-
total_call_sites: 0,
|
|
34
|
-
call_sites: [],
|
|
35
|
-
summary: `Function "${function_name}" not found in codebase.`,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
// Use first match if multiple functions with same name
|
|
39
|
-
const targetNode = functionNodes[0];
|
|
40
|
-
const targetId = targetNode.id;
|
|
41
|
-
// Get incoming call edges
|
|
42
|
-
const callAdj = graph.callAdj.get(targetId);
|
|
43
|
-
if (!callAdj || callAdj.in.length === 0) {
|
|
44
|
-
return {
|
|
45
|
-
function_name,
|
|
46
|
-
total_call_sites: 0,
|
|
47
|
-
call_sites: [],
|
|
48
|
-
summary: `Function "${function_name}" is not called by any other functions.`,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// Build call site results
|
|
52
|
-
const callSites = [];
|
|
53
|
-
for (const callerId of callAdj.in) {
|
|
54
|
-
const callerNode = graph.nodeById.get(callerId);
|
|
55
|
-
if (!callerNode)
|
|
56
|
-
continue;
|
|
57
|
-
// Find edge details (if available)
|
|
58
|
-
const edge = findCallEdge(graph, callerId, targetId);
|
|
59
|
-
const result = {
|
|
60
|
-
caller: {
|
|
61
|
-
name: callerNode.properties?.name || 'unknown',
|
|
62
|
-
file: callerNode.properties?.filePath || 'unknown',
|
|
63
|
-
line: callerNode.properties?.startLine || 0,
|
|
64
|
-
},
|
|
65
|
-
call_site: {
|
|
66
|
-
line: edge?.properties?.lineNumber || 0,
|
|
67
|
-
column: edge?.properties?.columnNumber,
|
|
68
|
-
context: edge?.properties?.context,
|
|
69
|
-
code_snippet: include_context ? edge?.properties?.codeSnippet : undefined,
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
callSites.push(result);
|
|
73
|
-
if (callSites.length >= max_results) {
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// Generate summary
|
|
78
|
-
const summary = generateSummary(function_name, callSites, callAdj.in.length);
|
|
79
|
-
return {
|
|
80
|
-
function_name,
|
|
81
|
-
total_call_sites: callAdj.in.length,
|
|
82
|
-
call_sites: callSites,
|
|
83
|
-
summary,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Helper: Find function nodes by name
|
|
88
|
-
*/
|
|
89
|
-
function findFunctionsByName(graph, name) {
|
|
90
|
-
const lowerName = name.toLowerCase();
|
|
91
|
-
const nodeIds = graph.nameIndex.get(lowerName) || [];
|
|
92
|
-
return nodeIds
|
|
93
|
-
.map((id) => graph.nodeById.get(id))
|
|
94
|
-
.filter((node) => node && node.labels?.[0] === 'Function');
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Helper: Find specific call edge between two functions
|
|
98
|
-
*/
|
|
99
|
-
function findCallEdge(graph, fromId, toId) {
|
|
100
|
-
// In original cache, edges aren't indexed by ID
|
|
101
|
-
// This is a limitation we'd fix in edge-aware cache
|
|
102
|
-
// For now, search through raw relationships
|
|
103
|
-
const relationships = graph.raw?.graph?.relationships || [];
|
|
104
|
-
return relationships.find((rel) => rel.type === 'calls' && rel.startNode === fromId && rel.endNode === toId);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Helper: Generate natural language summary
|
|
108
|
-
*/
|
|
109
|
-
function generateSummary(functionName, callSites, total) {
|
|
110
|
-
if (callSites.length === 0) {
|
|
111
|
-
return `Function "${functionName}" is not called by any functions.`;
|
|
112
|
-
}
|
|
113
|
-
const callerNames = callSites.map(cs => cs.caller.name);
|
|
114
|
-
const uniqueFiles = new Set(callSites.map(cs => cs.caller.file));
|
|
115
|
-
let summary = `Function "${functionName}" is called by ${total} function(s) in ${uniqueFiles.size} file(s).`;
|
|
116
|
-
if (callSites.length > 0) {
|
|
117
|
-
summary += ` Primary callers: ${callerNames.slice(0, 3).join(', ')}`;
|
|
118
|
-
if (total > 3) {
|
|
119
|
-
summary += ` and ${total - 3} more`;
|
|
120
|
-
}
|
|
121
|
-
summary += '.';
|
|
122
|
-
}
|
|
123
|
-
return summary;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Helper: Generate cache key (simplified - should match main implementation)
|
|
127
|
-
*/
|
|
128
|
-
function getCacheKey(path) {
|
|
129
|
-
// In real implementation, this would include git hash, etc.
|
|
130
|
-
return `cache_${path}`;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Tool metadata for MCP registration
|
|
134
|
-
*/
|
|
135
|
-
exports.findCallSitesTool = {
|
|
136
|
-
name: 'find_call_sites',
|
|
137
|
-
description: 'Find all places where a specific function is called, with line numbers and context',
|
|
138
|
-
inputSchema: FindCallSitesArgsSchema,
|
|
139
|
-
handler: findCallSites,
|
|
140
|
-
};
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Task-specific tool: Find definition of a symbol
|
|
4
|
-
* Fast lookup in cache indexes to locate where something is defined
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.findDefinitionTool = void 0;
|
|
8
|
-
exports.findDefinition = findDefinition;
|
|
9
|
-
const zod_1 = require("zod");
|
|
10
|
-
const cache_1 = require("../cache");
|
|
11
|
-
const FindDefinitionArgsSchema = zod_1.z.object({
|
|
12
|
-
path: zod_1.z.string().describe('Repository path'),
|
|
13
|
-
name: zod_1.z.string().describe('Name of the symbol to find'),
|
|
14
|
-
type: zod_1.z.enum(['function', 'class', 'variable', 'type', 'any']).optional().describe('Type of symbol'),
|
|
15
|
-
max_results: zod_1.z.number().optional().describe('Maximum number of results if multiple matches'),
|
|
16
|
-
});
|
|
17
|
-
/**
|
|
18
|
-
* Find where a symbol is defined
|
|
19
|
-
*/
|
|
20
|
-
async function findDefinition(args) {
|
|
21
|
-
const { path, name, type = 'any', max_results = 5 } = args;
|
|
22
|
-
// Get cached graph
|
|
23
|
-
const cacheKey = getCacheKey(path);
|
|
24
|
-
const graph = cache_1.graphCache.get(cacheKey);
|
|
25
|
-
if (!graph) {
|
|
26
|
-
throw new Error('Graph not cached. Run explore_codebase first to analyze the repository.');
|
|
27
|
-
}
|
|
28
|
-
// Find nodes by name (case-insensitive)
|
|
29
|
-
const lowerName = name.toLowerCase();
|
|
30
|
-
const nodeIds = graph.nameIndex.get(lowerName) || [];
|
|
31
|
-
if (nodeIds.length === 0) {
|
|
32
|
-
return {
|
|
33
|
-
query_name: name,
|
|
34
|
-
query_type: type,
|
|
35
|
-
found: false,
|
|
36
|
-
results: [],
|
|
37
|
-
summary: `No definition found for "${name}".`,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
// Filter by type if specified
|
|
41
|
-
const nodes = nodeIds
|
|
42
|
-
.map(id => graph.nodeById.get(id))
|
|
43
|
-
.filter((node) => node !== undefined && matchesType(node, type))
|
|
44
|
-
.slice(0, max_results);
|
|
45
|
-
if (nodes.length === 0) {
|
|
46
|
-
return {
|
|
47
|
-
query_name: name,
|
|
48
|
-
query_type: type,
|
|
49
|
-
found: false,
|
|
50
|
-
results: [],
|
|
51
|
-
summary: `No ${type} definition found for "${name}".`,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
// Build results
|
|
55
|
-
const results = nodes.map(node => {
|
|
56
|
-
const props = node.properties || {};
|
|
57
|
-
return {
|
|
58
|
-
name: props.name || name,
|
|
59
|
-
type: node.labels?.[0] || 'unknown',
|
|
60
|
-
file: props.filePath || 'unknown',
|
|
61
|
-
line: props.startLine || 0,
|
|
62
|
-
end_line: props.endLine,
|
|
63
|
-
kind: props.kind,
|
|
64
|
-
context: buildContext(node),
|
|
65
|
-
};
|
|
66
|
-
});
|
|
67
|
-
// Generate summary
|
|
68
|
-
const summary = generateSummary(name, type, results);
|
|
69
|
-
return {
|
|
70
|
-
query_name: name,
|
|
71
|
-
query_type: type,
|
|
72
|
-
found: true,
|
|
73
|
-
results,
|
|
74
|
-
summary,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Check if node matches the requested type
|
|
79
|
-
*/
|
|
80
|
-
function matchesType(node, requestedType) {
|
|
81
|
-
if (requestedType === 'any') {
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
const primaryLabel = node.labels?.[0]?.toLowerCase() || '';
|
|
85
|
-
// Map requested type to node labels
|
|
86
|
-
const typeMap = {
|
|
87
|
-
function: ['function', 'method'],
|
|
88
|
-
class: ['class', 'interface', 'struct'],
|
|
89
|
-
variable: ['variable', 'constant', 'parameter', 'field'],
|
|
90
|
-
type: ['type', 'typedef', 'enum', 'interface'],
|
|
91
|
-
};
|
|
92
|
-
const acceptedLabels = typeMap[requestedType] || [requestedType];
|
|
93
|
-
return acceptedLabels.some(label => primaryLabel.includes(label));
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Build context string for a definition
|
|
97
|
-
*/
|
|
98
|
-
function buildContext(node) {
|
|
99
|
-
const props = node.properties || {};
|
|
100
|
-
const label = node.labels?.[0] || 'symbol';
|
|
101
|
-
const parts = [];
|
|
102
|
-
// Add scope if available
|
|
103
|
-
if (props.scope) {
|
|
104
|
-
parts.push(`in ${props.scope}`);
|
|
105
|
-
}
|
|
106
|
-
// Add signature for functions
|
|
107
|
-
if (label === 'Function' && props.signature) {
|
|
108
|
-
parts.push(`signature: ${props.signature}`);
|
|
109
|
-
}
|
|
110
|
-
// Add modifiers
|
|
111
|
-
const modifiers = [];
|
|
112
|
-
if (props.isStatic)
|
|
113
|
-
modifiers.push('static');
|
|
114
|
-
if (props.isAsync)
|
|
115
|
-
modifiers.push('async');
|
|
116
|
-
if (props.isPublic)
|
|
117
|
-
modifiers.push('public');
|
|
118
|
-
if (props.isPrivate)
|
|
119
|
-
modifiers.push('private');
|
|
120
|
-
if (modifiers.length > 0) {
|
|
121
|
-
parts.push(modifiers.join(' '));
|
|
122
|
-
}
|
|
123
|
-
return parts.join(', ') || undefined;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Generate natural language summary
|
|
127
|
-
*/
|
|
128
|
-
function generateSummary(name, type, results) {
|
|
129
|
-
if (results.length === 0) {
|
|
130
|
-
return `No definition found for "${name}".`;
|
|
131
|
-
}
|
|
132
|
-
if (results.length === 1) {
|
|
133
|
-
const result = results[0];
|
|
134
|
-
return `${result.type} "${name}" defined in ${result.file}:${result.line}`;
|
|
135
|
-
}
|
|
136
|
-
// Multiple results
|
|
137
|
-
const typeCount = new Map();
|
|
138
|
-
for (const result of results) {
|
|
139
|
-
typeCount.set(result.type, (typeCount.get(result.type) || 0) + 1);
|
|
140
|
-
}
|
|
141
|
-
const typeSummary = Array.from(typeCount.entries())
|
|
142
|
-
.map(([t, count]) => `${count} ${t}${count > 1 ? 's' : ''}`)
|
|
143
|
-
.join(', ');
|
|
144
|
-
return `Found ${results.length} definitions for "${name}": ${typeSummary}`;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Helper: Generate cache key
|
|
148
|
-
*/
|
|
149
|
-
function getCacheKey(path) {
|
|
150
|
-
return `cache_${path}`;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Tool metadata for MCP registration
|
|
154
|
-
*/
|
|
155
|
-
exports.findDefinitionTool = {
|
|
156
|
-
name: 'find_definition',
|
|
157
|
-
description: 'Find where a symbol (function, class, variable, type) is defined in the codebase',
|
|
158
|
-
inputSchema: FindDefinitionArgsSchema,
|
|
159
|
-
handler: findDefinition,
|
|
160
|
-
};
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Individual graph type tools for targeted codebase analysis.
|
|
4
|
-
* Each tool calls a specific graph API endpoint for focused results.
|
|
5
|
-
*/
|
|
6
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
-
if (k2 === undefined) k2 = k;
|
|
8
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
-
}
|
|
12
|
-
Object.defineProperty(o, k2, desc);
|
|
13
|
-
}) : (function(o, m, k, k2) {
|
|
14
|
-
if (k2 === undefined) k2 = k;
|
|
15
|
-
o[k2] = m[k];
|
|
16
|
-
}));
|
|
17
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
-
}) : function(o, v) {
|
|
20
|
-
o["default"] = v;
|
|
21
|
-
});
|
|
22
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
-
var ownKeys = function(o) {
|
|
24
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
-
var ar = [];
|
|
26
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
-
return ar;
|
|
28
|
-
};
|
|
29
|
-
return ownKeys(o);
|
|
30
|
-
};
|
|
31
|
-
return function (mod) {
|
|
32
|
-
if (mod && mod.__esModule) return mod;
|
|
33
|
-
var result = {};
|
|
34
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
-
__setModuleDefault(result, mod);
|
|
36
|
-
return result;
|
|
37
|
-
};
|
|
38
|
-
})();
|
|
39
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
-
exports.graphTools = exports.parseGraphTool = exports.domainGraphTool = exports.dependencyGraphTool = exports.callGraphTool = void 0;
|
|
41
|
-
const promises_1 = require("fs/promises");
|
|
42
|
-
const buffer_1 = require("buffer");
|
|
43
|
-
const types_1 = require("../types");
|
|
44
|
-
const filtering_1 = require("../filtering");
|
|
45
|
-
const zip_repository_1 = require("../utils/zip-repository");
|
|
46
|
-
const logger = __importStar(require("../utils/logger"));
|
|
47
|
-
const api_helpers_1 = require("../utils/api-helpers");
|
|
48
|
-
const GRAPH_TYPES = [
|
|
49
|
-
{
|
|
50
|
-
name: 'call',
|
|
51
|
-
toolName: 'get_call_graph',
|
|
52
|
-
description: `Generate a call graph showing function-to-function call relationships.
|
|
53
|
-
|
|
54
|
-
Returns: Function nodes with "calls" relationships between them.
|
|
55
|
-
|
|
56
|
-
Use this to:
|
|
57
|
-
- Find all callers of a specific function
|
|
58
|
-
- Find all functions called by a specific function
|
|
59
|
-
- Trace execution flow through the codebase
|
|
60
|
-
- Debug by following call chains
|
|
61
|
-
|
|
62
|
-
Best for: Debugging, understanding "what calls what", tracing execution paths.`,
|
|
63
|
-
endpoint: '/v1/graphs/call',
|
|
64
|
-
operationId: 'generateCallGraph',
|
|
65
|
-
apiMethod: 'generateCallGraph',
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'dependency',
|
|
69
|
-
toolName: 'get_dependency_graph',
|
|
70
|
-
description: `Generate a dependency graph showing import relationships between files.
|
|
71
|
-
|
|
72
|
-
Returns: File nodes with "IMPORTS" relationships between them.
|
|
73
|
-
|
|
74
|
-
Use this to:
|
|
75
|
-
- Map which files import which other files
|
|
76
|
-
- Find circular dependencies
|
|
77
|
-
- Understand module coupling
|
|
78
|
-
- Plan safe refactoring of imports
|
|
79
|
-
|
|
80
|
-
Best for: Refactoring, understanding module dependencies, finding import cycles.`,
|
|
81
|
-
endpoint: '/v1/graphs/dependency',
|
|
82
|
-
operationId: 'generateDependencyGraph',
|
|
83
|
-
apiMethod: 'generateDependencyGraph',
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: 'domain',
|
|
87
|
-
toolName: 'get_domain_graph',
|
|
88
|
-
description: `Generate a domain classification graph showing high-level architecture.
|
|
89
|
-
|
|
90
|
-
Returns: Domains with descriptions, responsibilities, subdomains, and file/function/class assignments.
|
|
91
|
-
|
|
92
|
-
Use this to:
|
|
93
|
-
- Understand the architectural structure of a codebase
|
|
94
|
-
- See how code is organized into logical domains
|
|
95
|
-
- Identify domain boundaries and responsibilities
|
|
96
|
-
- Get a bird's-eye view before diving into details
|
|
97
|
-
|
|
98
|
-
Best for: New codebases, architecture overview, understanding system organization.`,
|
|
99
|
-
endpoint: '/v1/graphs/domain',
|
|
100
|
-
operationId: 'generateDomainGraph',
|
|
101
|
-
apiMethod: 'generateDomainGraph',
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: 'parse',
|
|
105
|
-
toolName: 'get_parse_graph',
|
|
106
|
-
description: `Generate a full parse graph with all code structure elements.
|
|
107
|
-
|
|
108
|
-
Returns: All nodes (File, Directory, Class, Function, Type) and structural relationships (CONTAINS, DEFINES, DECLARES, IMPORTS).
|
|
109
|
-
|
|
110
|
-
Use this to:
|
|
111
|
-
- Get complete structural information about the codebase
|
|
112
|
-
- Find all classes, functions, and types
|
|
113
|
-
- Understand containment and definition relationships
|
|
114
|
-
- Support detailed refactoring analysis
|
|
115
|
-
|
|
116
|
-
Best for: Comprehensive analysis when you need the full code structure.`,
|
|
117
|
-
endpoint: '/v1/graphs/parse',
|
|
118
|
-
operationId: 'generateParseGraph',
|
|
119
|
-
apiMethod: 'generateParseGraph',
|
|
120
|
-
},
|
|
121
|
-
];
|
|
122
|
-
/**
|
|
123
|
-
* Create a tool definition and handler for a specific graph type
|
|
124
|
-
*/
|
|
125
|
-
function createGraphTool(config) {
|
|
126
|
-
const metadata = {
|
|
127
|
-
resource: 'graphs',
|
|
128
|
-
operation: 'write',
|
|
129
|
-
tags: [config.name],
|
|
130
|
-
httpMethod: 'post',
|
|
131
|
-
httpPath: config.endpoint,
|
|
132
|
-
operationId: config.operationId,
|
|
133
|
-
};
|
|
134
|
-
const tool = {
|
|
135
|
-
name: config.toolName,
|
|
136
|
-
description: config.description,
|
|
137
|
-
inputSchema: {
|
|
138
|
-
type: 'object',
|
|
139
|
-
properties: {
|
|
140
|
-
directory: {
|
|
141
|
-
type: 'string',
|
|
142
|
-
description: 'Path to the repository directory to analyze.',
|
|
143
|
-
},
|
|
144
|
-
jq_filter: {
|
|
145
|
-
type: 'string',
|
|
146
|
-
title: 'jq Filter',
|
|
147
|
-
description: 'Optional jq filter to extract specific data from the response.',
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
required: [],
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
const handler = async (client, args, defaultWorkdir) => {
|
|
154
|
-
if (!args) {
|
|
155
|
-
args = {};
|
|
156
|
-
}
|
|
157
|
-
const { jq_filter, directory: providedDirectory } = args;
|
|
158
|
-
if (providedDirectory !== undefined && typeof providedDirectory !== 'string') {
|
|
159
|
-
return (0, types_1.asErrorResult)({
|
|
160
|
-
type: 'validation_error',
|
|
161
|
-
message: 'Invalid "directory" parameter. Provide a valid directory path as a string.',
|
|
162
|
-
code: 'INVALID_DIRECTORY',
|
|
163
|
-
recoverable: false,
|
|
164
|
-
suggestion: 'Pass directory as a string path, e.g. directory="/workspace/my-repo".',
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
if (jq_filter !== undefined && typeof jq_filter !== 'string') {
|
|
168
|
-
return (0, types_1.asErrorResult)({
|
|
169
|
-
type: 'validation_error',
|
|
170
|
-
message: 'Invalid "jq_filter" parameter. Provide a jq filter string.',
|
|
171
|
-
code: 'INVALID_JQ_FILTER',
|
|
172
|
-
recoverable: false,
|
|
173
|
-
suggestion: 'Pass jq_filter as a string, e.g. jq_filter=".nodes".',
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
const directory = providedDirectory ?? defaultWorkdir;
|
|
177
|
-
if (!directory || typeof directory !== 'string') {
|
|
178
|
-
return (0, types_1.asErrorResult)({
|
|
179
|
-
type: 'validation_error',
|
|
180
|
-
message: 'No "directory" parameter provided and no default workdir configured.',
|
|
181
|
-
code: 'MISSING_DIRECTORY',
|
|
182
|
-
recoverable: false,
|
|
183
|
-
suggestion: 'Provide a directory path or start the MCP server with a workdir argument.',
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
const idempotencyKey = (0, api_helpers_1.generateIdempotencyKey)(directory, config.name);
|
|
187
|
-
logger.debug(`[${config.toolName}] Idempotency key:`, idempotencyKey);
|
|
188
|
-
// Create ZIP of repository
|
|
189
|
-
let zipPath;
|
|
190
|
-
let cleanup = null;
|
|
191
|
-
try {
|
|
192
|
-
const zipResult = await (0, zip_repository_1.zipRepository)(directory);
|
|
193
|
-
zipPath = zipResult.path;
|
|
194
|
-
cleanup = zipResult.cleanup;
|
|
195
|
-
logger.debug(`[${config.toolName}] ZIP created:`, zipResult.fileCount, 'files,', (0, api_helpers_1.formatBytes)(zipResult.sizeBytes));
|
|
196
|
-
}
|
|
197
|
-
catch (error) {
|
|
198
|
-
const message = typeof error?.message === 'string' ? error.message : String(error);
|
|
199
|
-
if (message.includes('does not exist')) {
|
|
200
|
-
return (0, types_1.asErrorResult)({
|
|
201
|
-
type: 'not_found_error',
|
|
202
|
-
message: `Directory not found: ${directory}`,
|
|
203
|
-
code: 'DIRECTORY_NOT_FOUND',
|
|
204
|
-
recoverable: false,
|
|
205
|
-
suggestion: 'Verify the path exists.',
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
return (0, types_1.asErrorResult)({
|
|
209
|
-
type: 'internal_error',
|
|
210
|
-
message: `Failed to create ZIP archive: ${message}`,
|
|
211
|
-
code: 'ZIP_CREATION_FAILED',
|
|
212
|
-
recoverable: false,
|
|
213
|
-
reportable: true,
|
|
214
|
-
repo: api_helpers_1.REPORT_REPO,
|
|
215
|
-
suggestion: api_helpers_1.REPORT_SUGGESTION,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
try {
|
|
219
|
-
const fileBuffer = await (0, promises_1.readFile)(zipPath);
|
|
220
|
-
const fileBlob = new buffer_1.Blob([fileBuffer], { type: 'application/zip' });
|
|
221
|
-
logger.debug(`[${config.toolName}] Calling API...`);
|
|
222
|
-
console.error(`[Supermodel] Generating ${config.name} graph...`);
|
|
223
|
-
// Call the appropriate API method via SupermodelClient
|
|
224
|
-
const apiMethod = client.graphs[config.apiMethod].bind(client.graphs);
|
|
225
|
-
const response = await apiMethod(fileBlob, { idempotencyKey });
|
|
226
|
-
console.error(`[Supermodel] ${config.name} graph complete.`);
|
|
227
|
-
// Apply optional jq filter
|
|
228
|
-
const result = await (0, filtering_1.maybeFilter)(jq_filter, response);
|
|
229
|
-
return (0, types_1.asTextContentResult)(result);
|
|
230
|
-
}
|
|
231
|
-
catch (error) {
|
|
232
|
-
if ((0, filtering_1.isJqError)(error)) {
|
|
233
|
-
logger.error(`[${config.toolName}] jq filter error:`, error.message);
|
|
234
|
-
return (0, types_1.asErrorResult)({
|
|
235
|
-
type: 'validation_error',
|
|
236
|
-
message: `Invalid jq filter syntax: ${error.message}`,
|
|
237
|
-
code: 'INVALID_JQ_FILTER',
|
|
238
|
-
recoverable: false,
|
|
239
|
-
suggestion: 'Check jq filter syntax. Example: jq_filter=".nodes" or jq_filter=".graph.nodeCount"',
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
logger.error(`[${config.toolName}] API error:`, error.message);
|
|
243
|
-
return (0, types_1.asErrorResult)((0, api_helpers_1.classifyApiError)(error));
|
|
244
|
-
}
|
|
245
|
-
finally {
|
|
246
|
-
if (cleanup) {
|
|
247
|
-
try {
|
|
248
|
-
await cleanup();
|
|
249
|
-
}
|
|
250
|
-
catch (cleanupError) {
|
|
251
|
-
logger.warn(`[${config.toolName}] Cleanup failed:`, cleanupError);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
return { metadata, tool, handler };
|
|
257
|
-
}
|
|
258
|
-
// Helper to find graph type by name (safer than array indexing)
|
|
259
|
-
function getGraphType(name) {
|
|
260
|
-
const config = GRAPH_TYPES.find(t => t.name === name);
|
|
261
|
-
if (!config) {
|
|
262
|
-
throw new Error(`Unknown graph type: ${name}`);
|
|
263
|
-
}
|
|
264
|
-
return config;
|
|
265
|
-
}
|
|
266
|
-
// Create all graph tools
|
|
267
|
-
exports.callGraphTool = createGraphTool(getGraphType('call'));
|
|
268
|
-
exports.dependencyGraphTool = createGraphTool(getGraphType('dependency'));
|
|
269
|
-
exports.domainGraphTool = createGraphTool(getGraphType('domain'));
|
|
270
|
-
exports.parseGraphTool = createGraphTool(getGraphType('parse'));
|
|
271
|
-
// Export all tools as an array for easy registration
|
|
272
|
-
exports.graphTools = [
|
|
273
|
-
exports.callGraphTool,
|
|
274
|
-
exports.dependencyGraphTool,
|
|
275
|
-
exports.domainGraphTool,
|
|
276
|
-
exports.parseGraphTool,
|
|
277
|
-
];
|