From 0e319af12ce522895eed6654d4a45675a38a79e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:15:19 +0000 Subject: [PATCH 1/6] Initial plan From 95f6ade51dce1cee79e1e7f6dc9c2b314af3a176 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:17:52 +0000 Subject: [PATCH 2/6] Improve type safety in test utilities: replace 'any' types with proper interfaces Co-authored-by: maxgolov <34072974+maxgolov@users.noreply.github.com> --- package-lock.json | 8 +++++ test/test-utils.ts | 78 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56fb93a..bbc6c80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -880,6 +880,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -993,6 +994,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.5.0.tgz", "integrity": "sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -3051,6 +3053,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3709,6 +3712,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -4018,6 +4022,7 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -4657,6 +4662,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -5370,6 +5376,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -5705,6 +5712,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/test/test-utils.ts b/test/test-utils.ts index a76b4a0..47c70c3 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -1,5 +1,42 @@ import { spawn, ChildProcess } from "child_process"; +/** + * A single MCP tool description returned by the tools/list method. + * This is a minimal structural type to avoid using `any` while allowing + * the response to include additional properties. + */ +export interface McpToolDescription { + name: string; + description?: string; + // Allow additional properties without losing type safety. + [key: string]: unknown; +} + +/** + * JSON-RPC 2.0 response for the tools/list method, + * when returned as a standard JSON HTTP response. + */ +export interface ListMcpToolsResponse { + jsonrpc: "2.0"; + id: number | string | null; + result?: { + tools?: McpToolDescription[]; + [key: string]: unknown; + }; + error?: { + code: number; + message: string; + data?: unknown; + }; +} + +/** + * Response shape when the tools/list call is delivered via + * Server-Sent Events and parsed by `parseSSEResponse`. + * Kept as `unknown` to reflect that it may differ from the JSON response. + */ +export type ListMcpToolsSseResponse = unknown; + /** * Wait for server to be ready by polling health endpoint */ @@ -41,7 +78,9 @@ export async function isServerRunning(port: number): Promise { /** * Parse SSE (Server-Sent Events) response */ -export function parseSSEResponse(sseText: string): any { +export type SSEResponseData = Record; + +export function parseSSEResponse(sseText: string): SSEResponseData { const lines = sseText.trim().split("\n"); for (const line of lines) { if (line.startsWith("data: ")) { @@ -158,15 +197,40 @@ export async function initializeMCPSession( return sessionId; } +/** + * JSON-RPC response types for MCP tool calls + */ +interface McpToolError { + code: number; + message: string; + data?: unknown; +} + +interface McpToolSuccessResult { + jsonrpc: "2.0"; + id: number; + result: unknown; +} + +interface McpToolErrorResult { + jsonrpc: "2.0"; + id: number | null; + error: McpToolError; +} + +type McpToolResponse = McpToolSuccessResult | McpToolErrorResult; + /** * Call MCP tool */ +let nextJsonRpcId = 1; + export async function callMCPTool( baseUrl: string, sessionId: string, toolName: string, - args: any -): Promise { + args: unknown +): Promise { const response = await fetch(baseUrl, { method: "POST", headers: { @@ -181,7 +245,7 @@ export async function callMCPTool( name: toolName, arguments: args, }, - id: Math.floor(Math.random() * 10000), + id: nextJsonRpcId++, }), }); @@ -195,7 +259,7 @@ export async function callMCPTool( const text = await response.text(); return parseSSEResponse(text); } else { - return response.json(); + return response.json() as Promise; } } @@ -205,7 +269,7 @@ export async function callMCPTool( export async function listMCPTools( baseUrl: string, sessionId: string -): Promise { +): Promise { const response = await fetch(baseUrl, { method: "POST", headers: { @@ -230,6 +294,6 @@ export async function listMCPTools( const text = await response.text(); return parseSSEResponse(text); } else { - return response.json(); + return response.json() as Promise; } } From 97775ce197727f31f38e343070b0e0fc737b40f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:18:45 +0000 Subject: [PATCH 3/6] Address code review feedback: improve return type precision and fix type assertions Co-authored-by: maxgolov <34072974+maxgolov@users.noreply.github.com> --- test/test-utils.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test-utils.ts b/test/test-utils.ts index 47c70c3..50acb18 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -230,7 +230,7 @@ export async function callMCPTool( sessionId: string, toolName: string, args: unknown -): Promise { +): Promise { const response = await fetch(baseUrl, { method: "POST", headers: { @@ -259,7 +259,8 @@ export async function callMCPTool( const text = await response.text(); return parseSSEResponse(text); } else { - return response.json() as Promise; + const jsonResponse = await response.json(); + return jsonResponse as McpToolResponse; } } @@ -294,6 +295,7 @@ export async function listMCPTools( const text = await response.text(); return parseSSEResponse(text); } else { - return response.json() as Promise; + const jsonResponse = await response.json(); + return jsonResponse as ListMcpToolsResponse; } } From ba1f07484c09e1efdb9f103604db2f90da630d97 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:19:39 +0000 Subject: [PATCH 4/6] Further improve type safety: add resetJsonRpcId function and fix SSE response type Co-authored-by: maxgolov <34072974+maxgolov@users.noreply.github.com> --- test/test-utils.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/test-utils.ts b/test/test-utils.ts index 50acb18..23b86f6 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -33,9 +33,8 @@ export interface ListMcpToolsResponse { /** * Response shape when the tools/list call is delivered via * Server-Sent Events and parsed by `parseSSEResponse`. - * Kept as `unknown` to reflect that it may differ from the JSON response. */ -export type ListMcpToolsSseResponse = unknown; +export type ListMcpToolsSseResponse = SSEResponseData; /** * Wait for server to be ready by polling health endpoint @@ -221,10 +220,20 @@ interface McpToolErrorResult { type McpToolResponse = McpToolSuccessResult | McpToolErrorResult; /** - * Call MCP tool + * Counter for generating sequential JSON-RPC IDs for deterministic testing */ let nextJsonRpcId = 1; +/** + * Reset the JSON-RPC ID counter. Call this in test setup/teardown to ensure test isolation. + */ +export function resetJsonRpcId(): void { + nextJsonRpcId = 1; +} + +/** + * Call MCP tool + */ export async function callMCPTool( baseUrl: string, sessionId: string, From 6497a51f6c738382dcf43cedce5891c811d10a6a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:20:26 +0000 Subject: [PATCH 5/6] Fix McpToolSuccessResult id field type to match JSON-RPC 2.0 spec Co-authored-by: maxgolov <34072974+maxgolov@users.noreply.github.com> --- test/test-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-utils.ts b/test/test-utils.ts index 23b86f6..12c26ff 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -207,7 +207,7 @@ interface McpToolError { interface McpToolSuccessResult { jsonrpc: "2.0"; - id: number; + id: number | string | null; result: unknown; } From 4ef7ff8de6e93fe436e7e5f9495f823b54a4240b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:21:05 +0000 Subject: [PATCH 6/6] Fix McpToolErrorResult id field type to be consistent with JSON-RPC 2.0 spec Co-authored-by: maxgolov <34072974+maxgolov@users.noreply.github.com> --- test/test-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-utils.ts b/test/test-utils.ts index 12c26ff..ebed907 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -213,7 +213,7 @@ interface McpToolSuccessResult { interface McpToolErrorResult { jsonrpc: "2.0"; - id: number | null; + id: number | string | null; error: McpToolError; }