Skip to content

MCP exposure & input validation TODO's Completion#349

Closed
MarawanYakout wants to merge 40 commits intoGitlawb:mainfrom
MarawanYakout:mcpExposure-InputValidation
Closed

MCP exposure & input validation TODO's Completion#349
MarawanYakout wants to merge 40 commits intoGitlawb:mainfrom
MarawanYakout:mcpExposure-InputValidation

Conversation

@MarawanYakout
Copy link
Copy Markdown
Contributor

@MarawanYakout MarawanYakout commented Apr 4, 2026

Summary

Tool Re-exposure: src/entrypoints/mcp.ts has TODOs to re-expose any connected MCP tools back through the server, enabling "Inception-style" tool chaining

what changed & why it changed:

  1. Import and Initialization (File: src/entrypoints/mcp.ts)

    • Action: Import getMcpToolsCommandsAndResources. Add arrays for mcpClients and mcpTools.
    • Why: We need to store the state of connected MCP servers and their tools.
  2. Load Connections (File: src/entrypoints/mcp.ts)

    • Action: Await getMcpToolsCommandsAndResources inside startMCPServer, pushing each client and its tools to the arrays.
    • Why: Establishes connections so tools can be queried and executed.
  3. Re-expose Tools (File: src/entrypoints/mcp.ts)

    • Action: In ListToolsRequestSchema, combine getTools(...) with mcpTools.
    • Why: This fulfills the TODO to re-expose connected MCP tools to the caller.
  4. Execute Tools (File: src/entrypoints/mcp.ts)

    • Action: In CallToolRequestSchema, combine getTools(...) with mcpTools for findToolByName. Pass mcpClients into toolUseContext.options.mcpClients.
    • Why: Our internal tool abstraction for MCP tools relies on finding the active connection in toolUseContext.options.mcpClients to execute the remote call.

Impact

  • user-facing impact:
  • developer/maintainer impact:

Testing

Testing Strategy

  • Security scan: Run npx ecc-agentshield scan .
  • Manual check or unit test of claude mcp output if possible.

Risks & Mitigations

  • Risk: Connecting to slow MCP servers delays the claude mcp startup.

    • Mitigation: getMcpToolsCommandsAndResources runs in parallel with timeouts, so it will bound the startup delay.
  • Risk: Name collisions between native tools and MCP tools.

    • Mitigation: Our MCP tool wrapper automatically prefixes or handles tool names appropriately if conflicts exist, but findToolByName will return the first match.
  • bun run build

  • bun run smoke

  • [ X ] focused tests:

Success Criteria

  • claude mcp loads MCP configurations.
  • ListToolsRequestSchema returns native + MCP tools.
  • CallToolRequestSchema can successfully route calls to the connected MCP tools.

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

solved merge conflicts

kevincodex1
kevincodex1 previously approved these changes Apr 4, 2026
Copy link
Copy Markdown
Contributor

@kevincodex1 kevincodex1 left a comment

Choose a reason for hiding this comment

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

looks great

anandh8x and others added 19 commits April 4, 2026 23:04
* Remove internal-only tooling without changing external runtime contracts

This trims the lowest-risk internal-only surfaces first: deleted internal
modules are replaced by build-time no-op stubs, the bundled stuck skill is
removed, and the insights S3 upload path now stays local-only. The privacy
verifier is expanded and the remaining bundled internal Slack/Artifactory
strings are neutralized without broad repo-wide renames.

Constraint: Keep the first PR deletion-heavy and avoid mass rewrites of USER_TYPE, tengu, or claude_code identifiers
Rejected: One-shot DMCA cleanup branch | too much semantic risk for a first PR
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat full-repo typecheck as a baseline issue on this upstream snapshot; do not claim this commit introduced the existing non-Phase-A errors without isolating them first
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Not-tested: Full repo typecheck (currently fails on widespread pre-existing upstream errors outside this change set)

* Keep minimal source shims so CI can import Phase A cleanup paths

