{
  "openapi": "3.1.0",
  "info": {
    "title": "Plan Harmony Experiences API",
    "version": "1.0.0",
    "description": "JSON-RPC over HTTP interface to the Plan Harmony Experiences MCP server (Model Context Protocol 2025-06-18). Provides tools for destination search, experience search, and experience details lookup. The canonical interface is MCP — see https://www.planharmony.com/.well-known/mcp/server-card.json for the server card and tool schemas.",
    "contact": {
      "name": "Plan Harmony",
      "url": "https://www.planharmony.com"
    },
    "license": {
      "name": "Terms of Service",
      "url": "https://www.planharmony.com/terms/"
    }
  },
  "servers": [
    {
      "url": "https://api.planharmony.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/mcp/": {
      "post": {
        "operationId": "mcpJsonRpc",
        "summary": "MCP JSON-RPC endpoint",
        "description": "Streamable HTTP transport for the Model Context Protocol. Send JSON-RPC 2.0 requests for `tools/list`, `tools/call`, and other MCP methods. Available tools: `destinations_search`, `experiences_search`, `experiences_details`. No authentication required.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              },
              "examples": {
                "listTools": {
                  "summary": "List available tools",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "tools/list"
                  }
                },
                "searchExperiences": {
                  "summary": "Search experiences by keyword",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 2,
                    "method": "tools/call",
                    "params": {
                      "name": "experiences_search",
                      "arguments": {
                        "query": "rome colosseum tour"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC 2.0 response",
            "headers": {
              "X-RateLimit-Limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/XRateLimitReset" },
              "X-RateLimit-Policy": { "$ref": "#/components/headers/XRateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-sent events stream for streamable responses"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON-RPC request"
          },
          "429": {
            "description": "Rate limit exceeded. Wait `Retry-After` seconds before retrying.",
            "headers": {
              "X-RateLimit-Limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/XRateLimitReset" },
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "XRateLimitLimit": {
        "description": "Requests allowed in the current rate-limit window.",
        "schema": { "type": "integer" },
        "example": 60
      },
      "XRateLimitRemaining": {
        "description": "Requests remaining in the current rate-limit window.",
        "schema": { "type": "integer" },
        "example": 59
      },
      "XRateLimitReset": {
        "description": "Unix timestamp (seconds) at which the current rate-limit window resets.",
        "schema": { "type": "integer" },
        "example": 1747257600
      },
      "XRateLimitPolicy": {
        "description": "Rate-limit policy descriptor in the form `<limit>;w=<window-seconds>`.",
        "schema": { "type": "string" },
        "example": "60;w=60"
      },
      "RetryAfter": {
        "description": "Seconds the client should wait before retrying after a 429.",
        "schema": { "type": "integer" },
        "example": 60
      }
    },
    "schemas": {
      "JsonRpcRequest": {
        "type": "object",
        "required": ["jsonrpc", "method"],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              { "type": "string" },
              { "type": "number" }
            ]
          },
          "method": {
            "type": "string",
            "description": "MCP method name (e.g., `tools/list`, `tools/call`)"
          },
          "params": {
            "type": "object",
            "description": "Method-specific parameters"
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": ["jsonrpc"],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              { "type": "string" },
              { "type": "number" },
              { "type": "null" }
            ]
          },
          "result": {
            "description": "Result payload (present on success)"
          },
          "error": {
            "type": "object",
            "description": "Error object (present on failure)",
            "properties": {
              "code": { "type": "integer" },
              "message": { "type": "string" },
              "data": {}
            }
          }
        }
      }
    }
  }
}
