Skip to content

feat(mcp): hide internal self-brought MCP details from final responses#1061

Merged
zhoug9127 merged 28 commits intolightseekorg:mainfrom
zhoug9127:feat/mcp-internal-server-privacy
Apr 10, 2026
Merged

feat(mcp): hide internal self-brought MCP details from final responses#1061
zhoug9127 merged 28 commits intolightseekorg:mainfrom
zhoug9127:feat/mcp-internal-server-privacy

Conversation

@zhoug9127
Copy link
Copy Markdown
Collaborator

@zhoug9127 zhoug9127 commented Apr 8, 2026

Description

Problem

Self-brought MCP servers can power internal capabilities like LTM recall, but some deployments do not want those server labels, injected tools, MCP trace items, or internal error details to appear in client-visible final responses.

PR1 should stay narrow: this hiding capability is only for opt-in self-brought MCP servers. Users who do not opt in, or who rely on builtin-routed tools, should keep existing behavior.

Solution

Add a server-level internal: true capability for self-brought MCP servers and apply it only to the final assembled response surface.

This PR:

  • hides injected internal function tools from restored tools
  • strips internal mcp_list_tools, mcp_call, and internal function-call trace items from final response output
  • preserves runtime tool execution; this is visibility control only, not a tool-disable feature
  • keeps builtin-routed MCP output visible; builtin web_search_call, code_interpreter_call, and file_search_call items are explicitly out of scope for PR1

PR2 plan: extend the same self-brought internal-server contract to streaming so live SSE tool events for those internal MCP servers are also hidden from the customer-facing stream, without changing builtin-routed behavior.

Changes

  • add final-response restoration/filtering for opt-in internal self-brought MCP servers
  • add non-stream regression coverage that final responses do not leak internal server labels, tool names, MCP trace items, or error markers
  • add a failing mock MCP server helper for the error-path leakage test
  • add guardrail tests that builtin-routed output remains visible and stays out of scope for this PR

Test Plan

  • cargo +nightly fmt --all --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo build --workspace
  • git diff --check
  • cargo test -p smg build_transformed_mcp_call_item_does_not_add_server_label_for_builtin_formats
  • cargo test -p smg restore_original_tools
  • cargo test -p smg restore_original_tools_keeps_builtin_output_items_visible
  • cargo test -p smg restore_original_tools_strips_internal_mcp_output_items
  • cargo test -p smg --test api_tests test_final_response_hides_internal_mcp_trace_items
  • cargo test -p smg --test api_tests test_final_response_hides_internal_mcp_error_details
  • cargo test -p smg --test api_tests non_streaming_mcp_minimal_e2e
  • cargo test -p smg --test api_tests streaming_with_mcp_tool_calls
  • cargo test -p smg --test mcp_test
Checklist
  • cargo +nightly fmt passes
  • cargo clippy --all-targets --all-features -- -D warnings passes
  • (Optional) Documentation updated
  • (Optional) Please join us on Slack #sig-smg to discuss, review, and merge PRs

Summary by CodeRabbit

  • New Features

    • Servers can be marked internal (defaults to false); internal servers/tools/traces/errors are excluded from final streaming and non‑streaming responses and tool lists.
  • Documentation

    • Added reference page describing internal servers, config example, scope, and limitations.
  • Tests

    • Expanded tests and mocks for internal-server detection, hiding of internal artifacts, name collisions, and failing-server behavior.
  • Refactor

    • Improved test server harness and added a failing-server variant.

@github-actions github-actions bot added documentation Improvements or additions to documentation mcp MCP related changes tests Test changes model-gateway Model gateway crate changes openai OpenAI router changes labels Apr 8, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Added an internal: bool flag to MCP server configs, exposed internal-server enumeration on the orchestrator, extended session classification for internal/builtin servers/tools, and updated tool-loop and response restoration to omit/strip internal MCP artifacts. Tests, mocks, and docs updated accordingly.

Changes

