Skip to content

Commit 2968a6f

Browse files
committed
Major refactor to lift state management out of InspectorClient (now we have state managers for resources, resource templates, prompts, tools, requestor tasks, messages, stderr logs, and requests which are driven by InspectorClient events and are employed by clients, including through specific hooks, to manage state). All app usage updated to use state managers. Task tab in web app is now implemented properly.
1 parent 64b4b61 commit 2968a6f

80 files changed

Lines changed: 8625 additions & 5978 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cli/__tests__/tools.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ describe("Tool Tests", () => {
378378
"message=test",
379379
]);
380380

381-
// CLI returns exit code 0 but includes isError: true in JSON
381+
// CLI returns exit code 0 but includes isError: true in JSON (server returns error)
382382
expectJsonError(result);
383383
});
384384

cli/src/index.ts

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import type {
1313
StreamableHttpServerConfig,
1414
} from "@modelcontextprotocol/inspector-core/mcp/types.js";
1515
import { InspectorClient } from "@modelcontextprotocol/inspector-core/mcp/index.js";
16+
import {
17+
ManagedToolsState,
18+
ManagedResourcesState,
19+
ManagedResourceTemplatesState,
20+
ManagedPromptsState,
21+
} from "@modelcontextprotocol/inspector-core/mcp/state/index.js";
1622
import { createTransportNode } from "@modelcontextprotocol/inspector-core/mcp/node/index.js";
1723
import type { JsonValue } from "@modelcontextprotocol/inspector-core/mcp/index.js";
1824
import {
@@ -181,55 +187,97 @@ async function callMethod(args: Args): Promise<void> {
181187
transport: createTransportNode,
182188
},
183189
clientIdentity,
184-
autoSyncLists: false, // CLI doesn't need auto-syncing, it calls methods directly
185190
initialLoggingLevel: "debug", // Set debug logging level for CLI
186191
progress: false, // CLI doesn't use progress; avoids SDK injecting progressToken into _meta
187192
sample: false, // CLI doesn't need sampling capability
188193
elicit: false, // CLI doesn't need elicitation capability
189194
});
190195

196+
let managedToolsState: ManagedToolsState | null = null;
197+
let managedResourcesState: ManagedResourcesState | null = null;
198+
let managedResourceTemplatesState: ManagedResourceTemplatesState | null =
199+
null;
200+
let managedPromptsState: ManagedPromptsState | null = null;
201+
191202
try {
192203
await inspectorClient.connect();
193204

194205
let result: McpResponse;
195206

196-
// Tools methods
207+
// Tools methods: use ManagedToolsState for both tools/list and tools/call
208+
if (args.method === "tools/list" || args.method === "tools/call") {
209+
managedToolsState = new ManagedToolsState(inspectorClient);
210+
managedToolsState.setMetadata(args.metadata);
211+
await managedToolsState.refresh();
212+
}
213+
214+
// Resources / resource templates / prompts: use managed state when listing
215+
if (args.method === "resources/list") {
216+
managedResourcesState = new ManagedResourcesState(inspectorClient);
217+
managedResourcesState.setMetadata(args.metadata);
218+
await managedResourcesState.refresh();
219+
} else if (args.method === "resources/templates/list") {
220+
managedResourceTemplatesState = new ManagedResourceTemplatesState(
221+
inspectorClient,
222+
);
223+
managedResourceTemplatesState.setMetadata(args.metadata);
224+
await managedResourceTemplatesState.refresh();
225+
} else if (args.method === "prompts/list") {
226+
managedPromptsState = new ManagedPromptsState(inspectorClient);
227+
managedPromptsState.setMetadata(args.metadata);
228+
await managedPromptsState.refresh();
229+
}
230+
197231
if (args.method === "tools/list") {
198-
result = { tools: await inspectorClient.listAllTools(args.metadata) };
232+
result = { tools: managedToolsState!.getTools() };
199233
} else if (args.method === "tools/call") {
200234
if (!args.toolName) {
201235
throw new Error(
202236
"Tool name is required for tools/call method. Use --tool-name to specify the tool name.",
203237
);
204238
}
205239

206-
const invocation = await inspectorClient.callTool(
207-
args.toolName,
208-
args.toolArg || {},
209-
args.metadata,
210-
args.toolMeta,
211-
);
212-
// Extract the result from the invocation object for CLI compatibility
213-
if (invocation.result !== null) {
214-
// Success case: result is a valid CallToolResult
215-
result = invocation.result;
216-
} else {
217-
// Error case: construct an error response matching CallToolResult structure
240+
const tool = managedToolsState!
241+
.getTools()
242+
.find((t) => t.name === args.toolName);
243+
if (!tool) {
244+
// Same result shape as server error (so CLI output and tests unchanged)
218245
result = {
219246
content: [
220247
{
221248
type: "text" as const,
222-
text: invocation.error || "Tool call failed",
249+
text: `Tool '${args.toolName}' not found.`,
223250
},
224251
],
225252
isError: true,
226253
};
254+
} else {
255+
const invocation = await inspectorClient.callTool(
256+
tool,
257+
args.toolArg || {},
258+
args.metadata,
259+
args.toolMeta,
260+
);
261+
// Extract the result from the invocation object for CLI compatibility
262+
if (invocation.result !== null) {
263+
result = invocation.result;
264+
} else {
265+
result = {
266+
content: [
267+
{
268+
type: "text" as const,
269+
text: invocation.error || "Tool call failed",
270+
},
271+
],
272+
isError: true,
273+
};
274+
}
227275
}
228276
}
229277
// Resources methods
230278
else if (args.method === "resources/list") {
231279
result = {
232-
resources: await inspectorClient.listAllResources(args.metadata),
280+
resources: managedResourcesState!.getResources(),
233281
};
234282
} else if (args.method === "resources/read") {
235283
if (!args.uri) {
@@ -246,14 +294,13 @@ async function callMethod(args: Args): Promise<void> {
246294
result = invocation.result;
247295
} else if (args.method === "resources/templates/list") {
248296
result = {
249-
resourceTemplates: await inspectorClient.listAllResourceTemplates(
250-
args.metadata,
251-
),
297+
resourceTemplates:
298+
managedResourceTemplatesState!.getResourceTemplates(),
252299
};
253300
}
254301
// Prompts methods
255302
else if (args.method === "prompts/list") {
256-
result = { prompts: await inspectorClient.listAllPrompts(args.metadata) };
303+
result = { prompts: managedPromptsState!.getPrompts() };
257304
} else if (args.method === "prompts/get") {
258305
if (!args.promptName) {
259306
throw new Error(
@@ -287,6 +334,10 @@ async function callMethod(args: Args): Promise<void> {
287334

288335
await awaitableLog(JSON.stringify(result, null, 2));
289336
} finally {
337+
managedToolsState?.destroy();
338+
managedResourcesState?.destroy();
339+
managedResourceTemplatesState?.destroy();
340+
managedPromptsState?.destroy();
290341
await inspectorClient.disconnect();
291342
}
292343
}

0 commit comments

Comments
 (0)