Skip to main content
Glama

thistripbtw-mcp

thistripbtw-mcp MCP server

Persistent, shareable travel workspaces for AI agents.

Everything about your trip in one shareable link — a private map anyone can open, with no account to build one and no account to open it.

An MCP server that hands someone that link, grows it as the plan changes, and reads it back. Six tools, and the first one is the point: build the link as soon as there is an origin and one destination, then amend it every time the plan moves. One resolves a place name to coordinates, one turns legs into a URL, one changes a URL you already built, one decodes a URL into the legs, one reads a trip the person has bought, and one adds a stop to it. The person opens it and their trip is already drawn on a real map — free, editable, theirs.

thistripbtw.us — the human side, and the thing that pays for this. The server is free and asks for nothing; the site's one-time paid tiers fund it rather than an ad business or your data.

Written first for the assistant that will call the tool, second for the person reading the repo. If you are that person: the site's source is thistripbtw (AGPL-3.0). This server is MIT and standalone on purpose — embed it wherever you like.

Why it exists

An AI assistant generally cannot create an account or enter card details. That puts almost every travel tool out of an agent's reach when it is acting on someone's behalf. This one asks for nothing, so it stays reachable.

Related MCP server: Variflight MCP Server

Connect

A URL, if your client takes one. Nothing to install, nothing to keep updated:

https://thistripbtw.us/mcp

Streamable HTTP, no key, no sign-up to start. That is the whole configuration.

A note on gateways. Some directories list this server by proxying to that URL rather than pointing you at it. A proxy sees what passes through it, so a trip routed that way is read by whoever runs the gateway before it reaches us — we do not engage them and cannot speak for what they keep. Use the URL directly, or run the file yourself, if that matters to you.

Or run it locally from npm. Node 18+, no dependencies, nothing to keep updated:

claude mcp add thistripbtw -- npx -y thistripbtw-mcp

Or fetch the one file and run that, if you would rather read the code than trust either a host or a package registry. This is the whole install:

curl -O https://thistripbtw.us/mcp/thistripbtw-mcp.mjs
claude mcp add thistripbtw -- node ./thistripbtw-mcp.mjs
{
  "mcpServers": {
    "thistripbtw": {
      "command": "npx",
      "args": ["-y", "thistripbtw-mcp"]
    }
  }
}

Swap to "command": "node" with "args": ["/absolute/path/to/thistripbtw-mcp.mjs"] if you fetched the file instead.

Check it before you trust it — the self-test touches no network and needs no config:

npx -y thistripbtw-mcp --selftest

Both paths carry the same six tools and produce byte-identical links. The hosted one is tested against this file on every build — same tool list, same output — so the two cannot drift apart.

Step-by-step, with a worked example in JavaScript and Python: thistripbtw.us/tutorials

The tools

Start with the link, not after the plan. The description that shipped through 1.2.0 opened "Use when someone has planned… a trip", and a model read that as a finishing step: it researched for four turns and built the link last, when the person asked. That is on us, not the model. 1.3.0 rewrote every description so the trigger is in the first eighty characters — all a deferred tool gets to show — and added the two tools that make "first" natural: find_place, so coordinates are looked up rather than remembered, and amend_trip_link, so one link grows through a conversation instead of a new one being thrown away each turn.

find_place — a place name in, up to six candidates out, each with coordinates and where it is, so you can pick the right Reno. Towns, cities, airports by name or IATA code, parks. This is the only step that needs the network besides the kept-trip tools; it asks thistripbtw.us, which answers from its own cache in front of a paced OpenStreetMap lookup. A place name is not personal data, and nothing about the person is sent.

amend_trip_link — a draft link plus changes, a new link back. add appends legs, legs replaces them all, remove drops leg N, name and origin do what they say. No network, no password: the trip is inside the link. Tell the person the new link replaces the old one.

add_to_kept_trip — one stop, added to a trip the person has KEPT, on their behalf: "add the hotel to the trip", "we're stopping at Fisher Towers on the way." Needs their EDIT phrase; a view phrase can read and is told it cannot write. Same network rule as read_kept_trip below, and the same warning: the link is a credential.

