feat(app-server): add mcpServer/startupStatus/updated notification (#15220)

Exposes the legacy `codex/event/mcp_startup_update` event as an API v2
notification.

The legacy event has this shape:
```
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
pub struct McpStartupUpdateEvent {
    /// Server name being started.
    pub server: String,
    /// Current startup status.
    pub status: McpStartupStatus,
}

#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
#[serde(rename_all = "snake_case", tag = "state")]
#[ts(rename_all = "snake_case", tag = "state")]
pub enum McpStartupStatus {
    Starting,
    Ready,
    Failed { error: String },
    Cancelled,
}
```
This commit is contained in:
Owen Lin 2026-03-19 15:09:59 -07:00 committed by GitHub
parent 2bee37fe69
commit 9e695fe830
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 389 additions and 1 deletions

View file

@ -1435,6 +1435,36 @@
],
"type": "object"
},
"McpServerStartupState": {
"enum": [
"starting",
"ready",
"failed",
"cancelled"
],
"type": "string"
},
"McpServerStatusUpdatedNotification": {
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/McpServerStartupState"
}
},
"required": [
"name",
"status"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@ -4214,6 +4244,26 @@
"title": "McpServer/oauthLogin/completedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"mcpServer/startupStatus/updated"
],
"title": "McpServer/startupStatus/updatedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/McpServerStatusUpdatedNotification"
}
},
"required": [
"method",
"params"
],
"title": "McpServer/startupStatus/updatedNotification",
"type": "object"
},
{
"properties": {
"method": {

View file

@ -3973,6 +3973,26 @@
"title": "McpServer/oauthLogin/completedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"mcpServer/startupStatus/updated"
],
"title": "McpServer/startupStatus/updatedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/McpServerStatusUpdatedNotification"
}
},
"required": [
"method",
"params"
],
"title": "McpServer/startupStatus/updatedNotification",
"type": "object"
},
{
"properties": {
"method": {
@ -8570,6 +8590,15 @@
"title": "McpServerRefreshResponse",
"type": "object"
},
"McpServerStartupState": {
"enum": [
"starting",
"ready",
"failed",
"cancelled"
],
"type": "string"
},
"McpServerStatus": {
"properties": {
"authStatus": {
@ -8606,6 +8635,29 @@
],
"type": "object"
},
"McpServerStatusUpdatedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/v2/McpServerStartupState"
}
},
"required": [
"name",
"status"
],
"title": "McpServerStatusUpdatedNotification",
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {

View file

@ -5358,6 +5358,15 @@
"title": "McpServerRefreshResponse",
"type": "object"
},
"McpServerStartupState": {
"enum": [
"starting",
"ready",
"failed",
"cancelled"
],
"type": "string"
},
"McpServerStatus": {
"properties": {
"authStatus": {
@ -5394,6 +5403,29 @@
],
"type": "object"
},
"McpServerStatusUpdatedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/McpServerStartupState"
}
},
"required": [
"name",
"status"
],
"title": "McpServerStatusUpdatedNotification",
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@ -8373,6 +8405,26 @@
"title": "McpServer/oauthLogin/completedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"mcpServer/startupStatus/updated"
],
"title": "McpServer/startupStatus/updatedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/McpServerStatusUpdatedNotification"
}
},
"required": [
"method",
"params"
],
"title": "McpServer/startupStatus/updatedNotification",
"type": "object"
},
{
"properties": {
"method": {

View file

@ -0,0 +1,34 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"McpServerStartupState": {
"enum": [
"starting",
"ready",
"failed",
"cancelled"
],
"type": "string"
}
},
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/McpServerStartupState"
}
},
"required": [
"name",
"status"
],
"title": "McpServerStatusUpdatedNotification",
"type": "object"
}

View file

@ -22,6 +22,7 @@ import type { ItemGuardianApprovalReviewCompletedNotification } from "./v2/ItemG
import type { ItemGuardianApprovalReviewStartedNotification } from "./v2/ItemGuardianApprovalReviewStartedNotification";
import type { ItemStartedNotification } from "./v2/ItemStartedNotification";
import type { McpServerOauthLoginCompletedNotification } from "./v2/McpServerOauthLoginCompletedNotification";
import type { McpServerStatusUpdatedNotification } from "./v2/McpServerStatusUpdatedNotification";
import type { McpToolCallProgressNotification } from "./v2/McpToolCallProgressNotification";
import type { ModelReroutedNotification } from "./v2/ModelReroutedNotification";
import type { PlanDeltaNotification } from "./v2/PlanDeltaNotification";
@ -54,4 +55,4 @@ import type { WindowsWorldWritableWarningNotification } from "./v2/WindowsWorldW
/**
* Notification sent from the server to the client.
*/
export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification };
export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "mcpServer/startupStatus/updated", "params": McpServerStatusUpdatedNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification };

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type McpServerStartupState = "starting" | "ready" | "failed" | "cancelled";

View file

@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { McpServerStartupState } from "./McpServerStartupState";
export type McpServerStatusUpdatedNotification = { name: string, status: McpServerStartupState, error: string | null, };

View file

@ -171,7 +171,9 @@ export type { McpServerOauthLoginCompletedNotification } from "./McpServerOauthL
export type { McpServerOauthLoginParams } from "./McpServerOauthLoginParams";
export type { McpServerOauthLoginResponse } from "./McpServerOauthLoginResponse";
export type { McpServerRefreshResponse } from "./McpServerRefreshResponse";
export type { McpServerStartupState } from "./McpServerStartupState";
export type { McpServerStatus } from "./McpServerStatus";
export type { McpServerStatusUpdatedNotification } from "./McpServerStatusUpdatedNotification";
export type { McpToolCallError } from "./McpToolCallError";
export type { McpToolCallProgressNotification } from "./McpToolCallProgressNotification";
export type { McpToolCallResult } from "./McpToolCallResult";

View file

@ -905,6 +905,7 @@ server_notification_definitions! {
ServerRequestResolved => "serverRequest/resolved" (v2::ServerRequestResolvedNotification),
McpToolCallProgress => "item/mcpToolCall/progress" (v2::McpToolCallProgressNotification),
McpServerOauthLoginCompleted => "mcpServer/oauthLogin/completed" (v2::McpServerOauthLoginCompletedNotification),
McpServerStatusUpdated => "mcpServer/startupStatus/updated" (v2::McpServerStatusUpdatedNotification),
AccountUpdated => "account/updated" (v2::AccountUpdatedNotification),
AccountRateLimitsUpdated => "account/rateLimits/updated" (v2::AccountRateLimitsUpdatedNotification),
AppListUpdated => "app/list/updated" (v2::AppListUpdatedNotification),

View file

@ -5002,6 +5002,25 @@ pub struct McpServerOauthLoginCompletedNotification {
pub error: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub enum McpServerStartupState {
Starting,
Ready,
Failed,
Cancelled,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct McpServerStatusUpdatedNotification {
pub name: String,
pub status: McpServerStartupState,
pub error: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]

View file

@ -836,6 +836,10 @@ Because audio is intentionally separate from `ThreadItem`, clients can opt out o
- `windowsSandbox/setupCompleted``{ mode, success, error }` after a `windowsSandbox/setupStart` request finishes.
### MCP server startup events
- `mcpServer/startupStatus/updated``{ name, status, error }` when app-server observes an MCP server startup transition. `status` is one of `starting`, `ready`, `failed`, or `cancelled`. `error` is `null` except for `failed`.
### Turn events
The app-server streams JSON-RPC notifications while a turn is running. Each turn emits `turn/started` when it begins running and ends with `turn/completed` (final `turn` status). Token usage events stream separately via `thread/tokenUsage/updated`. Clients subscribe to the events they care about, rendering each item incrementally as updates arrive. The per-item lifecycle is always: `item/started` → zero or more item-specific deltas → `item/completed`.
@ -1258,6 +1262,7 @@ Codex supports these authentication modes. The current mode is surfaced in `acco
- `account/rateLimits/read` — fetch ChatGPT rate limits; updates arrive via `account/rateLimits/updated` (notify).
- `account/rateLimits/updated` (notify) — emitted whenever a user's ChatGPT rate limits change.
- `mcpServer/oauthLogin/completed` (notify) — emitted after a `mcpServer/oauth/login` flow finishes for a server; payload includes `{ name, success, error? }`.
- `mcpServer/startupStatus/updated` (notify) — emitted when a configured MCP server's startup status changes for a loaded thread; payload includes `{ name, status, error }` where `status` is `starting`, `ready`, `failed`, or `cancelled`.
### 1) Check auth state

View file

@ -57,6 +57,8 @@ use codex_app_server_protocol::JSONRPCErrorError;
use codex_app_server_protocol::McpServerElicitationAction;
use codex_app_server_protocol::McpServerElicitationRequestParams;
use codex_app_server_protocol::McpServerElicitationRequestResponse;
use codex_app_server_protocol::McpServerStartupState;
use codex_app_server_protocol::McpServerStatusUpdatedNotification;
use codex_app_server_protocol::McpToolCallError;
use codex_app_server_protocol::McpToolCallResult;
use codex_app_server_protocol::McpToolCallStatus;
@ -310,6 +312,34 @@ pub(crate) async fn apply_bespoke_event_handling(
.await;
}
}
EventMsg::McpStartupUpdate(update) => {
if let ApiVersion::V2 = api_version {
let (status, error) = match update.status {
codex_protocol::protocol::McpStartupStatus::Starting => {
(McpServerStartupState::Starting, None)
}
codex_protocol::protocol::McpStartupStatus::Ready => {
(McpServerStartupState::Ready, None)
}
codex_protocol::protocol::McpStartupStatus::Failed { error } => {
(McpServerStartupState::Failed, Some(error))
}
codex_protocol::protocol::McpStartupStatus::Cancelled => {
(McpServerStartupState::Cancelled, None)
}
};
let notification = McpServerStatusUpdatedNotification {
name: update.server,
status,
error,
};
outgoing
.send_server_notification(ServerNotification::McpServerStatusUpdated(
notification,
))
.await;
}
}
EventMsg::Warning(_warning_event) => {}
EventMsg::GuardianAssessment(assessment) => {
if let ApiVersion::V2 = api_version {

View file

@ -7,7 +7,10 @@ use app_test_support::write_chatgpt_auth;
use codex_app_server_protocol::JSONRPCError;
use codex_app_server_protocol::JSONRPCMessage;
use codex_app_server_protocol::JSONRPCResponse;
use codex_app_server_protocol::McpServerStartupState;
use codex_app_server_protocol::McpServerStatusUpdatedNotification;
use codex_app_server_protocol::RequestId;
use codex_app_server_protocol::ServerNotification;
use codex_app_server_protocol::ThreadStartParams;
use codex_app_server_protocol::ThreadStartResponse;
use codex_app_server_protocol::ThreadStartedNotification;
@ -328,6 +331,103 @@ async fn thread_start_fails_when_required_mcp_server_fails_to_initialize() -> Re
Ok(())
}
#[tokio::test]
async fn thread_start_emits_mcp_server_status_updated_notifications() -> Result<()> {
let server = create_mock_responses_server_repeating_assistant("Done").await;
let codex_home = TempDir::new()?;
create_config_toml_with_optional_broken_mcp(codex_home.path(), &server.uri())?;
let mut mcp = McpProcess::new(codex_home.path()).await?;
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
let req_id = mcp
.send_thread_start_request(ThreadStartParams::default())
.await?;
let _: ThreadStartResponse = to_response(
timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_response_message(RequestId::Integer(req_id)),
)
.await??,
)?;
let starting = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_matching_notification(
"mcpServer/startupStatus/updated starting",
|notification| {
notification.method == "mcpServer/startupStatus/updated"
&& notification
.params
.as_ref()
.and_then(|params| params.get("name"))
.and_then(Value::as_str)
== Some("optional_broken")
&& notification
.params
.as_ref()
.and_then(|params| params.get("status"))
.and_then(Value::as_str)
== Some("starting")
},
),
)
.await??;
let starting: ServerNotification = starting.try_into()?;
let ServerNotification::McpServerStatusUpdated(starting) = starting else {
anyhow::bail!("unexpected notification variant");
};
assert_eq!(
starting,
McpServerStatusUpdatedNotification {
name: "optional_broken".to_string(),
status: McpServerStartupState::Starting,
error: None,
}
);
let failed = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_matching_notification(
"mcpServer/startupStatus/updated failed",
|notification| {
notification.method == "mcpServer/startupStatus/updated"
&& notification
.params
.as_ref()
.and_then(|params| params.get("name"))
.and_then(Value::as_str)
== Some("optional_broken")
&& notification
.params
.as_ref()
.and_then(|params| params.get("status"))
.and_then(Value::as_str)
== Some("failed")
},
),
)
.await??;
let failed: ServerNotification = failed.try_into()?;
let ServerNotification::McpServerStatusUpdated(failed) = failed else {
anyhow::bail!("unexpected notification variant");
};
assert_eq!(failed.name, "optional_broken");
assert_eq!(failed.status, McpServerStartupState::Failed);
assert!(
failed
.error
.as_deref()
.is_some_and(|error| error.contains("MCP client for `optional_broken` failed to start")),
"unexpected MCP startup error: {:?}",
failed.error
);
Ok(())
}
#[tokio::test]
async fn thread_start_surfaces_cloud_requirements_load_errors() -> Result<()> {
let server = MockServer::start().await;
@ -491,3 +591,32 @@ required = true
),
)
}
fn create_config_toml_with_optional_broken_mcp(
codex_home: &Path,
server_uri: &str,
) -> std::io::Result<()> {
let config_toml = codex_home.join("config.toml");
std::fs::write(
config_toml,
format!(
r#"
model = "mock-model"
approval_policy = "never"
sandbox_mode = "read-only"
model_provider = "mock_provider"
[model_providers.mock_provider]
name = "Mock provider for test"
base_url = "{server_uri}/v1"
wire_api = "responses"
request_max_retries = 0
stream_max_retries = 0
[mcp_servers.optional_broken]
command = "codex-definitely-not-a-real-binary"
"#
),
)
}

View file

@ -492,6 +492,7 @@ fn server_notification_thread_target(
Some(notification.thread_id.as_str())
}
ServerNotification::SkillsChanged(_)
| ServerNotification::McpServerStatusUpdated(_)
| ServerNotification::McpServerOauthLoginCompleted(_)
| ServerNotification::AccountUpdated(_)
| ServerNotification::AccountRateLimitsUpdated(_)

View file

@ -6047,6 +6047,7 @@ impl ChatWidget {
| ServerNotification::RawResponseItemCompleted(_)
| ServerNotification::CommandExecOutputDelta(_)
| ServerNotification::McpToolCallProgress(_)
| ServerNotification::McpServerStatusUpdated(_)
| ServerNotification::McpServerOauthLoginCompleted(_)
| ServerNotification::AppListUpdated(_)
| ServerNotification::ContextCompacted(_)