Skip to main content
Glama

Plan eSIMs for a trip

plan-trip
Read-onlyIdempotent

Answer "which eSIM should I buy for this trip?". Give it the stops, a country code and the days spent in each, and it compares one plan covering the whole route against one plan per country against a mix of the two, on live prices, then flags the cheapest option that covers everything and explains the choice in a sentence you can quote. It also estimates the data each stop needs, names any country SimFuse cannot cover, and returns package ids that go straight into create-checkout-session. Use it whenever a trip has two or more countries, and for a single country when the traveller wants a recommendation rather than a list. Read-only: nothing is reserved and nothing is charged, and the totals are today's catalog prices, not a quote held for later.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
startNoOptional. Departure date as YYYY-MM-DD, e.g. "2026-04-18". Only used to date the stops in the answer; it does not change prices. Defaults to today.
stopsYesThe trip, one entry per country, in travel order. 1 to 12 stops, e.g. [{"country":"JP","days":7},{"country":"KR","days":5}].
usageNoOptional. Trip-wide data usage for stops that do not set their own: "light" (about 300 MB a day), "regular" (about 800 MB a day) or "heavy" (about 2 GB a day). Defaults to "regular".regular
currencyNoOptional. ISO 4217 three-letter code every price is quoted in, e.g. "USD", "EUR", "GBP". Defaults to EUR. An unknown code falls back to EUR rather than failing.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
tripYesThe trip as it was understood, which is worth reading back to the traveller.
reasonYesOne sentence explaining the recommendation, written to be quoted to the traveller verbatim.
optionsYesEvery way of buying the trip that we could price, cheapest-first within each strategy. Empty when nothing we sell covers it.
checkoutYesHow to act on the recommendation.
contractYesVersion of this answer's shape. "1" today; it only changes when an existing field changes meaning.
currencyYesISO 4217 code every amount below is quoted in, e.g. "EUR".
warningsYesTrip-level caveats: a country SimFuse does not sell, or a gap the recommended option leaves. Say these out loud rather than dropping them.
planner_urlYesThe same trip on the SimFuse website, for a person who wants to finish it themselves.
recommendationYesWhich strategy won: one plan for the whole route, one plan per country, or a mix. Null when nothing we sell covers the trip.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed15 schema fields changed
    • changedInput schema / properties / currency / description
      Previous value: -"Three-letter currency code for pricing (e.g. \"USD\", \"EUR\"). Defaults to the visitor-neutral base currency."New value: +"Optional. ISO 4217 three-letter code every price is quoted in, e.g. \"USD\", \"EUR\", \"GBP\". Defaults to EUR. An unknown code falls back to EUR rather than failing."
    • addedInput schema / properties / currency / maxLength
      Added value: +3
    • addedInput schema / properties / currency / minLength
      Added value: +3
    • changedInput schema / properties / start / description
      Previous value: -"Departure date as YYYY-MM-DD. Defaults to today."New value: +"Optional. Departure date as YYYY-MM-DD, e.g. \"2026-04-18\". Only used to date the stops in the answer; it does not change prices. Defaults to today."
    • addedInput schema / properties / start / maxLength
      Added value: +10
    • addedInput schema / properties / start / minLength
      Added value: +10
    • changedInput schema / properties / stops / description
      Previous value: -"The trip, one entry per country, in travel order."New value: +"The trip, one entry per country, in travel order. 1 to 12 stops, e.g. [{\"country\":\"JP\",\"days\":7},{\"country\":\"KR\",\"days\":5}]."
    • changedInput schema / properties / stops / items / properties / country / description
      Previous value: -"Two-letter ISO country code, e.g. \"JP\"."New value: +"ISO 3166-1 alpha-2 country code, e.g. \"JP\" for Japan. Look one up with list-destinations rather than guessing. Each country may appear once: give one stop with the total days rather than two visits."
    • addedInput schema / properties / stops / items / properties / country / maxLength
      Added value: +2
    • addedInput schema / properties / stops / items / properties / country / minLength
      Added value: +2
    • changedInput schema / properties / stops / items / properties / days / description
      Previous value: -"Days spent in that country, 1-365."New value: +"Days spent in that country, 1 to 365. Count the nights of the stay."
    • changedInput schema / properties / stops / items / properties / usage / description
      Previous value: -"How heavily data is used during this stop. Overrides the trip-wide usage."New value: +"Optional. How heavily data is used during this stop: \"light\" (about 300 MB a day, maps and messaging), \"regular\" (about 800 MB a day) or \"heavy\" (about 2 GB a day, video and hotspot). Overrides the trip-wide `usage` for this stop only."
    • addedInput schema / properties / usage / default
      Added value: +"regular"
    • changedInput schema / properties / usage / description
      Previous value: -"Trip-wide data usage for stops that do not set their own. Defaults to regular (about 800 MB/day)."New value: +"Optional. Trip-wide data usage for stops that do not set their own: \"light\" (about 300 MB a day), \"regular\" (about 800 MB a day) or \"heavy\" (about 2 GB a day). Defaults to \"regular\"."
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "properties": {
      +    "checkout": {
      +      "description": "How to act on the recommendation.",
      +      "properties": {
      +        "checkout_sessions": {
      +          "description": "HTTP endpoint that opens a checkout session, if you would rather not use the create-checkout-session tool.",
      +          "type": "string"
      +        },
      +        "human_url": {
      +          "description": "Where to send a person to buy this themselves.",
      +          "type": "string"
      +        },
      +        "items": {
      +          "description": "The recommended option as checkout line items, ready to pass to create-checkout-session. Null when nothing covers the trip.",
      +          "items": {
      +            "properties": {
      +              "id": {
      +                "description": "Plan id.",
      +                "type": "string"
      +              },
      +              "quantity": {
      +                "description": "How many to buy.",
      +                "type": "integer"
      +              }
      +            },
      +            "required": [
      +              "id",
      +              "quantity"
      +            ],
      +            "type": "object"
      +          },
      +          "type": [
      +            "array",
      +            "null"
      +          ]
      +        },
      +        "note": {
      +          "description": "What the totals are and are not: catalog prices today, never a reservation.",
      +          "type": "string"
      +        },
      +        "register": {
      +          "description": "HTTP endpoint that mints an agent key for that API.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "items",
      +        "checkout_sessions",
      +        "register",
      +        "human_url",
      +        "note"
      +      ],
      +      "type": "object"
      +    },
      +    "contract": {
      +      "description": "Version of this answer's shape. \"1\" today; it only changes when an existing field changes meaning.",
      +      "type": "string"
      +    },
      +    "currency": {
      +      "description": "ISO 4217 code every amount below is quoted in, e.g. \"EUR\".",
      +      "type": "string"
      +    },
      +    "options": {
      +      "description": "Every way of buying the trip that we could price, cheapest-first within each strategy. Empty when nothing we sell covers it.",
      +      "items": {
      +        "properties": {
      +          "complete": {
      +            "description": "True when this option covers every stop. False means at least one stop is left without data.",
      +            "type": "boolean"
      +          },
      +          "esims": {
      +            "description": "How many eSIMs the traveller installs under this option.",
      +            "type": "integer"
      +          },
      +          "items": {
      +            "description": "The plans this option buys.",
      +            "items": {
      +              "properties": {
      +                "covers": {
      +                  "description": "ISO 3166-1 alpha-2 codes of the stops this line covers.",
      +                  "items": {
      +                    "type": "string"
      +                  },
      +                  "type": "array"
      +                },
      +                "data": {
      +                  "description": "Allowance written for a person, e.g. \"5 GB\" or \"Unlimited\".",
      +                  "type": "string"
      +                },
      +                "data_mb": {
      +                  "description": "Allowance in megabytes. 0 on an unlimited plan, where `policy` carries the real terms.",
      +                  "type": [
      +                    "integer",
      +                    "null"
      +                  ]
      +                },
      +                "name": {
      +                  "description": "Plan name as a traveller sees it.",
      +                  "type": "string"
      +                },
      +                "package_id": {
      +                  "description": "The plan id to buy. Pass it to create-checkout-session or get-plan.",
      +                  "type": "string"
      +                },
      +                "policy": {
      +                  "description": "What the plan really gives you. Null when the supplier has never published its terms, which is different from having no limits.",
      +                  "properties": {
      +                    "high_speed_data_mb": {
      +                      "description": "Full-speed allowance in megabytes PER RESET PERIOD, so 1 GB a day for 30 days is 1024, not 30720. 0 means genuinely uncapped.",
      +                      "type": [
      +                        "integer",
      +                        "null"
      +                      ]
      +                    },
      +                    "max_speed_kbps": {
      +                      "description": "Speed ceiling in kbit/s from the first megabyte. Null means no ceiling.",
      +                      "type": [
      +                        "integer",
      +                        "null"
      +                      ]
      +                    },
      +                    "reduced_speed_kbps": {
      +                      "description": "Speed in kbit/s after the full-speed allowance is used. Null means the data STOPS rather than slowing down.",
      +                      "type": [
      +                        "integer",
      +                        "null"
      +                      ]
      +                    },
      +                    "reset_period": {
      +                      "description": "How often the full-speed allowance resets. Null means it covers the whole plan.",
      +                      "enum": [
      +                        "daily",
      +                        "weekly",
      +                        "monthly",
      +                        null
      +                      ],
      +                      "type": [
      +                        "string",
      +                        "null"
      +                      ]
      +                    }
      +                  },
      +                  "required": [
      +                    "high_speed_data_mb",
      +                    "reset_period",
      +                    "max_speed_kbps",
      +                    "reduced_speed_kbps"
      +                  ],
      +                  "type": [
      +                    "object",
      +                    "null"
      +                  ]
      +                },
      +                "price": {
      +                  "description": "The same price formatted for a person.",
      +                  "type": "string"
      +                },
      +                "price_cents": {
      +                  "description": "Price for one of this plan, in minor units (cents) of the response currency.",
      +                  "type": "integer"
      +                },
      +                "quantity": {
      +                  "description": "How many of this plan to buy.",
      +                  "type": "integer"
      +                },
      +                "unlimited": {
      +                  "description": "True when the plan is sold as unlimited, which almost always means unlimited up to a fair-use cap.",
      +                  "type": "boolean"
      +                },
      +                "validity_days": {
      +                  "description": "How many days the plan stays valid once it activates.",
      +                  "type": "integer"
      +                }
      +              },
      +              "required": [
      +                "package_id",
      +                "name",
      +                "covers",
      +                "quantity",
      +                "data",
      +                "data_mb",
      +                "unlimited",
      +                "validity_days",
      +                "policy",
      +                "price_cents",
      +                "price"
      +              ],
      +              "type": "object"
      +            },
      +            "type": "array"
      +          },
      +          "purchasable": {
      +            "description": "False when the option needs more eSIMs than one order can carry.",
      +            "type": "boolean"
      +          },
      +          "recommended": {
      +            "description": "True on the one option this answer recommends.",
      +            "type": "boolean"
      +          },
      +          "saves_cents": {
      +            "description": "What this option saves against the next cheapest complete alternative, in minor units. 0 when there is none or when it is dearer.",
      +            "type": "integer"
      +          },
      +          "strategy": {
      +            "description": "How this option buys the trip.",
      +            "enum": [
      +              "single",
      +              "per_country",
      +              "mixed"
      +            ],
      +            "type": "string"
      +          },
      +          "total": {
      +            "description": "The same total formatted for a person, e.g. \"24.50 EUR\".",
      +            "type": "string"
      +          },
      +          "total_cents": {
      +            "description": "Total price in minor units (cents) of the response currency, so 2450 is 24.50.",
      +            "type": "integer"
      +          },
      +          "warnings": {
      +            "description": "What this option does not do: a stop it leaves uncovered, a plan that runs out or expires early. Empty when there is nothing to say.",
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          }
      +        },
      +        "required": [
      +          "strategy",
      +          "recommended",
      +          "esims",
      +          "total_cents",
      +          "total",
      +          "complete",
      +          "purchasable",
      +          "saves_cents",
      +          "items",
      +          "warnings"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "planner_url": {
      +      "description": "The same trip on the SimFuse website, for a person who wants to finish it themselves.",
      +      "type": "string"
      +    },
      +    "reason": {
      +      "description": "One sentence explaining the recommendation, written to be quoted to the traveller verbatim.",
      +      "type": "string"
      +    },
      +    "recommendation": {
      +      "description": "Which strategy won: one plan for the whole route, one plan per country, or a mix. Null when nothing we sell covers the trip.",
      +      "enum": [
      +        "single",
      +        "per_country",
      +        "mixed"
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "trip": {
      +      "description": "The trip as it was understood, which is worth reading back to the traveller.",
      +      "properties": {
      +        "end": {
      +          "description": "Last day of the trip, YYYY-MM-DD.",
      +          "type": "string"
      +        },
      +        "span_days": {
      +          "description": "Total days from arrival at the first stop to departure from the last.",
      +          "type": "integer"
      +        },
      +        "start": {
      +          "description": "First day of the trip, YYYY-MM-DD.",
      +          "type": "string"
      +        },
      +        "stops": {
      +          "description": "The stops, in travel order, with their dates and data estimates.",
      +          "items": {
      +            "properties": {
      +              "arrive": {
      +                "description": "Arrival date, YYYY-MM-DD.",
      +                "type": "string"
      +              },
      +              "country": {
      +                "description": "ISO 3166-1 alpha-2 code of the stop.",
      +                "type": "string"
      +              },
      +              "depart": {
      +                "description": "Departure date, YYYY-MM-DD.",
      +                "type": "string"
      +              },
      +              "estimated_data": {
      +                "description": "The same estimate written for a person, e.g. \"3.9 GB\".",
      +                "type": "string"
      +              },
      +              "estimated_mb": {
      +                "description": "Data this stop is estimated to need, in megabytes (1 GB is 1024 MB).",
      +                "type": "integer"
      +              },
      +              "nights": {
      +                "description": "Days spent at this stop.",
      +                "type": "integer"
      +              },
      +              "usage": {
      +                "description": "The data appetite used for this stop.",
      +                "enum": [
      +                  "light",
      +                  "regular",
      +                  "heavy"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "country",
      +              "nights",
      +              "usage",
      +              "arrive",
      +              "depart",
      +              "estimated_mb",
      +              "estimated_data"
      +            ],
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "token": {
      +          "description": "Compact encoding of the trip, for the planner_url link.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "token",
      +        "start",
      +        "end",
      +        "span_days",
      +        "stops"
      +      ],
      +      "type": "object"
      +    },
      +    "warnings": {
      +      "description": "Trip-level caveats: a country SimFuse does not sell, or a gap the recommended option leaves. Say these out loud rather than dropping them.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "contract",
      +    "currency",
      +    "trip",
      +    "recommendation",
      +    "reason",
      +    "options",
      +    "warnings",
      +    "planner_url",
      +    "checkout"
      +  ],
      +  "type": "object"
      +}
  2. First observed

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, and the description adds genuinely new behavioral context: nothing is reserved or charged, prices are today's catalog rates rather than a held quote, and the returned package ids flow directly into create-checkout-session. It also discloses the side finding that uncovered countries are named.

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?

Front-loaded with the question it answers, then capabilities, then usage guidance, then the read-only caveat. Efficient overall, though the middle sentence bundles several distinct outputs (cheapest option, data estimate, uncovered countries, package ids) into one long chain.

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 read-only planning tool with an output schema, the description covers the computation logic, the return payload shape, the read-only guarantee, and price freshness. Nothing an agent needs to decide whether or how to call it is missing.

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

Parameters3/5

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

Schema coverage is 100%, so the schema already documents every parameter including the usage enums, defaults, and country-code format. The description only restates 'the stops, a country code and the days spent in each' and adds no syntax or format detail beyond the schema, so the baseline 3 applies.

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?

Opens with the exact question the tool answers ('which eSIM should I buy for this trip?') and states the specific computation: comparing one whole-route plan vs per-country vs a mix on live prices. It clearly distinguishes itself from siblings like list-plans and get-plan, which return catalog data rather than a recommendation.

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?

Explicit routing: 'Use it whenever a trip has two or more countries, and for a single country when the traveller wants a recommendation rather than a list.' That names both the trigger condition and the alternative (listing via list-plans), and it points to create-checkout-session as the downstream step.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources