@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.
@@ -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
- ];