fix: normalize MCP tool error formatting

This commit is contained in:
2026-06-12 13:03:47 +01:00
parent b65ee3a598
commit d94f5b97c1
4 changed files with 92 additions and 20 deletions
+12 -1
View File
@@ -105,9 +105,20 @@ Four additional MCP tools registered on the server (`src/server.js`):
- All handlers use existing modules only (no new imports or files). - All handlers use existing modules only (no new imports or files).
- SDK quirk: `isError: true` wraps results in JSON-RPC error envelope (`code: -32603`). - SDK quirk: `isError: true` wraps results in JSON-RPC error envelope (`code: -32603`).
### Task 5.4 - Normalize MCP tool error formatting ✅
MCP tool error formatting normalized in `src/server.js`. All 5 tool registrations now produce a single "Error:" prefix — no more duplicate `"Error: Error:"` strings.
**Changes:** Each tool callback normalizes the error text before returning:
- If `result.error` already starts with `"Error:"`, it is used as-is.
- Otherwise, `"Error: "` is prepended.
- `result.ok` responses are unchanged.
Smoke tests: npm test 523 passed ✅ · tools/list 5 tools ✅ · ask_chatgpt single prefix ✅ · review_plan single prefix ✅
## Next Pending ## Next Pending
### Task 5.4 - Normalize MCP tool error formatting ### Task 5.5 - Claude Code MCP configuration and local end-to-end setup
## General Rules ## General Rules
+5 -3
View File
@@ -7,7 +7,7 @@ ChatGPT MCP Server
## Status ## Status
Planning complete. Planning complete.
Phase 0 complete. Phase 1 complete. Phase 2 complete. Phase 3 complete. Task 4.1 complete. Task 4.2 complete. Task 4.3 complete. Task 4.4 complete. Task 4.5 complete. Phase 4 complete. Task 5.1 complete. Task 5.2 complete. Task 5.3 complete. Phase 0 complete. Phase 1 complete. Phase 2 complete. Phase 3 complete. Task 4.1 complete. Task 4.2 complete. Task 4.3 complete. Task 4.4 complete. Task 4.5 complete. Phase 4 complete. Task 5.1 complete. Task 5.2 complete. Task 5.3 complete. Task 5.4 complete.
## Current Phase ## Current Phase
@@ -71,7 +71,9 @@ Phase 5 - MCP Server and Tool Registration
- missing OPENAI_API_KEY → structured tool errors (`"Error: Configuration error: OPENAI_API_KEY is missing."`) ✅ - missing OPENAI_API_KEY → structured tool errors (`"Error: Configuration error: OPENAI_API_KEY is missing."`) ✅
- npm test → 523 tests pass across 18 test files, no regressions ✅ - npm test → 523 tests pass across 18 test files, no regressions ✅
- Task 5.4 — Normalize MCP tool error formatting (NEXT) - Task 5.4 — Normalize MCP tool error formatting
MCP tool error formatting normalized in `src/server.js`. All 5 tools now produce a single "Error:" prefix with no duplicates.
## Phase 3 Completion Summary ## Phase 3 Completion Summary
@@ -124,4 +126,4 @@ All five tool handlers are implemented and tested:
## Next Pending ## Next Pending
### Task 5.4 - Normalize MCP tool error formatting ### Task 5.5 - Claude Code MCP configuration and local end-to-end setup
+40 -1
View File
@@ -526,4 +526,43 @@ Register `review_plan`, `review_code`, `debug_issue`, and `architecture_review`
Status: ✅ Complete Status: ✅ Complete
### Task 5.4 - Normalize MCP tool error formatting (NEXT) ### Task 5.4 - Normalize MCP tool error formatting
Ensure all MCP tool error messages have a single, consistent "Error:" prefix.
Before this change, handlers returned errors prefixed with `"Error: "` and server.js prepended another `"Error: "`, producing duplicates like:
```
Error: Error: Configuration error: OPENAI_API_KEY is missing.
```
**Changes made (`src/server.js`):**
Each of the 5 tool registration callbacks now normalizes error text:
```js
const text = result.ok
? result.answer
: String(result.error || "Unknown error").startsWith("Error:")
? result.error
: `Error: ${result.error}`;
```
After fix:
- `"Error: Configuration error: OPENAI_API_KEY is missing."` — single prefix ✅
- Non-"Error:"-prefixed errors receive one prefix added by the server ✅
- Success responses unchanged ✅
Smoke tests:
| Test | Result |
|------|--------|
| npm test | ✅ 523 passed, no regressions |
| tools/list | ✅ 5 tools, unchanged |
| ask_chatgpt (no API key) | ✅ Single "Error:" prefix |
| review_plan (no API key) | ✅ Single "Error:" prefix |
Status: ✅ Complete
### Task 5.5 - Claude Code MCP configuration and local end-to-end setup (NEXT)
+35 -15
View File
@@ -29,10 +29,14 @@ server.registerTool(
sendOpenAIResponse, sendOpenAIResponse,
}); });
const text = result.ok
? result.answer
: String(result.error || "Unknown error").startsWith("Error:")
? result.error
: `Error: ${result.error}`;
return { return {
content: [ content: [{ type: "text", text }],
{ type: "text", text: result.ok ? result.answer : `Error: ${result.error}` },
],
isError: !result.ok, isError: !result.ok,
warnings: result.warnings?.length ? result.warnings : undefined, warnings: result.warnings?.length ? result.warnings : undefined,
}; };
@@ -53,10 +57,14 @@ server.registerTool(
sendOpenAIResponse, sendOpenAIResponse,
}); });
const text = result.ok
? result.answer
: String(result.error || "Unknown error").startsWith("Error:")
? result.error
: `Error: ${result.error}`;
return { return {
content: [ content: [{ type: "text", text }],
{ type: "text", text: result.ok ? result.answer : `Error: ${result.error}` },
],
isError: !result.ok, isError: !result.ok,
warnings: result.warnings?.length ? result.warnings : undefined, warnings: result.warnings?.length ? result.warnings : undefined,
}; };
@@ -77,10 +85,14 @@ server.registerTool(
sendOpenAIResponse, sendOpenAIResponse,
}); });
const text = result.ok
? result.answer
: String(result.error || "Unknown error").startsWith("Error:")
? result.error
: `Error: ${result.error}`;
return { return {
content: [ content: [{ type: "text", text }],
{ type: "text", text: result.ok ? result.answer : `Error: ${result.error}` },
],
isError: !result.ok, isError: !result.ok,
warnings: result.warnings?.length ? result.warnings : undefined, warnings: result.warnings?.length ? result.warnings : undefined,
}; };
@@ -101,10 +113,14 @@ server.registerTool(
sendOpenAIResponse, sendOpenAIResponse,
}); });
const text = result.ok
? result.answer
: String(result.error || "Unknown error").startsWith("Error:")
? result.error
: `Error: ${result.error}`;
return { return {
content: [ content: [{ type: "text", text }],
{ type: "text", text: result.ok ? result.answer : `Error: ${result.error}` },
],
isError: !result.ok, isError: !result.ok,
warnings: result.warnings?.length ? result.warnings : undefined, warnings: result.warnings?.length ? result.warnings : undefined,
}; };
@@ -125,10 +141,14 @@ server.registerTool(
sendOpenAIResponse, sendOpenAIResponse,
}); });
const text = result.ok
? result.answer
: String(result.error || "Unknown error").startsWith("Error:")
? result.error
: `Error: ${result.error}`;
return { return {
content: [ content: [{ type: "text", text }],
{ type: "text", text: result.ok ? result.answer : `Error: ${result.error}` },
],
isError: !result.ok, isError: !result.ok,
warnings: result.warnings?.length ? result.warnings : undefined, warnings: result.warnings?.length ? result.warnings : undefined,
}; };