The first PR removed internal-only source files entirely, but CI provider
and context tests import those modules directly from source rather than
through the build-time no-telemetry stubs. This restores tiny no-op source
shims so tests and local source imports resolve while preserving the same
external runtime behavior.

Constraint: GitHub Actions runs source-level tests in addition to bundled build/privacy checks
Rejected: Revert the entire deletion pass | unnecessary once the import contract is satisfied by small shims
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: For later cleanup phases, treat build-time stubs and source-test imports as separate compatibility surfaces
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (still noisy on this upstream snapshot)

---------

Co-authored-by: anandh8x <test@example.com>
This pass rewrites comment-only ANT-ONLY markers to neutral internal-only
language across the source tree without changing runtime strings, flags,
commands, or protocol identifiers. The goal is to lower obvious internal
prose leakage while keeping the diff mechanically safe and easy to review.

Constraint: Phase B is limited to comments/prose only; runtime strings and user-facing labels remain deferred
Rejected: Broad search-and-replace across strings and command descriptions | too risky for a prose-only pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly runtime/user-facing strings and should be handled separately from comment cleanup
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>
)

This is a small prose-only follow-up that rewrites clearly internal or
explanatory Anthropic comment language to neutral wording in a handful of
high-confidence files. It avoids runtime strings, flags, command labels,
protocol identifiers, and provider-facing references.

Constraint: Keep this pass narrowly scoped to comments/documentation only
Rejected: Broader Anthropic comment sweep across functional API/protocol references | too ambiguous for a safe prose-only PR
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Leave functional Anthropic references (API behavior, SDKs, URLs, provider labels, protocol docs) for separate reviewed passes
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>
This pass rewrites a small set of ant-only diagnostic and UI labels to
neutral internal wording while leaving command definitions, flags, and
runtime logic untouched. It focuses on internal debug output, dead UI
branches, and noninteractive headings rather than broader product text.

Constraint: Label cleanup only; do not change command semantics or ant-only logic gates
Rejected: Renaming ant-only command descriptions in main.tsx | broader UX surface better handled in a separate reviewed pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly command descriptions and intentionally deferred user-facing strings
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>
This extends the label-only cleanup to the remaining internal-only command,
debug, and heading strings so the source tree no longer contains ANT-ONLY
markers. The pass still avoids logic changes and only renames labels shown
in internal or gated surfaces.

Constraint: Update the existing label-cleanup PR without widening scope into behavior changes
Rejected: Leave the last ANT-ONLY strings for a later pass | low-cost cleanup while the branch is already focused on labels
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: The next phase should move off label cleanup and onto a separately scoped logic or rebrand slice
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>
This follow-up Phase C-lite slice replaces purely internal helper modules
with stable external no-op surfaces and collapses internal elevated error
logging to a no-op. The change removes additional USER_TYPE-gated helper
behavior without touching product-facing runtime flows.

Constraint: Keep this PR limited to isolated helper modules that are already external no-ops in practice
Rejected: Pulling in broader speculation or logging sink changes | less isolated and easier to debate during review
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue Phase C with similarly isolated helpers before moving into mixed behavior files
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>
* Remove internal-only bundled skills and mock rate-limit behavior

This takes the next planned Phase C-lite slice by deleting bundled skills
that only ever registered for internal users and replacing the internal
mock rate-limit helper with a stable no-op external stub. The external
build keeps the same behavior while removing a concentrated block of
USER_TYPE-gated dead code.

Constraint: Limit this PR to isolated internal-only helpers and avoid bridge, oauth, or rebrand behavior
Rejected: Broad USER_TYPE cleanup across mixed runtime surfaces | too risky for the next medium-sized PR
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: The next cleanup pass should continue with similarly isolated USER_TYPE helpers before touching main.tsx or protocol-heavy code
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

* Align internal-only helper removal with remaining user guidance

