Files
codex/codex-rs/codex-mcp/src/user_verification_elicitation.rs
T
sayan-oai 561f0f5cf0 Keep same-named MCP servers separate across environments (#60905)
## Why

MCP servers discovered on different executors can share a name. Resolving them by name alone exposes only one server and prevents tools and resources from being addressed independently.

## What changed

- Add the disabled-by-default `multi_environment_mcp` feature to expose environment-scoped servers, including multiple installations of the same plugin.
- Carry exact `McpServerKey` identities through catalogs, connections, tool calls, resources, and approval tracking. Give environment-scoped tools stable namespaces derived from their environment.
- Include `environment_id` in scoped resource listings and accept it in resource requests. Require it for environment-owned servers when multiple environments are selected.
- Preserve server ownership through hooks and use the owning environment's permissions for scoped elicitation review.

## Testing

Add coverage for same-named servers across environments, independent calls and approvals, resource selection, plugin discovery, and rejection of hook changes to the tool environment.

GitOrigin-RevId: 5593372b06a15c16aa3220faa3b19f5d3b20e67e
2026-11-11 23:36:19 +00:00

39 lines
1.2 KiB
Rust

//! Routes device verification directly to the app, outside automated approval policy.
use super::*;
pub(super) async fn route(
router: ElicitationRequestRouter,
events: Option<Sender<Event>>,
authority: Option<ElicitationAuthority>,
server_key: McpServerKey,
request: ElicitationRequest,
) -> Result<ElicitationResponse> {
let plugin_service = authority.as_ref().is_some_and(|authority| {
authority
.config
.mcp_server_catalog
.server(&server_key)
.is_some_and(|server| {
server
.source()
.is_host_owned_apps(server_key.name(), server.config())
})
});
let Some((events, authority)) = events.zip(authority).filter(|_| plugin_service) else {
return Ok(ElicitationResponse {
action: ElicitationAction::Cancel,
content: None,
meta: Some(codex_rmcp_client::UserVerificationReason::ApprovalUnavailable.into_meta()),
});
};
router
.request_user_interaction(
Some(events),
&authority,
server_key.name().to_owned(),
request,
)
.await
}