The HTTP side of the MCP server: POST /mcp, one JSON-RPC message per request.
Each check runs only if the previous ones passed, and the first failure answers and halts:
- the route: any path but
/mcpis 404, any method but POST is 405 withallow: POST(the server has no event stream to offer); - the bearer token (401,
www-authenticate: Bearer), compared in constant time and checked before the body is read, so an unauthenticated client makes the server read nothing; - the
Originheader, when present: loopback or listed inallowed_origins, else 403. This is the protection against DNS rebinding that the MCP specification asks for; - the content type:
application/json, else 415; - the body: at most 1 MiB, else 413;
- decoding: text that is not JSON is 400 with
-32700; JSON that is not a request, notification, or response (a batch included) is 400 with-32600.
Every refusal is a JSON-RPC error with "id": null. A message that decodes is handed to the
dispatcher: a reply is 200 with one JSON object, no reply is 202 with an empty body. A bug in
the dispatcher becomes a generic 500; only the exception module is logged, because a crash
report of a request process can print the whole connection, Authorization header included.
No cookies and no CORS headers are ever set.
Options
:configuration- theMead.MCP.Server.Configuration(required).:dispatcher- a module withdispatch/2; defaults toMead.MCP.Server.Dispatcher, and is only replaced by tests.