fix(#2038): don't treat MCP 'pending' status as degraded
pending is the claude CLI's normal init-event race for a freshly spawned stdio server (status reported before the handshake completes, then flips to connected moments later in the same turn — see anthropics/claude-agent-sdk-typescript#368). flagging it fired on nearly every turn for all three configured servers with zero actual impact, which is why #2038's persistent-vs-one-turn repro question looked answered when it wasn't — that was this false positive, not the real bug.
This commit is contained in:
parent
a80d0b0fed
commit
ee072149c9
1 changed files with 32 additions and 6 deletions
|
|
@ -677,9 +677,18 @@ impl Bus {
|
||||||
/// never touches the session. It exists because the harness is
|
/// never touches the session. It exists because the harness is
|
||||||
/// otherwise blind to the init event — the only place claude reports
|
/// otherwise blind to the init event — the only place claude reports
|
||||||
/// MCP-server status — so a dropped/failed stdio bridge (e.g. matrix
|
/// MCP-server status — so a dropped/failed stdio bridge (e.g. matrix
|
||||||
/// after a core bounce) went silent. Emitted every degraded turn on
|
/// after a core bounce) went silent.
|
||||||
/// purpose: whether it persists across fresh turns is the signal that
|
///
|
||||||
/// picks the real fix.
|
/// `pending` is deliberately NOT treated as degraded: it's the claude
|
||||||
|
/// CLI's normal init-event race for a freshly spawned stdio server
|
||||||
|
/// (status is reported before the handshake completes, then flips to
|
||||||
|
/// `connected` moments later in the same turn — see the upstream
|
||||||
|
/// claude-agent-sdk-typescript repo, issue number 368, for confirmation).
|
||||||
|
/// Flagging it fired on nearly every turn for all three configured
|
||||||
|
/// servers with zero actual impact (confirmed: tools kept working),
|
||||||
|
/// which is why the MCP-dropped-after-restart tracker issue's
|
||||||
|
/// persistent-vs-one-turn repro question looked answered "persistent"
|
||||||
|
/// when it wasn't — that was this false positive, not the real bug.
|
||||||
pub(crate) fn observe_mcp_health(&self, v: &serde_json::Value) {
|
pub(crate) fn observe_mcp_health(&self, v: &serde_json::Value) {
|
||||||
if v.get("type").and_then(|t| t.as_str()) != Some("system")
|
if v.get("type").and_then(|t| t.as_str()) != Some("system")
|
||||||
|| v.get("subtype").and_then(|s| s.as_str()) != Some("init")
|
|| v.get("subtype").and_then(|s| s.as_str()) != Some("init")
|
||||||
|
|
@ -886,8 +895,11 @@ impl Default for Bus {
|
||||||
/// Compare the configured MCP server names against the `{name -> status}`
|
/// Compare the configured MCP server names against the `{name -> status}`
|
||||||
/// map parsed from the init event, returning display strings for the
|
/// map parsed from the init event, returning display strings for the
|
||||||
/// degraded ones: a configured server absent from the report was dropped
|
/// degraded ones: a configured server absent from the report was dropped
|
||||||
/// entirely; one present with a non-`connected` status failed to register.
|
/// entirely; one present with a non-`connected`, non-`pending` status
|
||||||
/// Pure so it's unit-testable without a live `Bus`.
|
/// failed to register. `pending` is excluded — it's the CLI's normal
|
||||||
|
/// init-event race for a server still completing its handshake, not a
|
||||||
|
/// failure (see the doc comment on `observe_mcp_health`). Pure so it's
|
||||||
|
/// unit-testable without a live `Bus`.
|
||||||
fn degraded_mcp_servers(
|
fn degraded_mcp_servers(
|
||||||
configured: &[String],
|
configured: &[String],
|
||||||
reported: &std::collections::HashMap<&str, &str>,
|
reported: &std::collections::HashMap<&str, &str>,
|
||||||
|
|
@ -895,7 +907,7 @@ fn degraded_mcp_servers(
|
||||||
configured
|
configured
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|name| match reported.get(name.as_str()).copied() {
|
.filter_map(|name| match reported.get(name.as_str()).copied() {
|
||||||
Some("connected") => None,
|
Some("connected" | "pending") => None,
|
||||||
Some(status) => Some(format!("{name} ({status})")),
|
Some(status) => Some(format!("{name} ({status})")),
|
||||||
None => Some(format!("{name} (absent)")),
|
None => Some(format!("{name} (absent)")),
|
||||||
})
|
})
|
||||||
|
|
@ -963,4 +975,18 @@ mod tests {
|
||||||
.collect();
|
.collect();
|
||||||
assert!(super::degraded_mcp_servers(&configured, &reported).is_empty());
|
assert!(super::degraded_mcp_servers(&configured, &reported).is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn degraded_mcp_servers_ignores_pending() {
|
||||||
|
// `pending` is the CLI's normal init-event race for a stdio server
|
||||||
|
// still completing its handshake (flips to `connected` moments
|
||||||
|
// later in the same turn) — not a real failure, per the
|
||||||
|
// MCP-dropped-after-restart tracker issue.
|
||||||
|
use std::collections::HashMap;
|
||||||
|
let configured = ["hyperhive".to_owned(), "matrix".to_owned()];
|
||||||
|
let reported: HashMap<&str, &str> = [("hyperhive", "pending"), ("matrix", "pending")]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
assert!(super::degraded_mcp_servers(&configured, &reported).is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue