{
 "openapi": "3.1.0",
 "info": {
  "title": "RoundTrips",
  "version": "1.2.0",
  "description": "Plan and coordinate a group trip from your AI assistant: start a trip, invite friends with one link, add and vote on ideas, build the days, RSVP and split costs. Also plans a few free hours or a few days in a city, in walking order.",
  "contact": {
   "email": "partnership@thehowtonetwork.com",
   "url": "https://roundtrips.org/connect/"
  }
 },
 "servers": [
  {
   "url": "https://mcp.roundtrips.org"
  }
 ],
 "paths": {
  "/api/free_time_plan": {
   "get": {
    "operationId": "free_time_plan",
    "summary": "Plan a few free hours",
    "description": "Answers: \"We're in this city with a few free hours, what do we do?\" Returns 2–3 options, each a short route of stops in walking order with the walking minutes between them and a total that fits the hours. Inputs: city (required), hours (1–12, required), group (couple | friends | kids), vibe (e.g. \"music\", \"food, views\", \"relaxed\"), start_location (address, landmark or \"lat,lng\"; when given, the route starts there), when (morning | afternoon | evening | night or a time; evenings favour music and bars, daytime favours museums and parks). Stops from a published RoundTrips trip carry Zoe's own note; other stops come from open data (Wikidata, Wikipedia, OpenStreetMap) and are labelled that way. If coverage is thin the response says so. Example: {\"city\":\"Nashville\",\"hours\":4,\"group\":\"friends\"}",
    "parameters": [
     {
      "name": "city",
      "in": "query",
      "required": true,
      "description": "City name, e.g. \"Nashville\" or \"Lisbon, Portugal\"",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "hours",
      "in": "query",
      "required": true,
      "description": "Free time in hours",
      "schema": {
       "type": "number"
      }
     },
     {
      "name": "group",
      "in": "query",
      "required": false,
      "description": "Who is going",
      "schema": {
       "type": "string",
       "enum": [
        "couple",
        "friends",
        "kids"
       ]
      }
     },
     {
      "name": "vibe",
      "in": "query",
      "required": false,
      "description": "One or more of: culture, history, food, nightlife, music, outdoors, views, relaxed, iconic, family, shopping",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "start_location",
      "in": "query",
      "required": false,
      "description": "Where you are now: address, landmark or \"lat,lng\"",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "when",
      "in": "query",
      "required": false,
      "description": "morning | afternoon | evening | night, or a clock time like \"18:30\". Default: daytime.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Result with a `summary` string plus structured fields",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "summary": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with `message` and `suggestion`",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Rate limited",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/day_itinerary": {
   "get": {
    "operationId": "day_itinerary",
    "summary": "Day-by-day city plan",
    "description": "Answers: \"We have N days in this city, what should each day look like?\" Plans each day with AI from the city's place data (Zoe's picks first where she has them) (a main sight or two, lunch, an evening idea, in time order), with every stop checked on the map and nothing scheduled on a day it is normally closed; cities RoundTrips doesn't cover get the same, clearly labelled as an AI suggestion. Pass start_date so closing days line up, and pass the traveller's own wishes in notes (e.g. \"daytime only on the last day, don't over plan\"). Every answer includes save_plan, ready for start_trip. related.trips lists Zoe's published trips for the city; offer one only if the user wants it (start_trip from_zoe copies it). Inputs: city (required), days (1–14, required), start_date (YYYY-MM-DD), group (couple | friends | kids), pace (relaxed | moderate | packed), vibe (interests), notes (free text). Example: {\"city\":\"Madrid\",\"days\":4,\"start_date\":\"2026-11-10\",\"pace\":\"relaxed\",\"notes\":\"daytime only on Friday\"}",
    "parameters": [
     {
      "name": "city",
      "in": "query",
      "required": true,
      "description": "",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "days",
      "in": "query",
      "required": true,
      "description": "",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "start_date",
      "in": "query",
      "required": false,
      "description": "First day, YYYY-MM-DD (optional)",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "group",
      "in": "query",
      "required": false,
      "description": "",
      "schema": {
       "type": "string",
       "enum": [
        "couple",
        "friends",
        "kids"
       ]
      }
     },
     {
      "name": "pace",
      "in": "query",
      "required": false,
      "description": "",
      "schema": {
       "type": "string",
       "enum": [
        "relaxed",
        "moderate",
        "packed"
       ]
      }
     },
     {
      "name": "vibe",
      "in": "query",
      "required": false,
      "description": "Interests, one or more of: culture, history, food, nightlife, music, outdoors, views, relaxed, iconic, family, shopping",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "notes",
      "in": "query",
      "required": false,
      "description": "The traveller's wishes in their words, e.g. \"daytime only on the last day\", \"no museums\", \"late starts\"",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Result with a `summary` string plus structured fields",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "summary": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with `message` and `suggestion`",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Rate limited",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/whats_near": {
   "get": {
    "operationId": "whats_near",
    "summary": "What's near here",
    "description": "Answers: \"What's worth walking to from right here?\" Returns up to 10 places within the walking time, nearest first, each with walking minutes, a one-line reason or description, opening hours when known, and a directions link. Inputs: location (required: address, landmark or \"lat,lng\"), minutes_walk (1–45, default 15), type (e.g. food, coffee, bars, music, museum, park, views, kids, market, history). Example: {\"location\":\"Ryman Auditorium, Nashville\",\"minutes_walk\":10,\"type\":\"music\"}",
    "parameters": [
     {
      "name": "location",
      "in": "query",
      "required": true,
      "description": "",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "minutes_walk",
      "in": "query",
      "required": false,
      "description": "",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "type",
      "in": "query",
      "required": false,
      "description": "",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Result with a `summary` string plus structured fields",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "summary": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with `message` and `suggestion`",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Rate limited",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/list_cities": {
   "get": {
    "operationId": "list_cities",
    "summary": "Which cities are covered",
    "description": "Answers: \"Which cities can RoundTrips plan for, and how deep is the coverage?\" Returns every covered city with its coverage level (curated = a published RoundTrips trip exists; open-map = OpenStreetMap places only; thin = few places) and place counts. No inputs. Example: {}",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Result with a `summary` string plus structured fields",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "summary": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with `message` and `suggestion`",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Rate limited",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "message": {
      "type": "string"
     },
     "suggestion": {
      "type": "string"
     },
     "retry_after": {
      "type": "integer"
     }
    }
   }
  }
 }
}