AI
Build with AI
ShipThis is built to be used by AI agents as well as people. Connect your agent to the ShipThis MCP server to call the platform’s tools and APIs, and point tools at our llms.txt for AI-friendly docs discovery.
Model Context Protocol (MCP) server
The ShipThis MCP server exposes platform tools (reporting, navigation, and operations — e.g. get_report_info, generate_report_url, get_layout) to MCP-compatible clients such as Claude, Cursor, and Windsurf.
Every tool runs as the user that owns the API key, so the data and actions available follow that user’s roles and permissions.
- Endpoint
- https://mcp.shipthis.ai/mcp
- Transport
- streamable-http
- Auth
- x-api-key + organisation
Connect a client
First, generate an API key from your ShipThis account. Every request needs two headers: x-api-key (your API key) and organisation (your organisation identifier, e.g. the slug in your manage URL). Without both you’ll get Access denied. Setup differs slightly per client.
Cursor
Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (per project):
{
"mcpServers": {
"shipthis": {
"url": "https://mcp.shipthis.ai/mcp",
"headers": {
"x-api-key": "YOUR_SHIPTHIS_API_KEY",
"organisation": "YOUR_ORG"
}
}
}
}Claude Code
Register the server from your terminal:
claude mcp add --transport http shipthis https://mcp.shipthis.ai/mcp \
--header "x-api-key: YOUR_SHIPTHIS_API_KEY" \
--header "organisation: YOUR_ORG"Claude Desktop
Claude Desktop’s connector UI only supports OAuth, so for header auth bridge the server with mcp-remote in claude_desktop_config.json:
{
"mcpServers": {
"shipthis": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://mcp.shipthis.ai/mcp",
"--header", "x-api-key:${SHIPTHIS_API_KEY}",
"--header", "organisation:${SHIPTHIS_ORG}"
],
"env": {
"SHIPTHIS_API_KEY": "YOUR_SHIPTHIS_API_KEY",
"SHIPTHIS_ORG": "YOUR_ORG"
}
}
}
}Optional headers. region, usertype, and location are sent by the ShipThis web app for UI context and aren’t required by the MCP server — auth and the data you can access are scoped by your API key and organisation. If your organisation spans multiple regions, you can pass region (e.g. usa) to target a specific one.
Other clients (Windsurf, VS Code, and similar) use the same url + x-api-key + organisation shape as Cursor — check your client’s docs for the exact config file. See the API reference for the full set of operations.
Available tools (31)
The tools your MCP client can call. Every client sees this same catalogue — tools/list is unauthenticated. Your API key’s roles and permissions decide which of these calls actually succeed, not which ones appear here.
An agent picks its own tools, so a connected client can create, change, or delete records without asking first. Scope the API key to what the agent genuinely needs — a read-only key is the safest default while you are experimenting.
create_collection_item, delete_collection_item, execute_generic_action, execute_workflow_transition, trigger_automation, update_collection_item
Essential · 3
Navigation · 2
Reporting · 4
Read · 6
Configuration · 3
Workflow · 7
Write · 4
Audit · 2
Example prompts
Once connected, ask your agent in plain language — it picks the right tools on its own. A few things you can try:
- “What collections and views can I access?”get_collection_list, get_layout
- “How many shipments are in each workflow status?”count_documents_by_status
- “Build a report of overdue invoices this month and give me a shareable link.”create_ai_report, generate_report_url
- “Find the coordinates and country for the port of Rotterdam.”search_location
- “Show the recent edit history for this shipment.”get_document_history
Skipping the client and speaking to the server yourself? See Calling the server directly below.
Calling the server directly
MCP clients handle this for you. If you are writing the integration yourself, the streamable-http transport has three requirements that are easy to miss:
- Carry the session id
initializereturns anmcp-session-idresponse header — not a field in the body. Every later request must send it back, or the server answers400 Missing session ID. - Accept both content typesSend
Accept: application/json, text/event-stream. Offering only one of the two is rejected with406. - Parse the SSE framesSuccessful replies come back as server-sent events, not a bare JSON document: each JSON-RPC message arrives as a
data:line preceded byevent: message. Decode thedata:payloads rather than runningJSON.parseover the whole body.
A complete exchange — handshake, tool call, and releasing the session:
MCP_URL="https://mcp.shipthis.ai/mcp"
API_KEY="YOUR_SHIPTHIS_API_KEY"
ORG="YOUR_ORG"
# 1. initialize — the session id arrives in the mcp-session-id response header
SID=$(curl -sS -D - -o /dev/null -X POST "$MCP_URL" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "x-api-key: $API_KEY" \
-H "organisation: $ORG" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0.0"}}}' \
| awk 'tolower($1)=="mcp-session-id:"{print $2}' | tr -d '\r')
# 2. confirm the handshake (a notification — no response body)
curl -sS -o /dev/null -X POST "$MCP_URL" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SID" \
-H "x-api-key: $API_KEY" \
-H "organisation: $ORG" \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
# 3. call a tool — repeat the session id and auth headers on every request
curl -sS -X POST "$MCP_URL" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SID" \
-H "x-api-key: $API_KEY" \
-H "organisation: $ORG" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_location","arguments":{"query":"Rotterdam"}}}'
# 4. optional: release the session when you are done
curl -sS -X DELETE "$MCP_URL" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SID"Decoding the data: line of that tool call gives you the JSON-RPC result:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{ "type": "text", "text": "..." }
],
"isError": false
}
}Sessions are cheap to keep and cheap to drop. Reuse one across many calls rather than re-running initialize per request, and DELETE it when you are finished. The protocol version above (2024-11-05) is the one this portal uses to build its own tool catalogue.
Auth and errors
The server splits its failures into two shapes, and they do not look alike. Handling only one of them is the most common integration bug.
Auth failures return HTTP 200
A rejected tool call is still a successful HTTP request and still a well-formed JSON-RPC response. There is no error member — the failure is reported as result.isError, with the reason in the text content. Branch on isError; a status-code check alone will read this as success:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{ "type": "text", "text": "Access denied: Authentication error occurred" }
],
"isError": true
}
}Transport failures return a real status code
Problems the server hits before it reaches your tool — a missing session, an unacceptable Accept header — come back as plain JSON (no SSE framing) with a genuine 4xx status and a JSON-RPC error member:
{
"jsonrpc": "2.0",
"id": "server-error",
"error": {
"code": -32600,
"message": "Bad Request: Missing session ID"
}
}What each failure means
| Status | Message | Cause |
|---|---|---|
| 400 | Bad Request: Missing session ID | A post-handshake request left out the mcp-session-id header. |
| 404 | Session not found | The session id is unknown — often a restarted server or a stale id. |
| 404 | Not Found: Session has been terminated | The session was already released with DELETE. |
| 406 | Not Acceptable: Client must accept both application/json and text/event-stream | The Accept header did not offer both content types. |
| 200 | Access denied: Authentication error occurred | x-api-key or organisation is missing or invalid. Returned as result.isError, not an HTTP error. |
A quick way to triage. tools/list needs no credentials. If it succeeds but your tool calls come back denied, the transport is fine and the problem is your x-api-key / organisation pair. If tools/list itself fails, the problem is the connection, not your credentials.
Limits and retries
ShipThis does not currently publish numeric rate limits for the MCP server, and its responses carry no x-ratelimit-* or Retry-After headers. Treat the limits as unpublished rather than absent: an agent left in a loop can issue a lot of calls very quickly, so build the usual defences instead of relying on the server to push back.
- Reuse the sessionOne
initializeper client, not per tool call. Re-handshaking on every request triples your traffic for no benefit. - Back off on transport errorsRetry 5xx responses and timeouts with exponential backoff. Do not retry a
result.isErrorauth failure — bad credentials stay bad, and retrying just multiplies the load. - Set a timeoutThe service can cold-start, so give the first request room. This portal allows ten seconds for its whole build-time handshake, which is a reasonable starting point.
- Keep concurrency modestPrefer sequential calls within a session. If you need throughput beyond a handful of concurrent requests, talk to us first so we can tell you what the backend will take.
Troubleshooting
The failures we see most often, and what each one actually means:
- Every call after connecting returns 400 Missing session ID
- Your client is not echoing the mcp-session-id header. Read it from the initialize response headers and attach it to every subsequent request.
- Calls that worked earlier now return 404 Session not found
- The server no longer recognises that session id — it may have expired, or the server may have restarted. Run initialize again and switch to the new id; session ids are not durable.
- 404 Not Found: Session has been terminated
- Something already sent DELETE for that session. Start a fresh one with initialize.
- 406 Not Acceptable
- The Accept header must offer application/json and text/event-stream together. Some HTTP clients default to */* or application/json only.
- Access denied: Authentication error occurred, but the HTTP status is 200
- That is the expected shape for an auth failure, not a bug — the server reports it on the result rather than the status line. Check that both x-api-key and organisation are present and correct; the server answers identically whether the headers are absent or simply wrong, so the message alone will not tell you which.
- Claude Desktop connects but every tool call is denied
- mcp-remote splits --header values on whitespace, so "x-api-key: KEY" loses everything after the space. Use the env-var form shown above, with no space after the colon.
- The client shows no tools at all
- tools/list needs no credentials, so an empty list points at the connection or the client config rather than your API key. Confirm the endpoint URL and that your network allows streaming responses.
llms.txt
This portal publishes an /llms.txt index and a full /llms-full.txt document so AI tools can discover and read our docs, SDKs, and API reference. Point your agent or IDE at these URLs for ShipThis context.