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 caseControlVerification
Oversized searchSchema and result capCall with 101 characters and limit 11
Unknown or expanded IDExact stable-ID lookupCall with a missing ID and path-like text
Prompt injection in noteUntrusted-content handlingRun the harmless injection test
Token for another serviceAudience validationPresent a wrong-audience token
Secret in logsRedaction and safe fieldsInspect captured stderr and platform logs
Dependency compromisePinning and reviewRecord 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