An MCP server that connects and then drops at once. Or one that works, gets published, and carries a real key in its example configuration. Both are the kind of flaw you can find in the few minutes before release. Here are seven checks for a local MCP server on the stdio transport.

The reference MCP servers repository shows v2.4.0 dated 2026-11-11, and MCP servers are prominent among this week's new public repositories (we read the headlines and dates only and verified nothing behind them). More people are writing and publishing their own, so this is where to look first.

The full checklist in English and Japanese, with questions and answers: https://zero-trace-ship-kit.zeus-lab-global.workers.dev/guides/mcp-server-stdio-secrets-checklist/?utm_source=devto

1. Standard output carries protocol messages only

The specification (Transports, version 2025-06-18; read on its page on 2026-11-12 UTC) says for stdio:

  • The server must not write anything to its standard output that is not a valid MCP message.
  • Messages are delimited by newlines and must not contain embedded newlines.
  • The server may write logs to standard error.

A debugging print, a library banner, a progress line: any one of them on standard output is read by the client as a message, and the session breaks. Send every log line to standard error.

2. Try the handshake by hand

The first thing on standard output should be one JSON-RPC response to the initialize request: the same id, and a result. Anything before it is a bug.

printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"check","version":"0"}}}' \ | python3 your_server.py 2>/dev/null | head -c 400 

This is a quick look, not a conformance test. The protocol version is one published version; use the one your server supports.

3. No secrets in committed configuration

Keep keys out of .mcp.json and out of example configurations. Read them inside the server from its environment, and commit a placeholder.

{ "mcpServers": { "example": { "command": "python3", "args": ["server.py"], "env": { "API_TOKEN": "${API_TOKEN}" } } } } 

Whether a ${VAR} placeholder is expanded depends on the client, so check yours. In our count of 100 public AI and MCP repositories on 2026-11-12, 7 had a .mcp.json at the root (existence only; we did not read the contents).

4. Ignore what stays local

In .gitignore and, if you ship an image, in .dockerignore as well. .gitignore does not keep a file out of docker build.

.env .env.* .claude/settings.local.json *.pem 

5. Tool descriptions say what the tool does, nothing else

A description is read by the model as text. Do not put instructions to the model, credentials or internal addresses in it.

6. Default to reading, make writing explicit

A server that only reports is easier to trust and to review. If a tool changes something, say so in its name and description.

7. Scan the folder you are about to publish

Last, look at the folder itself. A free MIT-licensed command lists supported leak patterns in a folder's text files, with the values masked.

python3 zero_trace_lite.py . 

In our independent test it detected 32 of 32 planted samples (a figure for planted samples, not a detection rate for real folders). None found is not proof that nothing is there. The command reports only; it does not stop a commit.

To try it in a browser, there is a scanner you drop a folder onto (the check runs in the browser and the files under inspection are not sent): https://zero-trace-ship-kit.zeus-lab-global.workers.dev/?utm_source=devto

In short

  • If it connects and drops, suspect standard output first.
  • Keys come from the environment; the repository carries a placeholder.
  • Scan the folder once, right before release.

Disclosure: this article was drafted with AI assistance (Claude) and checked against the measured results and the published files. Product links lead to our own paid kits.