fix(mcp): coerce corrupted consecutiveFailures instead of crashing the whole server list#5593
Conversation
…e whole server list
Root cause: updateServerStatus() only fell back to the default status
config when the whole statusConfig column was null/undefined, not when
it was a real object missing consecutiveFailures (e.g. the column's
'{}' default on server creation). currentConfig.consecutiveFailures
was then undefined, undefined + 1 evaluated to NaN, and
JSON.stringify(NaN) persisted as a literal `null` into the DB the
first time a freshly-created server had a connection failure.
That corrupted value then failed listMcpServersContract's Zod parse
client-side (consecutiveFailures: z.number() rejects null), and since
the response is a single array, one bad server blanked the entire MCP
servers list with "Response failed contract validation" for the whole
workspace — currently affecting 81 servers across 69 production
workspaces.
Two fixes:
- service.ts: normalize the read-back statusConfig so
consecutiveFailures is always a real number, never NaN, going
forward.
- contracts/mcp.ts: coerce any non-number consecutiveFailures
(including the already-corrupted `null` rows) to the schema's
default of 0 instead of failing validation, so every
already-affected workspace self-heals on next load with no DB
migration needed.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview
The MCP server list contract preprocesses Reviewed by Cursor Bugbot for commit 95f9625. Configure here. |
Greptile SummaryThis PR makes MCP server status parsing tolerate corrupted failure counts. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (1): Last reviewed commit: "fix(mcp): coerce corrupted consecutiveFa..." | Re-trigger Greptile |
Summary
updateServerStatus()inlib/mcp/service.tsonly fell back to a default status config when the wholestatusConfigcolumn was null, not when it was a real-but-incomplete object (e.g. the column's'{}'default on server creation). This madeconsecutiveFailuresundefined,undefined + 1evaluate toNaN, andJSON.stringify(NaN)persist as a literalnullthe first time a freshly-created server hit a connection failurenullthen failed the server-list contract's Zod parse client-side (consecutiveFailures: z.number()rejectsnull) — since the response is an array, one bad server blanks the entire list for the whole workspaceservice.tsnow normalizes the read-back status config soconsecutiveFailuresis always a real number going forward; the contract schema also coerces any non-numberconsecutiveFailures(including already-corruptednullrows) to the default of0, so all 69 currently-broken workspaces self-heal immediately on next page load — no DB migration neededType of Change
Testing
{consecutiveFailures: null}→{consecutiveFailures: 0, ...}, no longer throws)lib/mcp/service.test.tssuite passes (11/11)bun run check:api-validationpassesChecklist