Fix/MCP exposure v2 TODO's - #675
Conversation
Fixes the MCP re-exposure bug by correctly handling tool deduplication, input validation with Ajv, and structured output (including images). Also disables experimental API betas by default to prevent 500 errors on external accounts.
Prevents unnecessary calls to Anthropic's MCP registry when using other API providers.
This prevents 500 errors from Anthropic's API when tool-calling with non-Anthropic accounts or models that don't support certain beta features.
|
Merging was a little messy , if there is any issues i will amend |
Vasanthdev2004
left a comment
There was a problem hiding this comment.
Review: PR #675 — Fix/MCP exposure v2 TODO's
Reviewed on head 2c60b1a. CI green ✅. 5 files, +182/-20.
This PR addresses several MCP server TODOs: tool re-exposure, input validation with Ajv, structured output handling (including images), and auth-needed server exposure. The direction is solid — these are real gaps in the MCP server implementation. However, there are a few issues that need fixing before merge.
🔧 Blockers
1. ValidationResult imported from non-existent export
In src/tools/MCPTool/MCPTool.ts:
import type { PermissionResult, ValidationResult } from '../../types/permissions.js'ValidationResult is not exported from ../../types/permissions.js. It's defined and exported from ../../Tool.js. This is a type error that CI doesn't catch (Bun's test runner doesn't do full type checking), but it will break for anyone running tsc or IDE type checking.
On main, the import is:
import type { PermissionResult } from '../../utils/permissions/PermissionResult.js'which correctly gets PermissionResult via the re-export chain. The PR should either:
- Keep the existing
PermissionResultimport path and addValidationResultfrom../../Tool.jsseparately, or - Use
../../types/permissions.jsforPermissionResult(which works) and importValidationResultfrom../../Tool.js
2. Duplicate CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS env var set
In src/entrypoints/cli.tsx, the same line appears twice:
// Line 44 (already on main):
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS ??= 'true'
// Line 51 (new in this PR — exact duplicate):
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS ??= 'true'The ??= operator makes the second line a no-op (first-set-wins), so this isn't functionally broken, but it's clearly a copy-paste mistake. The comment block above line 51 is also redundant. Remove the duplicate block (lines ~47-51).
3. Unused import: getMcpClientConfig in mcp.tsx
The PR adds getMcpClientConfig to the imports in src/cli/handlers/mcp.tsx but it's never used in that file. Dead import should be removed.
🟡 Non-blocking but important
4. inputSchema.parse() before validateInput — double parsing
The PR runs tool.inputSchema.parse(args ?? {}) and then passes parsedArgs to tool.validateInput(). If parse() throws on invalid input, it's caught by the outer try/catch which returns a generic error message. The MCP protocol distinguishes between client errors (invalid arguments) and server errors — a schema validation failure should ideally return a structured error indicating which fields failed, not a catch-all isError: true response. Consider catching Zod errors separately and returning the validation issues in the content.
5. PR description overclaims scope
The PR body says "Prevented registry prefetching when not in first-party mode" (src/services/mcp/officialRegistry.ts), but that file is not in the actual diff. The description should match the actual changes.
6. Content type mapping for images
The image mapping logic:
if (block.type === 'image' && block.source) {
return { type: 'image', data: block.source.data, mimeType: block.source.media_type }
}This maps the internal source.data / source.media_type format to MCP's data / mimeType format. The mapping looks correct, but only handles the source-nested image format. If any tool returns images in a different internal format, they'll fall through to jsonStringify. Worth adding a console.warn or debug log for unmapped block types so these don't silently degrade.
7. loadReexposedMcpTools loads ALL MCP servers at startup
This function is called unconditionally in startMCPServer, which means every configured MCP server gets connected before the MCP server even starts accepting requests. This is fine for the initial implementation, but could become a startup latency issue with many servers. Not a blocker, just something to be aware of.
✅ What looks good
- Tool re-exposure via
getCombinedTools— clean deduplication logic, MCP tools prioritized over builtins inputJSONSchemafallback inListToolsRequestSchema— handles MCP tools that provide raw JSON Schema instead of Zod- Test coverage for deduplication and auth-needed server exposure — good additions
- Ajv validation in MCPTool — correct approach for validating JSON Schema inputs
- Stale import fix in
mcp.tsx(clearServerTokensFromLocalStorage→clearServerTokensFromSecureStorage) isErrorpropagation inCallToolResult— previously missing, now correctly set
Verdict: Needs changes 🔧
Three blockers: (1) ValidationResult imported from wrong module, (2) duplicate env var set, (3) unused import. All are straightforward fixes.
|
@Vasanthdev2004 review pls as according I will change the files #674 |
Blockers Resolved
Non-blocking Issues Resolved
Testing :
|
|
@kevincodex1 see the suggestions issue section |
|
@Vasanthdev2004 all good |
Vasanthdev2004
left a comment
There was a problem hiding this comment.
Re-review: PR #675 — MCP tool inputSchema validation + re-exposure (head fa7f88f)
CI green ✅. 4 files, +190/-21. Previously requested changes on head 2c60b1a.
Blocker fix check
1. ValidationResult imported from wrong module ✅ Fixed
Now correctly: import { buildTool, type ToolDef, type ValidationResult } from '../../Tool.js' and import type { PermissionResult } from '../../types/permissions.js'.
2. Duplicate CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS env var line ✅ Fixed
Only one occurrence remains in cli.tsx.
3. Unused import getMcpClientConfig in mcp.tsx ✅ Fixed
Removed from imports.
New code review
MCPTool.validateInput — Ajv validation ✅
Good pattern: compiles inputJSONSchema with Ajv, returns {result: false, message, errorCode: 400} on validation failure, {result: false, message, errorCode: 500} on compilation error. Falls through to {result: true} when no inputJSONSchema is set.
mcp.ts — Zod + Ajv validation flow ✅
inputSchema.parse(args) runs first (Zod), then validateInput(parsedArgs) (Ajv). Both paths produce proper error messages — ZodError has a dedicated catch block with per-field error formatting, Ajv errors go through the existing error handler. No silent failures.
mcp.ts — Content mapping ✅
Properly handles string → text block, array → text/image blocks, unknown → JSON stringified. Includes isError flag in result. Much better than the previous jsonStringify(everything) approach.
mcp.ts — getCombinedTools() ✅
Simple deduplication: MCP tools take priority over builtins with same name. Extracted into a testable function.
mcp.ts — inputJSONSchema ?? zodToJsonSchema(tool.inputSchema) ✅
Uses MCP JSON Schema when available, falls back to Zod-to-JSON-Schema conversion for builtins.
Tests — mcp.test.ts ✅
Uses bun:test. Covers getCombinedTools (deduplication) and loadReexposedMcpTools (needs-auth + connected servers).
Verdict: Approve-ready ✅
All 3 original blockers fixed. The validation flow, content mapping, and MCP tool re-exposure are solid. Tests use correct test framework.
|
@gnanam1990 your turn buddy |
|
@MarawanYakout good work! |
gnanam1990
left a comment
There was a problem hiding this comment.
Rechecked current head fa7f88f. This is much cleaner now and the earlier blockers look addressed. I verified the focused MCP entrypoint test locally, the diff is now scoped to the MCP re-exposure/validation path, and this looks good to merge. Nice cleanup here, appreciate you tightening this up.
|
Thank you all guys once more, @kevincodex1 @Vasanthdev2004 @gnanam1990 lets fix the next one ) |
* fix: OAuth tokens secure storage for Windows & Linux * fix(mcp): MCP Tool Re-exposure & Strict Input Validation Fixes the MCP re-exposure bug by correctly handling tool deduplication, input validation with Ajv, and structured output (including images). Also disables experimental API betas by default to prevent 500 errors on external accounts. * fix(mcp): skip official registry prefetch in non-first-party mode Prevents unnecessary calls to Anthropic's MCP registry when using other API providers. * fix(cli): disable experimental API betas by default This prevents 500 errors from Anthropic's API when tool-calling with non-Anthropic accounts or models that don't support certain beta features. * fix: issues raised in the PR review for Twigpine#675
* fix: OAuth tokens secure storage for Windows & Linux * fix(mcp): MCP Tool Re-exposure & Strict Input Validation Fixes the MCP re-exposure bug by correctly handling tool deduplication, input validation with Ajv, and structured output (including images). Also disables experimental API betas by default to prevent 500 errors on external accounts. * fix(mcp): skip official registry prefetch in non-first-party mode Prevents unnecessary calls to Anthropic's MCP registry when using other API providers. * fix(cli): disable experimental API betas by default This prevents 500 errors from Anthropic's API when tool-calling with non-Anthropic accounts or models that don't support certain beta features. * fix: issues raised in the PR review for Twigpine#675
* fix: OAuth tokens secure storage for Windows & Linux * fix(mcp): MCP Tool Re-exposure & Strict Input Validation Fixes the MCP re-exposure bug by correctly handling tool deduplication, input validation with Ajv, and structured output (including images). Also disables experimental API betas by default to prevent 500 errors on external accounts. * fix(mcp): skip official registry prefetch in non-first-party mode Prevents unnecessary calls to Anthropic's MCP registry when using other API providers. * fix(cli): disable experimental API betas by default This prevents 500 errors from Anthropic's API when tool-calling with non-Anthropic accounts or models that don't support certain beta features. * fix: issues raised in the PR review for Twigpine#675

Summary
Testing
Looks good on my side pass all tests
Notes
I identified the core changes from the previous messy branch and applied them to a fresh branch based on main. The total changes are now 180 insertions.