From 3f079aa987051cc65c9db06d74227f8e9a9d61da Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 24 Apr 2026 05:42:55 +0700 Subject: [PATCH] chore(lint): no-explicit-any in mcp-server.test --- .../src/server/agent/mcp-server.test.ts | 200 ++++++++++++------ 1 file changed, 138 insertions(+), 62 deletions(-) diff --git a/packages/server/src/server/agent/mcp-server.test.ts b/packages/server/src/server/agent/mcp-server.test.ts index 2ab984283..234299571 100644 --- a/packages/server/src/server/agent/mcp-server.test.ts +++ b/packages/server/src/server/agent/mcp-server.test.ts @@ -13,6 +13,9 @@ import type { ProviderDefinition } from "./provider-registry.js"; import { AgentListItemPayloadSchema, AgentSnapshotPayloadSchema } from "../../shared/messages.js"; import type { PersistedProjectRecord, PersistedWorkspaceRecord } from "../workspace-registry.js"; import type { CreateScheduleInput, StoredSchedule } from "../schedule/types.js"; +import type { ScheduleService } from "../schedule/service.js"; +import type { AgentProvider } from "./agent-sdk-types.js"; +import type { WorkspaceGitService } from "../workspace-git-service.js"; import { createPaseoWorktree as createPaseoWorktreeService, type CreatePaseoWorktreeFn, @@ -21,17 +24,72 @@ import { createWorktreeCoreDeps } from "../worktree-core.js"; import { WorkspaceGitServiceImpl } from "../workspace-git-service.js"; import type { GitHubService } from "../../services/github-service.js"; +interface LooseSafeParseResult { + success: boolean; + data: unknown; + error: { + issues: Array<{ path: Array; message: string; code: string }>; + }; +} + +interface LooseInputSchema { + safeParseAsync(input: unknown): Promise; +} + +interface LooseStructuredContent { + [key: string]: unknown; +} + +interface RegisteredMcpTool { + inputSchema: LooseInputSchema; + callback: (input: unknown) => Promise<{ + structuredContent: LooseStructuredContent; + content?: Array<{ type: string; text?: string }>; + }>; +} + +interface McpServerInternals { + _registeredTools: Record; +} + +function lookupTool( + server: Awaited>, + name: string, +): RegisteredMcpTool | undefined { + return (server as unknown as McpServerInternals)._registeredTools[name]; +} + +function registeredTool( + server: Awaited>, + name: string, +): RegisteredMcpTool { + const tool = lookupTool(server, name); + if (!tool) { + throw new Error(`MCP tool not registered: ${name}`); + } + return tool; +} + +function agentsOf(response: { + structuredContent: LooseStructuredContent; +}): Array> { + return response.structuredContent.agents as Array>; +} + +type AgentManagerSpies = ReturnType; +type AgentStorageSpies = ReturnType; + interface TestDeps { agentManager: AgentManager; agentStorage: AgentStorage; spies: { - agentManager: Record; - agentStorage: Record; + agentManager: AgentManagerSpies; + agentStorage: AgentStorageSpies; }; } -function createTestDeps(): TestDeps { - const agentManagerSpies = { +function buildAgentManagerSpies() { + return { createAgent: vi.fn(), waitForAgentEvent: vi.fn(), recordUserMessage: vi.fn(), @@ -55,8 +113,10 @@ function createTestDeps(): TestDeps { getPendingPermissions: vi.fn(), getRegisteredProviderIds: vi.fn().mockReturnValue(["claude"]), }; +} - const agentStorageSpies = { +function buildAgentStorageSpies() { + return { get: vi.fn().mockResolvedValue(null), setTitle: vi.fn().mockResolvedValue(undefined), upsert: vi.fn().mockResolvedValue(undefined), @@ -64,6 +124,11 @@ function createTestDeps(): TestDeps { list: vi.fn().mockResolvedValue([]), remove: vi.fn(), }; +} + +function createTestDeps(): TestDeps { + const agentManagerSpies = buildAgentManagerSpies(); + const agentStorageSpies = buildAgentStorageSpies(); return { agentManager: agentManagerSpies as unknown as AgentManager, @@ -252,7 +317,7 @@ describe("create_agent MCP tool", () => { it("requires a concise title no longer than 60 characters", async () => { const { agentManager, agentStorage } = createTestDeps(); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); expect(tool).toBeDefined(); const missingTitle = await tool.inputSchema.safeParseAsync({ @@ -287,7 +352,7 @@ describe("create_agent MCP tool", () => { it("requires initialPrompt", async () => { const { agentManager, agentStorage } = createTestDeps(); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); const parsed = await tool.inputSchema.safeParseAsync({ cwd: existingCwd, mode: "default", @@ -296,14 +361,16 @@ describe("create_agent MCP tool", () => { }); expect(parsed.success).toBe(false); expect( - parsed.error.issues.some((issue: { path: string[] }) => issue.path[0] === "initialPrompt"), + parsed.error.issues.some( + (issue: { path: Array }) => issue.path[0] === "initialPrompt", + ), ).toBe(true); }); it("requires provider as provider/model and rejects the old model field", async () => { const { agentManager, agentStorage } = createTestDeps(); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); const missingProvider = await tool.inputSchema.safeParseAsync({ cwd: existingCwd, @@ -314,7 +381,7 @@ describe("create_agent MCP tool", () => { expect(missingProvider.success).toBe(false); expect( missingProvider.error.issues.some( - (issue: { path: string[] }) => issue.path[0] === "provider", + (issue: { path: Array }) => issue.path[0] === "provider", ), ).toBe(true); @@ -360,7 +427,7 @@ describe("create_agent MCP tool", () => { it("accepts optional worktree intent fields in create_agent input validation", async () => { const { agentManager, agentStorage } = createTestDeps(); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); const parsed = await tool.inputSchema.safeParseAsync({ cwd: existingCwd, @@ -379,7 +446,7 @@ describe("create_agent MCP tool", () => { it("accepts optional worktree intent fields in create_worktree input validation", async () => { const { agentManager, agentStorage } = createTestDeps(); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_worktree"]; + const tool = registeredTool(server, "create_worktree"); const parsed = await tool.inputSchema.safeParseAsync({ cwd: existingCwd, @@ -394,7 +461,7 @@ describe("create_agent MCP tool", () => { it("rejects create_worktree without a branch name or checkout intent", async () => { const { agentManager, agentStorage } = createTestDeps(); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_worktree"]; + const tool = registeredTool(server, "create_worktree"); await expect(tool.callback({})).rejects.toThrow( "create_worktree requires branchName, refName, or githubPrNumber", @@ -407,7 +474,7 @@ describe("create_agent MCP tool", () => { new Error("Working directory does not exist: /path/that/does/not/exist"), ); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); await expect( tool.callback({ @@ -431,7 +498,7 @@ describe("create_agent MCP tool", () => { } as ManagedAgent); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); await tool.callback({ cwd: existingCwd, title: " Fix auth bug ", @@ -461,7 +528,7 @@ describe("create_agent MCP tool", () => { } as ManagedAgent); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); await tool.callback({ cwd: existingCwd, title: " Fix auth ", @@ -490,7 +557,7 @@ describe("create_agent MCP tool", () => { } as ManagedAgent); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); await tool.callback({ cwd: existingCwd, title: "Config test", @@ -552,7 +619,7 @@ describe("create_agent MCP tool", () => { }), logger, }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); await tool.callback({ cwd: repoDir, title: "Worktree agent", @@ -603,10 +670,13 @@ describe("create_agent MCP tool", () => { agentStorage, paseoHome, createPaseoWorktree: createPaseoWorktreeForMcpTest({ paseoHome, broadcasts }), - workspaceGitService: workspaceGitService as any, + workspaceGitService: workspaceGitService as unknown as Pick< + WorkspaceGitService, + "getSnapshot" | "listWorktrees" + >, logger, }); - const tool = (server as any)._registeredTools["create_worktree"]; + const tool = registeredTool(server, "create_worktree"); const response = await tool.callback({ cwd: repoDir, branchName: "tool-worktree", @@ -660,15 +730,18 @@ describe("create_agent MCP tool", () => { agentStorage, paseoHome, createPaseoWorktree: createPaseoWorktreeForMcpTest({ paseoHome, broadcasts: [] }), - workspaceGitService: workspaceGitService as any, + workspaceGitService: workspaceGitService as unknown as Pick< + WorkspaceGitService, + "getSnapshot" | "listWorktrees" + >, archiveWorkspaceRecord, emitWorkspaceUpdatesForCwds, emitSessionMessage, github: createGitHubServiceStub(), logger, }); - const createTool = (server as any)._registeredTools["create_worktree"]; - const archiveTool = (server as any)._registeredTools["archive_worktree"]; + const createTool = registeredTool(server, "create_worktree"); + const archiveTool = registeredTool(server, "archive_worktree"); const created = await createTool.callback({ cwd: repoDir, branchName: "archive-tool-worktree", @@ -709,10 +782,13 @@ describe("create_agent MCP tool", () => { const server = await createAgentMcpServer({ agentManager, agentStorage, - workspaceGitService: workspaceGitService as any, + workspaceGitService: workspaceGitService as unknown as Pick< + WorkspaceGitService, + "getSnapshot" | "listWorktrees" + >, logger, }); - const tool = (server as any)._registeredTools["list_worktrees"]; + const tool = registeredTool(server, "list_worktrees"); const response = await tool.callback({ cwd: "/tmp/repo" }); @@ -731,7 +807,7 @@ describe("create_agent MCP tool", () => { it("accepts custom provider IDs in create_agent input validation", async () => { const { agentManager, agentStorage } = createTestDeps(); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); const parsed = await tool.inputSchema.safeParseAsync({ cwd: existingCwd, @@ -775,7 +851,7 @@ describe("create_agent MCP tool", () => { logger, }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); await tool.callback({ cwd: "subdir", title: "Child", @@ -814,7 +890,7 @@ describe("create_agent MCP tool", () => { agentStorage, logger, }); - const tool = (server as any)._registeredTools["create_agent"]; + const tool = registeredTool(server, "create_agent"); await tool.callback({ cwd: existingCwd, title: "Injected config test", @@ -843,10 +919,10 @@ describe("create_schedule MCP tool", () => { const server = await createAgentMcpServer({ agentManager, agentStorage, - scheduleService: { create } as any, + scheduleService: { create } as unknown as ScheduleService, logger, }); - const tool = (server as any)._registeredTools["create_schedule"]; + const tool = registeredTool(server, "create_schedule"); const response = await tool.callback({ prompt: "say hello", @@ -881,10 +957,10 @@ describe("create_schedule MCP tool", () => { const server = await createAgentMcpServer({ agentManager, agentStorage, - scheduleService: { create } as any, + scheduleService: { create } as unknown as ScheduleService, logger, }); - const tool = (server as any)._registeredTools["create_schedule"]; + const tool = registeredTool(server, "create_schedule"); await tool.callback({ prompt: "say hello", @@ -951,7 +1027,7 @@ describe("provider listing MCP tool", () => { providerRegistry, logger, }); - const tool = (server as any)._registeredTools["list_providers"]; + const tool = registeredTool(server, "list_providers"); const response = await tool.callback({}); expect(response.structuredContent).toEqual({ @@ -985,7 +1061,7 @@ describe("speak MCP tool", () => { resolveSpeakHandler: () => speak, logger, }); - const tool = (server as any)._registeredTools["speak"]; + const tool = registeredTool(server, "speak"); expect(tool).toBeDefined(); await tool.callback({ text: "Hello from voice agent." }); @@ -1007,7 +1083,7 @@ describe("speak MCP tool", () => { resolveSpeakHandler: () => null, logger, }); - const tool = (server as any)._registeredTools["speak"]; + const tool = registeredTool(server, "speak"); await expect(tool.callback({ text: "Hello." })).rejects.toThrow( "No speak handler registered for caller agent", ); @@ -1021,7 +1097,7 @@ describe("speak MCP tool", () => { callerAgentId: "agent-no-voice", logger, }); - const tool = (server as any)._registeredTools["speak"]; + const tool = lookupTool(server, "speak"); expect(tool).toBeUndefined(); }); }); @@ -1043,9 +1119,9 @@ describe("agent snapshot MCP serialization", () => { ]); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["list_agents"]; + const tool = registeredTool(server, "list_agents"); const response = await tool.callback({}); - const structured = response.structuredContent; + const structured = response.structuredContent as { agents: Array> }; expect(structured).toEqual({ agents: [ @@ -1093,9 +1169,9 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, }); - const tool = (server as any)._registeredTools["get_agent_status"]; + const tool = registeredTool(server, "get_agent_status"); const response = await tool.callback({ agentId: "archived-agent" }); expect(response.structuredContent).toEqual({ @@ -1151,9 +1227,9 @@ describe("agent snapshot MCP serialization", () => { ); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["get_agent_status"]; + const tool = registeredTool(server, "get_agent_status"); const response = await tool.callback({ agentId: "full-detail-agent" }); - const snapshot = response.structuredContent.snapshot; + const snapshot = response.structuredContent.snapshot as Record; const parsed = AgentSnapshotPayloadSchema.safeParse(snapshot); if (!parsed.success) { @@ -1224,9 +1300,9 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, }); - const tool = (server as any)._registeredTools["get_agent_status"]; + const tool = registeredTool(server, "get_agent_status"); await expect(tool.callback({ agentId: "internal-agent" })).rejects.toThrow( "Agent internal-agent not found", @@ -1268,13 +1344,13 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, callerAgentId: "caller-agent", }); - const tool = (server as any)._registeredTools["list_agents"]; + const tool = registeredTool(server, "list_agents"); const response = await tool.callback({}); - const agentIds = response.structuredContent.agents.map((agent: { id: string }) => agent.id); + const agentIds = agentsOf(response).map((agent) => agent.id); expect(agentIds).toHaveLength(3); expect(new Set(agentIds)).toEqual(new Set(["in-cwd", "in-child-cwd", "stored-in-cwd"])); }); @@ -1317,9 +1393,9 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, }); - const tool = (server as any)._registeredTools["list_agents"]; + const tool = registeredTool(server, "list_agents"); const response = await tool.callback({ cwd: "/tmp/target", includeArchived: true, @@ -1328,7 +1404,7 @@ describe("agent snapshot MCP serialization", () => { limit: 3, }); - expect(response.structuredContent.agents.map((agent: { id: string }) => agent.id)).toEqual([ + expect(agentsOf(response).map((agent) => agent.id)).toEqual([ "running-target", "old-running-target", "recent-archived", @@ -1358,11 +1434,11 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, }); - const tool = (server as any)._registeredTools["list_agents"]; + const tool = registeredTool(server, "list_agents"); const response = await tool.callback({ includeArchived: true }); - const agentIds = response.structuredContent.agents.map((agent: { id: string }) => agent.id); + const agentIds = agentsOf(response).map((agent) => agent.id); expect(agentIds).toHaveLength(50); expect(agentIds).toEqual( @@ -1401,11 +1477,11 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, }); - const tool = (server as any)._registeredTools["list_agents"]; + const tool = registeredTool(server, "list_agents"); const response = await tool.callback({ cwd: "/tmp/repo", includeArchived: true }); - const item = response.structuredContent.agents[0]; + const item = agentsOf(response)[0]; expect(item).toEqual({ id: "stored-archived-compact", @@ -1476,10 +1552,10 @@ describe("agent snapshot MCP serialization", () => { ]); const server = await createAgentMcpServer({ agentManager, agentStorage, logger }); - const tool = (server as any)._registeredTools["list_agents"]; + const tool = registeredTool(server, "list_agents"); const response = await tool.callback({}); - expect(response.structuredContent.agents.map((agent: { id: string }) => agent.id)).toEqual([ + expect(agentsOf(response).map((agent) => agent.id)).toEqual([ "idle-attention-oldest", "running-older", "initializing-middle", @@ -1509,9 +1585,9 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, }); - const tool = (server as any)._registeredTools["list_agents"]; + const tool = registeredTool(server, "list_agents"); const response = await tool.callback({ includeArchived: true }); const parsed = z.array(AgentListItemPayloadSchema).safeParse(response.structuredContent.agents); @@ -1549,9 +1625,9 @@ describe("agent snapshot MCP serialization", () => { logger, providerRegistry: { claude: createProviderDefinition({}), - } as any, + } as unknown as Record, }); - const tool = (server as any)._registeredTools["get_agent_activity"]; + const tool = registeredTool(server, "get_agent_activity"); const response = await tool.callback({ agentId: "archived-activity-agent" }); expect(response.structuredContent).toEqual(