MCP
Endpoint: https://mcp.vesselmcp.com/mcp. This is stateless Streamable HTTP. A new server is created for every request and no session is issued.
GET https://mcp.vesselmcp.com/ is an unauthenticated introduction page and does not query vessels. /health is also public; both paths support GET and HEAD. The health response confirms only that this endpoint responds, not that authenticated tool queries will succeed. A request to /mcp that includes Origin returns HTTP 403 before authentication and has no CORS header. Do not call the tools from a browser.
Tools
Two read-only, idempotent tools are registered in this fixed order. Both accept only imo:
| Tool | Purpose |
|---|---|
vesselmcp_get_vessel | Identity |
vesselmcp_get_recent_ports | Recent ports, at most 10 entries |
There is no search, resources, prompts, session, or write operation. See the query guide for field rules.
On success, structuredContent has the same shape as REST data (without the {data:...} wrapper). There are also two text parts: a summary and JSON for that same object.
An identity miss returns isError with the text Vessel not found.. Other identity failures and all port-query failures return a general isError text and no invalid content.
POST /mcp
Authorization: Bearer vmcp_mcp_v1_<key-id>_<secret>
MCP-Protocol-Version: 2025-11-25
Content-Type: application/json
Accept: application/json, text/event-stream{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "vesselmcp_get_vessel",
"arguments": { "imo": "9331919" }
}
}Only vmcp_mcp_v1_... keys are accepted. API keys cannot call this service.
Protocol
2025-06-18 and 2025-11-25 are supported; 2025-11-25 is current. initialize may omit MCP-Protocol-Version. Every subsequent non-initialize JSON-RPC request, notification, and response must include a supported version header. An unsupported version header returns HTTP 400. When the protocolVersion in initialize is neither supported version, the negotiated version is 2025-11-25. notifications/initialized returns an empty 202 response and does not create a session. Every POST /mcp must list both application/json and text/event-stream in Accept; otherwise the transport returns HTTP 406. Content-Type must be application/json or the transport returns HTTP 415. The Worker authenticates, rate-limits, and prepares the JSON-RPC body first, so a parse or protocol-version failure returns HTTP 400 even when Accept is also missing.
Every request body must be a single JSON-RPC object and is limited to 16 KiB. Batches are rejected. JSON/UTF-8 parse failures return -32700; structurally invalid messages return -32600.
Rate limits
Rate limiting first uses requester IP address, then the non-sensitive key ID after successful authentication. Limits are counted per Cloudflare location. initialize, tools/list, and tools/call each count once.
| Stage | Limit |
|---|---|
| Before authentication, by IP | 30 requests per 60 seconds |
| After authentication, by key ID | 20 requests per 60 seconds |
An exceeded limit returns HTTP 429, JSON-RPC -32002, and Retry-After: 60.
Errors
Except for public GET/HEAD requests to / and /health, validation runs in this order: reject Origin on /mcp, IP rate limit, authentication, key-ID rate limit, exact path and absence of query parameters, HTTP method, then protocol and body validation. Route errors below therefore assume the earlier stages have passed; an unauthenticated request to an unknown path normally returns 401, not 404. Accept and Content-Type are checked after body preparation.
| HTTP | JSON-RPC error.code | When |
|---|---|---|
| 403 | -32003 | Origin is present |
| 401 | -32001 | Missing or invalid MCP key |
| 429 | -32002 | Rate limit exceeded |
| 503 | -32000 | Service temporarily unavailable |
| 404 | -32601 | Unknown path or /mcp with query parameters |
| 405 | -32600 | Exact /mcp path without query parameters, using a method other than POST |
| 406 | -32000 | Accept does not accept both application/json and text/event-stream |
| 415 | -32000 | Content-Type is not application/json |
| 400 | -32700 | JSON/UTF-8 parse failure or empty body |
| 400 | -32600 | Invalid JSON-RPC, batch, unsupported protocol version, or oversized body |
| 500 | -32603 | Uncategorized internal error |