From 167a52ca5da211171548cd82f851c377999488e5 Mon Sep 17 00:00:00 2001 From: wwhsaber Date: Sun, 31 May 2026 21:05:53 +0800 Subject: [PATCH] fix: handle missing/empty task param gracefully in codegraph_context Two changes to address #577: 1. In handleContext, fall back from to so MCP clients that pass instead of still work. 2. In validateString, improve error messages: - Show the actual type/value received instead of generic message - Add hint about passing the parameter directly (not wrapped) - Trim whitespace before checking length - Distinguish between undefined/non-string vs whitespace-only The root cause is that some MCP clients (notably Cursor Agent) may pass the search text under a different parameter name or in a malformed way. The fallback + better diagnostics should catch these edge cases. Fixes #577 --- package-lock.json | 1 - src/mcp/tools.ts | 23 +++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index e418a36e5..9809977a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1460,7 +1460,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/src/mcp/tools.ts b/src/mcp/tools.ts index 2e9c6f816..8bb6e524f 100644 --- a/src/mcp/tools.ts +++ b/src/mcp/tools.ts @@ -873,15 +873,26 @@ export class ToolHandler { name: string, maxLength: number = MAX_INPUT_LENGTH ): string | ToolResult { - if (typeof value !== 'string' || value.length === 0) { - return this.errorResult(`${name} must be a non-empty string`); + // Accept common MCP-client aliases: if `task` is missing but `query` + // was supplied (or vice-versa), the caller already resolves the + // fallback via `args.task ?? args.query`. Here we only validate. + if (typeof value !== 'string') { + const got = value === undefined ? 'undefined' : typeof value; + return this.errorResult( + `${name} must be a non-empty string (got ${got}). ` + + `Make sure to pass the \`${name}\` parameter directly — not wrapped in an object or nested.` + ); } - if (value.length > maxLength) { + const trimmed = value.trim(); + if (trimmed.length === 0) { + return this.errorResult(`${name} must be a non-empty string (received whitespace only)`); + } + if (trimmed.length > maxLength) { return this.errorResult( - `${name} exceeds maximum length of ${maxLength} characters (got ${value.length})` + `${name} exceeds maximum length of ${maxLength} characters (got ${trimmed.length})` ); } - return value; + return trimmed; } /** @@ -1147,7 +1158,7 @@ export class ToolHandler { * Handle codegraph_context */ private async handleContext(args: Record): Promise { - const task = this.validateString(args.task, 'task'); + const task = this.validateString(args.task ?? args.query, 'task'); if (typeof task !== 'string') return task; // Mark session as consulted (enables Grep/Glob/Bash)