Summary
If any tool returned by tools/list has an input/output JSON Schema pattern that isn't a valid ECMAScript (ECMA-262) regex, Client.listTools() throws while compiling schema validators, and OpenCode tears down the entire MCP server connection — even though the connection and every other tool are fine.
Worse: for OAuth servers authenticated via opencode mcp auth, the OAuth token exchange has already succeeded and been persisted by the time this happens, yet the CLI reports "Authentication failed". A purely schema-side problem is misattributed to authentication, so users re-authenticate in a loop that can never succeed.
Environment
- opencode
1.17.14
@modelcontextprotocol/sdk 1.29.0
- Reproduced on both Bun and Node runtimes.
Root cause
listTools() calls cacheToolMetadata(), which compiles a validator for each tool's schema. A pattern that is invalid in ECMA-262 makes new RegExp(pattern) throw, so the whole listTools() call throws.
create() in packages/opencode/src/mcp/index.ts runs McpCatalog.defs() (i.e. listTools) after the transport has already connected successfully. The throw is caught by create()'s outer handler and returned as status: "failed" with message "Failed to get tools" — failing the whole server, not just the one tool.
- In the OAuth path,
finishAuth() calls provider.commit() (persist tokens) before createAndStore() (which runs the failing listTools). So valid tokens are already written to mcp-auth.json.
opencode mcp auth (packages/opencode/src/cli/cmd/mcp.ts) maps status: "failed" to the message "Authentication failed" followed by the underlying "Failed to get tools".
Net effect: OAuth actually succeeded, the token works, but the user sees "Authentication failed" and re-auths repeatedly.
Reproduction
Connect to a remote MCP server that returns a tool whose schema pattern uses a Python-style named group (?P<name>...), which is invalid in ECMA-262.
Concrete example (Tracecat): tools get_workflow_execution, run_published_workflow, run_draft_workflow, list_workflow_executions, run_case_task emit:
(?P<workflow_id>wf-[0-9a-f]{32}|wf_[0-9a-zA-Z]+)[:/](?P<execution_id>...)
new RegExp("(?P<workflow_id>wf-[0-9a-f]{32})[:/](?P<execution_id>.*)")
// -> SyntaxError: Invalid regular expression: Invalid group (Node and Bun)
Result: opencode mcp auth <server> shows Authentication failed / Failed to get tools, and the server never reaches connected, despite a valid token being persisted.
Suggested fix
- In
cacheToolMetadata, wrap the per-tool validator compilation in try/catch so one un-compilable pattern degrades that tool's output validation instead of throwing out of listTools() and failing the whole connection.
- Don't surface a post-authentication tool-listing failure as an authentication failure — distinguish "connected but tool-listing failed" from "auth failed" in
create()/cmd/mcp.ts.
(The server also shouldn't emit non-ECMA-262 patterns — that's a server-side bug being fixed separately — but a single malformed tool schema shouldn't take down an otherwise-healthy MCP connection.)
Summary
If any tool returned by
tools/listhas an input/output JSON Schemapatternthat isn't a valid ECMAScript (ECMA-262) regex,Client.listTools()throws while compiling schema validators, and OpenCode tears down the entire MCP server connection — even though the connection and every other tool are fine.Worse: for OAuth servers authenticated via
opencode mcp auth, the OAuth token exchange has already succeeded and been persisted by the time this happens, yet the CLI reports "Authentication failed". A purely schema-side problem is misattributed to authentication, so users re-authenticate in a loop that can never succeed.Environment
1.17.14@modelcontextprotocol/sdk1.29.0Root cause
listTools()callscacheToolMetadata(), which compiles a validator for each tool's schema. Apatternthat is invalid in ECMA-262 makesnew RegExp(pattern)throw, so the wholelistTools()call throws.create()inpackages/opencode/src/mcp/index.tsrunsMcpCatalog.defs()(i.e.listTools) after the transport has already connected successfully. The throw is caught bycreate()'s outer handler and returned asstatus: "failed"with message"Failed to get tools"— failing the whole server, not just the one tool.finishAuth()callsprovider.commit()(persist tokens) beforecreateAndStore()(which runs the failinglistTools). So valid tokens are already written tomcp-auth.json.opencode mcp auth(packages/opencode/src/cli/cmd/mcp.ts) mapsstatus: "failed"to the message "Authentication failed" followed by the underlying "Failed to get tools".Net effect: OAuth actually succeeded, the token works, but the user sees "Authentication failed" and re-auths repeatedly.
Reproduction
Connect to a remote MCP server that returns a tool whose schema
patternuses a Python-style named group(?P<name>...), which is invalid in ECMA-262.Concrete example (Tracecat): tools
get_workflow_execution,run_published_workflow,run_draft_workflow,list_workflow_executions,run_case_taskemit:Result:
opencode mcp auth <server>showsAuthentication failed/Failed to get tools, and the server never reachesconnected, despite a valid token being persisted.Suggested fix
cacheToolMetadata, wrap the per-tool validator compilation in try/catch so one un-compilablepatterndegrades that tool's output validation instead of throwing out oflistTools()and failing the whole connection.create()/cmd/mcp.ts.(The server also shouldn't emit non-ECMA-262 patterns — that's a server-side bug being fixed separately — but a single malformed tool schema shouldn't take down an otherwise-healthy MCP connection.)