Harden server stability and fix MCP protocol hygiene#7
Merged
Conversation
Addresses the WordPress server intermittently showing as disconnected in Claude Desktop, and two protocol-level bugs found while auditing it: - capabilities.tools was a map of full tool objects, which serialized every tool's zod schema internals into the initialize response (~65KB per connection). It's now the spec-correct capability flags object; tool advertisement happens through server.tool() registration. initialize drops to ~164 bytes. - server.tool() was never passed the tool description, so tools/list served all 43 tools with no descriptions at all — clients picked tools on names alone. Descriptions are now registered. - unhandledRejection no longer kills the process: a stray background rejection surfaced to clients as an unexplained disconnect. It now logs loudly (with stack) and the server continues. uncaughtException still exits but logs the full stack first. - The process logs an exit trace ([SHUTDOWN] code N) so future "transport closed unexpectedly" reports can be correlated with a cause on the server side. - cli.ts wrote its startup banner to stdout, which belongs to the JSON-RPC channel of the inherited-stdio child server; moved to stderr. - Add CI workflow (job "test": npm ci, tsc --noEmit, build) matching the org template's expected status check. Verified by stdio handshake probe: initialize 164 bytes, zero zod internals, 43/43 tools with descriptions, SIGTERM leaves shutdown traces. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR hardens the WordPress MCP server’s protocol compliance and runtime stability to reduce “disconnected” events in MCP clients and improve tool discoverability.
Changes:
- Fixes MCP
initializecapability advertisement to avoid embedding full tool definitions (and zod internals) in the handshake payload. - Registers tools with descriptions and improves process-level error/shutdown logging behavior.
- Moves the CLI startup banner to stderr and adds a new GitHub Actions CI workflow.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/server.ts |
Corrects MCP capabilities/tool registration behavior and improves error/shutdown logging. |
src/cli.ts |
Ensures startup banner goes to stderr to keep stdout clean for JSON-RPC. |
.github/workflows/ci.yml |
Adds CI workflow to run TypeScript checks and build. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| with: | ||
| node-version: 22 | ||
| cache: npm | ||
| - run: npm ci |
Comment on lines
+104
to
+105
| process.on('exit', (code) => { | ||
| process.stderr.write(`[SHUTDOWN] Process exiting with code ${code}\n`); |
Comment on lines
+46
to
+47
| const zodSchema = z.object(tool.inputSchema.properties as z.ZodRawShape); | ||
| server.tool(tool.name, tool.description ?? '', zodSchema.shape, wrappedHandler) |
Comment on lines
22
to
24
| capabilities: { | ||
| tools: allTools.reduce((acc, tool) => { | ||
| acc[tool.name] = tool; | ||
| return acc; | ||
| }, {} as Record<string, any>) | ||
| tools: {} | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The WordPress server intermittently shows as disconnected in Claude Desktop. Audit of
server.ts+ Desktop logs found real protocol bugs and a fragile failure mode:capabilities.toolswas stuffed with full tool objects, serializing zod schema internals ("vendor":"zod",ZodOptional, …) into every connection handshake.server.tool()was called without the description argument, sotools/listserved all 43 tools with names and schemas only. Clients have been selecting tools blind.unhandledRejection→process.exit(1): any stray background rejection killed the server — exactly what a user sees as "server disconnected, tools gone until restart".Fix
capabilities: { tools: {} }; advertisement via registration. Initialize: 65KB → 164 bytes.server.tool(): 43/43 tools now describe themselves intools/list.unhandledRejection(with stack);uncaughtExceptionstill exits but logs the stack first;[SHUTDOWN] Process exiting with code Ntrace on every exit.cli.tsstartup banner moved to stderr (stdout belongs to the inherited JSON-RPC channel).test(npm ci,tsc --noEmit, build) — the status check the org MCP template expects.Verified
Stdio handshake probe against the built server: initialize 164 bytes with
{"tools":{"listChanged":true}}, zero zod internals, 43/43 tool descriptions present, SIGTERM produces[SHUTDOWN]traces.🤖 Generated with Claude Code