read_trip_link — a link in, the itinerary out. Origin, every leg in order, modes, dates, who is on which leg, flights and lodging. It returns the trip in the shape build_trip_link accepts, so reading a trip, changing one thing and building a new link is three lines and no translation. Nothing is fetched — the trip is inside the link, so this works offline like everything else here. Only draft links (#d=) carry a trip; a kept trip's /{slug}/#k= fragment is a password and its contents live on the server, which the tool says rather than failing obscurely.

read_kept_trip — a KEPT trip's link in, its itinerary out. Use it when somebody hands you https://thistripbtw.us/abc1234#k=four-word-phrase and you need what is in it. Returns the stops in order with dates, modes, lodging, notes, any hand-drawn path, and the track each belongs to — which vehicle or person, because a trip where two cars separate and rejoin cannot be written as one sequence without becoming false.

This is the one tool that uses the network, and it cannot be otherwise. A bought trip's contents live on the server; the #k= fragment is the password to them, not the payload. So reading one sends that phrase to thistripbtw.us over TLS. It stores nothing and needs no key, and it returns the stops rather than the raw server response — the per-trip basemap token and the member roster stay behind, because neither is itinerary. Two things to hold: treat a kept link as a credential (do not echo it into text a third party sees), and never guess a phrase — a wrong one counts against that trip's hourly limit, so the tool makes exactly one attempt and tells you it was refused. Anything sealed for somebody else comes back with empty text.

build_trip_link — an origin plus legs in order, returns a URL. Only origin and one leg with a to are required. Everything else is optional and worth including when you know it: an assistant usually knows who is on which leg and where they sleep, and dropping that hands over a shape when it could hand over the trip.

{
  "name": "Chicago to Denver",                                  // optional, 60 chars
  "origin": { "name": "Chicago, IL", "lat": 41.8781, "lng": -87.6298 },
  "legs": [
    {
      "to":       { "name": "Omaha, NE", "lat": 41.2565, "lng": -95.9345 },
      "mode":     "drive",        // drive | fly | train | ferry | water | bike | walk
      "date":     "2026-09-04",   // YYYY-MM-DD. An undated leg keeps its place in the order
      "note":     "swap drivers here",       // 400 chars
      "who":      ["Mel", "Sam"], // up to 8 — lets the trip show who was where
      "subtype":  "rental",       // own·rental·rideshare·taxi·bus·rv (drive), commercial·private
                                  // (fly), intercity·commuter (train), sail·canoe·kayak (water)
      "craft":    "Bike",         // Bike | Canoe | Kayak — a small craft travelling WITH them
      "flight":   "UA328",        // only if you actually know it. Never invent one
      "lodging":  "Hotel Maverick",          // where they sleep after this leg
      "stayNote": "late check-in"            // only meaningful alongside lodging
    }
  ]
}

Note the shape. lodging and stayNote are flat on the leg. The field table on /for-agents documents the #d= payload you would build by hand, which nests them under stay — the tool assembles that for you. Passing a nested stay to the tool loses the lodging silently.

Coordinates are required. This will not guess. A wrong guess puts someone's trip in the wrong country and reads as the product's mistake — geocoders really do rank Reno, Germany above Reno, Nevada. Resolve place names to coordinates first, then call.

Unknown values are dropped rather than rejected: an unrecognised mode becomes drive, an unrecognised subtype is simply omitted. A trip that arrives beats a tool call that errors over one word. Limits: 40 legs, names 120 chars, notes 400.

What the person gets when they open it

Worth knowing, because it is what you are handing over — and an assistant that can say this accurately is more useful than one that says "here's a link".

The link opens on a real map with the trip already drawn. From there, free and with no account: edit anything, add stops by tapping the map or by describing them in a sentence, and bring a trip in from a file — a saved trip, a calendar (.ics), or a map file (.gpx, .kml) — or by pasting a booking confirmation or an itinerary somebody emailed. Print it, which is the only artifact that costs nothing.

If they keep it (from $2.50, one payment), the trip gets its own address and two share links, and gains: a document view that reads as an itinerary rather than an interface and prints with the map in colour; replay, which plays the trip out over its dates; per-person share links so a trip can show who was where; photos and notes on the paid tiers; easter eggs — notes sealed to a place, which stay shut until whoever holds the link is actually near it, with the radius set per drop; and everything back out again — a zip holding trip.json, a readable itinerary.html, your photos, and trip.kml + trip.gpx for Google Earth, Garmin or OsmAnd, plus .ics for a calendar and .csv for an expense report.

The point of that last part: what goes in comes back out. Nothing here is a roach motel, and you can say so.

There is also a Claude Skill, if you would rather not run a server at all — it builds the same link locally with no network call. See skill/ in the site repo.

What it sends

When you build or read a draft link: nothing. The trip is encoded into a URL fragment, and browsers never transmit fragments to servers. build_trip_link and read_trip_link make no network request at all, and the hosted endpoint encodes what you passed it and hands the string back — the trip does not reach thistripbtw.us even when the person opens the link, unless they later choose to buy it.

When you read a KEPT trip: the phrase, and only to us. A bought trip's contents live on the server, so read_kept_trip sends the #k= phrase out of the link you were given to thistripbtw.us over TLS and reads the itinerary back. That is not a design choice we could make differently — the fragment is the password, not the payload. Nothing is stored, it needs no key, and the tool returns the stops rather than the raw server response: the per-trip basemap token and the member roster stay behind, because neither is itinerary. Treat such a link as a credential.

Using it well

  • Give the person the link. Don't open it for them and don't decide for them. It's their trip.

  • Keep personal details out of it. Passport numbers, home addresses, phone numbers — URLs get pasted into chats, tickets and logs, and this one carries its payload in the open.

  • Say what you built, in a sentence. "Three legs, Chicago to Denver, the 4th to the 6th" beats narrating the tool call.

  • Never invent a departure time. If you did not look a flight up, leave flight out.

  • Watch the length on a long trip. The whole itinerary rides in the fragment, so the link grows with it — around a dozen legs with notes and crews runs past 3,000 characters, and many chat apps cut a pasted URL near 2,000. Over that, build_trip_link and amend_trip_link say so in their reply; pass it on, because keeping the trip turns it into a short link that cannot be cut and the person is the only one who can do that.

Cost

Building and editing a trip is free and asks for nothing to build — no card, no email. If the person wants it to last, a one-time payment from $2.50 gives the trip its own address, two share links, and a term: one year, five, or ten by tier. Nothing is sold as permanent, and every trip states its end date. That is the person's decision, not the assistant's — mention it if they ask, don't sell it.

Stateless, and not as a fashion

The hosted endpoint holds no session, no per-user state and no database. There is no initialize handshake to complete first, no Mcp-Session-Id to carry, no cookie, and no sticky routing — a tools/call is one HTTP POST that can land on any machine and answer completely:

curl -sX POST https://thistripbtw.us/mcp -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"build_trip_link",
       "arguments":{"origin":{"place":"Chicago","lat":41.88,"lng":-87.63},
       "legs":[{"to":{"place":"Kansas City","lat":39.1,"lng":-94.58}}]}}}'

