mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
chore: spawn MCP for memories (#21214)
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
8f3bb355f4
commit
ca257b6ce5
Generated
+13
@@ -2126,6 +2126,17 @@ dependencies = [
|
||||
"serde_with",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-builtin-mcps"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"codex-config",
|
||||
"codex-memories-mcp",
|
||||
"codex-utils-absolute-path",
|
||||
"pretty_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-bwrap"
|
||||
version = "0.0.0"
|
||||
@@ -2171,6 +2182,7 @@ dependencies = [
|
||||
"codex-app-server-protocol",
|
||||
"codex-app-server-test-client",
|
||||
"codex-arg0",
|
||||
"codex-builtin-mcps",
|
||||
"codex-chatgpt",
|
||||
"codex-cloud-tasks",
|
||||
"codex-config",
|
||||
@@ -2998,6 +3010,7 @@ dependencies = [
|
||||
"async-channel",
|
||||
"codex-api",
|
||||
"codex-async-utils",
|
||||
"codex-builtin-mcps",
|
||||
"codex-config",
|
||||
"codex-exec-server",
|
||||
"codex-login",
|
||||
|
||||
@@ -5,6 +5,7 @@ members = [
|
||||
"agent-graph-store",
|
||||
"agent-identity",
|
||||
"backend-client",
|
||||
"builtin-mcps",
|
||||
"bwrap",
|
||||
"ansi-escape",
|
||||
"async-utils",
|
||||
@@ -138,6 +139,7 @@ codex-apply-patch = { path = "apply-patch" }
|
||||
codex-arg0 = { path = "arg0" }
|
||||
codex-async-utils = { path = "async-utils" }
|
||||
codex-backend-client = { path = "backend-client" }
|
||||
codex-builtin-mcps = { path = "builtin-mcps" }
|
||||
codex-chatgpt = { path = "chatgpt" }
|
||||
codex-cli = { path = "cli" }
|
||||
codex-client = { path = "codex-client" }
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
codex_rust_crate(
|
||||
name = "builtin-mcps",
|
||||
crate_name = "codex_builtin_mcps",
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
name = "codex-builtin-mcps"
|
||||
version.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "codex_builtin_mcps"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-memories-mcp = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = { workspace = true }
|
||||
@@ -0,0 +1,132 @@
|
||||
//! Built-in MCP servers shipped with Codex.
|
||||
//!
|
||||
//! Built-ins use the same stdio MCP path as user-configured servers, but are
|
||||
//! declared here so product-owned MCPs do not need to live in `codex-core`.
|
||||
|
||||
use codex_config::McpServerConfig;
|
||||
use codex_config::McpServerTransportConfig;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
pub const MEMORIES_MCP_SERVER_NAME: &str = "memories";
|
||||
const BUILTIN_MCP_SUBCOMMAND: &str = "builtin-mcp";
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BuiltinMcpServerOptions<'a> {
|
||||
pub codex_self_exe: Option<&'a Path>,
|
||||
pub codex_home: &'a Path,
|
||||
pub memories_enabled: bool,
|
||||
}
|
||||
|
||||
pub fn configured_builtin_mcp_servers(
|
||||
options: BuiltinMcpServerOptions<'_>,
|
||||
) -> HashMap<String, McpServerConfig> {
|
||||
let Some(codex_self_exe) = options.codex_self_exe else {
|
||||
return HashMap::new();
|
||||
};
|
||||
|
||||
let mut servers = HashMap::new();
|
||||
if options.memories_enabled {
|
||||
servers.insert(
|
||||
MEMORIES_MCP_SERVER_NAME.to_string(),
|
||||
builtin_stdio_server_config(
|
||||
codex_self_exe,
|
||||
options.codex_home,
|
||||
MEMORIES_MCP_SERVER_NAME,
|
||||
),
|
||||
);
|
||||
}
|
||||
servers
|
||||
}
|
||||
|
||||
pub async fn run_builtin_mcp_server(
|
||||
name: &str,
|
||||
codex_home: &AbsolutePathBuf,
|
||||
) -> anyhow::Result<()> {
|
||||
match name {
|
||||
MEMORIES_MCP_SERVER_NAME => codex_memories_mcp::run_stdio_server(codex_home).await,
|
||||
_ => anyhow::bail!("unknown built-in MCP server: {name}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_stdio_server_config(
|
||||
codex_self_exe: &Path,
|
||||
codex_home: &Path,
|
||||
name: &str,
|
||||
) -> McpServerConfig {
|
||||
McpServerConfig {
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: codex_self_exe.to_string_lossy().into_owned(),
|
||||
args: vec![
|
||||
BUILTIN_MCP_SUBCOMMAND.to_string(),
|
||||
name.to_string(),
|
||||
"--codex-home".to_string(),
|
||||
codex_home.to_string_lossy().into_owned(),
|
||||
],
|
||||
env: None,
|
||||
env_vars: Vec::new(),
|
||||
cwd: None,
|
||||
},
|
||||
experimental_environment: None,
|
||||
enabled: true,
|
||||
required: false,
|
||||
supports_parallel_tool_calls: true,
|
||||
disabled_reason: None,
|
||||
startup_timeout_sec: None,
|
||||
tool_timeout_sec: None,
|
||||
default_tools_approval_mode: None,
|
||||
enabled_tools: None,
|
||||
disabled_tools: None,
|
||||
scopes: None,
|
||||
oauth_resource: None,
|
||||
tools: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn configured_builtin_mcp_servers_adds_memories_when_enabled() {
|
||||
let codex_home = AbsolutePathBuf::try_from("/tmp/codex-home").expect("absolute codex home");
|
||||
let servers = configured_builtin_mcp_servers(BuiltinMcpServerOptions {
|
||||
codex_self_exe: Some(Path::new("/tmp/codex")),
|
||||
codex_home: codex_home.as_path(),
|
||||
memories_enabled: true,
|
||||
});
|
||||
|
||||
let server = servers
|
||||
.get(MEMORIES_MCP_SERVER_NAME)
|
||||
.expect("memories server should exist");
|
||||
assert_eq!(
|
||||
server.transport,
|
||||
McpServerTransportConfig::Stdio {
|
||||
command: "/tmp/codex".to_string(),
|
||||
args: vec![
|
||||
"builtin-mcp".to_string(),
|
||||
"memories".to_string(),
|
||||
"--codex-home".to_string(),
|
||||
"/tmp/codex-home".to_string(),
|
||||
],
|
||||
env: None,
|
||||
env_vars: Vec::new(),
|
||||
cwd: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn configured_builtin_mcp_servers_requires_reexec_path() {
|
||||
let codex_home = AbsolutePathBuf::try_from("/tmp/codex-home").expect("absolute codex home");
|
||||
let servers = configured_builtin_mcp_servers(BuiltinMcpServerOptions {
|
||||
codex_self_exe: None,
|
||||
codex_home: codex_home.as_path(),
|
||||
memories_enabled: true,
|
||||
});
|
||||
|
||||
assert!(servers.is_empty());
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ codex-app-server = { workspace = true }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-app-server-test-client = { workspace = true }
|
||||
codex-arg0 = { workspace = true }
|
||||
codex-builtin-mcps = { workspace = true }
|
||||
codex-chatgpt = { workspace = true }
|
||||
codex-cloud-tasks = { path = "../cloud-tasks" }
|
||||
codex-utils-cli = { workspace = true }
|
||||
|
||||
@@ -123,6 +123,10 @@ enum Subcommand {
|
||||
/// Start Codex as an MCP server (stdio).
|
||||
McpServer,
|
||||
|
||||
/// Internal: start a Codex-shipped MCP server (stdio).
|
||||
#[clap(hide = true, name = "builtin-mcp")]
|
||||
BuiltinMcp(BuiltinMcpCommand),
|
||||
|
||||
/// [experimental] Run the app server or related tooling.
|
||||
AppServer(AppServerCommand),
|
||||
|
||||
@@ -175,6 +179,13 @@ enum Subcommand {
|
||||
Features(FeaturesCli),
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
struct BuiltinMcpCommand {
|
||||
name: String,
|
||||
#[arg(long)]
|
||||
codex_home: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(bin_name = "codex plugin")]
|
||||
struct PluginCli {
|
||||
@@ -809,6 +820,15 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
)?;
|
||||
codex_mcp_server::run_main(arg0_paths.clone(), root_config_overrides).await?;
|
||||
}
|
||||
Some(Subcommand::BuiltinMcp(command)) => {
|
||||
reject_remote_mode_for_subcommand(
|
||||
root_remote.as_deref(),
|
||||
root_remote_auth_token_env.as_deref(),
|
||||
"builtin-mcp",
|
||||
)?;
|
||||
let codex_home = AbsolutePathBuf::try_from(command.codex_home)?;
|
||||
codex_builtin_mcps::run_builtin_mcp_server(&command.name, &codex_home).await?;
|
||||
}
|
||||
Some(Subcommand::Mcp(mut mcp_cli)) => {
|
||||
reject_remote_mode_for_subcommand(
|
||||
root_remote.as_deref(),
|
||||
|
||||
@@ -16,6 +16,7 @@ anyhow = { workspace = true }
|
||||
async-channel = { workspace = true }
|
||||
codex-async-utils = { workspace = true }
|
||||
codex-api = { workspace = true }
|
||||
codex-builtin-mcps = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-exec-server = { workspace = true }
|
||||
codex-login = { workspace = true }
|
||||
|
||||
@@ -19,6 +19,9 @@ pub use auth_elicitation::build_auth_elicitation_plan;
|
||||
pub use auth_elicitation::connector_auth_failure_from_tool_result;
|
||||
pub use codex_apps::CodexAppsToolsCacheKey;
|
||||
pub use codex_apps::codex_apps_tools_cache_key;
|
||||
pub use codex_builtin_mcps::BuiltinMcpServerOptions;
|
||||
pub use codex_builtin_mcps::MEMORIES_MCP_SERVER_NAME;
|
||||
pub use codex_builtin_mcps::configured_builtin_mcp_servers;
|
||||
|
||||
pub use mcp::configured_mcp_servers;
|
||||
pub use mcp::effective_mcp_servers;
|
||||
|
||||
@@ -129,7 +129,11 @@ pub struct McpConfig {
|
||||
/// ChatGPT auth is checked separately at runtime before the built-in apps
|
||||
/// MCP server is added.
|
||||
pub apps_enabled: bool,
|
||||
/// User-configured and plugin-provided MCP servers keyed by server name.
|
||||
/// Configured MCP servers keyed by server name.
|
||||
///
|
||||
/// This includes product-owned built-ins, user-configured servers, and
|
||||
/// plugin-provided servers. Runtime-only additions belong in
|
||||
/// [`effective_mcp_servers`].
|
||||
pub configured_mcp_servers: HashMap<String, McpServerConfig>,
|
||||
/// Plugin metadata used to attribute MCP tools/connectors to plugin display names.
|
||||
pub plugin_capability_summaries: Vec<PluginCapabilitySummary>,
|
||||
|
||||
@@ -379,6 +379,9 @@
|
||||
"browser_use_external": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"builtin_mcp": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"child_agents_md": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -3931,6 +3934,9 @@
|
||||
"browser_use_external": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"builtin_mcp": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"child_agents_md": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -195,12 +195,13 @@ async fn load_config_loads_global_agents_instructions() -> std::io::Result<()> {
|
||||
"\n global instructions \n",
|
||||
)?;
|
||||
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
let mut config = Config::load_from_base_config_with_overrides(
|
||||
ConfigToml::default(),
|
||||
ConfigOverrides::default(),
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
let _ = config.features.enable(Feature::MemoryTool);
|
||||
|
||||
assert_eq!(
|
||||
config.user_instructions.as_deref(),
|
||||
@@ -3344,6 +3345,77 @@ async fn add_dir_override_extends_workspace_writable_roots() -> std::io::Result<
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_mcp_config_empty_mcp_requirements_preserve_builtin_mcps() -> anyhow::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let requirements = codex_config::ConfigRequirementsToml {
|
||||
mcp_servers: Some(BTreeMap::new()),
|
||||
..Default::default()
|
||||
};
|
||||
let mut config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.cloud_requirements(CloudRequirementsLoader::new(async move {
|
||||
Ok(Some(requirements))
|
||||
}))
|
||||
.build()
|
||||
.await?;
|
||||
config.codex_self_exe = Some(PathBuf::from("/tmp/codex"));
|
||||
let _ = config.features.enable(Feature::BuiltInMcp);
|
||||
let _ = config.features.enable(Feature::MemoryTool);
|
||||
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||
|
||||
let mcp_config = config.to_mcp_config(&plugins_manager).await;
|
||||
|
||||
assert_eq!(
|
||||
mcp_config
|
||||
.configured_mcp_servers
|
||||
.get(codex_mcp::MEMORIES_MCP_SERVER_NAME)
|
||||
.map(|server| (server.enabled, server.disabled_reason.clone())),
|
||||
Some((true, None))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_mcp_config_nonempty_mcp_requirements_preserve_builtin_mcps() -> anyhow::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let requirements = codex_config::ConfigRequirementsToml {
|
||||
mcp_servers: Some(BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerRequirement {
|
||||
identity: McpServerIdentity::Command {
|
||||
command: "docs-mcp".to_string(),
|
||||
},
|
||||
},
|
||||
)])),
|
||||
..Default::default()
|
||||
};
|
||||
let mut config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.cloud_requirements(CloudRequirementsLoader::new(async move {
|
||||
Ok(Some(requirements))
|
||||
}))
|
||||
.build()
|
||||
.await?;
|
||||
config.codex_self_exe = Some(PathBuf::from("/tmp/codex"));
|
||||
let _ = config.features.enable(Feature::BuiltInMcp);
|
||||
let _ = config.features.enable(Feature::MemoryTool);
|
||||
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||
|
||||
let mcp_config = config.to_mcp_config(&plugins_manager).await;
|
||||
|
||||
assert_eq!(
|
||||
mcp_config
|
||||
.configured_mcp_servers
|
||||
.get(codex_mcp::MEMORIES_MCP_SERVER_NAME)
|
||||
.map(|server| (server.enabled, server.disabled_reason.clone())),
|
||||
Some((true, None))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sqlite_home_defaults_to_codex_home_for_workspace_write() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
@@ -4166,6 +4238,107 @@ async fn to_mcp_config_preserves_apps_feature_from_config() -> std::io::Result<(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_mcp_config_includes_enabled_builtin_mcps() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let mut config = Config::load_from_base_config_with_overrides(
|
||||
ConfigToml::default(),
|
||||
ConfigOverrides {
|
||||
codex_self_exe: Some(PathBuf::from("/tmp/codex")),
|
||||
..ConfigOverrides::default()
|
||||
},
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
let _ = config.features.enable(Feature::BuiltInMcp);
|
||||
let _ = config.features.enable(Feature::MemoryTool);
|
||||
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||
|
||||
let mcp_config = config.to_mcp_config(&plugins_manager).await;
|
||||
|
||||
assert_eq!(
|
||||
mcp_config
|
||||
.configured_mcp_servers
|
||||
.get(codex_mcp::MEMORIES_MCP_SERVER_NAME)
|
||||
.map(|server| &server.transport),
|
||||
Some(&McpServerTransportConfig::Stdio {
|
||||
command: "/tmp/codex".to_string(),
|
||||
args: vec![
|
||||
"builtin-mcp".to_string(),
|
||||
"memories".to_string(),
|
||||
"--codex-home".to_string(),
|
||||
codex_home.path().display().to_string(),
|
||||
],
|
||||
env: None,
|
||||
env_vars: Vec::new(),
|
||||
cwd: None,
|
||||
})
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_mcp_config_omits_builtin_mcps_when_feature_is_disabled() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let mut config = Config::load_from_base_config_with_overrides(
|
||||
ConfigToml::default(),
|
||||
ConfigOverrides {
|
||||
codex_self_exe: Some(PathBuf::from("/tmp/codex")),
|
||||
..ConfigOverrides::default()
|
||||
},
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
let _ = config.features.enable(Feature::MemoryTool);
|
||||
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||
|
||||
let mcp_config = config.to_mcp_config(&plugins_manager).await;
|
||||
|
||||
assert!(
|
||||
!mcp_config
|
||||
.configured_mcp_servers
|
||||
.contains_key(codex_mcp::MEMORIES_MCP_SERVER_NAME)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_mcp_config_reserves_enabled_builtin_mcp_names() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let mut config = Config::load_from_base_config_with_overrides(
|
||||
ConfigToml {
|
||||
mcp_servers: HashMap::from([(
|
||||
codex_mcp::MEMORIES_MCP_SERVER_NAME.to_string(),
|
||||
http_mcp("https://user.example/memories"),
|
||||
)]),
|
||||
..ConfigToml::default()
|
||||
},
|
||||
ConfigOverrides {
|
||||
codex_self_exe: Some(PathBuf::from("/tmp/codex")),
|
||||
..ConfigOverrides::default()
|
||||
},
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
let _ = config.features.enable(Feature::BuiltInMcp);
|
||||
let _ = config.features.enable(Feature::MemoryTool);
|
||||
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||
|
||||
let mcp_config = config.to_mcp_config(&plugins_manager).await;
|
||||
|
||||
assert!(matches!(
|
||||
mcp_config
|
||||
.configured_mcp_servers
|
||||
.get(codex_mcp::MEMORIES_MCP_SERVER_NAME)
|
||||
.map(|server| &server.transport),
|
||||
Some(McpServerTransportConfig::Stdio { .. })
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn load_global_mcp_servers_rejects_inline_bearer_token() -> anyhow::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
|
||||
@@ -70,7 +70,9 @@ use codex_features::FeaturesToml;
|
||||
use codex_features::MultiAgentV2ConfigToml;
|
||||
use codex_git_utils::resolve_root_git_project_for_trust;
|
||||
use codex_login::AuthManagerConfig;
|
||||
use codex_mcp::BuiltinMcpServerOptions;
|
||||
use codex_mcp::McpConfig;
|
||||
use codex_mcp::configured_builtin_mcp_servers;
|
||||
use codex_memories_read::memory_root;
|
||||
use codex_model_provider_info::LEGACY_OLLAMA_CHAT_PROVIDER_ID;
|
||||
use codex_model_provider_info::ModelProviderInfo;
|
||||
@@ -1087,6 +1089,13 @@ impl Config {
|
||||
) -> McpConfig {
|
||||
let plugins_input = self.plugins_config_input();
|
||||
let loaded_plugins = plugins_manager.plugins_for_config(&plugins_input).await;
|
||||
let builtin_mcp_servers = configured_builtin_mcp_servers(BuiltinMcpServerOptions {
|
||||
codex_self_exe: self.codex_self_exe.as_deref(),
|
||||
codex_home: self.codex_home.as_path(),
|
||||
memories_enabled: self.features.enabled(Feature::BuiltInMcp)
|
||||
&& self.features.enabled(Feature::MemoryTool)
|
||||
&& self.memories.use_memories,
|
||||
});
|
||||
let mut configured_mcp_servers = self.mcp_servers.get().clone();
|
||||
for plugin in loaded_plugins
|
||||
.plugins()
|
||||
@@ -1106,9 +1115,12 @@ impl Config {
|
||||
if let Some(mcp_requirements) = self.config_layer_stack.requirements().mcp_servers.as_ref()
|
||||
&& mcp_requirements.value.is_empty()
|
||||
{
|
||||
// A present empty allowlist bans all MCPs, including plugin MCPs merged above.
|
||||
// A present empty allowlist bans configurable MCPs, including plugin MCPs merged
|
||||
// above. Built-ins are product-owned and stay available regardless of admin
|
||||
// allowlists.
|
||||
filter_mcp_servers_by_requirements(&mut configured_mcp_servers, Some(mcp_requirements));
|
||||
}
|
||||
configured_mcp_servers.extend(builtin_mcp_servers);
|
||||
|
||||
McpConfig {
|
||||
chatgpt_base_url: self.chatgpt_base_url.clone(),
|
||||
|
||||
@@ -134,6 +134,8 @@ pub enum Feature {
|
||||
Sqlite,
|
||||
/// Enable startup memory extraction and file-backed memory consolidation.
|
||||
MemoryTool,
|
||||
/// Enable product-owned built-in MCP servers.
|
||||
BuiltInMcp,
|
||||
/// Enable the Chronicle sidecar for passive screen-context memories.
|
||||
Chronicle,
|
||||
/// Append additional AGENTS.md guidance to user instructions.
|
||||
@@ -793,6 +795,12 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
},
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::BuiltInMcp,
|
||||
key: "builtin_mcp",
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::Chronicle,
|
||||
key: "chronicle",
|
||||
|
||||
@@ -129,6 +129,13 @@ fn remote_compaction_v2_is_under_development() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_mcp_is_under_development() {
|
||||
assert_eq!(Feature::BuiltInMcp.stage(), Stage::UnderDevelopment);
|
||||
assert_eq!(Feature::BuiltInMcp.default_enabled(), false);
|
||||
assert_eq!(feature_for_key("builtin_mcp"), Some(Feature::BuiltInMcp));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_resize_reflow_is_experimental_and_enabled_by_default() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -10,6 +10,8 @@ Runtime orchestration for Phase 1 and Phase 2 still lives in `codex-core` under
|
||||
- `codex-rs/memories/read` (`codex-memories-read`) owns the read path:
|
||||
memory developer-instruction injection, memory citation parsing, and
|
||||
read-usage telemetry classification.
|
||||
- `codex-rs/memories/mcp` (`codex-memories-mcp`) exposes the read-only memory
|
||||
filesystem through the built-in MCP surface.
|
||||
- `codex-rs/memories/write` (`codex-memories-write`) owns the write path:
|
||||
Phase 1 and Phase 2 prompt rendering, filesystem artifact helpers,
|
||||
workspace diff helpers, and extension resource pruning.
|
||||
|
||||
Reference in New Issue
Block a user