This follow-up fixes the mock billing stub to be a true no-op and removes
stale user-facing references to /verify and /skillify from the same PR.
It also leaves a clearer paper trail for review: the deleted verify skill
was explicitly ant-gated before removal, and the remaining mock helper
callers still resolve to safe no-op returns in the external build.

Constraint: Keep the PR focused on consistency fixes and reviewer-requested evidence, not new cleanup scope
Rejected: Leave stale guidance for a later PR | would make this branch internally inconsistent after skill removal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When deleting gated features, always sweep user guidance and coordinator prompts in the same pass
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy; changed-file scan still shows only pre-existing tipRegistry errors outside edited lines)

* Clarify generic workflow wording after skill removal

This removes the last generic verification-skill wording that could still
be read as pointing at a deleted bundled command. The guidance now talks
about project workflows rather than a specific bundled verify skill.

Constraint: Keep the follow-up limited to reviewer-facing wording cleanup on the same PR
Rejected: Leave generic wording as-is | still too easy to misread after the explicit /verify references were removed
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When removing bundled commands, scrub both explicit and generic references in the same branch
Tested: bun run build
Tested: bun run smoke
Not-tested: Additional checks unchanged by wording-only follow-up

---------

Co-authored-by: anandh8x <test@example.com>
* test: stabilize suite and add coverage heatmap

* ci: run full bun test suite in pr checks
* security: harden suspicious PR intent scanner

* security: reduce pr scanner false positives
## Summary

- Extract retry-after header from 429 API errors and include timing
  guidance in the user-facing error message
- Previously, non-quota 429 errors showed a generic message with no
  guidance on when to retry, only a link to status.anthropic.com

## Impact

- user-facing impact: 429 error messages now tell users when to retry
  instead of just linking to a status page
- developer/maintainer impact: none

## Testing

- [x] `bun run build`
- [ ] `bun run smoke`
- [ ] focused tests: error formatting is pure string construction,
  verified via build + manual inspection

## Notes

- provider/model path tested: applies to all providers returning 429
- screenshots attached (if UI changed): n/a
- follow-up work or known limitations: 529 errors could get similar
  treatment in a follow-up

https://claude.ai/code/session_01D7kprMn4c66a5WrZscF7rv

Co-authored-by: Claude <noreply@anthropic.com>
Reproduction:
- Enable `frontend-design@claude-code-plugins`
- Enable `frontend-design@claude-plugins-official`
- Start OpenClaude with both marketplace plugins active
- Both plugins load, but downstream command and skill scopes key off the short plugin name, so both collapse to `frontend-design` and can interfere with interactive startup

Fix:
- Collapse duplicate marketplace plugins by short name during merge
- Keep the enabled copy when enabled state differs; otherwise keep the later config entry
- Add regression coverage for both cases
…#242)

* security: force lodash-es 4.18.0 for transitive dependencies

PR Gitlawb#225 bumped the direct lodash-es dependency to 4.18.0, but
@anthropic-ai/sandbox-runtime still pulled lodash-es@4.17.23 via its
own ^4.17.23 range. The transitive copy was vulnerable to:

- HIGH: Code Injection via _.template (GHSA-r5fr-rjxr-66jc)
- MODERATE: Prototype Pollution via _.unset/_.omit (GHSA-f23m-r3pf-42rh)

Added overrides field in package.json to force all copies to 4.18.0.
bun audit now reports zero vulnerabilities.

* fix: use lodash-es 4.18.1 instead of deprecated 4.18.0

lodash-es 4.18.0 is explicitly deprecated by the maintainer with
the message "Bad release. Please use lodash-es@4.17.23 instead."
Updated both the direct dependency and the override to 4.18.1, which
is the latest non-deprecated release that patches the CVEs.
…itlawb#250)

Models not in the lookup table fall through to a 200k default, causing
auto-compact to never trigger for models with smaller actual context
windows. Users hit hard context_window_exceeded errors instead.

Added to both context window and max output token tables:
- o1, o1-mini, o1-preview, o1-pro (OpenAI reasoning models)
- llama3.2:1b, qwen3:8b, codestral (common Ollama models)

