Before submitting
Area
apps/server / Codex provider / preview MCP authentication
Summary
A long-lived Codex-backed thread loses access to every t3-code preview tool after the preview MCP credential has been idle for more than 30 minutes. The Codex app-server remains alive and still has T3_MCP_BEARER_TOKEN, but T3's /mcp endpoint returns HTTP 401. Repeating preview_status or preview_open cannot recover the session. Opening a fresh T3 Code thread immediately works because it receives a new credential.
This appears to be an expiry/refresh lifecycle gap rather than target-page, browser, DNS, or TLS failure.
Steps to reproduce
- Start a Codex-backed thread in T3 Code Desktop.
- Leave the thread's
t3-code preview MCP credential unused for more than 30 minutes. The agent and Codex app-server may remain otherwise active.
- Call
preview_status.
- Call
preview_open, for example:
{
"show": true,
"reuseExistingTab": true,
"url": "https://example.com"
}
- Observe that both calls fail immediately with
Auth required.
- Open a fresh T3 Code agent thread and repeat the same calls.
- Observe that the new thread succeeds.
Expected behavior
An active provider session should retain or transparently refresh its preview MCP authorization. If a credential expires, T3 Code should rotate/reload it or restart/recover the provider session and retry. At minimum, it should surface an actionable credential-expired error.
Actual behavior
Both preview calls failed in about 23 ms:
tool call error: tool call failed for `t3-code/preview_open`
Caused by:
Transport send error: Transport [rmcp::transport::worker::WorkerTransport<rmcp::transport::streamable_http_client::StreamableHttpClientWorker<codex_rmcp_client::http_client_adapter::StreamableHttpClientAdapter>>] error: Auth required
The local T3 server trace confirms that these were authorization failures at the local MCP endpoint:
2026-07-24T17:23:57.823Z POST /mcp 401
2026-07-24T17:24:02.179Z POST /mcp 401
The affected Codex app-server started at approximately 2026-07-24T16:48:04Z, about 35 minutes 53 seconds before the first failure. Its process environment still contained the T3_MCP_BEARER_TOKEN key. The token value was not logged or exposed.
A fresh thread then initialized /mcp successfully with HTTP 200/202 responses and loaded the identical requested page.
Likely root cause
The timing matches the 30-minute idle timeout in McpSessionRegistry.ts:
const DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1_000;
const DEFAULT_MAXIMUM_LIFETIME_MS = 8 * 60 * 60 * 1_000;
pruneExpired() removes a record when timestamp - record.lastUsedAt > idleTimeoutMs. Successful calls update lastUsedAt, but after the record is removed, the live Codex app-server continues presenting its original environment-provided bearer token. I could not find a path that refreshes the live process credential or recovers automatically after the resulting 401.
Suggested implementation directions
The best choice depends on the intended security policy, but possible approaches are:
- Keep the MCP credential valid while its provider session is alive, retaining the existing eight-hour maximum lifetime and explicit revocation on provider/thread teardown.
- Proactively rotate the credential before idle expiry and reload/restart the provider's MCP configuration.
- Detect an MCP authentication failure, recover the provider session with a new credential, and retry once.
- Surface a specific message such as
Preview credential expired; restart provider session instead of the generic RMCP transport error.
I would avoid solving this only with a periodic keepalive because that effectively bypasses the intended idle policy without fixing credential lifecycle management.
Impact
Major degradation for long-running coding threads. Once expired, all collaborative preview automation becomes unavailable in that thread, and agents may incorrectly investigate the target site or browser instead of the local T3 credential.
Version or commit
T3 Code 0.0.29-nightly.20260724.891
Codex CLI 0.145.0
Environment
Arch Linux x86_64
Linux 7.1.3-arch1-1
Hyprland / Wayland
T3 Code local server: http://127.0.0.1:3773
Workaround
- Open a fresh agent thread, or fully quit/relaunch T3 Code and resume the affected thread so a new provider credential is issued.
- Calling a preview tool at least once within each 30-minute window keeps
lastUsedAt current, but this is only a workaround.
codex login does not help; the rejected credential is T3 Code's session-scoped T3_MCP_BEARER_TOKEN, not the user's OpenAI login.
Additional context
This is separate from #3718. After authentication succeeded in the fresh thread, preview_open(show: true) loaded the page but returned visible: false, matching that existing visibility issue.
Before submitting
Area
apps/server/ Codex provider / preview MCP authenticationSummary
A long-lived Codex-backed thread loses access to every
t3-codepreview tool after the preview MCP credential has been idle for more than 30 minutes. The Codex app-server remains alive and still hasT3_MCP_BEARER_TOKEN, but T3's/mcpendpoint returns HTTP 401. Repeatingpreview_statusorpreview_opencannot recover the session. Opening a fresh T3 Code thread immediately works because it receives a new credential.This appears to be an expiry/refresh lifecycle gap rather than target-page, browser, DNS, or TLS failure.
Steps to reproduce
t3-codepreview MCP credential unused for more than 30 minutes. The agent and Codex app-server may remain otherwise active.preview_status.preview_open, for example:{ "show": true, "reuseExistingTab": true, "url": "https://example.com" }Auth required.Expected behavior
An active provider session should retain or transparently refresh its preview MCP authorization. If a credential expires, T3 Code should rotate/reload it or restart/recover the provider session and retry. At minimum, it should surface an actionable credential-expired error.
Actual behavior
Both preview calls failed in about 23 ms:
The local T3 server trace confirms that these were authorization failures at the local MCP endpoint:
The affected Codex app-server started at approximately
2026-07-24T16:48:04Z, about 35 minutes 53 seconds before the first failure. Its process environment still contained theT3_MCP_BEARER_TOKENkey. The token value was not logged or exposed.A fresh thread then initialized
/mcpsuccessfully with HTTP 200/202 responses and loaded the identical requested page.Likely root cause
The timing matches the 30-minute idle timeout in
McpSessionRegistry.ts:pruneExpired()removes a record whentimestamp - record.lastUsedAt > idleTimeoutMs. Successful calls updatelastUsedAt, but after the record is removed, the live Codex app-server continues presenting its original environment-provided bearer token. I could not find a path that refreshes the live process credential or recovers automatically after the resulting 401.Suggested implementation directions
The best choice depends on the intended security policy, but possible approaches are:
Preview credential expired; restart provider sessioninstead of the generic RMCP transport error.I would avoid solving this only with a periodic keepalive because that effectively bypasses the intended idle policy without fixing credential lifecycle management.
Impact
Major degradation for long-running coding threads. Once expired, all collaborative preview automation becomes unavailable in that thread, and agents may incorrectly investigate the target site or browser instead of the local T3 credential.
Version or commit
T3 Code
0.0.29-nightly.20260724.891Codex CLI
0.145.0Environment
Workaround
lastUsedAtcurrent, but this is only a workaround.codex logindoes not help; the rejected credential is T3 Code's session-scopedT3_MCP_BEARER_TOKEN, not the user's OpenAI login.Additional context
This is separate from #3718. After authentication succeeded in the fresh thread,
preview_open(show: true)loaded the page but returnedvisible: false, matching that existing visibility issue.