mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Dedupe plugin MCPs by app declaration name (#27607)
## Context
This is the next step in the plugin auth-routing stack. The earlier PRs
make `PluginsManager` auth-aware and move the broad App/MCP surface
decision into that layer. This PR narrows the ChatGPT/SIWC behavior so
we only hide a plugin MCP server when it conflicts with an App
declaration of the same name.
In product terms: if a plugin exposes both an App route and MCP route
for `foo`, ChatGPT/SIWC sessions should use the App route for `foo`. If
the same plugin also exposes a separate MCP server like `foo2`, that MCP
server should remain available.
```json
// .app.json
{
"apps": {
"foo": {
"id": "connector_abc"
}
}
}
```
```json
// .mcp.json
{
"mcpServers": {
"foo": {
"url": "https://mcp.foo.com/mcp"
},
"foo2": {
"url": "https://mcp.foo2.com/mcp"
}
}
}
```
## Stack
- PR1: #27652 seed plugin manager auth at construction.
- PR2: #27459 route plugin surfaces by auth mode.
- PR3: #27607 dedupe plugin MCP servers by App declaration name.
- PR4: #27602 preserve plugin Apps in connector listings.
- PR5: #27461 skip install-time plugin MCP OAuth for matching App
routes.
## Summary
- Preserve App declaration names in loaded plugin metadata.
- Keep public effective App outputs as deduped connector IDs for
existing callers.
- For ChatGPT/SIWC, suppress only plugin MCP servers whose names match
declared App names.
## Validation
```bash
cargo fmt --all
cargo test -p codex-core-plugins plugin_auth_projection
cargo test -p codex-core-plugins effective_apps
cargo test -p codex-core-plugins read_plugin_for_config_installed_git_source_reads_from_cache_without_cloning
cargo test -p codex-core explicit_plugin_mentions_use_apps_for_chatgpt_dual_surface_plugins
cargo test -p codex-core explicit_plugin_mentions_keep_non_conflicting_mcp_for_chatgpt_auth
cargo test -p codex-app-server --test all plugin_install_filters_disallowed_apps_needing_auth
git diff --check
```
---------
Co-authored-by: Xin Lin <xl@openai.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
0fed4497f5
commit
51316ead4a
@@ -5,7 +5,7 @@ use crate::loader::PluginHookLoadOutcome;
|
||||
use crate::loader::configured_curated_plugin_ids_from_codex_home;
|
||||
use crate::loader::curated_plugin_cache_version;
|
||||
use crate::loader::installed_plugin_telemetry_metadata;
|
||||
use crate::loader::load_plugin_app_metadata;
|
||||
use crate::loader::load_plugin_apps;
|
||||
use crate::loader::load_plugin_hooks;
|
||||
use crate::loader::load_plugin_hooks_from_layer_stack;
|
||||
use crate::loader::load_plugin_mcp_servers;
|
||||
@@ -63,6 +63,7 @@ use codex_plugin::AppConnectorId;
|
||||
use codex_plugin::PluginCapabilitySummary;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_plugin::PluginIdError;
|
||||
use codex_plugin::app_connector_ids_from_declarations;
|
||||
use codex_plugin::prompt_safe_plugin_description;
|
||||
use codex_protocol::protocol::HookEventName;
|
||||
use codex_protocol::protocol::Product;
|
||||
@@ -214,7 +215,14 @@ fn project_plugin_load_outcome_for_auth(
|
||||
for plugin in &mut plugins {
|
||||
if apps_route_available {
|
||||
if plugin.is_active() && !plugin.apps.is_empty() {
|
||||
plugin.mcp_servers.clear();
|
||||
let app_declaration_names = plugin
|
||||
.apps
|
||||
.iter()
|
||||
.map(|app| app.name.as_str())
|
||||
.collect::<HashSet<_>>();
|
||||
plugin
|
||||
.mcp_servers
|
||||
.retain(|name, _| !app_declaration_names.contains(name.as_str()));
|
||||
}
|
||||
} else {
|
||||
plugin.apps.clear();
|
||||
@@ -1311,12 +1319,17 @@ impl PluginsManager {
|
||||
event_name: hook.event_name,
|
||||
})
|
||||
.collect();
|
||||
let app_metadata = load_plugin_app_metadata(source_path.as_path()).await;
|
||||
let apps = app_metadata.iter().map(|app| app.id.clone()).collect();
|
||||
let app_category_by_id = app_metadata
|
||||
.into_iter()
|
||||
.filter_map(|app| app.category.map(|category| (app.id.0, category)))
|
||||
.collect();
|
||||
let app_declarations = load_plugin_apps(source_path.as_path()).await;
|
||||
let apps = app_connector_ids_from_declarations(&app_declarations);
|
||||
let mut seen_app_connector_ids = HashSet::new();
|
||||
let mut app_category_by_id = HashMap::new();
|
||||
for app in &app_declarations {
|
||||
if seen_app_connector_ids.insert(app.connector_id.0.as_str())
|
||||
&& let Some(category) = &app.category
|
||||
{
|
||||
app_category_by_id.insert(app.connector_id.0.clone(), category.clone());
|
||||
}
|
||||
}
|
||||
let mut mcp_server_names = load_plugin_mcp_servers(source_path.as_path())
|
||||
.await
|
||||
.into_keys()
|
||||
|
||||
Reference in New Issue
Block a user