Relates to Gitlawb#248
…wb#201)

* Add local OpenAI-compatible model discovery to /model

* Guard local OpenAI model discovery from Codex routing

* Preserve remote OpenAI Codex alias behavior
…ls (Gitlawb#241)

Models served through Ollama/vLLM with strict Jinja templates (Devstral,
Mistral, etc.) require strict user↔assistant role alternation and reject
requests with consecutive messages of the same role.

convertMessages() could produce consecutive user or assistant messages in
three scenarios: batched user input, text-only + tool_use assistant turns,
and tool result remainders followed by another user message.

Added a coalescing pass at the end of convertMessages() that merges
consecutive same-role messages (string concat or array concat), preserving
tool_calls on assistant messages. Tool and system messages are excluded
from coalescing as they have their own alternation rules.

Includes regression tests for both user and assistant coalescing.

Fixes Gitlawb#202
* fix: preserve unicode in Windows clipboard fallback

* fix: avoid Windows clipboard stdin codepage issues

* test: fix Windows clipboard temp path fixture
@MarawanYakout
Copy link
Copy Markdown
Contributor Author

Here are 2 potential solutions i can start with:

Solution 1: Tool Deduplication (Recommended)

This solution explicitly removes built-in tools that share a name with an overriding MCP tool. This prevents findToolByName from returning the wrong tool and ensures the ListTools endpoint doesn't return duplicate tool definitions.

Implementation:
In src/entrypoints/mcp.ts, replace:

const toolPermissionContext = getEmptyToolPermissionContext()
const tools = [...getTools(toolPermissionContext), ...mcpTools]

With:

const toolPermissionContext = getEmptyToolPermissionContext()
const builtins = getTools(toolPermissionContext)
const mcpToolNames = new Set(mcpTools.map(t => t.name))
const deduplicatedBuiltins = builtins.filter(t => !mcpToolNames.has(t.name))

const tools = [...mcpTools, ...deduplicatedBuiltins]

(This change must be applied inside both the ListToolsRequestSchema and CallToolRequestSchema handlers).

Solution 2: Reordering the Spread (Simpler, but less robust)

If we only care about findToolByName picking the correct tool, we could simply swap the order of the arrays so mcpTools comes first.

Implementation:

const tools = [...mcpTools, ...getTools(toolPermissionContext)]

Pros: One-line fix.
Cons: The ListTools endpoint will still return two tools with the exact same name (e.g., two Bash tools), which violates the intended uniqueness of tool schemas and might break external MCP clients.

Personally, Solution 1 is the correct path forward because it fixes the immediate bug in CallTool (correct resolution) while simultaneously preventing malformed duplicate schemas in ListTools.

@kevincodex1
Copy link
Copy Markdown
Contributor

lets go with solution 1 then

@anandh8x
Copy link
Copy Markdown
Collaborator

anandh8x commented Apr 6, 2026

@MarawanYakout I reviewed this branch locally and I think Solution 1 is the correct fix, not Solution 2.

Reordering alone fixes the immediate findToolByName() precedence issue, but it still leaves duplicate tool names in ListTools.

One additional change is still needed though: in ListTools, MCP tools should prefer tool.inputJSONSchema ?? zodToJsonSchema(tool.inputSchema). Right now the MCP wrapper's inputSchema is just the generic passthrough object, so otherwise the re-exposed MCP tools lose their real remote argument schema even after the collision fix.

So I'd recommend:

  1. apply Solution 1 in both handlers
  2. in ListTools, prefer tool.inputJSONSchema when present
  3. add a focused regression test for the no-prefix collision + duplicate-name + schema-preservation path

After that, the logic looks good to me.

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

  1. Added getCombinedTools: Created and exported the getCombinedTools helper function in src/entrypoints/mcp.ts to implement the
    deduplication logic properly:
   1    export function getCombinedTools(
   2      builtins: InternalTool[],
   3      mcpTools: InternalTool[],
   4    ): InternalTool[] {
   5      const mcpToolNames = new Set(mcpTools.map(t => t.name))
   6      const deduplicatedBuiltins = builtins.filter(t => !mcpToolNames.has(t.name))
   7
   8      return [...mcpTools, ...deduplicatedBuiltins]
   9    }
  1. Applied the Fix: Updated the ListToolsRequestSchema and CallToolRequestSchema handlers in src/entrypoints/mcp.ts to construct
    the tools array using this new function:

   1    const toolPermissionContext = getEmptyToolPermissionContext()
   2    const tools = getCombinedTools(getTools(toolPermissionContext), mcpTools)
  1. Verified via TDD: I wrote a test in src/entrypoints/mcp.test.ts to ensure that when a collision occurs, the MCP tool takes precedence over the built-in tool.
  2. Validation: I ran the full test suite (bun test) and the build script (bun run build). All tests, including the newly added
    one, passed successfully.

Copy link
Copy Markdown
Collaborator

@gnanam1990 gnanam1990 left a comment

Choose a reason for hiding this comment

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

Thanks for pushing this forward. I can see the MCP collision follow-up work on the branch, and I agree with the direction of re-exposing connected MCP tools. That said, after taking a deeper look at the current head, I’m still not comfortable approving this PR in its current form for three reasons:

  1. PR scope is much broader than the stated change
    The PR is described as “MCP tool re-exposure & strict input validation,” but the current branch also includes a large number of unrelated changes across gRPC, onboarding, UI, docs, workflow, privacy/tooling, and other areas. That makes it very difficult to review or merge safely as a single unit.

Examples include changes in:

  • src/grpc/server.ts
  • src/components/ProviderManager.tsx
  • src/components/ThemePicker.tsx
  • docs/litellm-setup.md
  • scripts/pr-intent-scan.ts
  • .github/workflows/pr-checks.yml

I think this needs to be narrowed down substantially before it is mergeable.

  1. “Strict input validation” for re-exposed MCP tools still does not appear to be truly enforced
    The current MCP server path still seems to rely on the MCP tool wrapper schema rather than the real upstream MCP schema when validating tool inputs.

Relevant files:

  • src/entrypoints/mcp.ts
  • src/services/mcp/client.ts
  • src/tools/MCPTool/MCPTool.ts

As a result, the branch appears to re-expose MCP tools, but not actually validate arguments strictly against the real remote tool schema in the way the PR description claims.

  1. Re-exposed MCP tool outputs are still flattened into plain text
    In the current mcp.ts path, tool results are converted into a single text response using either the string result or jsonStringify(finalResult.data). That loses the native structure of upstream MCP tool responses and will break or degrade any non-text or structured MCP result.

Relevant files:

  • src/entrypoints/mcp.ts
  • src/services/mcp/client.ts

So even if tool lookup precedence is fixed, the proxy path still looks lossy for richer MCP tools.

I think the MCP re-exposure idea is worth pursuing, but I’d want this PR either:

  • split down to just the MCP-specific change, or
  • updated so the current branch actually enforces strict upstream MCP schemas and preserves structured MCP outputs

Once that is tightened up, I’d be happy to take another look.

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Rechecked the current head ad6ae12c3089a317d6fb30d7d31b90d12e7461bf against current origin/main.

The earlier no-prefix collision blocker is fixed on this head: MCP tools now win name collisions over builtins via getCombinedTools(...), and the focused tests/build/smoke pass.

I still can't approve because there is another real behavior bug in the new MCP exposure path.

  1. src/entrypoints/mcp.ts:79-88
    getMcpToolsCommandsAndResources(...) can return synthetic tools for non-connected states, especially the OAuth recovery tool for needs-auth servers (createMcpAuthTool(...)). But this entrypoint only records tools when client.type === 'connected':

    • if (client.type === 'connected') { mcpClients.push(client); mcpTools.push(...clientTools) }

    That means OAuth-gated MCP servers silently disappear from the re-exposed MCP server instead of surfacing their ...authenticate tool.

    This is a real regression relative to the intended behavior of getMcpToolsCommandsAndResources(...) itself, which explicitly emits:

    • client: { type: 'needs-auth', ... }
    • tools: [createMcpAuthTool(name, config)]

    So on this branch, a caller can no longer see or invoke the auth/recovery path for a needs-auth MCP server through this MCP entrypoint, even though the lower-level MCP client layer provides it.

Non-blocking note:

  • the new src/entrypoints/mcp.test.ts only covers builtin-vs-MCP name deduplication. It does not cover the needs-auth path above, which is why this slipped through.

What I verified on this head:

  • bun test src/entrypoints/mcp.test.ts src/utils/secureStorage/platformStorage.test.ts -> 12 pass
  • direct runtime repro of MCP precedence: getCombinedTools([builtin Bash, builtin Read], [MCP Bash]) returns MCP Bash first
  • bun run build -> success
  • bun run smoke -> success

I did not find another high-confidence blocker beyond the dropped needs-auth tool path, but I wouldn't merge this until OAuth-gated MCP servers remain visible/authenticatable through the re-exposed MCP surface.

@gnanam1990
Copy link
Copy Markdown
Collaborator

@MarawanYakout good job.....! just one step more to reach target

@kevincodex1
Copy link
Copy Markdown
Contributor

I'm looking into this and theres a lot of touched files?

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

After going about few things , MCP is very good on my end.

1. OAuth-gated MCP Server Visibility Restored

Issue: src/entrypoints/mcp.ts was silently dropping MCP servers that required authentication (needs-auth type), preventing users from invoking the ...authenticate tool through the re-exposed MCP entrypoint.
Resolution:
Modified src/entrypoints/mcp.ts to push tools and client connection contexts regardless of connection status, aligning with the expected behavior of getMcpToolsCommandsAndResources().

2. Strict Input Validation Enforced via Ajv

Issue: The proxy path previously relied on the local wrapper schema (z.object({}).passthrough()) for validation, allowing arbitrary inputs to bypass local inspection. The advertised schema was also inaccurately exposed.
Resolution:

  • Schema Exposure: Updated src/entrypoints/mcp.ts to advertise the actual upstream JSON schema (tool.inputJSONSchema) instead of the empty wrapper schema.
  • Strict Validation: Integrated ajv inside src/tools/MCPTool/MCPTool.ts. We now override validateInput to compile and enforce the real remote tool JSON schema (this.inputJSONSchema) before proceeding. If validation fails, it correctly surfaces an explicit validation error, preventing invalid parameters from reaching downstream layers.

3. Preserved Structured Output for MCP Tool Results

Issue: Re-exposed MCP tool outputs were being flattened into single plain-text blocks, losing native structures (like distinct image or text blocks) that are essential for richer tool responses.
Resolution:
Updated the final response mapping in src/entrypoints/mcp.ts. If the finalResult.data comprises an array of content blocks (matching the ContentBlockParam[] format), the blocks are now properly translated back into the MCP-compliant CallToolResult.content structures, accurately maintaining text and image block integrity.

Validations Performed

  1. Unit Testing:
    Ran bun test src/entrypoints/mcp.test.ts src/utils/secureStorage/platformStorage.test.ts. All 12 test cases successfully passed.
  2. Build Success:
    Executed bun run build cleanly without side effects or typing failures.
  3. Security Standards Alignment:
    Followed best practices out of the Sec_skill guidelines ensuring:
    • Input Validation: Enforced explicit whitelist/schema verification (ajv.compile()) to reject invalid inputs early.
    • Error Handling: Enhanced error handling during schema compilation explicitly catches formatting errors while shielding sensitive inner stack traces from escaping directly to users.
    • Structured Responses: Correctly isolating text/images mitigates unintended parsing exploits when passing strings between sub-systems.

Technically system now upholds strict schema enforcement and full-spectrum MCP transparency while resolving the specific blockers noted in the latest PR review. lets see if there is any other adjustments needed, i am more than happy to adhere.

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

@kevincodex1 is there something in specific the project needs help in developing ? i can aim my focus towards specific areas of need or importance, tried to contacting on X but couldn't

Vasanthdev2004
Vasanthdev2004 previously approved these changes Apr 9, 2026
Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Rechecked the current head b4d424b4f3d393889e588a3c9b1b5390bd704f5c against current origin/main.

Scope

This is a targeted re-review of the current head and the previously-blocked MCP areas, not a full fresh re-review of every historical branch state.

Verdict

Approve-ready

The confusing part here was mostly earlier branch churn and stale review context. On the current head, the actual merge surface is now narrow and coherent again:

  • src/entrypoints/mcp.ts
  • src/entrypoints/mcp.test.ts
  • src/tools/MCPTool/MCPTool.ts
  • src/utils/secureStorage/platformStorage.test.ts

What I specifically rechecked on this head:

  1. No-prefix MCP collisions are fixed

    • getCombinedTools(...) deduplicates builtins when an MCP tool reuses the same name
    • MCP tools are ordered ahead of remaining builtins, so findToolByName(...) resolves the MCP override path correctly
  2. Needs-auth / OAuth recovery tools are no longer dropped

    • loadReexposedMcpTools() now records tools and client contexts regardless of connection state, so the needs-auth recovery/authenticate path stays visible through the re-exposed MCP surface
    • there is focused coverage for that behavior in src/entrypoints/mcp.test.ts
  3. The strict-validation / schema-exposure story is now materially better

    • ListTools now prefers tool.inputJSONSchema ?? zodToJsonSchema(tool.inputSchema)
    • MCPTool.validateInput() compiles and enforces inputJSONSchema with Ajv when present instead of only trusting the passthrough wrapper schema
  4. Structured MCP outputs are preserved better than before

    • the CallTool result mapping now preserves text/image block structure instead of flattening everything into a single text blob by default
  5. Checks

    • smoke-and-tests is green on this head

I’m approving this current shape. The earlier confusion was real, but the branch now looks focused and the previously-blocking MCP behavior issues appear addressed on the current head.

@MarawanYakout MarawanYakout dismissed Vasanthdev2004’s stale review April 9, 2026 04:12

The merge-base changed after approval.

Vasanthdev2004
Vasanthdev2004 previously approved these changes Apr 9, 2026
Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

GitHub auto-dismissed the earlier approval after the merge base changed, so I rechecked the current state.

This is still a targeted re-review of the same head commit b4d424b4f3d393889e588a3c9b1b5390bd704f5c against the updated base, not a new full review from scratch.

I do not see a new blocker from the merge-base movement alone. The approval still stands on the current head:

  • MCP/builtin collision handling still looks correct
  • needs-auth / OAuth recovery tools are still preserved
  • schema exposure + Ajv-backed validation still look correct for this scope
  • structured MCP output preservation still looks intact
  • checks are still green

So my verdict remains Approve-ready on the current head.

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

@gnanam1990 one more eyes

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

good work @MarawanYakout

@MarawanYakout MarawanYakout dismissed Vasanthdev2004’s stale review April 9, 2026 04:17

The merge-base changed after approval.

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004 @gnanam1990 Thanks guys !

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

i'm here if there is any extra adjustments

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

@kevincodex1 @gnanam1990 @Vasanthdev2004 if guys need help with important issues / pull requests i can help with that too if you guys are working on something challenging or needs collap.

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

sure @MarawanYakout we will let you know

@kevincodex1
Copy link
Copy Markdown
Contributor

theres a lot of change files here @Vasanthdev2004 @gnanam1990

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

@MarawanYakout can you make a new pr for this fix seems this pr messed up with lot of commits shows 5k line of code change

@MarawanYakout
Copy link
Copy Markdown
Contributor Author

made a new one @Vasanthdev2004 #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.