@navigation-agent/mcp-server 0.1.5 → 0.2.1
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/app/createMcpServer.js +3 -3
- package/dist/contracts/public/code.d.ts +25 -11
- package/dist/contracts/public/code.js +4 -4
- package/dist/engine/protocol.d.ts +19 -5
- package/dist/engine/protocol.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/services/findSymbolService.js +1 -0
- package/dist/services/traceFlowService.d.ts +11 -0
- package/dist/services/traceFlowService.js +245 -0
- package/dist/tools/registerCodeTools.d.ts +1 -1
- package/dist/tools/registerCodeTools.js +8 -8
- package/package.json +6 -6
|
@@ -6,7 +6,7 @@ import { createInspectTreeService } from "../services/inspectTreeService.js";
|
|
|
6
6
|
import { createListEndpointsService } from "../services/listEndpointsService.js";
|
|
7
7
|
import { createSearchTextService } from "../services/searchTextService.js";
|
|
8
8
|
import { createTraceCallersService } from "../services/traceCallersService.js";
|
|
9
|
-
import {
|
|
9
|
+
import { createTraceFlowService } from "../services/traceFlowService.js";
|
|
10
10
|
import { registerCodeTools, } from "../tools/registerCodeTools.js";
|
|
11
11
|
function toSdkToolResult(result) {
|
|
12
12
|
return {
|
|
@@ -38,7 +38,7 @@ export function createMcpServer(options) {
|
|
|
38
38
|
workspaceRoot: options.workspaceRoot,
|
|
39
39
|
engineClient,
|
|
40
40
|
});
|
|
41
|
-
const
|
|
41
|
+
const traceFlowService = createTraceFlowService({
|
|
42
42
|
workspaceRoot: options.workspaceRoot,
|
|
43
43
|
engineClient,
|
|
44
44
|
});
|
|
@@ -52,7 +52,7 @@ export function createMcpServer(options) {
|
|
|
52
52
|
listEndpointsHandler: (payload) => listEndpointsService.validateAndExecute(payload),
|
|
53
53
|
searchTextHandler: (payload) => searchTextService.validateAndExecute(payload),
|
|
54
54
|
traceCallersHandler: (payload) => traceCallersService.validateAndExecute(payload),
|
|
55
|
-
|
|
55
|
+
traceFlowHandler: (payload) => traceFlowService.validateAndExecute(payload),
|
|
56
56
|
});
|
|
57
57
|
const sdkServer = new SdkMcpServer({
|
|
58
58
|
name: "navigation-agent-mcp",
|
|
@@ -8,7 +8,7 @@ export declare const PUBLIC_SYMBOL_KINDS: readonly ["any", "class", "interface",
|
|
|
8
8
|
export type PublicSymbolKind = (typeof PUBLIC_SYMBOL_KINDS)[number];
|
|
9
9
|
export declare const MATCH_MODES: readonly ["exact", "fuzzy"];
|
|
10
10
|
export type MatchMode = (typeof MATCH_MODES)[number];
|
|
11
|
-
export declare const CODE_TOOL_NAMES: readonly ["code.inspect_tree", "code.list_endpoints", "code.find_symbol", "code.search_text", "code.
|
|
11
|
+
export declare const CODE_TOOL_NAMES: readonly ["code.inspect_tree", "code.list_endpoints", "code.find_symbol", "code.search_text", "code.trace_flow", "code.trace_callers"];
|
|
12
12
|
export type CodeToolName = (typeof CODE_TOOL_NAMES)[number];
|
|
13
13
|
export interface InspectTreeInput {
|
|
14
14
|
path?: string | null;
|
|
@@ -50,6 +50,7 @@ export interface PublicSymbolDefinition {
|
|
|
50
50
|
kind: PublicSymbolKind;
|
|
51
51
|
path: string;
|
|
52
52
|
line: number;
|
|
53
|
+
lineEnd: number;
|
|
53
54
|
language: PublicLanguage | null;
|
|
54
55
|
}
|
|
55
56
|
export interface FindSymbolData {
|
|
@@ -124,25 +125,38 @@ export interface SearchTextData {
|
|
|
124
125
|
totalMatchCount: number;
|
|
125
126
|
items: SearchTextFileMatch[];
|
|
126
127
|
}
|
|
127
|
-
export interface
|
|
128
|
+
export interface TraceFlowInput {
|
|
128
129
|
path: string;
|
|
129
130
|
symbol: string;
|
|
130
131
|
language?: PublicLanguage | null;
|
|
131
132
|
framework?: PublicFramework | null;
|
|
132
133
|
}
|
|
133
|
-
export interface
|
|
134
|
+
export interface TraceFlowEntrypoint {
|
|
134
135
|
path: string;
|
|
135
136
|
symbol: string;
|
|
136
137
|
language: PublicLanguage | null;
|
|
137
138
|
}
|
|
138
|
-
export interface
|
|
139
|
+
export interface TraceFlowFile {
|
|
139
140
|
path: string;
|
|
140
141
|
language: PublicLanguage | null;
|
|
141
142
|
}
|
|
142
|
-
export interface
|
|
143
|
-
|
|
143
|
+
export interface TraceFlowCallee {
|
|
144
|
+
path: string;
|
|
145
|
+
line: number;
|
|
146
|
+
endLine: number;
|
|
147
|
+
column: number | null;
|
|
148
|
+
callee: string;
|
|
149
|
+
calleeSymbol: string | null;
|
|
150
|
+
relation: string;
|
|
151
|
+
language: PublicLanguage | null;
|
|
152
|
+
snippet: string | null;
|
|
153
|
+
depth: number;
|
|
154
|
+
}
|
|
155
|
+
export interface TraceFlowData {
|
|
156
|
+
entrypoint: TraceFlowEntrypoint;
|
|
144
157
|
fileCount: number;
|
|
145
|
-
items:
|
|
158
|
+
items: TraceFlowFile[];
|
|
159
|
+
callees: TraceFlowCallee[];
|
|
146
160
|
}
|
|
147
161
|
export interface TraceCallersInput {
|
|
148
162
|
path: string;
|
|
@@ -553,7 +567,7 @@ export declare const searchTextInputSchema: {
|
|
|
553
567
|
};
|
|
554
568
|
};
|
|
555
569
|
};
|
|
556
|
-
export declare const
|
|
570
|
+
export declare const traceFlowInputSchema: {
|
|
557
571
|
readonly type: "object";
|
|
558
572
|
readonly properties: {
|
|
559
573
|
readonly path: {
|
|
@@ -943,7 +957,7 @@ export declare const codeToolSchemas: {
|
|
|
943
957
|
};
|
|
944
958
|
};
|
|
945
959
|
};
|
|
946
|
-
readonly "code.
|
|
960
|
+
readonly "code.trace_flow": {
|
|
947
961
|
readonly type: "object";
|
|
948
962
|
readonly properties: {
|
|
949
963
|
readonly path: {
|
|
@@ -1090,9 +1104,9 @@ export declare function normalizeSearchTextInput(payload: Record<string, unknown
|
|
|
1090
1104
|
ok: false;
|
|
1091
1105
|
issues: ValidationIssue[];
|
|
1092
1106
|
};
|
|
1093
|
-
export declare function
|
|
1107
|
+
export declare function normalizeTraceFlowInput(payload: Record<string, unknown>): {
|
|
1094
1108
|
ok: true;
|
|
1095
|
-
value:
|
|
1109
|
+
value: TraceFlowInput;
|
|
1096
1110
|
} | {
|
|
1097
1111
|
ok: false;
|
|
1098
1112
|
issues: ValidationIssue[];
|
|
@@ -18,7 +18,7 @@ export const CODE_TOOL_NAMES = [
|
|
|
18
18
|
"code.list_endpoints",
|
|
19
19
|
"code.find_symbol",
|
|
20
20
|
"code.search_text",
|
|
21
|
-
"code.
|
|
21
|
+
"code.trace_flow",
|
|
22
22
|
"code.trace_callers",
|
|
23
23
|
];
|
|
24
24
|
const sharedDefs = {
|
|
@@ -196,7 +196,7 @@ export const searchTextInputSchema = {
|
|
|
196
196
|
required: ["query"],
|
|
197
197
|
$defs: sharedDefs,
|
|
198
198
|
};
|
|
199
|
-
export const
|
|
199
|
+
export const traceFlowInputSchema = {
|
|
200
200
|
type: "object",
|
|
201
201
|
properties: {
|
|
202
202
|
path: { type: "string", minLength: 1 },
|
|
@@ -252,7 +252,7 @@ export const codeToolSchemas = {
|
|
|
252
252
|
"code.list_endpoints": listEndpointsInputSchema,
|
|
253
253
|
"code.find_symbol": findSymbolInputSchema,
|
|
254
254
|
"code.search_text": searchTextInputSchema,
|
|
255
|
-
"code.
|
|
255
|
+
"code.trace_flow": traceFlowInputSchema,
|
|
256
256
|
"code.trace_callers": traceCallersInputSchema,
|
|
257
257
|
};
|
|
258
258
|
export function normalizeInspectTreeInput(payload) {
|
|
@@ -351,7 +351,7 @@ export function normalizeSearchTextInput(payload) {
|
|
|
351
351
|
},
|
|
352
352
|
};
|
|
353
353
|
}
|
|
354
|
-
export function
|
|
354
|
+
export function normalizeTraceFlowInput(payload) {
|
|
355
355
|
const issues = [];
|
|
356
356
|
const scopedPath = normalizeRequiredTrimmedString(payload.path, "path", issues);
|
|
357
357
|
const symbol = normalizeRequiredTrimmedString(payload.symbol, "symbol", issues);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MatchMode, PublicFramework, PublicLanguage, PublicEndpointKind, PublicSymbolKind } from "../contracts/public/code.ts";
|
|
2
|
-
export declare const ENGINE_CAPABILITIES: readonly ["workspace.inspect_tree", "workspace.find_symbol", "workspace.list_endpoints", "workspace.search_text", "workspace.
|
|
2
|
+
export declare const ENGINE_CAPABILITIES: readonly ["workspace.inspect_tree", "workspace.find_symbol", "workspace.list_endpoints", "workspace.search_text", "workspace.trace_flow", "workspace.trace_callers"];
|
|
3
3
|
export type EngineCapability = (typeof ENGINE_CAPABILITIES)[number];
|
|
4
4
|
export type AnalyzerLanguage = "auto" | "java" | "typescript" | "python" | "rust";
|
|
5
5
|
export interface InspectTreeEnginePayload {
|
|
@@ -57,6 +57,7 @@ export interface FindSymbolEngineItem {
|
|
|
57
57
|
kind: PublicSymbolKind;
|
|
58
58
|
path: string;
|
|
59
59
|
line: number;
|
|
60
|
+
lineEnd: number;
|
|
60
61
|
language: PublicLanguage | null;
|
|
61
62
|
}
|
|
62
63
|
export interface FindSymbolEngineResult {
|
|
@@ -132,19 +133,32 @@ export interface SearchTextEngineResult {
|
|
|
132
133
|
totalMatchCount: number;
|
|
133
134
|
truncated: boolean;
|
|
134
135
|
}
|
|
135
|
-
export interface
|
|
136
|
+
export interface TraceFlowEnginePayload {
|
|
136
137
|
path: string;
|
|
137
138
|
symbol: string;
|
|
138
139
|
analyzerLanguage: AnalyzerLanguage;
|
|
139
140
|
publicLanguageFilter: PublicLanguage | null;
|
|
140
141
|
}
|
|
141
|
-
export interface
|
|
142
|
+
export interface TraceFlowEngineItem {
|
|
142
143
|
path: string;
|
|
143
144
|
language: PublicLanguage | null;
|
|
144
145
|
}
|
|
145
|
-
export interface
|
|
146
|
+
export interface TraceFlowEngineCallee {
|
|
147
|
+
path: string;
|
|
148
|
+
line: number;
|
|
149
|
+
endLine: number;
|
|
150
|
+
column: number | null;
|
|
151
|
+
callee: string;
|
|
152
|
+
calleeSymbol: string | null;
|
|
153
|
+
relation: string;
|
|
154
|
+
language: PublicLanguage | null;
|
|
155
|
+
snippet: string | null;
|
|
156
|
+
depth: number;
|
|
157
|
+
}
|
|
158
|
+
export interface TraceFlowEngineResult {
|
|
146
159
|
resolvedPath: string | null;
|
|
147
|
-
items:
|
|
160
|
+
items: TraceFlowEngineItem[];
|
|
161
|
+
callees: TraceFlowEngineCallee[];
|
|
148
162
|
totalMatched: number;
|
|
149
163
|
truncated: boolean;
|
|
150
164
|
}
|
package/dist/engine/protocol.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export * from "./services/inspectTreeService.ts";
|
|
|
8
8
|
export * from "./services/listEndpointsService.ts";
|
|
9
9
|
export * from "./services/searchTextService.ts";
|
|
10
10
|
export * from "./services/traceCallersService.ts";
|
|
11
|
-
export * from "./services/
|
|
11
|
+
export * from "./services/traceFlowService.ts";
|
|
12
12
|
export * from "./tools/registerCodeTools.ts";
|
package/dist/index.js
CHANGED
|
@@ -8,5 +8,5 @@ export * from "./services/inspectTreeService.js";
|
|
|
8
8
|
export * from "./services/listEndpointsService.js";
|
|
9
9
|
export * from "./services/searchTextService.js";
|
|
10
10
|
export * from "./services/traceCallersService.js";
|
|
11
|
-
export * from "./services/
|
|
11
|
+
export * from "./services/traceFlowService.js";
|
|
12
12
|
export * from "./tools/registerCodeTools.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type TraceFlowData, type TraceFlowInput } from "../contracts/public/code.ts";
|
|
2
|
+
import { type ResponseEnvelope } from "../contracts/public/common.ts";
|
|
3
|
+
import type { EngineClient } from "../engine/rustEngineClient.ts";
|
|
4
|
+
export interface TraceFlowService {
|
|
5
|
+
execute(input: TraceFlowInput): Promise<ResponseEnvelope<TraceFlowData>>;
|
|
6
|
+
validateAndExecute(payload: Record<string, unknown>): Promise<ResponseEnvelope<TraceFlowData>>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createTraceFlowService(options: {
|
|
9
|
+
workspaceRoot: string;
|
|
10
|
+
engineClient: EngineClient;
|
|
11
|
+
}): TraceFlowService;
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { normalizeTraceFlowInput, } from "../contracts/public/code.js";
|
|
2
|
+
import { createResponseMeta, } from "../contracts/public/common.js";
|
|
3
|
+
import { nextRequestId, } from "../engine/protocol.js";
|
|
4
|
+
const TOOL_NAME = "code.trace_flow";
|
|
5
|
+
export function createTraceFlowService(options) {
|
|
6
|
+
return {
|
|
7
|
+
async execute(input) {
|
|
8
|
+
let response;
|
|
9
|
+
try {
|
|
10
|
+
response = await options.engineClient.request({
|
|
11
|
+
id: nextRequestId(),
|
|
12
|
+
capability: "workspace.trace_flow",
|
|
13
|
+
workspaceRoot: options.workspaceRoot,
|
|
14
|
+
payload: {
|
|
15
|
+
path: input.path,
|
|
16
|
+
symbol: input.symbol,
|
|
17
|
+
analyzerLanguage: resolveAnalyzerLanguage(input.language, input.framework),
|
|
18
|
+
publicLanguageFilter: resolveEffectiveLanguage(input.language, input.framework),
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return buildEngineFailureResponse(input, error);
|
|
24
|
+
}
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
return buildMappedErrorResponse(input, response.error.code, response.error.message, response.error.details, response.error.retryable);
|
|
27
|
+
}
|
|
28
|
+
return buildSuccessResponse(input, response.result);
|
|
29
|
+
},
|
|
30
|
+
async validateAndExecute(payload) {
|
|
31
|
+
const normalized = normalizeTraceFlowInput(payload);
|
|
32
|
+
if (!normalized.ok) {
|
|
33
|
+
return buildValidationErrorResponse(normalized.issues);
|
|
34
|
+
}
|
|
35
|
+
return this.execute(normalized.value);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function buildSuccessResponse(input, result) {
|
|
40
|
+
const entrypointPath = result.resolvedPath ?? input.path;
|
|
41
|
+
const effectiveLanguage = resolveEffectiveLanguage(input.language, input.framework);
|
|
42
|
+
const fileCount = result.items.length;
|
|
43
|
+
const calleeCount = result.callees?.length ?? 0;
|
|
44
|
+
return {
|
|
45
|
+
tool: TOOL_NAME,
|
|
46
|
+
status: result.truncated ? "partial" : "ok",
|
|
47
|
+
summary: buildSummary(input.symbol, entrypointPath, calleeCount),
|
|
48
|
+
data: {
|
|
49
|
+
entrypoint: {
|
|
50
|
+
path: entrypointPath,
|
|
51
|
+
symbol: input.symbol,
|
|
52
|
+
language: inferLanguageFromPath(entrypointPath),
|
|
53
|
+
},
|
|
54
|
+
fileCount,
|
|
55
|
+
items: result.items.map((item) => ({
|
|
56
|
+
path: item.path,
|
|
57
|
+
language: item.language,
|
|
58
|
+
})),
|
|
59
|
+
callees: (result.callees ?? []).map((callee) => ({
|
|
60
|
+
path: callee.path,
|
|
61
|
+
line: callee.line,
|
|
62
|
+
endLine: callee.endLine,
|
|
63
|
+
column: callee.column,
|
|
64
|
+
callee: callee.callee,
|
|
65
|
+
calleeSymbol: callee.calleeSymbol,
|
|
66
|
+
relation: callee.relation,
|
|
67
|
+
language: callee.language,
|
|
68
|
+
snippet: callee.snippet,
|
|
69
|
+
depth: callee.depth,
|
|
70
|
+
})),
|
|
71
|
+
},
|
|
72
|
+
errors: [],
|
|
73
|
+
meta: createResponseMeta({
|
|
74
|
+
query: { ...input },
|
|
75
|
+
resolvedPath: result.resolvedPath,
|
|
76
|
+
truncated: result.truncated,
|
|
77
|
+
counts: {
|
|
78
|
+
returnedCount: fileCount,
|
|
79
|
+
totalMatched: result.totalMatched,
|
|
80
|
+
},
|
|
81
|
+
detection: {
|
|
82
|
+
effectiveLanguage,
|
|
83
|
+
framework: input.framework ?? null,
|
|
84
|
+
},
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function buildValidationErrorResponse(issues) {
|
|
89
|
+
return {
|
|
90
|
+
tool: TOOL_NAME,
|
|
91
|
+
status: "error",
|
|
92
|
+
summary: "Request validation failed.",
|
|
93
|
+
data: emptyData(),
|
|
94
|
+
errors: [
|
|
95
|
+
{
|
|
96
|
+
code: "INVALID_INPUT",
|
|
97
|
+
message: "One or more input fields are invalid.",
|
|
98
|
+
retryable: false,
|
|
99
|
+
suggestion: "Correct the invalid fields and try again.",
|
|
100
|
+
details: { issues },
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
meta: createResponseMeta({ query: {} }),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function buildMappedErrorResponse(input, code, message, details, retryable) {
|
|
107
|
+
const query = { ...input };
|
|
108
|
+
if (code === "FILE_NOT_FOUND") {
|
|
109
|
+
return {
|
|
110
|
+
tool: TOOL_NAME,
|
|
111
|
+
status: "error",
|
|
112
|
+
summary: "Path not found.",
|
|
113
|
+
data: emptyData(input.path, input.symbol),
|
|
114
|
+
errors: [
|
|
115
|
+
{
|
|
116
|
+
code,
|
|
117
|
+
message,
|
|
118
|
+
retryable,
|
|
119
|
+
suggestion: "Provide an existing file path inside the workspace root.",
|
|
120
|
+
details,
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
meta: createResponseMeta({ query }),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (code === "PATH_OUTSIDE_WORKSPACE") {
|
|
127
|
+
return {
|
|
128
|
+
tool: TOOL_NAME,
|
|
129
|
+
status: "error",
|
|
130
|
+
summary: "Path validation failed.",
|
|
131
|
+
data: emptyData(input.path, input.symbol),
|
|
132
|
+
errors: [
|
|
133
|
+
{
|
|
134
|
+
code,
|
|
135
|
+
message,
|
|
136
|
+
retryable,
|
|
137
|
+
suggestion: "Use a file path inside the workspace root.",
|
|
138
|
+
details,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
meta: createResponseMeta({ query }),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (code === "UNSUPPORTED_CAPABILITY") {
|
|
145
|
+
return {
|
|
146
|
+
tool: TOOL_NAME,
|
|
147
|
+
status: "error",
|
|
148
|
+
summary: "Flow trace failed.",
|
|
149
|
+
data: emptyData(input.path, input.symbol),
|
|
150
|
+
errors: [
|
|
151
|
+
{
|
|
152
|
+
code: "BACKEND_EXECUTION_FAILED",
|
|
153
|
+
message,
|
|
154
|
+
retryable,
|
|
155
|
+
suggestion: "Verify the engine supports workspace.trace_flow and retry.",
|
|
156
|
+
details,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
meta: createResponseMeta({ query }),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
tool: TOOL_NAME,
|
|
164
|
+
status: "error",
|
|
165
|
+
summary: "Flow trace failed.",
|
|
166
|
+
data: emptyData(input.path, input.symbol),
|
|
167
|
+
errors: [
|
|
168
|
+
{
|
|
169
|
+
code,
|
|
170
|
+
message,
|
|
171
|
+
retryable,
|
|
172
|
+
details,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
meta: createResponseMeta({ query }),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function buildEngineFailureResponse(input, error) {
|
|
179
|
+
return buildMappedErrorResponse(input, "BACKEND_EXECUTION_FAILED", error instanceof Error ? error.message : String(error), {}, false);
|
|
180
|
+
}
|
|
181
|
+
function emptyData(path = "", symbol = "") {
|
|
182
|
+
return {
|
|
183
|
+
entrypoint: {
|
|
184
|
+
path,
|
|
185
|
+
symbol,
|
|
186
|
+
language: inferLanguageFromPath(path),
|
|
187
|
+
},
|
|
188
|
+
fileCount: 0,
|
|
189
|
+
items: [],
|
|
190
|
+
callees: [],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function buildSummary(symbol, path, calleeCount) {
|
|
194
|
+
if (calleeCount === 0) {
|
|
195
|
+
return `Trace completed for '${symbol}' from '${path}' with no callees found.`;
|
|
196
|
+
}
|
|
197
|
+
if (calleeCount === 1) {
|
|
198
|
+
return `Traced 1 callee for '${symbol}' from '${path}'.`;
|
|
199
|
+
}
|
|
200
|
+
return `Traced ${calleeCount} callees for '${symbol}' from '${path}'.`;
|
|
201
|
+
}
|
|
202
|
+
function resolveEffectiveLanguage(language, framework) {
|
|
203
|
+
if (language) {
|
|
204
|
+
return language;
|
|
205
|
+
}
|
|
206
|
+
if (framework === "react-router") {
|
|
207
|
+
return "typescript";
|
|
208
|
+
}
|
|
209
|
+
if (framework === "spring") {
|
|
210
|
+
return "java";
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
function resolveAnalyzerLanguage(language, framework) {
|
|
215
|
+
const effective = resolveEffectiveLanguage(language, framework);
|
|
216
|
+
if (effective === "java") {
|
|
217
|
+
return "java";
|
|
218
|
+
}
|
|
219
|
+
if (effective === "python") {
|
|
220
|
+
return "python";
|
|
221
|
+
}
|
|
222
|
+
if (effective === "rust") {
|
|
223
|
+
return "rust";
|
|
224
|
+
}
|
|
225
|
+
return "typescript";
|
|
226
|
+
}
|
|
227
|
+
function inferLanguageFromPath(path) {
|
|
228
|
+
const normalized = path.toLowerCase();
|
|
229
|
+
if (normalized.endsWith(".ts") || normalized.endsWith(".tsx")) {
|
|
230
|
+
return "typescript";
|
|
231
|
+
}
|
|
232
|
+
if (normalized.endsWith(".js") || normalized.endsWith(".jsx")) {
|
|
233
|
+
return "javascript";
|
|
234
|
+
}
|
|
235
|
+
if (normalized.endsWith(".java")) {
|
|
236
|
+
return "java";
|
|
237
|
+
}
|
|
238
|
+
if (normalized.endsWith(".py")) {
|
|
239
|
+
return "python";
|
|
240
|
+
}
|
|
241
|
+
if (normalized.endsWith(".rs")) {
|
|
242
|
+
return "rust";
|
|
243
|
+
}
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
@@ -15,6 +15,6 @@ export interface RegisterCodeToolsOptions {
|
|
|
15
15
|
listEndpointsHandler?: (payload: Record<string, unknown>) => Promise<ResponseEnvelope<unknown>>;
|
|
16
16
|
searchTextHandler?: (payload: Record<string, unknown>) => Promise<ResponseEnvelope<unknown>>;
|
|
17
17
|
traceCallersHandler?: (payload: Record<string, unknown>) => Promise<ResponseEnvelope<unknown>>;
|
|
18
|
-
|
|
18
|
+
traceFlowHandler?: (payload: Record<string, unknown>) => Promise<ResponseEnvelope<unknown>>;
|
|
19
19
|
}
|
|
20
20
|
export declare function registerCodeTools(options: RegisterCodeToolsOptions): RegisteredCodeTool[];
|
|
@@ -89,10 +89,10 @@ const toolMetadata = [
|
|
|
89
89
|
},
|
|
90
90
|
},
|
|
91
91
|
{
|
|
92
|
-
name: "code.
|
|
93
|
-
title: "Trace
|
|
94
|
-
description: "Trace
|
|
95
|
-
inputSchema: { ...codeToolSchemas["code.
|
|
92
|
+
name: "code.trace_flow",
|
|
93
|
+
title: "Trace execution flow forward",
|
|
94
|
+
description: "Trace execution flow forward from a starting file and symbol to related workspace files. The starting path must exist inside the workspace.",
|
|
95
|
+
inputSchema: { ...codeToolSchemas["code.trace_flow"] },
|
|
96
96
|
sdkInputSchema: {
|
|
97
97
|
path: z.string().trim().min(1),
|
|
98
98
|
symbol: z.string().trim().min(1),
|
|
@@ -161,14 +161,14 @@ export function registerCodeTools(options) {
|
|
|
161
161
|
},
|
|
162
162
|
};
|
|
163
163
|
}
|
|
164
|
-
if (tool.name === "code.
|
|
164
|
+
if (tool.name === "code.trace_flow") {
|
|
165
165
|
return {
|
|
166
166
|
...tool,
|
|
167
167
|
execute: async (payload) => {
|
|
168
|
-
if (!options.
|
|
169
|
-
throw new Error("Trace
|
|
168
|
+
if (!options.traceFlowHandler) {
|
|
169
|
+
throw new Error("Trace flow migrated handler is scaffolded but not yet wired.");
|
|
170
170
|
}
|
|
171
|
-
return options.
|
|
171
|
+
return options.traceFlowHandler(payload);
|
|
172
172
|
},
|
|
173
173
|
};
|
|
174
174
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navigation-agent/mcp-server",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "MCP server for AI-assisted code navigation — find symbols, trace callers, list endpoints and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"check": "tsc --noEmit"
|
|
23
23
|
},
|
|
24
24
|
"optionalDependencies": {
|
|
25
|
-
"@navigation-agent/mcp-server-linux-x64": "0.1
|
|
26
|
-
"@navigation-agent/mcp-server-linux-arm64": "0.1
|
|
27
|
-
"@navigation-agent/mcp-server-darwin-x64": "0.1
|
|
28
|
-
"@navigation-agent/mcp-server-darwin-arm64": "0.1
|
|
29
|
-
"@navigation-agent/mcp-server-win32-x64": "0.1
|
|
25
|
+
"@navigation-agent/mcp-server-linux-x64": "0.2.1",
|
|
26
|
+
"@navigation-agent/mcp-server-linux-arm64": "0.2.1",
|
|
27
|
+
"@navigation-agent/mcp-server-darwin-x64": "0.2.1",
|
|
28
|
+
"@navigation-agent/mcp-server-darwin-arm64": "0.2.1",
|
|
29
|
+
"@navigation-agent/mcp-server-win32-x64": "0.2.1"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.29.0",
|