feat: load from plugins (#12864)

Support loading plugins.

Plugins can now be enabled via [plugins.<name>] in config.toml. They are
loaded as first-class entities through PluginsManager, and their default
skills/ and .mcp.json contributions are integrated into the existing
skills and MCP flows.
This commit is contained in:
xl-openai
2026-03-01 10:50:56 -08:00
committed by GitHub
parent 6a673e7339
commit 752402c4fe
24 changed files with 1389 additions and 113 deletions

View File

@@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::sync::Arc;
use anyhow::Context;
use anyhow::Result;
@@ -11,9 +12,11 @@ use codex_core::config::find_codex_home;
use codex_core::config::load_global_mcp_servers;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_core::mcp::McpManager;
use codex_core::mcp::auth::McpOAuthLoginSupport;
use codex_core::mcp::auth::compute_auth_statuses;
use codex_core::mcp::auth::oauth_login_support;
use codex_core::plugins::PluginsManager;
use codex_protocol::protocol::McpAuthStatus;
use codex_rmcp_client::delete_oauth_tokens;
use codex_rmcp_client::perform_oauth_login;
@@ -329,10 +332,12 @@ async fn run_login(config_overrides: &CliConfigOverrides, login_args: LoginArgs)
let config = Config::load_with_cli_overrides(overrides)
.await
.context("failed to load configuration")?;
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(config.codex_home.clone())));
let mcp_servers = mcp_manager.effective_servers(&config, None);
let LoginArgs { name, scopes } = login_args;
let Some(server) = config.mcp_servers.get().get(&name) else {
let Some(server) = mcp_servers.get(&name) else {
bail!("No MCP server named '{name}' found.");
};
@@ -374,12 +379,12 @@ async fn run_logout(config_overrides: &CliConfigOverrides, logout_args: LogoutAr
let config = Config::load_with_cli_overrides(overrides)
.await
.context("failed to load configuration")?;
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(config.codex_home.clone())));
let mcp_servers = mcp_manager.effective_servers(&config, None);
let LogoutArgs { name } = logout_args;
let server = config
.mcp_servers
.get()
let server = mcp_servers
.get(&name)
.ok_or_else(|| anyhow!("No MCP server named '{name}' found in configuration."))?;
@@ -404,14 +409,13 @@ async fn run_list(config_overrides: &CliConfigOverrides, list_args: ListArgs) ->
let config = Config::load_with_cli_overrides(overrides)
.await
.context("failed to load configuration")?;
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(config.codex_home.clone())));
let mcp_servers = mcp_manager.effective_servers(&config, None);
let mut entries: Vec<_> = config.mcp_servers.iter().collect();
let mut entries: Vec<_> = mcp_servers.iter().collect();
entries.sort_by(|(a, _), (b, _)| a.cmp(b));
let auth_statuses = compute_auth_statuses(
config.mcp_servers.iter(),
config.mcp_oauth_credentials_store_mode,
)
.await;
let auth_statuses =
compute_auth_statuses(mcp_servers.iter(), config.mcp_oauth_credentials_store_mode).await;
if list_args.json {
let json_entries: Vec<_> = entries
@@ -654,8 +658,10 @@ async fn run_get(config_overrides: &CliConfigOverrides, get_args: GetArgs) -> Re
let config = Config::load_with_cli_overrides(overrides)
.await
.context("failed to load configuration")?;
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(config.codex_home.clone())));
let mcp_servers = mcp_manager.effective_servers(&config, None);
let Some(server) = config.mcp_servers.get().get(&get_args.name) else {
let Some(server) = mcp_servers.get(&get_args.name) else {
bail!("No MCP server named '{name}' found.", name = get_args.name);
};