{
  "openapi": "3.1.0",
  "info": {
    "title": "Dunelm Cottage API",
    "version": "1.0.0",
    "summary": "Read-only, keyless data API for the Dunelm Cottage holiday rental in Edale, Peak District.",
    "description": "Public API for dunelmcottage.co.uk, a luxury three-bedroom holiday cottage in Edale, Peak District National Park, England. Agents can fetch property facts, guest reviews, local attractions and booking channels without authentication. There is no write surface; bookings are completed on Airbnb or Booking.com. Fair-use limit of about 60 requests per minute per client.",
    "contact": {
      "name": "Dunelm Cottage",
      "url": "https://dunelmcottage.co.uk/contact"
    },
    "license": { "name": "CC-BY-4.0", "identifier": "CC-BY-4.0" }
  },
  "servers": [{ "url": "https://dunelmcottage.co.uk", "description": "Production" }],
  "tags": [
    { "name": "Property", "description": "The cottage itself" },
    { "name": "Content", "description": "Reviews and local attractions" },
    { "name": "Booking", "description": "Where to book" },
    { "name": "Integration", "description": "Machine-facing surfaces" }
  ],
  "paths": {
    "/api/": {
      "get": {
        "operationId": "getApiIndex",
        "tags": ["Integration"],
        "summary": "List all API endpoints",
        "description": "Returns an index of every endpoint in this API plus links to the OpenAPI spec, MCP server and developer docs.",
        "responses": {
          "200": {
            "description": "Endpoint index",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiIndex" },
                "example": {
                  "object": "api_index",
                  "name": "Dunelm Cottage API",
                  "version": "1.0.0",
                  "endpoints": [
                    "https://dunelmcottage.co.uk/api/v1/cottage",
                    "https://dunelmcottage.co.uk/api/v1/reviews",
                    "https://dunelmcottage.co.uk/api/v1/attractions",
                    "https://dunelmcottage.co.uk/api/v1/booking"
                  ],
                  "openapi": "https://dunelmcottage.co.uk/openapi.json",
                  "mcp": "https://dunelmcottage.co.uk/mcp",
                  "docs": "https://dunelmcottage.co.uk/developers"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cottage": {
      "get": {
        "operationId": "getCottage",
        "tags": ["Property"],
        "summary": "Get the property profile",
        "description": "Full factual profile of Dunelm Cottage: address, coordinates, bedrooms, amenities, pet policy, price range and aggregate rating.",
        "responses": {
          "200": {
            "description": "Property profile",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Cottage" } } }
          },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      }
    },
    "/api/v1/reviews": {
      "get": {
        "operationId": "listGuestReviews",
        "tags": ["Content"],
        "summary": "List verified guest reviews",
        "description": "Guest reviews with ratings and publication dates, as shown on the homepage. All reviews are from verified stays booked through Airbnb.",
        "responses": {
          "200": {
            "description": "Review list",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ReviewList" },
                "example": {
                  "object": "review_list",
                  "ratingValue": 5,
                  "reviewCount": 50,
                  "reviews": [
                    {
                      "author": "Rosemary",
                      "rating": 5,
                      "datePublished": "2024-12-01",
                      "body": "Dunelm cottage was a perfect base for our Peak District mini break for three cousins."
                    }
                  ]
                }
              }
            }
          },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      }
    },
    "/api/v1/attractions": {
      "get": {
        "operationId": "listAttractions",
        "tags": ["Content"],
        "summary": "List local Peak District attractions",
        "description": "Attractions near the cottage (Castleton, Bakewell, Chatsworth House and more) with short summaries and travel notes from the welcome guide.",
        "responses": {
          "200": {
            "description": "Attraction list",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AttractionList" } } }
          },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      }
    },
    "/api/v1/booking": {
      "get": {
        "operationId": "getBookingOptions",
        "tags": ["Booking"],
        "summary": "Get booking channels",
        "description": "URLs for booking the cottage on Airbnb and Booking.com plus general enquiries via Instagram. Live availability and pricing live on those platforms; there is no direct booking API.",
        "responses": {
          "200": {
            "description": "Booking channels",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BookingOptions" } } }
          },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "postMcpJsonRpc",
        "tags": ["Integration"],
        "summary": "MCP server endpoint (JSON-RPC 2.0)",
        "description": "Model Context Protocol server over Streamable HTTP. Send JSON-RPC 2.0 requests: `initialize`, `ping`, `tools/list`, `tools/call`. Tools: get-cottage, list-reviews, list-attractions, get-booking-options. GET returns 405 because no SSE stream is offered. Also discoverable at /.well-known/mcp.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object" },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/call",
                "params": { "name": "get-cottage", "arguments": {} }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (single message or batch)",
            "content": {
              "application/json": {
                "schema": { "type": "object" },
                "example": {
                  "jsonrpc": "2.0",
                  "id": 1,
                  "result": {
                    "protocolVersion": "2025-06-18",
                    "capabilities": { "tools": {} },
                    "serverInfo": { "name": "dunelm-cottage", "version": "1.0.0" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      },
      "get": {
        "operationId": "getMcpNotSupported",
        "tags": ["Integration"],
        "summary": "SSE stream not offered",
        "description": "Always returns 405 Method Not Allowed. This MCP server accepts POST only (stateless Streamable HTTP).",
        "responses": {
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      }
    }
  },
  "components": {
    "responses": {
      "MethodNotAllowed": {
        "description": "HTTP method not supported",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "BadRequest": {
        "description": "Malformed request body",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "examples": ["not_found"], "description": "Stable machine-readable error code." },
              "message": { "type": "string", "description": "Human-readable explanation." },
              "hint": { "type": "string", "description": "How to fix the request." }
            },
            "required": ["code", "message"]
          }
        },
        "required": ["error"],
        "examples": [
          {
            "error": {
              "code": "not_found",
              "message": "No API endpoint at /v1/cottages.",
              "hint": "See https://dunelmcottage.co.uk/openapi.json for valid endpoints."
            }
          }
        ]
      },
      "ApiIndex": {
        "type": "object",
        "properties": {
          "object": { "const": "api_index" },
          "name": { "type": "string" },
          "version": { "type": "string" },
          "description": { "type": "string" },
          "endpoints": { "type": "array", "items": { "type": "string", "format": "uri" } },
          "openapi": { "type": "string", "format": "uri" },
          "mcp": { "type": "string", "format": "uri" },
          "docs": { "type": "string", "format": "uri" }
        }
      },
      "Cottage": {
        "type": "object",
        "properties": {
          "object": { "const": "cottage" },
          "name": { "type": "string" },
          "type": { "type": "string", "const": "LodgingBusiness" },
          "description": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "address": {
            "type": "object",
            "properties": {
              "streetAddress": { "type": "string" },
              "addressLocality": { "type": "string" },
              "addressRegion": { "type": "string" },
              "postalCode": { "type": "string" },
              "addressCountry": { "type": "string" }
            }
          },
          "geo": {
            "type": "object",
            "properties": {
              "latitude": { "type": "number" },
              "longitude": { "type": "number" }
            }
          },
          "containedInPlace": { "type": "string" },
          "bedrooms": { "type": "integer" },
          "bathrooms": { "type": "integer" },
          "bedTypes": {
            "type": "object",
            "properties": {
              "king": { "type": "integer" },
              "double": { "type": "integer" }
            }
          },
          "amenities": { "type": "array", "items": { "type": "string" } },
          "petsAllowed": { "type": "boolean" },
          "smokingAllowed": { "type": "boolean" },
          "priceRange": { "type": "string" },
          "aggregateRating": {
            "type": "object",
            "properties": {
              "ratingValue": { "type": "number" },
              "reviewCount": { "type": "integer" },
              "bestRating": { "type": "number" },
              "worstRating": { "type": "number" }
            }
          },
          "sameAs": { "type": "array", "items": { "type": "string", "format": "uri" } }
        }
      },
      "Review": {
        "type": "object",
        "properties": {
          "author": { "type": "string" },
          "rating": { "type": "integer", "minimum": 1, "maximum": 5 },
          "datePublished": { "type": "string", "format": "date" },
          "body": { "type": "string" }
        },
        "required": ["author", "rating", "datePublished", "body"]
      },
      "ReviewList": {
        "type": "object",
        "properties": {
          "object": { "const": "review_list" },
          "ratingValue": { "type": "number", "description": "Average rating across all platforms." },
          "reviewCount": { "type": "integer" },
          "reviews": { "type": "array", "items": { "$ref": "#/components/schemas/Review" } }
        }
      },
      "Attraction": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "distanceFromCottage": { "type": "string" },
          "summary": { "type": "string" }
        },
        "required": ["name", "distanceFromCottage", "summary"]
      },
      "AttractionList": {
        "type": "object",
        "properties": {
          "object": { "const": "attraction_list" },
          "attractions": { "type": "array", "items": { "$ref": "#/components/schemas/Attraction" } }
        }
      },
      "BookingOptions": {
        "type": "object",
        "properties": {
          "object": { "const": "booking_options" },
          "note": { "type": "string" },
          "channels": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "platform": { "type": "string" },
                "url": { "type": "string", "format": "uri" },
                "supportsInstantBook": { "type": ["boolean", "null"] }
              },
              "required": ["platform", "url"]
            }
          }
        }
      }
    }
  }
}
