Move to remote HTTP safely
Write a threat checklist
Turn the server architecture into a short list of assets, entry points, abuse cases, controls, and remaining risk before deployment.
Before we deploy, let’s write down what could go wrong. One file, five headings, honest answers.
Create SECURITY.md with these sections: Assets, Entry points, Abuse cases, Controls, Remaining risks. Let’s fill them in for project-notes.
Assets
Start with what’s worth protecting: the note contents, any future backend credential, the caller’s identity, the logs, and the deployment configuration. “Just the notes” is the wrong answer. Logs and config are where secrets leak in practice.
Entry points
List every way data or commands get in:
- the command a host launches over stdio
- the public HTTP endpoint
- tool arguments and resource URIs
- prompt arguments and returned note text
- dependencies, environment values, and logs
That last line surprises people. A dependency is an entry point. So is an environment variable.
Abuse cases, with controls and proof
For each abuse case, name the control that stops it and the test that proves it:
| Abuse case | Control | Verification |
|---|---|---|
| Oversized search | Schema and result cap | Call with 101 characters and limit 11 |
| Unknown or expanded ID | Exact stable-ID lookup | Call with a missing ID and path-like text |
| Prompt injection in note | Untrusted-content handling | Run the harmless injection test |
| Token for another service | Audience validation | Present a wrong-audience token |
| Secret in logs | Redaction and safe fields | Inspect captured stderr and platform logs |
| Dependency compromise | Pinning and review | Record lockfile and audit process |
The third column turns a wish list into a checklist. “Schema caps the query” is a claim. “Called with 101 characters, got a validation error” is evidence.
Several controls sit outside the MCP handler: HTTPS, host and origin validation, rate limits, timeouts, secret storage, least-privilege backend access. List them anyway. The checklist covers the deployment, not just the code.
Remaining risks, stated plainly
Never write “mitigated” without a test to point at. Use four statuses: implemented, tested, planned, accepted. “Rate limiting: accepted, public demo with practice data” is honest. A blank row is not.
For every risk that survives into production, name an owner. A risk with no owner is a risk nobody is watching.
Keep it alive
The checklist earns its keep when the architecture changes. A new tool, data source, credential, transport, or dependency each expands the boundary. Add the row to SECURITY.md before shipping the change, not after.
Try this on a server you already run: write only the Assets and Entry points sections. If the list is longer than you expected, that alone was worth it.
Lesson completed