mirror of
https://github.com/openai/codex.git
synced 2026-11-04 00:24:43 +00:00
Allow ChatGPT-hosted MCP servers to use session auth (#29733)
## Why ChatGPT session authentication was inferred from the reserved Codex Apps server name. That couples credential routing to Codex Apps-specific behavior and prevents other MCP endpoints hosted by ChatGPT from explicitly using the current session. The opt-in also needs a clear security boundary: an arbitrary MCP configuration must not be able to redirect ChatGPT credentials to another origin. ## What changed - Add `use_chatgpt_auth` to HTTP MCP server configuration, defaulting to `false`. - Honor the setting only when the parsed server URL has the same HTTP(S) origin as the configured `chatgpt_base_url`; otherwise remove the capability before startup. - Resolve bearer tokens and static or environment-backed authorization headers before selecting authentication, with configured authorization taking precedence over ChatGPT session auth. - Enable the setting for the built-in Codex Apps and hosted plugin runtime endpoints while keeping Codex Apps caching and tool normalization scoped to the reserved server. - Persist the setting through MCP config rewrite paths and expose it in the generated config schema. - Load the current login state for `codex mcp list` so reported auth status matches runtime behavior. ## Verification Core integration coverage exercises the complete streamable HTTP MCP startup path and verifies that: - a same-origin opted-in server receives the current ChatGPT access token; - an explicitly configured authorization header takes precedence; - a different-origin server completes MCP initialization and tool listing without receiving any ChatGPT authorization header.
This commit is contained in:
1 parent
a0d5fd772e
commit
4c0706e24a
29 files changed
+313
-59
No files matched your search
@@ -114,6 +114,7 @@ use tempfile::TempDir;
|
||||
|
||||
fn stdio_mcp(command: &str) -> McpServerConfig {
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: command.to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -140,6 +141,7 @@ fn stdio_mcp(command: &str) -> McpServerConfig {
|
||||
|
||||
fn http_mcp(url: &str) -> McpServerConfig {
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: url.to_string(),
|
||||
bearer_token_env_var: None,
|
||||
@@ -5566,6 +5568,7 @@ async fn replace_mcp_servers_round_trips_entries() -> anyhow::Result<()> {
|
||||
servers.insert(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "echo".to_string(),
|
||||
args: vec!["hello".to_string()],
|
||||
@@ -5923,6 +5926,7 @@ async fn replace_mcp_servers_serializes_env_sorted() -> anyhow::Result<()> {
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: vec!["--verbose".to_string()],
|
||||
@@ -6002,6 +6006,7 @@ async fn replace_mcp_servers_serializes_env_vars() -> anyhow::Result<()> {
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -6057,6 +6062,7 @@ async fn replace_mcp_servers_serializes_sourced_env_vars() -> anyhow::Result<()>
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -6115,6 +6121,7 @@ async fn replace_mcp_servers_serializes_cwd() -> anyhow::Result<()> {
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -6170,6 +6177,7 @@ async fn replace_mcp_servers_streamable_http_serializes_bearer_token() -> anyhow
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: "https://example.com/mcp".to_string(),
|
||||
bearer_token_env_var: Some("MCP_TOKEN".to_string()),
|
||||
@@ -6237,6 +6245,7 @@ async fn replace_mcp_servers_streamable_http_serializes_custom_headers() -> anyh
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: "https://example.com/mcp".to_string(),
|
||||
bearer_token_env_var: Some("MCP_TOKEN".to_string()),
|
||||
@@ -6319,6 +6328,7 @@ async fn replace_mcp_servers_streamable_http_removes_optional_sections() -> anyh
|
||||
let mut servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: "https://example.com/mcp".to_string(),
|
||||
bearer_token_env_var: Some("MCP_TOKEN".to_string()),
|
||||
@@ -6357,6 +6367,7 @@ async fn replace_mcp_servers_streamable_http_removes_optional_sections() -> anyh
|
||||
servers.insert(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: "https://example.com/mcp".to_string(),
|
||||
bearer_token_env_var: None,
|
||||
@@ -6424,6 +6435,7 @@ async fn replace_mcp_servers_streamable_http_isolates_headers_between_servers()
|
||||
(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: "https://example.com/mcp".to_string(),
|
||||
bearer_token_env_var: Some("MCP_TOKEN".to_string()),
|
||||
@@ -6452,6 +6464,7 @@ async fn replace_mcp_servers_streamable_http_isolates_headers_between_servers()
|
||||
(
|
||||
"logs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "logs-server".to_string(),
|
||||
args: vec!["--follow".to_string()],
|
||||
@@ -6540,6 +6553,7 @@ async fn replace_mcp_servers_serializes_disabled_flag() -> anyhow::Result<()> {
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -6590,6 +6604,7 @@ async fn replace_mcp_servers_serializes_required_flag() -> anyhow::Result<()> {
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -6640,6 +6655,7 @@ async fn replace_mcp_servers_serializes_tool_filters() -> anyhow::Result<()> {
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -6695,6 +6711,7 @@ async fn replace_mcp_servers_streamable_http_serializes_oauth_resource() -> anyh
|
||||
let servers = BTreeMap::from([(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: "https://example.com/mcp".to_string(),
|
||||
bearer_token_env_var: None,
|
||||
|
||||
@@ -95,6 +95,9 @@ fn serialize_mcp_server_table(config: &McpServerConfig) -> TomlTable {
|
||||
}
|
||||
}
|
||||
|
||||
if config.use_chatgpt_auth {
|
||||
entry["use_chatgpt_auth"] = value(true);
|
||||
}
|
||||
if !config.enabled {
|
||||
entry["enabled"] = value(false);
|
||||
}
|
||||
|
||||
@@ -873,6 +873,7 @@ fn blocking_replace_mcp_servers_round_trips() {
|
||||
servers.insert(
|
||||
"stdio".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "cmd".to_string(),
|
||||
args: vec!["--flag".to_string()],
|
||||
@@ -907,6 +908,7 @@ fn blocking_replace_mcp_servers_round_trips() {
|
||||
servers.insert(
|
||||
"http".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: "https://example.com".to_string(),
|
||||
bearer_token_env_var: Some("TOKEN".to_string()),
|
||||
@@ -981,6 +983,7 @@ fn blocking_replace_mcp_servers_serializes_tool_approval_overrides() {
|
||||
servers.insert(
|
||||
"docs".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "docs-server".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -1041,6 +1044,7 @@ foo = { command = "cmd" }
|
||||
servers.insert(
|
||||
"foo".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "cmd".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -1091,6 +1095,7 @@ foo = { command = "cmd" } # keep me
|
||||
servers.insert(
|
||||
"foo".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "cmd".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -1140,6 +1145,7 @@ foo = { command = "cmd", args = ["--flag"] } # keep me
|
||||
servers.insert(
|
||||
"foo".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "cmd".to_string(),
|
||||
args: Vec::new(),
|
||||
@@ -1190,6 +1196,7 @@ foo = { command = "cmd" }
|
||||
servers.insert(
|
||||
"foo".to_string(),
|
||||
McpServerConfig {
|
||||
use_chatgpt_auth: false,
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
command: "cmd".to_string(),
|
||||
args: Vec::new(),
|
||||
|
||||
Reference in new issue
Block a user