Developer documentation
MCP server
Beta · free to useConnect an AI assistant to Vibe of the City through the Model Context Protocol. It can then look up a city’s week, find places and what stands at a spot, read a place from a link, and explain a city’s vibe. Once you sign in it can also read your trips, saved places and travel vibe, explain why a city fits you, plan your trips with you and save places for you.
These are the same tools Marvia, the app’s own AI guide, uses: what she can do for you in the app, your assistant can do here.
What you can ask
- “What’s on in Lisbon this weekend, and will it rain?”
- “What’s next on my Berlin trip on Saturday?”
- “What was that ramen place I saved in Tokyo?”
- “Save the café next to Bäckerei Hinz in Berlin to my want-to-go list.”
- “Add dinner at Lode & Stijn on Friday at 19:30 to our Berlin trip.”
- “Move the boat tour to Sunday and pin it to the pier.”
- “What’s my travel vibe, and why does Lisbon suit me better than Ibiza?”
- “Which place is at 36.7219, -4.4176? Save it.”
- “Add this restaurant from its website to our trip: https://…”
- “How do I export my data?” or “The invite link opens nothing — tell the team.”
Two ways to connect
- Sign in (OAuth): for Claude, ChatGPT and any client that adds a server by URL alone. You add the server, sign in with your Vibe of the City account and choose Allow. Nothing to copy, and you can disconnect it under Account → API keys.
- A personal API key: for clients where you set a request header, such as Claude Code, Cursor or VS Code, and for your own scripts.
Connect by signing in
Claude
Settings → Connectors → Add custom connector, with the URL https://www.vibeofthe.city/api/public/mcp. Claude opens our sign-in; choose Allow, and the tools appear in the chat’s tool menu.
ChatGPT
Settings → Apps & Connectors → Create (developer mode), with the same URL and authentication set to OAuth. ChatGPT registers itself with us and opens our sign-in.
Other clients
Any MCP client that supports the MCP authorization spec finds everything on its own from the endpoint’s 401: the protected resource metadata, our authorization server at https://www.vibeofthe.city/.well-known/oauth-authorization-server, dynamic client registration, and authorization code with PKCE (S256). Access tokens last an hour and refresh for 30 days.
Connect with a key
Get a key
Sign in on vibeofthe.city, open Account → API keys and create a key. It is the same key as for the Travel API.
Tick Let AI assistants use my trips and saved places to make it a personal key. Without it, the key sees only public tools: cities, host guides and place search. Whether a key is personal is set when it is created; to change it, create a new key and revoke the old one.
A personal key acts as you. Anyone holding it can read your trips and saved places and add to them. Put it only into assistants you run yourself, and revoke it on the same page the moment you stop using one.
Use it
Send the key as a bearer token to https://www.vibeofthe.city/api/public/mcp. Any client that lets you set a request header works.
Claude Code
claude mcp add --transport http vibeofthecity https://www.vibeofthe.city/api/public/mcp \
--header "Authorization: Bearer votc_live_…"Cursor, Windsurf and most MCP clients
{
"mcpServers": {
"vibeofthecity": {
"url": "https://www.vibeofthe.city/api/public/mcp",
"headers": { "Authorization": "Bearer votc_live_…" }
}
}
}VS Code
{
"servers": {
"vibeofthecity": {
"type": "http",
"url": "https://www.vibeofthe.city/api/public/mcp",
"headers": { "Authorization": "Bearer votc_live_…" }
}
}
}Claude Desktop
Through the mcp-remote bridge, in claude_desktop_config.json:
{
"mcpServers": {
"vibeofthecity": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://www.vibeofthe.city/api/public/mcp", "--header", "Authorization:${VOTC_AUTH}"],
"env": { "VOTC_AUTH": "Bearer votc_live_…" }
}
}
}Language
Add ?lang=de, es or hu to the URL for city and place data in that language. English is the default.
Tools
A connection lists only the tools it may use. Tools that change something tell your assistant so through MCP’s annotations, and the server tells it to check with you first; most clients also ask before running them.
| Tool | Who | Arguments | What it does |
|---|---|---|---|
find_city | Any key or sign-in | query | Looks up the cities Vibe of the City covers by name and returns their city_slug. Call it first whenever another tool needs a city_slug. |
get_city_week | Any key or sign-in | city_slug, days? | The weather forecast from today and what is on in a city (concerts, markets, festivals) over the next days. Use it to answer "what is on", "what will the weather be" or to plan around rain. |
get_host_guide | Any key or sign-in | host_slug | A published host guide (a holiday flat, a hotel, a guide's page): check-in facts, house information and the host's own tips with coordinates. |
search_places | Any key or sign-in | query, near_lat?, near_lng?, town?, limit? | Finds places (cafés, museums, bars, parks, shops) or a street address by name or kind, optionally near a point or a town. Returns a place_ref for each place, which save_place and add_trip_idea take, and matching addresses with their coordinates. Pass near_lat/near_lng to rank by distance, e.g. to resolve "the café next to X": search X first, then search "café" near its coordinates. |
find_places_near | Any key or sign-in | lat, lng, radius_m?, limit? | The places right at a point, nearest first: cafés, bars, restaurants, sights and shops within a short walk. Use it to find which place a photo shows from the GPS it was taken at, or what is at coordinates the user gives. Returns a place_ref for the places we can pin (save_place, add_trip_idea, update_trip_idea); one without a place_ref can be added with add_new_place. |
list_my_trips | Signed in or personal key | when? | The user's trips (their own and ones they joined), with city and dates. Returns the trip_id get_trip and add_trip_idea take. |
get_trip | Signed in or personal key | trip_id | One trip's plan: the ideas scheduled per day (with time and place), ideas not yet on a day, and the shortlist of places. Use it for "what's next", "what's on Saturday" or before adding to a trip. |
get_trip_balances | Signed in or personal key | trip_id | Who paid what on a trip, who owes whom, and the fewest transfers that settle it. Read-only: expenses are added in the app. Use it for "who owes what" or "how much have we spent". |
list_saved_places | Signed in or personal key | city_slug?, state?, query? | Places the user saved as want-to-go or marked as been, with their notes. Use it to recall "that ramen place in Tokyo" or to suggest from the user's own list first. |
save_place | Signed in or personal key · writes | place_ref, state?, note?, name?, lat?, lng? | Saves a place to the user's want-to-go list or marks it as been, with an optional note. As when saving in the app, the user's contacts may see the save in their feed. Confirm the exact place with the user first. For a place_ref starting with "osm:", also pass the name, lat and lng search_places returned with it. |
add_trip_idea | Signed in or personal key · writes | trip_id, text, date?, time?, note?, place_ref?, name?, lat?, lng? | Adds an idea to a trip: something to do, optionally on a day and at a time, optionally pinned to a place (place_ref) or to an address from search_places (name, lat, lng without a place_ref). Everyone on the trip sees it and may get a notification. Confirm the wording, day and time with the user first. |
update_trip_idea | Signed in or personal key · writes | trip_id, idea_id, text?, date?, time?, note?, place_ref?, name?, lat?, lng? | Changes something already on a trip's plan: its wording, day, time, note, or where it happens (a place_ref from search_places, or an address's name, lat and lng). Use it instead of add_trip_idea whenever the user means an item that is already there, e.g. "set the location of the ATP match"; get its idea_id from get_trip. Only set a time the user gave or a source confirmed. Everyone on the trip sees the change. Confirm it with the user first. |
set_trip_stay | Signed in or personal key · writes | trip_id, name, address?, lat?, lng? | Records where the group sleeps on a trip: a hotel, a flat. Only the trip's members see it; it places their plan's distances. Use it when the user says where they stay or asks to add it, and confirm the name first. |
add_trip_day_trip | Signed in or personal key · writes | trip_id, town, country_code?, date? | Adds a day out to another town to a trip's route, optionally on one of its days. Everyone on the trip sees it. Confirm the town and the day with the user first. |
get_my_vibe | Signed in or personal key | none | The user's own travel vibe as they set it in Vibe of the City: the travel types they like or love, how they take crowds, heat and rain, who they travel with, budget, diet, what they seek, care about and avoid, the vibe dimensions they value most, and how far their profile is filled in. Read it before recommending cities or places, or when the user asks what their vibe is. It is the user's own data: describe it to them, never to others. |
get_city_vibe | Any key or sign-in | city_slug | What a city is like, on the vibe dimensions (calm, adventure, nature, food, sport, culture, social, family, romance, productivity, value, authenticity, safety, weather, beauty, sea): how strongly it delivers each over the year, a sentence of local knowledge where we have one, and classic places that prove it. Not personal; for how it fits the user, use explain_city_match. |
explain_city_match | Signed in or personal key | city_slug | How a city fits the user's travel vibe, and why: the match label, where what they value meets what the city delivers, where it falls short, what it offers beyond their priorities, and classic places that prove each point. Use it for "why does Lisbon suit me?" or "why not Ibiza?"; compare two cities by calling it for each. Say the match label in words; give a percent only when match_percent is not null. |
read_place_link | Any key or sign-in | url | Reads a place from a link the user shares: a map link (Google Maps, Apple Maps, OpenStreetMap) or the place's own website. Returns its name, address and coordinates when the link carries them; needs_name when it can't be read, so ask the user for the name. Then search_places for it, and only if it isn't there, add_new_place. |
add_new_place | Signed in or personal key · writes | name, lat, lng, category?, address?, note?, state? | Adds a place that is not on the map yet, and saves it for the user (want to go, or been). Only after search_places did not find it. The name must be the place's real name, never an address; the coordinates come from read_place_link, from an address search_places returned, or from the user. It becomes a place everyone can find, so confirm the name and where it is with the user first. Returns a place_ref for add_trip_idea and update_trip_idea. |
get_app_help | Any key or sign-in | none | How Vibe of the City works and where things are: signing in, account and data, reporting and blocking, notifications and language, the travel vibe, the map, places, trips, tips, invites, Marvia, and how to reach a person. Read it before answering any question about the app, and answer only from it; when it doesn't say, say you aren't sure and offer report_problem or the contact address. |
report_problem | Signed in or personal key · writes | summary, details?, trip_id? | Sends the Vibe of the City team a bug or problem the user ran into, in their words: what happened, what they expected, and where in the app. A person reads every report. Use it when the user reports something broken or wrong in the app, after summing it up back to them and getting their yes. Not for reporting a person or a message — that is the report option on their profile or thread. |
Places come back with a place_ref: poi:… for a place in our catalog, or osm:… for one found live in OpenStreetMap. Pass it on to save_place, add_trip_idea or update_trip_idea; for an osm: ref, pass its name and coordinates too. A place nobody has mapped yet can be added with add_new_place, after search_places and find_places_near came back without it.
What a write does
- save_place works like saving in the app: the place lands on your want-to-go or been list, and your contacts may see the save in their feed.
- add_trip_idea adds the idea for everyone on the trip, and they may get a notification, as when you add it in the app. update_trip_idea changes one already there: its wording, day, time, note or where it happens.
- set_trip_stay records where the group sleeps, visible only to the trip; add_trip_day_trip adds a day out to another town.
- add_new_place adds a place the map doesn’t have yet, under its real name, and saves it for you. Everyone can find it afterwards.
- report_problem sends the team a bug in your words. A person reads every one.
- Nothing is deleted, sent to another traveller or paid through the server. Removing what was added is done in the app.
Limits during the beta
A key shares its allowance with the Travel API: 1000 calls per UTC day and bursts of 60, refilling 60 per minute. A signed-in assistant gets the same allowance of its own. Every MCP message counts as one call, so a session opening (initialize, tools/list) costs two or three and each tool use one. Over the allowance the server answers 429 with Retry-After.
Protocol details
- Streamable HTTP, stateless: send each JSON-RPC message as its own
POST; answers areapplication/json. No session id, no server-sent stream. - Protocol versions
2025-11-25,2025-06-18and2025-03-26. - Methods:
initialize,ping,tools/list,tools/call. Notifications are accepted with202. - Tool results carry the same JSON as
structuredContentand as text. A refusal the assistant can act on (“no such trip”) hasisError: trueand ahint.
curl https://www.vibeofthe.city/api/public/mcp \
-H "Authorization: Bearer votc_live_…" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"find_city","arguments":{"query":"Lisbon"}}}'Discovery
The server describes itself at https://www.vibeofthe.city/.well-known/mcp.json (also at /.well-known/mcp/server-card.json): its endpoint, sign-in and every tool with its schema, for registries and clients that discover servers on their own. AI crawlers find it, and this page, from /llms.txt.
While it is a beta
Tools will be added; existing ones will not change meaning without notice to key holders by email. Questions, a bug, or a tool you are missing: hello@vibeofthe.city.
See also the Travel API, the terms of service and the privacy policy.