Deploy and review
Review the security boundary
Compare the final implementation with the threat checklist and remove any access, output, or capability the project does not need.
We wrote SECURITY.md before deploying. Now the server is live, so let’s check whether the code and the configuration match what the file claims. This is the step most projects skip.
Open three things side by side: SECURITY.md, the source, and the deployed configuration. “Read-only” in a document means nothing if the backend credential can write.
Trace one request end to end
Follow a single get_note call across every boundary:
client → HTTPS/origin checks → token verification → MCP schema
→ handler authorization → notes backend → bounded result → logs
At each arrow, answer four questions. What data crosses here? Which identity is acting? What permission does it have? What happens when this step fails? An arrow you can’t answer for is where your next bug lives.
Read the logs like an attacker
Pull the captured stdio diagnostics and the platform logs from your test runs. Search them for note bodies, complete tool arguments, authorization headers, tokens, stack traces, and environment values.
Anything you find, remove. If a field has to be logged, write a narrow redaction rule and document it. “We log the note ID but never the body” is a rule. “We’re careful” is not.
Confirm each property with a test
For each line here, point to the matrix row that proves it:
- schemas bound input length and result count
- both handlers perform only reads
- backend credentials cannot write
- unknown IDs return safe tool errors
- untrusted note text remains labeled as data
- wrong-audience and wrong-scope tokens fail
- HTTP host and origin controls reject unexpected callers
No row? Add it and run it. Can’t be tested yet? Move it to “Remaining risks” with a status and an owner.
Upgrades are security events
Version 2 is the stable SDK line. But protocol revisions and SDK releases can still change behavior that matters here: what gets validated, what the fallback transport accepts, how errors are shaped. Pin the versions you tested. Read the release notes before upgrading. Rerun the full matrix after.
Delete what you don’t use
Compare the registered capabilities and the deployment permissions with your checklist. Anything not on it is a candidate for deletion: an unused registration, a secret nobody reads, a binding from an experiment, network access the server never needed, a legacy compatibility path you don’t support.
Removing is the cheapest security work there is. A deleted line can’t be exploited.
Finish the file honestly
End SECURITY.md with the remaining risks, each with a status and an owner. Don’t close it with “the server is secure”. “Read-only” and “authenticated” are properties you verified today. They are not reasons to stop looking tomorrow.
Lesson completed