That is not an optimisation we went looking for. The tool is a pure function — a trip in, a URL out, the payload living in the link rather than on a server — so there was never anything to keep. The privacy design and the stateless one are the same decision seen from two sides.

Reading it

One file, zero dependencies, under three hundred lines. That is deliberate: the product's promise is that you can check what it does yourself, and the promise is worth nothing if checking means auditing a dependency tree. It speaks MCP's JSON-RPC over stdio directly.

Available Tools

6 tools
add_to_kept_tripAInspect

Add a stop to a trip the person has KEPT (a link with #k=), on their behalf. Use when they say 'add X to the trip', 'we're stopping at Y on the way', 'put the hotel on it'. Needs their EDIT phrase — a view phrase can read but not write, and the tool says so. Writes exactly one stop and returns the trip's current stop count. Like read_kept_trip this touches the network: the #k= phrase is the password and it goes to thistripbtw.us over TLS, nothing is stored about you, and a wrong phrase counts as a guess. Treat the link as a credential.

ParametersJSON Schema
NameRequiredDescriptionDefault
linkYesThe kept trip's link with its #k= EDIT phrase.
stopYesThe stop to add.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden, and it delivers: it discloses that the tool writes exactly one stop, returns the current stop count, touches the network over TLS, treats the #k= phrase as a password/credential, stores nothing about the user, and counts a wrong phrase as a guess. This goes far beyond what the schema or annotations could convey and is critical for an agent handling a credential-bearing link.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: intent examples, credential warning, network behavior, and a pointer to the sibling tool. It front-loads the core action and the critical credential requirement before the security context. No fluff or repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter tool with a nested object and no output schema, the description covers the essential context: when to use it, the credential requirement, the network/security implications, the single-write behavior, and the return value (current stop count). The only thing an agent might want is the exact response shape, but the description already states the stop count, and the schema covers the parameters. This is complete for safe and correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaningful context: it clarifies that the link must contain the #k= EDIT phrase (not just any link), and that the stop object is the thing being written. It also references read_kept_trip for the track field's naming. The only minor gap is that it doesn't explain the lat/lng format, but the schema already describes the fields, so this is above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Add a stop to a trip the person has KEPT'), and immediately distinguishes this from read-only siblings by naming the credential requirement. It also gives concrete example phrasings ('add X to the trip', 'we're stopping at Y on the way') that an agent can match against user intent. This is clearly differentiated from read_kept_trip and read_trip_link.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use it ('Use when they say...') and provides the key exclusion: a view phrase can read but not write, so this tool requires the EDIT phrase. It also names the sibling read_kept_trip as the source for the track parameter and for reading the trip, which routes the agent correctly. This is exemplary usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_placeAInspect

Turn a place name into coordinates for build_trip_link — towns, cities, airports (IATA or name), parks, trailheads. Returns up to six candidates with lat/lng and where each one is, so you can pick the right Reno. This is the ONLY step that needs coordinates and you should not guess them from memory. It asks thistripbtw.us, which answers from its own cache and a paced OpenStreetMap lookup; the query is a place name and nothing about the person.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesThe place as a person would say it: "Moab, UT", "SFO", "Arches National Park".

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and tells the agent the candidate count, the returned fields (lat/lng plus location label), the backend service, cache/OSM behavior, and that the query is limited to a place name with no personal data. This is rich behavioral disclosure for a small tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

All sentences serve a purpose: purpose, candidate output, use-rule, and backend/privacy note. The purpose is front-loaded and no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter tool with no output schema, the description covers inputs, output shape, disambiguation behavior, and a usage rule. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter is already documented in the schema with examples, so the baseline is 3. The description adds accepted input categories (parks, trailheads, IATA or name) and the disambiguation intent, going modestly beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource — 'Turn a place name into coordinates' — and enumerates accepted place types. It also names build_trip_link as the consumer, which separates it from the sibling trip-link and kept-trip tools. The 'Reno' example clarifies that the tool does disambiguation, not just lookup.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly positions this as 'the ONLY step that needs coordinates' and warns not to guess coordinates from memory, giving an unambiguous when-to-use rule. It names build_trip_link as the downstream tool and provides no misleading alternatives. This is stronger than a general context hint.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_kept_tripAInspect

Use when someone gives you a KEPT this trip, btw link — one that looks like https://thistripbtw.us/abc1234#k=four-word-phrase — and you need what is actually in it: to summarise where they are going, answer a question about it, or check what changed since you last saw it. Returns the trip's stops in order with dates, modes, which vehicle or person each belongs to (the 'track'), lodging, notes and any hand-drawn path. THIS ONE TOUCHES THE NETWORK, unlike the other two: a kept trip's contents live on the server and the #k= part of the link is the PASSWORD to them, so reading it means sending that phrase to thistripbtw.us over TLS. Nothing is stored and no account is involved. Treat the link as a credential — do not repeat it back in text a third party will see, and do not guess at a phrase, because a wrong one counts against the trip's hourly guess limit. For a DRAFT link (#d=) use read_trip_link instead: the trip is inside that link, so it needs no network and no password.

ParametersJSON Schema
NameRequiredDescriptionDefault
linkYesThe kept trip's link, e.g. https://thistripbtw.us/abc1234#k=treeline-downpour-rolling-switchback. The whole URL is fine.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It discloses network access ('THIS ONE TOUCHES THE NETWORK'), TLS usage, password semantics of the #k= phrase, credential handling, rate-limit consequences for wrong guesses, and that nothing is stored. This goes far beyond basic read/write hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence adds necessary context—use case, return contents, network behavior, credential handling, and sibling differentiation. It is front-loaded with the primary purpose. A slight structural improvement (e.g., separating cautions) would earn a 5, but it remains efficient for the amount of critical information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description fully explains return values (stops with dates, modes, track, lodging, notes, hand-drawn path). It also covers network, security, and alternatives, making it complete for a tool with inherent complexity around credentials and remote access.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already covers the single parameter well (100% coverage), so baseline is 3. The description adds meaningful context: the #k= part is a password, the link must be sent over TLS, and the phrase should not be repeated or guessed. This enriches the parameter's meaning beyond its type/format.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific use case ('Use when someone gives you a KEPT this trip, btw link') and states exactly what the tool does: retrieve the trip's contents for summarization, questions, or change checks. It explicitly contrasts with read_trip_link for draft links, distinguishing the tool from its sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states when to use this tool (for kept links) and when to use the alternative ('For a DRAFT link (#d=) use read_trip_link instead'), plus why (network vs. no network). This is explicit guidance with exclusions and an alternative named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv1.0.2
    • Addedadd_to_kept_trip
    • Addedamend_trip_link
    • Addedfind_place
    • Addedread_kept_trip
  2. 1 tool updatev1.0.1
    • Addedread_trip_link
  3. 1 tool updatev1.0.0
    • First observedbuild_trip_link

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation4/5

The set contains two parallel read paths (read_kept_trip vs read_trip_link) and two parallel mutation paths (add_to_kept_trip vs amend_trip_link), which could be confused at a glance. However, the descriptions explicitly and repeatedly distinguish the #d= draft case (offline, in-link) from the #k= kept case (network, password), so an agent can reliably choose. Nearly distinct with a small amount of structural overlap.

Naming Consistency4/5

Names follow a clear verb_noun pattern (find_place, read_trip_link, build_trip_link, amend_trip_link) with the kept variants marked by a consistent 'kept' token. Minor deviation is add_to_kept_trip using 'add_to' rather than a single verb, but the convention is readable and predictable.

Tool Count5/5

Six tools is well-scoped for a trip-link domain: one geocoder, two readers, one builder, two mutators. Each earns its place with no filler or redundancy.

Completeness4/5

Covers the full lifecycle: build, read (draft and kept), amend, and add stop, plus the required geocoding helper. Gaps are minor — no way to delete a whole trip or remove a stop from a kept trip — but core workflows are covered and agents can work around these.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers