Skip to content

Fix/MCP exposure v2 TODO's - #675

Merged
kevincodex1 merged 6 commits into
Twigpine:mainfrom
MarawanYakout:fix/mcp-exposure-v2
Apr 15, 2026
Merged

kevincodex1 merged 6 commits into
Twigpine:mainfrom
MarawanYakout:fix/mcp-exposure-v2

Conversation

@MarawanYakout

@MarawanYakout MarawanYakout commented Apr 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • src/entrypoints/mcp.ts: Implemented tool re-exposure, input validation, and structured output handling (including images).
  • src/entrypoints/mcp.test.ts: Added new tests for tool deduplication and auth-needed server exposure.
  • src/tools/MCPTool/MCPTool.ts: Integrated Ajv for strict JSON schema validation of MCP tool inputs.
  • src/services/mcp/officialRegistry.ts: Prevented registry prefetching when not in first-party mode.
  • src/entrypoints/cli.tsx: Disabled experimental API betas by default to prevent 500 errors.

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.

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.
@MarawanYakout

Copy link
Copy Markdown
Contributor Author

Merging was a little messy , if there is any issues i will amend

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 PermissionResult import path and add ValidationResult from ../../Tool.js separately, or
  • Use ../../types/permissions.js for PermissionResult (which works) and import ValidationResult from ../../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
  • inputJSONSchema fallback in ListToolsRequestSchema — 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)
  • isError propagation in CallToolResult — 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.

@FluxLuFFy

Copy link
Copy Markdown
Contributor

@Vasanthdev2004 review pls as according I will change the files #674

@MarawanYakout

Copy link
Copy Markdown
Contributor Author

Blockers Resolved

  1. ValidationResult Import Fixed

    • File: src/tools/MCPTool/MCPTool.ts
    • Action: Removed ValidationResult from the ../../types/permissions.js import and properly imported it from ../../Tool.js where it is actually defined and exported. This resolves the type error that would break IDE and tsc checking.
  2. Duplicate Environment Variable Set Removed

    • File: src/entrypoints/cli.tsx
    • Action: Removed the exact duplicate assignment of process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS ??= 'true' (and its accompanying comment block) around lines 47-51.
  3. Unused Import Removed

    • File: src/cli/handlers/mcp.tsx
    • Action: Removed the unused getMcpClientConfig import from ../../services/mcp/auth.js to clear up dead code.

Non-blocking Issues Resolved

  1. Double Parsing & Structured ZodErrors

    • File: src/entrypoints/mcp.ts
    • Action: Updated the catch block within the CallToolRequestSchema handler. It now explicitly catches ZodError instances and maps them into structured error text detailing which fields failed validation. This prevents validation errors from falling back to a generic error message, accurately reflecting schema validation failures.
  2. PR Description Scope

    • Action: The PR description should be updated to accurately reflect the changes, specifically noting the inclusion of the registry prefetching fix (src/services/mcp/officialRegistry.ts).
  3. Content Type Mapping Warnings for Images

    • File: src/entrypoints/mcp.ts
    • Action: Added a console.warn statement inside the else block for unmapped content types in the tool output mapping. If a tool returns a non-text and non-standard-image block type, it will now log a warning so these unmapped types don't degrade silently when falling back to jsonStringify.

Testing :

  • Tests: bun test src/entrypoints/mcp.test.ts completed successfully.
  • Build: All TypeScript changes resolve the localized issues mentioned without breaking the application logic.

@Vasanthdev2004

@FluxLuFFy

FluxLuFFy commented Apr 14, 2026 •

Copy link
Copy Markdown
Contributor

@kevincodex1 see the suggestions issue section

@MarawanYakout

Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004 all good

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@MarawanYakout

Copy link
Copy Markdown
Contributor Author

@gnanam1990 your turn buddy

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

@MarawanYakout good work!

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@MarawanYakout

Copy link
Copy Markdown
Contributor Author

Thank you all guys once more, @kevincodex1 @Vasanthdev2004 @gnanam1990 lets fix the next one )

@MarawanYakout

Copy link
Copy Markdown
Contributor Author

@auriti @anandh8x

@kevincodex1
kevincodex1 merged commit 77083d7 into Twigpine:main Apr 15, 2026
1 check passed
@MarawanYakout

Copy link
Copy Markdown
Contributor Author

C1ph3r404 pushed a commit to C1ph3r404/openclaude that referenced this pull request Apr 29, 2026
* 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
The-FOOL-00 pushed a commit to The-FOOL-00/openclaude that referenced this pull request May 24, 2026
* 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
discopops pushed a commit to discopops/openclaude that referenced this pull request May 28, 2026
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants