Gate-by-gate checklist for shipping a production MCP server: transport selection, tool-schema quality, auth wiring, error-response contract, and the security hand-off items that must escalate to core/security-reviewer. Owned by mcp-and-server-tools-engineer.
How this skill is triggered — by the user, by Claude, or both
Slash command
/claude-app-engineering:mcp-server-authoring-checklistThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- Authoring a new MCP server from scratch.
| Transport | Choose when | Avoid when |
|---|---|---|
stdio | Local tool (CLI, dev machine, same process) | Multi-client or networked deployment |
SSE (HTTP + Server-Sent Events) | Remote, multi-client, cloud-hosted | Environments that block long-lived HTTP connections |
| Streamable HTTP | High-throughput, resumable, new deployments (MCP 2025-11+) | Clients not yet upgraded to 2025-11 spec |
For each tool, verify:
name: verb-noun, kebab-case, globally unique across the server (search_documents not search).description: 3–5 sentences covering what it does, when to call it, when NOT to call it, and whether it has side-effects (read vs write vs delete). This is a prompt — write it as one.inputSchema.properties: every property has a description with format hint and example value.required: only fields the tool cannot function without; optional fields have default values.additionalProperties: true on write tools — prevents hallucinated keys.| Scenario | Recommended approach |
|---|---|
| Internal/local server | No auth (stdio) |
| OAuth user-delegated | MCP OAuth 2.1 flow; use PKCE; do not pass tokens via tool arguments |
| Service-to-service | Client credentials; use environment variable / secret manager injection at server startup |
| API keys for downstream services | Injected as env vars at server start; never in the tool schema or description |
Escalate to ravenclaude-core/security-reviewer if: the server handles user PII, calls a payment/healthcare API, or accepts tokens in tool arguments.
Every tool handler must return a structured error on failure — not an unhandled exception:
{
"isError": true,
"content": [{"type": "text", "text": "Search failed: index unavailable (503). Retry in 30 s."}]
}
| Rule | Why |
|---|---|
Return isError: true in the tool result, not an exception | The MCP runtime surfaces it to Claude; an exception terminates the session |
| Include a human-readable message and a retry hint | Claude can relay the hint to the user or decide to retry |
| Never include stack traces or internal paths in the error | Information disclosure |
| Log the full error server-side; return only the user-safe summary | Debugging without leaking internals |
These items must be reviewed by ravenclaude-core/security-reviewer before production install:
../../) or shell injection.list_tools is implemented and returns current schemas (no stale cached schema).SIGTERM/SIGINT) without dropping in-flight tool calls.version field); bump on any schema change.npx @modelcontextprotocol/inspector) before install.description that mirrors the name with no boundary conditions — Claude over-calls tools when it can't distinguish them.* scope on a production agent that has destructive tools — scope to the minimum tool set the agent needs.name or inputSchema without bumping the server version — clients cache the old schema.npx claudepluginhub mcorbett51090/ravenclaude --plugin claude-app-engineeringCreates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.