{"openapi":"3.1.0","info":{"title":"Sorted Travel MCP","version":"1.0.0","summary":"Public MCP tools for destination ranking, facts, and weather.","description":"Integration is the Streamable HTTP MCP server at https://sorted.travel/mcp. No API key is required. Tools do not search or book flights or activities. The canonical MCP URL is /mcp and does not use a /v1/ path prefix. The tool and JSON contract is SemVer 1.0.0, published identically as OpenAPI info.version, the MCP server card version, the API-Version response header, and GET /mcp contractVersion. Major means a stable tool or field is removed, renamed, or changed in meaning. Minor means additive tools or fields. Patch means documentation or spec-only corrections. Clients may send the API-Version request header to pin the contract; only 1.0.0 is served today. Unknown values are ignored, and the API-Version response header reports the version actually served. Additive changes ship without notice. A major bump in API-Version is the signal that the previous contract is gone; there is no deprecation window and no Deprecation or Sunset headers. Responses include IETF RateLimit-Policy and RateLimit structured fields. Quotas are the server rate_limits configuration for the mcp bucket (second, minute, hour, day, and month windows). When a window is exhausted, the server returns 429 with Retry-After set to the seconds remaining in that window. POST /mcp accepts an optional Idempotency-Key header. Retry the same JSON-RPC body with the same key to replay the original response instead of running the tool twice.","contact":{"name":"Sorted Travel","email":"support@sorted.travel","url":"https://sorted.travel/developers"},"license":{"name":"Use under Sorted Travel Terms","url":"https://sorted.travel/terms"}},"servers":[{"url":"https://sorted.travel","description":"Production"}],"paths":{"/mcp":{"get":{"operationId":"mcpStreamableHttpGet","summary":"Sorted Travel MCP server (SSE)","description":"Public unauthenticated GET. Returns a JSON document with MCP Apps ui:// resources, tool _meta.ui.resourceUri links, contractVersion, and IETF RateLimit headers so agents can read remaining quota without a session. SSE GET (Accept: text/event-stream) returns 405 because this server has no standalone GET stream; use POST for MCP. The canonical MCP URL is /mcp and does not use a /v1/ path prefix. The tool and JSON contract is SemVer 1.0.0, published identically as OpenAPI info.version, the MCP server card version, the API-Version response header, and GET /mcp contractVersion. Major means a stable tool or field is removed, renamed, or changed in meaning. Minor means additive tools or fields. Patch means documentation or spec-only corrections. Clients may send the API-Version request header to pin the contract; only 1.0.0 is served today. Unknown values are ignored, and the API-Version response header reports the version actually served. Additive changes ship without notice. A major bump in API-Version is the signal that the previous contract is gone; there is no deprecation window and no Deprecation or Sunset headers. Responses include IETF RateLimit-Policy and RateLimit structured fields. Quotas are the server rate_limits configuration for the mcp bucket (second, minute, hour, day, and month windows). When a window is exhausted, the server returns 429 with Retry-After set to the seconds remaining in that window.","parameters":[{"name":"API-Version","in":"header","required":false,"description":"Pin the tool and JSON contract version. Currently only 1.0.0 is served. Omit the header to receive the current contract. Unknown values are ignored; the API-Version response header reports the version actually served.","schema":{"type":"string","enum":["1.0.0"]}}],"responses":{"200":{"description":"Public JSON document. No API key. Includes API-Version and RateLimit headers.","headers":{"API-Version":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}},"RateLimit-Policy":{"description":"IETF quota policy list. Each item is a named window from the server rate_limits config, with q=quota and w=window seconds.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota (r) and seconds until reset (t) for each advertised window.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Quota for the tightest advertised window, from the server rate_limits config.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in the tightest advertised window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until the tightest advertised window resets.","schema":{"type":"integer","minimum":0}},"Retry-After":{"description":"Seconds to wait before retrying. Present on 429 responses when a window is exhausted, and on 409 when an Idempotency-Key is still in flight.","schema":{"type":"integer","minimum":1}},"Idempotency-Key":{"description":"Echo of the request Idempotency-Key when the client sent one.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpPublicDocument"},"example":{"status":"OK","api":"sorted-travel-mcp","contractVersion":"1.0.0","transport":"streamable-http","url":"https://sorted.travel/mcp","authentication":"none","extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"resources":[{"name":"recommendations","uri":"ui://sorted/recommendations","mimeType":"text/html;profile=mcp-app"},{"name":"place","uri":"ui://sorted/place","mimeType":"text/html;profile=mcp-app"}],"tools":[{"name":"get_recommended_destinations","_meta":{"ui":{"resourceUri":"ui://sorted/recommendations","visibility":["model","app"]},"ui/resourceUri":"ui://sorted/recommendations"}},{"name":"get_destination_info","_meta":{"ui":{"resourceUri":"ui://sorted/place","visibility":["model","app"]},"ui/resourceUri":"ui://sorted/place"}},{"name":"get_destination_weather","_meta":{"ui":{"resourceUri":"ui://sorted/place","visibility":["model","app"]},"ui/resourceUri":"ui://sorted/place"}}],"hint":"POST JSON-RPC to this URL. No API key is required. MCP Apps UI resources use the ui:// scheme. See https://sorted.travel/developers and https://sorted.travel/openapi.json."}}}},"404":{"description":"This MCP path does not exist. Use POST /mcp.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"405":{"description":"SSE GET is not supported. Use POST for MCP JSON-RPC.","headers":{"API-Version":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"429":{"description":"MCP quota exhausted for this client.","headers":{"API-Version":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}},"RateLimit-Policy":{"description":"IETF quota policy list. Each item is a named window from the server rate_limits config, with q=quota and w=window seconds.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota (r) and seconds until reset (t) for each advertised window.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Quota for the tightest advertised window, from the server rate_limits config.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in the tightest advertised window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until the tightest advertised window resets.","schema":{"type":"integer","minimum":0}},"Retry-After":{"description":"Seconds to wait before retrying. Present on 429 responses when a window is exhausted, and on 409 when an Idempotency-Key is still in flight.","schema":{"type":"integer","minimum":1}},"Idempotency-Key":{"description":"Echo of the request Idempotency-Key when the client sent one.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpStatusMessage"}}}}}},"post":{"operationId":"mcpStreamableHttp","summary":"Sorted Travel MCP server","description":"Streamable HTTP MCP endpoint. Add this URL in an MCP host. Tools: resolve_destination, get_recommended_destinations, get_destination_info, get_destination_weather. MCP Apps-enabled: those destination tools set _meta.ui.resourceUri to ui://sorted/recommendations or ui://sorted/place. The canonical MCP URL is /mcp and does not use a /v1/ path prefix. The tool and JSON contract is SemVer 1.0.0, published identically as OpenAPI info.version, the MCP server card version, the API-Version response header, and GET /mcp contractVersion. Major means a stable tool or field is removed, renamed, or changed in meaning. Minor means additive tools or fields. Patch means documentation or spec-only corrections. Clients may send the API-Version request header to pin the contract; only 1.0.0 is served today. Unknown values are ignored, and the API-Version response header reports the version actually served. Additive changes ship without notice. A major bump in API-Version is the signal that the previous contract is gone; there is no deprecation window and no Deprecation or Sunset headers. Responses include IETF RateLimit-Policy and RateLimit structured fields. Quotas are the server rate_limits configuration for the mcp bucket (second, minute, hour, day, and month windows). When a window is exhausted, the server returns 429 with Retry-After set to the seconds remaining in that window. POST /mcp accepts an optional Idempotency-Key header. Retry the same JSON-RPC body with the same key to replay the original response instead of running the tool twice.","parameters":[{"name":"API-Version","in":"header","required":false,"description":"Pin the tool and JSON contract version. Currently only 1.0.0 is served. Omit the header to receive the current contract. Unknown values are ignored; the API-Version response header reports the version actually served.","schema":{"type":"string","enum":["1.0.0"]}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Client-generated key for this POST. Retry the same JSON-RPC body with the same key after a network failure. The server replays the original response for 24 hours. Reusing a key with a different body returns 422. A concurrent retry while the first request is still running returns 409.","schema":{"type":"string","minLength":1,"maxLength":256}}],"responses":{"200":{"description":"JSON-RPC 2.0 MCP response. application/json by default; text/event-stream when Accept lists it.","headers":{"API-Version":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}},"RateLimit-Policy":{"description":"IETF quota policy list. Each item is a named window from the server rate_limits config, with q=quota and w=window seconds.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota (r) and seconds until reset (t) for each advertised window.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Quota for the tightest advertised window, from the server rate_limits config.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in the tightest advertised window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until the tightest advertised window resets.","schema":{"type":"integer","minimum":0}},"Retry-After":{"description":"Seconds to wait before retrying. Present on 429 responses when a window is exhausted, and on 409 when an Idempotency-Key is still in flight.","schema":{"type":"integer","minimum":1}},"Idempotency-Key":{"description":"Echo of the request Idempotency-Key when the client sent one.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}},"text/event-stream":{"schema":{"type":"string","description":"The same JSON-RPC body as application/json, sent as one SSE data event when the client Accept lists text/event-stream."}}}},"404":{"description":"This MCP path does not exist. Use POST /mcp.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"A request with this Idempotency-Key is still running. Retry with the same key. Body status is IDEMPOTENCY_IN_FLIGHT.","headers":{"API-Version":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}},"RateLimit-Policy":{"description":"IETF quota policy list. Each item is a named window from the server rate_limits config, with q=quota and w=window seconds.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota (r) and seconds until reset (t) for each advertised window.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Quota for the tightest advertised window, from the server rate_limits config.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in the tightest advertised window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until the tightest advertised window resets.","schema":{"type":"integer","minimum":0}},"Retry-After":{"description":"Seconds to wait before retrying. Present on 429 responses when a window is exhausted, and on 409 when an Idempotency-Key is still in flight.","schema":{"type":"integer","minimum":1}},"Idempotency-Key":{"description":"Echo of the request Idempotency-Key when the client sent one.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpStatusMessage"}}}},"422":{"description":"This Idempotency-Key was already used with a different request body. Body status is IDEMPOTENCY_KEY_CONFLICT.","headers":{"API-Version":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}},"RateLimit-Policy":{"description":"IETF quota policy list. Each item is a named window from the server rate_limits config, with q=quota and w=window seconds.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota (r) and seconds until reset (t) for each advertised window.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Quota for the tightest advertised window, from the server rate_limits config.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in the tightest advertised window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until the tightest advertised window resets.","schema":{"type":"integer","minimum":0}},"Retry-After":{"description":"Seconds to wait before retrying. Present on 429 responses when a window is exhausted, and on 409 when an Idempotency-Key is still in flight.","schema":{"type":"integer","minimum":1}},"Idempotency-Key":{"description":"Echo of the request Idempotency-Key when the client sent one.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpStatusMessage"}}}},"429":{"description":"MCP quota exhausted. Body status is RATE_LIMIT_EXCEEDED.","headers":{"API-Version":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}},"RateLimit-Policy":{"description":"IETF quota policy list. Each item is a named window from the server rate_limits config, with q=quota and w=window seconds.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota (r) and seconds until reset (t) for each advertised window.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Quota for the tightest advertised window, from the server rate_limits config.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in the tightest advertised window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until the tightest advertised window resets.","schema":{"type":"integer","minimum":0}},"Retry-After":{"description":"Seconds to wait before retrying. Present on 429 responses when a window is exhausted, and on 409 when an Idempotency-Key is still in flight.","schema":{"type":"integer","minimum":1}},"Idempotency-Key":{"description":"Echo of the request Idempotency-Key when the client sent one.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpStatusMessage"}}}}}}}},"components":{"parameters":{"ApiVersion":{"name":"API-Version","in":"header","required":false,"description":"Pin the tool and JSON contract version. Currently only 1.0.0 is served. Omit the header to receive the current contract. Unknown values are ignored; the API-Version response header reports the version actually served.","schema":{"type":"string","enum":["1.0.0"]}}},"headers":{"ApiVersion":{"description":"SemVer tool and JSON contract version served for this response. Identical to OpenAPI info.version and the MCP server card version.","required":true,"schema":{"type":"string","enum":["1.0.0"]}}},"schemas":{"Problem":{"type":"object","required":["type","title","status","detail","error","message","hint"],"properties":{"type":{"type":"string","format":"uri","description":"URI that identifies this problem type."},"title":{"type":"string","description":"Short human-readable summary of the problem type."},"status":{"type":"integer","description":"HTTP status code of this occurrence."},"detail":{"type":"string","description":"Human-readable explanation of this occurrence."},"instance":{"type":"string","description":"The request path that produced this problem."},"error":{"type":"string","description":"Machine-readable error code, such as NOT_FOUND."},"code":{"type":"string","description":"Alias of error for clients that look for code."},"message":{"type":"string","description":"Human-readable explanation of this occurrence."},"hint":{"type":"string","description":"Where to go next: /developers, /openapi.json, and POST /mcp."}}},"McpPublicDocument":{"type":"object","additionalProperties":false,"required":["status","api","contractVersion","transport","url","authentication","extensions","resources","tools","hint"],"properties":{"status":{"type":"string","enum":["OK"],"description":"Service liveness marker."},"api":{"type":"string","enum":["sorted-travel-mcp"],"description":"Public identifier for this MCP server."},"contractVersion":{"type":"string","enum":["1.0.0"],"description":"SemVer tool and JSON contract version. Identical to OpenAPI info.version, the MCP server card version, and the API-Version response header."},"transport":{"type":"string","enum":["streamable-http"],"description":"MCP transport. Call tools with POST, not GET."},"url":{"type":"string","format":"uri","description":"Canonical Streamable HTTP MCP URL."},"authentication":{"type":"string","enum":["none"],"description":"No API key or OAuth is required."},"extensions":{"type":"object","description":"MCP Apps capability advertised on this public GET.","properties":{"io.modelcontextprotocol/ui":{"type":"object","required":["mimeTypes"],"properties":{"mimeTypes":{"type":"array","items":{"type":"string","enum":["text/html;profile=mcp-app"]}}}}}},"resources":{"type":"array","description":"MCP Apps ui:// HTML widgets this server exposes.","items":{"type":"object","required":["name","uri","mimeType"],"properties":{"name":{"type":"string","description":"Widget name, such as recommendations or place."},"uri":{"type":"string","description":"ui:// URI hosts fetch for the widget HTML."},"mimeType":{"type":"string","enum":["text/html;profile=mcp-app"]}}}},"tools":{"type":"array","description":"MCP Apps-enabled tools on this public GET. Full tool input schemas come from MCP tools/list, not this document.","items":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"MCP tool name."},"_meta":{"type":"object","properties":{"ui":{"type":"object","properties":{"resourceUri":{"type":"string","description":"ui:// widget to render for this tool."},"visibility":{"type":"array","items":{"type":"string","enum":["model","app"]}}}},"ui/resourceUri":{"type":"string","description":"Alias of ui.resourceUri for hosts that read the slash form."}}}}}},"hint":{"type":"string","description":"Where to go next: POST JSON-RPC to /mcp, /developers, and /openapi.json."}}},"JsonRpcError":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","description":"JSON-RPC error code, such as -32600 for invalid request."},"message":{"type":"string","description":"Human-readable JSON-RPC error message."},"data":{"description":"Optional JSON-RPC error payload."}}},"JsonRpcResponse":{"type":"object","required":["jsonrpc"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"],"description":"JSON-RPC protocol version."},"id":{"description":"Request id from the JSON-RPC call, or a server-assigned id on some errors.","oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"result":{"type":"object","additionalProperties":true,"description":"JSON-RPC result whose shape depends on the MCP method (initialize, tools/list, tools/call, resources/read). Tool payloads are not REST resources; use MCP tools/list for input schemas and structuredContent for tool results."},"error":{"$ref":"#/components/schemas/JsonRpcError"}}},"McpStatusMessage":{"type":"object","additionalProperties":false,"required":["status","message"],"properties":{"status":{"type":"string","enum":["RATE_LIMIT_EXCEEDED","IDEMPOTENCY_IN_FLIGHT","IDEMPOTENCY_KEY_CONFLICT"],"description":"Machine-readable MCP HTTP error code."},"message":{"type":"string","description":"Human-readable explanation of this occurrence."}}}}},"externalDocs":{"description":"Sorted Travel developer portal","url":"https://sorted.travel/developers"}}