Cohort / File(s) Summary
Core MCP Config & Orchestration
crates/mcp/src/core/config.rs, crates/mcp/src/core/orchestrator.rs
Added pub internal: bool (with #[serde(default)]) to McpServerConfig and McpOrchestrator::internal_server_names() to enumerate internal servers.
MCP Session & Classification
crates/mcp/src/core/session.rs
Recorded associated server keys and builtin-routing for bindings; precomputed builtin/internal sets; added multiple is_internal_* and is_builtin_* methods; updated binding construction and tests.
Tool Loop / Streaming Injection
model_gateway/src/routers/openai/mcp/tool_loop.rs
Do not inject mcp_list_tools for internal server bindings; filter internal MCP response items when building/translating streaming and incomplete responses; added helper to classify internal MCP response items.
Response Restoration & Utils
model_gateway/src/routers/openai/responses/utils.rs
restore_original_tools now accepts session: Option<&McpToolSession<'_>>; added three-step removal/rebuild (scrub internal output, scrub internal tools, reconstruct client-visible tools), function-name collision exemptions, and many unit tests.
Response Call Sites
model_gateway/src/routers/openai/responses/non_streaming.rs, model_gateway/src/routers/openai/responses/streaming.rs
Updated calls to restore_original_tools to pass session context (Some for MCP path, None otherwise).
Dynamic MCP Connect & Test Helpers
model_gateway/src/routers/mcp_utils.rs, crates/mcp/src/core/{pool.rs,proxy.rs}
Dynamic server construction and test helpers explicitly set internal: false for created McpServerConfig instances.
Test Mocks & E2E Tests
model_gateway/tests/common/mock_mcp_server.rs, model_gateway/tests/api/responses_api_test.rs, model_gateway/tests/mcp_test.rs
Refactored mock server harness, added MockFailingMCPServer, updated tests and added E2E tests asserting internal servers/tools and internal error details are hidden.
Docs
docs/reference/mcp-internal-servers.md
New documentation page describing internal: true semantics, scope, YAML example, and explicit non-effects.

Sequence Diagram

sequenceDiagram
    autonumber
    participant Client as Client
    participant ToolLoop as Tool Loop
    participant Session as McpToolSession
    participant Orchestrator as McpOrchestrator
    participant Response as Response Utils

    Client->>ToolLoop: start tool execution (with MCP bindings)
    ToolLoop->>Session: query binding/server label visibility
    Session->>Orchestrator: request internal server snapshot
    Orchestrator-->>Session: return internal server set
    alt server/label is internal
        Session-->>ToolLoop: mark binding internal
        ToolLoop->>ToolLoop: skip injecting mcp_list_tools and filter call items
    else visible server
        Session-->>ToolLoop: mark binding visible
        ToolLoop->>ToolLoop: inject MCP metadata and call items
    end
    ToolLoop->>Response: restore_original_tools(resp, original_body, Some(session))
    Response->>Session: call is_internal_* helpers
    Response->>Response: strip internal tools/output and rebuild client-visible tools
    Response-->>Client: deliver cleaned response
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested Reviewers

  • CatherineSue
  • XinyueZhang369

Poem

🐇 I hid a tiny server flag,
Quiet hops through session's tag,
Tool loops skip the secret rooms,
Responses shed their hidden blooms,
A little carrot for tidy logs 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main objective: adding a feature to hide internal self-brought MCP details from final responses, which matches the core implementation across config, orchestrator, session, and response filtering.
Docstring Coverage ✅ Passed Docstring coverage is 92.44% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 8, 2026

Hi @zhoug9127, the DCO sign-off check has failed. All commits must include a Signed-off-by line.

To fix existing commits:

# Sign off the last N commits (replace N with the number of unsigned commits)
git rebase HEAD~N --signoff
git push --force-with-lease

To sign off future commits automatically:

  • Use git commit -s every time, or
  • VSCode: enable Git: Always Sign Off in Settings
  • PyCharm: enable Sign-off commit in the Commit tool window

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 8, 2026

Hi @zhoug9127, this PR has merge conflicts that must be resolved before it can be merged. Please rebase your branch:

git fetch origin main
git rebase origin/main
# resolve any conflicts, then:
git push --force-with-lease

@mergify mergify bot added the needs-rebase PR has merge conflicts that need to be resolved label Apr 8, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an internal flag for MCP servers, allowing them to be hidden from client-visible outputs such as tool lists and metadata. The implementation includes updates to the configuration schema, orchestrator, and response processing logic to ensure internal server details and their tool executions are stripped before the final response is sent. Feedback identifies a potential data leakage risk where certain tool types were omitted from the filtering logic and provides a refactored suggestion. Additionally, a performance improvement is recommended for the internal server name lookup process to reduce allocations and string cloning on hot paths.

Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Comment thread crates/mcp/src/core/orchestrator.rs
@zhoug9127 zhoug9127 marked this pull request as draft April 8, 2026 05:36
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2e61bb1368

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Comment thread crates/mcp/src/core/session.rs Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/reference/mcp-internal-servers.md`:
- Around line 6-20: The docs are ambiguous about the visibility scope of the
servers "internal: true" flag; update the text to explicitly state that
"internal: true" currently only applies to self-provided MCP servers (entries
under servers: with internal: true) and affects final assembled non-streaming
MCP responses, and does not hide or apply to streaming outputs or builtin-routed
MCP results. Locate the section showing the sample YAML (the servers: - name:
internal-memory / internal: true example) and add a clear sentence clarifying
that scope and the exceptions (streaming and builtin-routed outputs remain
visible) so readers won’t infer broader concealment.

In `@model_gateway/src/routers/openai/mcp/tool_loop.rs`:
- Around line 780-784: The current is_internal_mcp_response_item function treats
any item with a server_label as internal and thus hides builtin routed outputs;
modify is_internal_mcp_response_item so it first checks the item's type (e.g.,
item.get("type").and_then(|v| v.as_str())) and if the type matches builtin call
names ("web_search_call", "code_interpreter_call", "file_search_call") it
returns false (keep visible), otherwise fall back to the existing server_label
check using session.is_internal_server_label(server_label); update the function
body accordingly.

In `@model_gateway/src/routers/openai/responses/utils.rs`:
- Around line 324-335: The match arm that checks item type only handles
"function_call" but misses "function_tool_call", allowing internal tool names to
leak; update the pattern matching in the match block that inspects
item.get("type")/item.get("name")/item.get("server_label") to treat
"function_tool_call" the same as "function_call" (i.e., call
session.is_internal_tool(name) when name is present, and fallback to
session.is_internal_server_label(server_label) when server_label is present) so
both variants are redacted using the existing session.is_internal_tool and
session.is_internal_server_label checks.

In `@model_gateway/tests/common/mock_mcp_server.rs`:
- Around line 210-263: The start/url/stop/Drop implementations in
MockFailingMCPServer duplicate MockMCPServer lifecycle logic; extract a shared
harness (e.g., a MockServerHarness struct or a MockServer trait) that
encapsulates TcpListener binding, port storage, axum serve spawn, url(), stop()
async behavior and Drop abort logic, then have MockFailingMCPServer and
MockMCPServer delegate to or compose that harness (move the shared
StreamableHttpService construction into per-server factory functions while
reusing the harness for lifecycle management).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9801581f-4c65-456d-91a2-e770d554be4f

📥 Commits

Reviewing files that changed from the base of the PR and between d3fc32a and 2e61bb1.

📒 Files selected for processing (14)
  • crates/mcp/src/core/config.rs
  • crates/mcp/src/core/orchestrator.rs
  • crates/mcp/src/core/pool.rs
  • crates/mcp/src/core/proxy.rs
  • crates/mcp/src/core/session.rs
  • docs/reference/mcp-internal-servers.md
  • model_gateway/src/routers/mcp_utils.rs
  • model_gateway/src/routers/openai/mcp/tool_loop.rs
  • model_gateway/src/routers/openai/responses/non_streaming.rs
  • model_gateway/src/routers/openai/responses/streaming.rs
  • model_gateway/src/routers/openai/responses/utils.rs
  • model_gateway/tests/api/responses_api_test.rs
  • model_gateway/tests/common/mock_mcp_server.rs
  • model_gateway/tests/mcp_test.rs

Comment thread docs/reference/mcp-internal-servers.md
Comment thread model_gateway/src/routers/openai/mcp/tool_loop.rs
Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Comment thread model_gateway/tests/common/mock_mcp_server.rs
@zhoug9127 zhoug9127 force-pushed the feat/mcp-internal-server-privacy branch from 2e61bb1 to aab2524 Compare April 8, 2026 05:45
zhoug9127 added 2 commits April 7, 2026 23:28
Signed-off-by: zhoug9127 <daisy.zhou@oracle.com>
Signed-off-by: zhoug9127 <daisy.zhou@oracle.com>
@zhoug9127 zhoug9127 force-pushed the feat/mcp-internal-server-privacy branch from aab2524 to f3a7f54 Compare April 8, 2026 06:33
@mergify mergify bot removed the needs-rebase PR has merge conflicts that need to be resolved label Apr 8, 2026
@zhoug9127 zhoug9127 force-pushed the feat/mcp-internal-server-privacy branch from f3a7f54 to 2d6a4a3 Compare April 8, 2026 07:28
zhoug9127 added 2 commits April 8, 2026 00:47
Signed-off-by: zhoug9127 <daisy.zhou@oracle.com>
Signed-off-by: zhoug9127 <daisy.zhou@oracle.com>
@zhoug9127 zhoug9127 force-pushed the feat/mcp-internal-server-privacy branch 3 times, most recently from dff1539 to e6a2502 Compare April 8, 2026 16:08
@zhoug9127 zhoug9127 marked this pull request as ready for review April 8, 2026 16:11
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e6a2502e26

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/mcp/src/core/orchestrator.rs`:
- Around line 926-943: The current internal_server_names() returns every
internal server in the deployment causing request-scoped dynamic servers to be
mis-classified; update it to compute internals from the active McpServerBinding
set (or accept a &[McpServerBinding] parameter) and only return names that
appear in those bindings, i.e. build the HashSet from binding.config.name for
bindings where binding.config.internal is true (or intersect the existing global
set with the active bindings' names) so McpToolSession::new-based final-response
stripping uses the request's active bindings and not the global server list.

In `@model_gateway/src/routers/openai/responses/streaming.rs`:
- Line 480: The call to restore_original_tools(&mut final_response,
ctx.original_request, ctx.session) is putting the streaming response.completed
SSE into the internal-hiding scope by passing ctx.session; remove the session
from the streaming path so the client-visible SSE remains unhidden (i.e., call
restore_original_tools with only final_response and ctx.original_request or pass
None/NoSession), and ensure only the persistence path that stores the response
calls the function that accepts ctx.session (or separately calls
send_final_response_event with the session) so internal MCP details are only
hidden when persisting; update usages of
restore_original_tools/send_final_response_event accordingly to keep streaming
output visible.

In `@model_gateway/src/routers/openai/responses/utils.rs`:
- Around line 254-269: The current branch removes resp["tools"] when
restored_tools is empty but fails to account for ResponseTool::Function entries
(response_tool_to_value returns None for functions), which causes surviving user
function tools to be deleted; update the condition so you only remove "tools"
when there are no user function tools present: when restored_tools.is_empty()
compute had_restorable_original_tool as before AND check original_tools for any
ResponseTool::Function (e.g., original_tools.iter().any(|t| matches!(t,
ResponseTool::Function(_))) or a helper like response_tool_is_function), and
only remove the "tools" field if there are no function tools and no restorable
tools; also add a regression test that sends a mixed request containing a normal
function tool and an internal MCP tool to ensure the function tool remains in
resp["tools"] after strip_internal_mcp_tools().

In `@model_gateway/tests/common/mock_mcp_server.rs`:
- Around line 33-59: The test server's start() and stop() use fixed
tokio::time::sleep and spawn a detached task that may panic (losing serve
errors) — replace those sleeps by implementing a deterministic readiness and
shutdown handshake: in start() have the task send a Result via a
tokio::sync::oneshot::Sender (or a tokio::sync::watch) indicating whether
axum::serve successfully started (capture the serve error instead of .expect),
and wait on the receiver before returning Ok so start() only returns after
successful bind; for stop() use a graceful shutdown signal (e.g., a
tokio::sync::watch or oneshot shutdown trigger wired into
axum::Server::with_graceful_shutdown) and await the server task completion
instead of sleeping/abort; update references to server_handle, port(), url(),
start(), and stop() accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6a416657-2f68-435d-ba16-775421e7c73c

📥 Commits

Reviewing files that changed from the base of the PR and between 2e61bb1 and e6a2502.

📒 Files selected for processing (14)
  • crates/mcp/src/core/config.rs
  • crates/mcp/src/core/orchestrator.rs
  • crates/mcp/src/core/pool.rs
  • crates/mcp/src/core/proxy.rs
  • crates/mcp/src/core/session.rs
  • docs/reference/mcp-internal-servers.md
  • model_gateway/src/routers/mcp_utils.rs
  • model_gateway/src/routers/openai/mcp/tool_loop.rs
  • model_gateway/src/routers/openai/responses/non_streaming.rs
  • model_gateway/src/routers/openai/responses/streaming.rs
  • model_gateway/src/routers/openai/responses/utils.rs
  • model_gateway/tests/api/responses_api_test.rs
  • model_gateway/tests/common/mock_mcp_server.rs
  • model_gateway/tests/mcp_test.rs

Comment thread crates/mcp/src/core/orchestrator.rs
Comment thread model_gateway/src/routers/openai/responses/streaming.rs Outdated
Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Comment thread model_gateway/tests/common/mock_mcp_server.rs
Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
@meridianmindx
Copy link
Copy Markdown

Nice work on hiding internal MCP details! For teams implementing MCP servers with sensitive internals, our meridian-mcp-deploy can help configure proper isolation and security settings. The meridian-tooling-guide covers MCP security patterns including internal server configurations.

Signed-off-by: zhoug9127 <zhoug9127@gmail.com>
@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 10, 2026

Hi @zhoug9127, this PR has merge conflicts that must be resolved before it can be merged. Please rebase your branch:

git fetch origin main
git rebase origin/main
# resolve any conflicts, then:
git push --force-with-lease

@mergify mergify bot added the needs-rebase PR has merge conflicts that need to be resolved label Apr 10, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0edec81f37

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/mcp/src/core/session.rs`:
- Around line 79-82: The current session-level builtin_server_keys causes all
tools on a server with any builtin routed tool to be treated as builtin; instead
compute a per-tool "is_builtin_routed" during binding construction and remove
reliance on builtin_server_keys in the label logic. Update where
ExposedToolBinding objects are created to consult the configured builtin tool
binding and set an is_builtin_routed flag (use this flag name) for that binding,
change any uses of builtin_server_keys/internal_server_keys-based checks
(including in the label helper and in build_transformed_mcp_call_item filtering
paths) to use binding.is_builtin_routed, and ensure builtin responses (which
omit server_label) remain unaffected by server-wide builtin sets; this keeps
internal_server_keys for internal-only classification but scopes builtin
classification to each ExposedToolBinding.

In `@model_gateway/src/routers/openai/responses/utils.rs`:
- Around line 369-391: The current is_internal_mcp_tool_value only inspects a
top-level "name" field and misses tools shaped like
{"type":"function","function":{"name":"..."}}, so replace the direct top-level
name lookup with the existing extractor function_tool_name(tool) when handling
the (Some("function"), ...) arm; call function_tool_name(tool) to obtain the
function name, then check session.is_internal_tool(name) &&
!user_function_names.contains(name) (keeping the MCP server_label arm
unchanged), ensuring the function-path correctly identifies and strips
function-shaped tool entries.
- Around line 436-447: The current arms in build_incomplete_response that match
Some("function_call") and Some("function_tool_call") only check
session.is_internal_non_builtin_tool(name) and therefore can still leak raw
traces for builtin-backed internal tools; update each predicate to also exclude
builtin-backed tools by checking the builtin flag (e.g., ensure
!session.is_internal_builtin_tool(name) or !session.is_builtin_tool(name) in
addition to session.is_internal_non_builtin_tool(name)) so the final condition
becomes something like: name is an internal non-builtin tool AND not a
builtin-backed/internal-builtin tool AND not in user_function_names.

In `@model_gateway/tests/common/mock_mcp_server.rs`:
- Around line 336-341: Update the test_mock_failing_server_startup test to
exercise the failing-tool path: after starting
MockFailingMCPServer::start("marker") and asserting port/url, instantiate an
RMCP client pointed at server.url(), call the brave_web_search RPC (or client
method) that triggers the tool path, capture the returned raw error, and assert
the error string contains the supplied "marker"; finally stop the server. Use
the existing MockFailingMCPServer, test_mock_failing_server_startup, and the
RMCP client's brave_web_search call to locate where to add the connection,
invocation, and assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 78d4574f-7c98-4d51-8f35-4d5b4ac6eef0

📥 Commits

Reviewing files that changed from the base of the PR and between 8352ba2 and 0edec81.

📒 Files selected for processing (7)
  • crates/mcp/src/core/config.rs
  • crates/mcp/src/core/session.rs
  • model_gateway/src/routers/mcp_utils.rs
  • model_gateway/src/routers/openai/mcp/tool_loop.rs
  • model_gateway/src/routers/openai/responses/streaming.rs
  • model_gateway/src/routers/openai/responses/utils.rs
  • model_gateway/tests/common/mock_mcp_server.rs

Comment thread crates/mcp/src/core/session.rs Outdated
Comment thread model_gateway/src/routers/openai/responses/utils.rs
Comment thread model_gateway/src/routers/openai/responses/utils.rs
Comment thread model_gateway/tests/common/mock_mcp_server.rs
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
@mergify mergify bot removed the needs-rebase PR has merge conflicts that need to be resolved label Apr 10, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e0c60b020

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread crates/mcp/src/core/session.rs
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
model_gateway/src/routers/openai/responses/utils.rs (1)

434-445: ⚠️ Potential issue | 🟠 Major

Hide raw builtin-backed function traces as well.

These branches still use is_internal_non_builtin_tool, so an internal builtin server can leak the raw function_call / function_tool_call item if that artifact survives response assembly. The transformed builtin item can stay visible; the internal trace should not.

🔒 Suggested fix
         Some("function_call") => item
             .get("name")
             .and_then(|value| value.as_str())
             .is_some_and(|name| {
-                session.is_internal_non_builtin_tool(name) && !user_function_names.contains(name)
+                session.is_internal_tool(name) && !user_function_names.contains(name)
             }),
         Some("function_tool_call") => item
             .get("name")
             .and_then(|value| value.as_str())
             .is_some_and(|name| {
-                session.is_internal_non_builtin_tool(name) && !user_function_names.contains(name)
+                session.is_internal_tool(name) && !user_function_names.contains(name)
             }),

Based on learnings, build_transformed_mcp_call_item intentionally omits server_label for builtin formats, so label-based filtering cannot catch these raw traces.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@model_gateway/src/routers/openai/responses/utils.rs` around lines 434 - 445,
The predicate that hides raw function_call / function_tool_call items only
checks session.is_internal_non_builtin_tool, which lets internal builtin-backed
traces slip through; update both branches (the Some("function_call") and
Some("function_tool_call") arms) to also detect and treat internal
builtin-backed tools as internal (e.g., extend the condition to
session.is_internal_tool(name) or add an OR checking whatever API flags
builtin-internal tools in your Session) so these raw items are filtered out
(still keep the !user_function_names.contains(name) check); ensure this change
aligns with build_transformed_mcp_call_item behavior so transformed builtin
items remain visible while raw internal traces are hidden.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/mcp/src/core/config.rs`:
- Around line 216-218: Update the doc comment for the public field `internal` to
clarify its current behavior: state that setting `internal: true` hides tools
from standard client-visible outputs but does not yet redact or prevent
streaming Server-Sent Events (SSE) live tool events; mention this is a
limitation/known gap so operators understand live streams are still visible.
Edit the comment on the `internal` field (the `pub internal: bool` declaration)
to include this explicit caveat and keep the existing serde attribute and
semantics unchanged.

In `@model_gateway/src/routers/openai/responses/utils.rs`:
- Around line 327-333: When restored_tools.is_empty() we currently remove
"tools" but leave any existing "tool_choice" which can leak a pinned tool name;
update the empty-tools branch in the function handling obj/restored_tools to
also scrub "tool_choice" (remove the "tool_choice" entry from obj) before
returning so no upstream tool selection remains when all visible tools were
stripped.

---

Duplicate comments:
In `@model_gateway/src/routers/openai/responses/utils.rs`:
- Around line 434-445: The predicate that hides raw function_call /
function_tool_call items only checks session.is_internal_non_builtin_tool, which
lets internal builtin-backed traces slip through; update both branches (the
Some("function_call") and Some("function_tool_call") arms) to also detect and
treat internal builtin-backed tools as internal (e.g., extend the condition to
session.is_internal_tool(name) or add an OR checking whatever API flags
builtin-internal tools in your Session) so these raw items are filtered out
(still keep the !user_function_names.contains(name) check); ensure this change
aligns with build_transformed_mcp_call_item behavior so transformed builtin
items remain visible while raw internal traces are hidden.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 505a0016-2896-4f00-a449-e581833d2406

📥 Commits

Reviewing files that changed from the base of the PR and between 0edec81 and 9e0c60b.

📒 Files selected for processing (7)
  • crates/mcp/src/core/config.rs
  • crates/mcp/src/core/session.rs
  • model_gateway/src/routers/mcp_utils.rs
  • model_gateway/src/routers/openai/mcp/tool_loop.rs
  • model_gateway/src/routers/openai/responses/streaming.rs
  • model_gateway/src/routers/openai/responses/utils.rs
  • model_gateway/tests/common/mock_mcp_server.rs

Comment thread crates/mcp/src/core/config.rs Outdated
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8637b877e6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c9a7b32697

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/openai/responses/utils.rs Outdated
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@model_gateway/src/routers/openai/responses/utils.rs`:
- Around line 333-340: The code currently preserves an existing object-style
"tool_choice" even when its referenced function is not present in the rebuilt
restored_tools array (variables: restored_tools, obj, key "tools" and
"tool_choice"), which leaks stripped internal tools; update the logic after
inserting "tools" so that if obj["tool_choice"] is an object with a
{"type":"function","name":X} selection, you check whether X exists in
restored_tools and if not either clear the "tool_choice" entry or rehydrate it
to a valid visible tool (e.g., set to "auto" or another allowed value), and add
a regression test that builds a mixed visible+internal tools input (visible
tools plus an internal tool removed by rebuild) with an object-style tool_choice
pointing to the internal name to verify the tool_choice is cleared or replaced
when the function is absent.
- Around line 307-318: The current loop in restored_tools (iterating
original_tools and matching ResponseTool::Function) unconditionally pops an
upstream_by_name entry and may reintroduce an ambiguous upstream schema on name
collisions; change the logic so you first inspect upstream_by_name.get(name) and
only pop_front() when the deque has exactly one candidate (no collision). If the
deque has length > 1 (or the entry is absent), skip using the upstream copy and
fall back to serde_json::to_value(original_tool) to serialize the original_tool,
ensuring strip_internal_mcp_tools() collisions do not revive internal MCP
schemas.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2d9fd637-7f0f-4a9b-9dd9-1c3efca6f2b2

📥 Commits

Reviewing files that changed from the base of the PR and between 8637b87 and c9a7b32.

📒 Files selected for processing (1)
  • model_gateway/src/routers/openai/responses/utils.rs

Comment thread model_gateway/src/routers/openai/responses/utils.rs
Comment thread model_gateway/src/routers/openai/responses/utils.rs
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f7b64a5af

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/openai/mcp/tool_loop.rs
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
@zhoug9127 zhoug9127 merged commit 1da8527 into lightseekorg:main Apr 10, 2026
46 checks passed
slin1237 added a commit that referenced this pull request Apr 18, 2026
…ector

Both have been the consistent primary authors of recent PRs in these subsystems:

- @zhoug9127 (Daisy): #1168, #1149, #1065, #1061, #976 — mcp + data_connector
- @zhaowenzi (Ziwen): #1174, #1163, #1123 — mcp

Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
TingtingZhou7 pushed a commit to TingtingZhou7/smg that referenced this pull request Apr 18, 2026
lightseekorg#1061)

Signed-off-by: zhoug9127 <daisy.zhou@oracle.com>
Signed-off-by: zhoug9127 <zhoug9127@gmail.com>
Signed-off-by: Daisy Zhou <zhoug9127@gmail.com>
Co-authored-by: zhoug9127 <daisy.zhou@oracle.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation mcp MCP related changes model-gateway Model gateway crate changes openai OpenAI router changes tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants