mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
4de7a2b9d8
## Why Codex persists OAuth expiry as an absolute `expires_at`, then reconstructs RMCP’s relative `expires_in` when credentials are loaded. For an already-expired token, Codex reconstructed `expires_in` as missing. [RMCP 0.15 treated a missing `expires_in` as zero when a refresh token was present](https://github.com/modelcontextprotocol/rust-sdk/blob/9cfc905a9ef17c8bba6748dc0a9bdd2452681733/crates/rmcp/src/transport/auth.rs#L704-L723), so this still triggered a refresh. [RMCP 1.7 treats missing expiry information as unknown and uses the access token as-is](https://github.com/modelcontextprotocol/rust-sdk/blob/3529c3675ff64db805bd947ca6ece6090809e43d/crates/rmcp/src/transport/auth.rs#L1233-L1265), causing the stale token to be sent during `initialize`. ## What changed - Represent a known-expired persisted token as `expires_in = 0`, preserving `None` for genuinely unknown expiry. - Add Streamable HTTP coverage requiring the token to refresh before the startup handshake. ## Validation - The new regression test fails on RMCP 1.7 before the fix and passes afterward. - The same scenario passes on the commit immediately before the RMCP 1.7 update, using RMCP 0.15. - `just test -p codex-rmcp-client` (63 passed).
88 lines
2.4 KiB
TOML
88 lines
2.4 KiB
TOML
[package]
|
|
name = "codex-rmcp-client"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
|
|
[lints]
|
|
workspace = true
|
|
|
|
[dependencies]
|
|
anyhow = "1"
|
|
axum = { workspace = true, default-features = false, features = [
|
|
"http1",
|
|
"json",
|
|
"tokio",
|
|
] }
|
|
base64 = { workspace = true }
|
|
codex-api = { workspace = true }
|
|
codex-client = { workspace = true }
|
|
codex-config = { workspace = true }
|
|
codex-exec-server = { workspace = true }
|
|
codex-keyring-store = { workspace = true }
|
|
codex-protocol = { workspace = true }
|
|
codex-utils-pty = { workspace = true }
|
|
codex-utils-home-dir = { workspace = true }
|
|
bytes = { workspace = true }
|
|
futures = { workspace = true, default-features = false, features = ["std"] }
|
|
keyring = { workspace = true, features = ["crypto-rust"] }
|
|
memchr = { workspace = true }
|
|
oauth2 = "5"
|
|
reqwest = { version = "0.13", default-features = false, features = [
|
|
"json",
|
|
"stream",
|
|
"rustls",
|
|
] }
|
|
rmcp = { workspace = true, default-features = false, features = [
|
|
"auth",
|
|
"base64",
|
|
"client",
|
|
"macros",
|
|
"schemars",
|
|
"server",
|
|
"transport-async-rw",
|
|
"transport-child-process",
|
|
"transport-streamable-http-client-reqwest",
|
|
"transport-streamable-http-server",
|
|
] }
|
|
serde = { workspace = true, features = ["derive"] }
|
|
serde_json = { workspace = true }
|
|
sha2 = { workspace = true }
|
|
sse-stream = "0.2.1"
|
|
thiserror = { workspace = true }
|
|
tiny_http = { workspace = true }
|
|
tokio = { workspace = true, features = [
|
|
"io-util",
|
|
"macros",
|
|
"process",
|
|
"rt-multi-thread",
|
|
"sync",
|
|
"io-std",
|
|
"time",
|
|
] }
|
|
tracing = { workspace = true, features = ["log"] }
|
|
urlencoding = { workspace = true }
|
|
webbrowser = { workspace = true }
|
|
which = { workspace = true }
|
|
|
|
[dev-dependencies]
|
|
codex-utils-cargo-bin = { workspace = true }
|
|
pretty_assertions = { workspace = true }
|
|
serial_test = { workspace = true }
|
|
tempfile = { workspace = true }
|
|
wiremock = { workspace = true }
|
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
keyring = { workspace = true, features = ["linux-native-async-persistent"] }
|
|
|
|
[target.'cfg(target_os = "macos")'.dependencies]
|
|
keyring = { workspace = true, features = ["apple-native"] }
|
|
|
|
[target.'cfg(target_os = "windows")'.dependencies]
|
|
keyring = { workspace = true, features = ["windows-native"] }
|
|
|
|
[target.'cfg(any(target_os = "freebsd", target_os = "openbsd"))'.dependencies]
|
|
keyring = { workspace = true, features = ["sync-secret-service"] }
|
|
|
|
[lib]
|
|
doctest = false
|