mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
17b9f4843e
## Why
We want a thread-selected plugin to eventually expose stdio MCP servers
that run on the executor owning that plugin.
The existing plugin MCP parser lived inside `core-plugins` and was
coupled to the host filesystem loader. Reusing it from an executor
provider would either duplicate MCP normalization or make the plugin
package layer own MCP runtime semantics. This PR creates the shared
MCP-owned boundary first.
In simple terms:
```text
plugin .mcp.json
|
v
shared parser in codex-mcp
|
+-- Declared placement: preserve current local-plugin behavior
|
+-- Environment placement: produce config bound to one executor
```
This builds on the authority-bound plugin descriptors from #27692. It
intentionally does not discover, register, or launch executor MCP
servers yet.
## What changed
- Moved plugin MCP file parsing and normalization from `core-plugins`
into `codex-mcp`.
- Kept support for both existing file shapes: a top-level server map and
an object containing `mcpServers`.
- Kept per-server failure isolation: one invalid server does not discard
valid siblings, while malformed top-level JSON still fails the whole
file.
- Updated the existing local plugin loader to use `Declared` placement,
preserving its current transport, OAuth, relative `cwd`, and error
behavior.
- Added `Environment` placement for the next stacked PR:
- the selected environment ID overrides anything declared by the plugin;
- missing stdio `cwd` defaults to the plugin root;
- relative `cwd` is resolved beneath the plugin root and cannot traverse
outside it;
- bare or source-less environment-variable references resolve on a
non-local executor;
- explicit orchestrator environment-variable forwarding is rejected for
executor-owned plugins.
## User impact
None in this PR. Existing local plugin MCP loading follows the same
behavior through the shared parser. The executor placement mode is not
connected to thread startup until the follow-up registration PR.
## Assumptions
- A selected capability root's environment is authoritative. A plugin
cannot redirect its stdio process to the orchestrator or another
executor.
- Relative working directories belong under the plugin package root.
Explicit absolute working directories remain valid within the owning
environment.
- For a non-local executor, unqualified environment-variable names refer
to that executor. Reading an orchestrator variable requires an explicit
contract and is rejected for now.
- Parsing only produces normalized `McpServerConfig` values. Process
startup remains owned by the existing MCP runtime and connection
manager.
## Follow-ups
1. Add the executor MCP provider and catalog registration: read the
selected plugin's MCP config through the same executor filesystem,
support stdio only, freeze the result per active thread, apply managed
policy, and resolve name collisions as discovered plugin < selected
plugin < explicit config.
2. Install that provider in app-server and add an end-to-end test
proving `thread/start.selectedCapabilityRoots` launches and calls the
MCP tool on the selected executor, preserves the frozen registration
across refresh, and does not expose it to an unselected thread.
3. After the initial executor-stdio vertical, define
resume/fork/environment-replacement semantics, executor HTTP placement,
warning delivery, common MCP tool-context bounds, and move remaining MCP
source composition above core.
## Verification
- `cargo check -p codex-mcp -p codex-core-plugins --tests`
- `just bazel-lock-check`
- Added focused parser coverage for legacy local normalization, executor
authority, working-directory handling, and environment-variable
sourcing.
55 lines
1.6 KiB
TOML
55 lines
1.6 KiB
TOML
[package]
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
name = "codex-core-plugins"
|
|
version.workspace = true
|
|
|
|
[lib]
|
|
doctest = false
|
|
name = "codex_core_plugins"
|
|
path = "src/lib.rs"
|
|
|
|
[lints]
|
|
workspace = true
|
|
|
|
[dependencies]
|
|
anyhow = { workspace = true }
|
|
codex-analytics = { workspace = true }
|
|
codex-app-server-protocol = { workspace = true }
|
|
codex-config = { workspace = true }
|
|
codex-core-skills = { workspace = true }
|
|
codex-exec-server = { workspace = true }
|
|
codex-git-utils = { workspace = true }
|
|
codex-hooks = { workspace = true }
|
|
codex-login = { workspace = true }
|
|
codex-mcp = { workspace = true }
|
|
codex-model-provider = { workspace = true }
|
|
codex-otel = { workspace = true }
|
|
codex-plugin = { workspace = true }
|
|
codex-protocol = { workspace = true }
|
|
codex-utils-absolute-path = { workspace = true }
|
|
codex-utils-path-uri = { workspace = true }
|
|
codex-utils-plugins = { workspace = true }
|
|
chrono = { workspace = true }
|
|
dirs = { workspace = true }
|
|
flate2 = { workspace = true }
|
|
indexmap = { workspace = true, features = ["serde"] }
|
|
reqwest = { workspace = true }
|
|
semver = { workspace = true }
|
|
serde = { workspace = true, features = ["derive"] }
|
|
serde_json = { workspace = true }
|
|
tar = { workspace = true }
|
|
tempfile = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
tokio = { workspace = true, features = ["fs", "macros", "rt", "time"] }
|
|
toml = { workspace = true }
|
|
tracing = { workspace = true }
|
|
url = { workspace = true }
|
|
zip = { workspace = true }
|
|
|
|
[dev-dependencies]
|
|
libc = { workspace = true }
|
|
pretty_assertions = { workspace = true }
|
|
tempfile = { workspace = true }
|
|
wiremock = { workspace = true }
|