Skip to main content
Glama

geocode

Turn a place (address, POI, town) into coordinates. Ask two ways, and they combine: query is free text, one run-together string, the way a person types into a search box, and street, housenumber, city, postcode and country name the parts of an address separately. At least one of the two is required. Pass the parts whenever you already hold the address in parts (a form, a CRM row, a manifest): components are REQUIREMENTS, not hints, so city: "London" means a result outside London cannot come back at all, where "London" inside query only reorders. country takes an ISO 3166-1 alpha-2 code or a country name ("GB", "United Kingdom"); a value naming no country is refused rather than silently matching nothing. Returns up to limit (default 10) candidates with name, one-line label, lat/lon, type and address parts. Pass focus {lat, lon} to rank results near a location higher. A bare city or town name (no comma) lists that city's airports and main railway stations directly behind it, ahead of namesakes elsewhere. Each hit also carries match: a per-component matched/inferred/unmatched verdict, the score_gap to the runner-up, and which backend answered. READ IT before acting on an address, an unmatched or inferred postcode on the top hit means the answer does not carry the address you asked for, and a small score_gap means the ranking barely chose, so show the alternatives instead of picking one. Use verify_places when the address came from a model or a user and needs checking rather than using. Results are matched in lang (default "en"), so English exonyms ("Munich", "Cologne", "Geneva") resolve to the place meant; pass lang when querying in another language, or "default" for each place's local name.

Input Schema

NameRequiredDescriptionDefault
cityNoStructured component: town or city, e.g. "London". Matches the containing city as well as the immediate locality, so a suburb name works here too.
langNoLanguage of the place names to match and return, as a two-letter code. Defaults to "en", which is what makes English exonyms ("Munich", "Cologne", "Geneva") resolve to the place meant rather than a same-named town elsewhere. Set it to the language your query is written in; "default" asks for each place's own local name. Deployments support a fixed set (this one: "en", "de", "fr"), and anything outside it is refused.
focusNoOptional location bias: results near this point rank higher.
limitNoMaximum number of results (1–50, default 10).
queryNoFree-text place query, e.g. "Dover ferry terminal". Required unless at least one structured component is supplied.
streetNoStructured component: street name, e.g. "Downing Street". Matches the street of addresses and POIs (transliterated street names included) as well as the street itself.
countryNoStructured component: ISO 3166-1 alpha-2 code or country name, "GB", "gb", "United Kingdom" and "UK" all mean the same country. A value naming no country is refused rather than quietly applied as a filter that matches nothing.
postcodeNoStructured component: postcode in any spacing or case, "SW1A 2AA" and "sw1a2aa" are one query. A bare UK outward code ("SW1A") selects the whole district.
housenumberNoStructured component: house number, e.g. "10" or "221B". Only meaningful alongside `street`, a house number on its own excludes nearly everything and identifies nothing.

Output Schema

NameRequiredDescriptionDefault
resultsYesMatching places, best first.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed7 schema fields changed
    • changedInput schema / properties / country / description
      Previous value: -"Structured component: ISO 3166-1 alpha-2 code or country name —\n\"GB\", \"gb\", \"United Kingdom\" and \"UK\" all mean the same country.\nA value naming no country is refused rather than quietly applied as\na filter that matches nothing."New value: +"Structured component: ISO 3166-1 alpha-2 code or country name,\n\"GB\", \"gb\", \"United Kingdom\" and \"UK\" all mean the same country.\nA value naming no country is refused rather than quietly applied as\na filter that matches nothing."
    • changedInput schema / properties / housenumber / description
      Previous value: -"Structured component: house number, e.g. \"10\" or \"221B\". Only\nmeaningful alongside `street` — a house number on its own excludes\nnearly everything and identifies nothing."New value: +"Structured component: house number, e.g. \"10\" or \"221B\". Only\nmeaningful alongside `street`, a house number on its own excludes\nnearly everything and identifies nothing."
    • changedInput schema / properties / postcode / description
      Previous value: -"Structured component: postcode in any spacing or case — \"SW1A 2AA\"\nand \"sw1a2aa\" are one query. A bare UK outward code (\"SW1A\")\nselects the whole district."New value: +"Structured component: postcode in any spacing or case, \"SW1A 2AA\"\nand \"sw1a2aa\" are one query. A bare UK outward code (\"SW1A\")\nselects the whole district."
    • changedOutput schema / $defs / GeocodeHit / properties / match / description
      Previous value: -"How far this hit can be trusted to be the place that was asked\nfor — see [`GeocodeMatch`]. Present whenever the MapMap gateway\nanswered; absent on a deployment falling back to the direct Photon\ngeocoder, and absent on the gateway's own fast paths (a pasted\ncoordinate pair, a bare UK outward code, a category browse), which\nanswer without a ranking to report on."New value: +"How far this hit can be trusted to be the place that was asked\nfor, see [`GeocodeMatch`]. Present whenever the MapMap gateway\nanswered; absent on a deployment falling back to the direct Photon\ngeocoder, and absent on the gateway's own fast paths (a pasted\ncoordinate pair, a bare UK outward code, a category browse), which\nanswer without a ranking to report on."
    • changedOutput schema / $defs / GeocodeMatch / description
      Previous value: -"How well one geocoding result answers what was actually asked.\n\nGeocoding's real failure mode is not \"no answer\" but a confident answer\nto a different question: a plausible row on the wrong street, with\nnothing in the response to say so. This object is that missing say-so,\nand an agent should read it before acting on an address.\n\nHow to read it:\n\n* Any component `unmatched` or `inferred` on the TOP hit means the\n  answer does not carry the address that was asked for — an `unmatched`\n  postcode means the result has no postcode at all, `inferred` means it\n  has a different one. Neither is a match. Say so rather than presenting\n  the hit as the address, and reach for `verify_places` when the address\n  came from a model or a user and needs checking rather than using.\n* A small `score_gap` means the ranking barely chose between this hit\n  and the runner-up, which is exactly when to show the alternatives\n  instead of picking one for the user."New value: +"How well one geocoding result answers what was actually asked.\n\nGeocoding's real failure mode is not \"no answer\" but a confident answer\nto a different question: a plausible row on the wrong street, with\nnothing in the response to say so. This object is that missing say-so,\nand an agent should read it before acting on an address.\n\nHow to read it:\n\n* Any component `unmatched` or `inferred` on the TOP hit means the\n  answer does not carry the address that was asked for, an `unmatched`\n  postcode means the result has no postcode at all, `inferred` means it\n  has a different one. Neither is a match. Say so rather than presenting\n  the hit as the address, and reach for `verify_places` when the address\n  came from a model or a user and needs checking rather than using.\n* A small `score_gap` means the ranking barely chose between this hit\n  and the runner-up, which is exactly when to show the alternatives\n  instead of picking one for the user."
    • changedOutput schema / $defs / GeocodeMatch / properties / score_gap / description
      Previous value: -"The top result's score minus the runner-up's, rounded to 3 decimal\nplaces. `0` for a single result, and `0` from the `photon` source,\nwhich publishes no per-result score — so a `0` is \"no signal\", not\n\"a tie\"."New value: +"The top result's score minus the runner-up's, rounded to 3 decimal\nplaces. `0` for a single result, and `0` from the `photon` source,\nwhich publishes no per-result score, so a `0` is \"no signal\", not\n\"a tie\"."
    • changedOutput schema / $defs / GeocodeMatchComponents / description
      Previous value: -"Per-component verdicts inside a [`GeocodeMatch`]. Each is one of\n\"matched\", \"inferred\" or \"unmatched\"; a component that was not supplied\nis absent entirely.\n\n* \"matched\" — the result's own field carries the value asked for (case-\n  and accent-insensitive, and by containment, so `city: \"London\"`\n  matches \"City of London\").\n* \"inferred\" — the result carries a value for that component, but not\n  the one asked for. It reached the page through ranking, as when a\n  street is found by its transliterated name and displayed under its\n  canonical one.\n* \"unmatched\" — the result carries no value for that component at all."New value: +"Per-component verdicts inside a [`GeocodeMatch`]. Each is one of\n\"matched\", \"inferred\" or \"unmatched\"; a component that was not supplied\nis absent entirely.\n\n* \"matched\", the result's own field carries the value asked for (case-\n  and accent-insensitive, and by containment, so `city: \"London\"`\n  matches \"City of London\").\n* \"inferred\", the result carries a value for that component, but not\n  the one asked for. It reached the page through ranking, as when a\n  street is found by its transliterated name and displayed under its\n  canonical one.\n* \"unmatched\", the result carries no value for that component at all."
  2. Changed5 schema fields changed
    • addedInput schema / $defs / LatLon / anyOf
      Added value: +[
      +  {
      +    "properties": {
      +      "lat": {
      +        "description": "Latitude in decimal degrees (−90 to 90).",
      +        "format": "double",
      +        "type": "number"
      +      },
      +      "lon": {
      +        "description": "Longitude in decimal degrees (−180 to 180).",
      +        "format": "double",
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "lat",
      +      "lon"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "description": "GeoJSON position [lon, lat]: longitude FIRST.",
      +    "items": {
      +      "format": "double",
      +      "type": "number"
      +    },
      +    "maxItems": 2,
      +    "minItems": 2,
      +    "type": "array"
      +  }
      +]
    • changedInput schema / $defs / LatLon / description
      Previous value: -"A WGS84 coordinate pair in decimal degrees."New value: +"A WGS84 coordinate in decimal degrees: a {lat, lon} object (preferred), or a GeoJSON [lon, lat] array with LONGITUDE FIRST, the same order as every polygon field on this server."
    • removedInput schema / $defs / LatLon / properties
      Removed value: -{
      -  "lat": {
      -    "description": "Latitude in decimal degrees (−90 to 90).",
      -    "format": "double",
      -    "type": "number"
      -  },
      -  "lon": {
      -    "description": "Longitude in decimal degrees (−180 to 180).",
      -    "format": "double",
      -    "type": "number"
      -  }
      -}
    • removedInput schema / $defs / LatLon / required
      Removed value: -[
      -  "lat",
      -  "lon"
      -]
    • removedInput schema / $defs / LatLon / type
      Removed value: -"object"
  3. Changed11 schema fields changed
    • addedInput schema / properties / city
      Added value: +{
      +  "description": "Structured component: town or city, e.g. \"London\". Matches the\ncontaining city as well as the immediate locality, so a suburb name\nworks here too.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedInput schema / properties / country
      Added value: +{
      +  "description": "Structured component: ISO 3166-1 alpha-2 code or country name —\n\"GB\", \"gb\", \"United Kingdom\" and \"UK\" all mean the same country.\nA value naming no country is refused rather than quietly applied as\na filter that matches nothing.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedInput schema / properties / housenumber
      Added value: +{
      +  "description": "Structured component: house number, e.g. \"10\" or \"221B\". Only\nmeaningful alongside `street` — a house number on its own excludes\nnearly everything and identifies nothing.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedInput schema / properties / postcode
      Added value: +{
      +  "description": "Structured component: postcode in any spacing or case — \"SW1A 2AA\"\nand \"sw1a2aa\" are one query. A bare UK outward code (\"SW1A\")\nselects the whole district.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • changedInput schema / properties / query / description
      Previous value: -"Free-text place query, e.g. \"Dover ferry terminal\"."New value: +"Free-text place query, e.g. \"Dover ferry terminal\". Required unless\nat least one structured component is supplied."
    • changedInput schema / properties / query / type
      Previous value: -"string"New value: +[
      +  "string",
      +  "null"
      +]
    • addedInput schema / properties / street
      Added value: +{
      +  "description": "Structured component: street name, e.g. \"Downing Street\". Matches\nthe street of addresses and POIs (transliterated street names\nincluded) as well as the street itself.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • removedInput schema / required
      Removed value: -[
      -  "query"
      -]
    • addedOutput schema / $defs / GeocodeHit / properties / match
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/GeocodeMatch"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "How far this hit can be trusted to be the place that was asked\nfor — see [`GeocodeMatch`]. Present whenever the MapMap gateway\nanswered; absent on a deployment falling back to the direct Photon\ngeocoder, and absent on the gateway's own fast paths (a pasted\ncoordinate pair, a bare UK outward code, a category browse), which\nanswer without a ranking to report on."
      +}
    • addedOutput schema / $defs / GeocodeMatch
      Added value: +{
      +  "description": "How well one geocoding result answers what was actually asked.\n\nGeocoding's real failure mode is not \"no answer\" but a confident answer\nto a different question: a plausible row on the wrong street, with\nnothing in the response to say so. This object is that missing say-so,\nand an agent should read it before acting on an address.\n\nHow to read it:\n\n* Any component `unmatched` or `inferred` on the TOP hit means the\n  answer does not carry the address that was asked for — an `unmatched`\n  postcode means the result has no postcode at all, `inferred` means it\n  has a different one. Neither is a match. Say so rather than presenting\n  the hit as the address, and reach for `verify_places` when the address\n  came from a model or a user and needs checking rather than using.\n* A small `score_gap` means the ranking barely chose between this hit\n  and the runner-up, which is exactly when to show the alternatives\n  instead of picking one for the user.",
      +  "properties": {
      +    "components": {
      +      "$ref": "#/$defs/GeocodeMatchComponents",
      +      "description": "Per-component verdict on this hit: one entry for each structured\ncomponent supplied, and empty when the query was free text only."
      +    },
      +    "score_gap": {
      +      "description": "The top result's score minus the runner-up's, rounded to 3 decimal\nplaces. `0` for a single result, and `0` from the `photon` source,\nwhich publishes no per-result score — so a `0` is \"no signal\", not\n\"a tie\".",
      +      "format": "double",
      +      "type": "number"
      +    },
      +    "source": {
      +      "description": "Which backend answered: \"mapmap-index\" (the first-party index) or\n\"photon\".",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "components",
      +    "score_gap",
      +    "source"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / GeocodeMatchComponents
      Added value: +{
      +  "description": "Per-component verdicts inside a [`GeocodeMatch`]. Each is one of\n\"matched\", \"inferred\" or \"unmatched\"; a component that was not supplied\nis absent entirely.\n\n* \"matched\" — the result's own field carries the value asked for (case-\n  and accent-insensitive, and by containment, so `city: \"London\"`\n  matches \"City of London\").\n* \"inferred\" — the result carries a value for that component, but not\n  the one asked for. It reached the page through ranking, as when a\n  street is found by its transliterated name and displayed under its\n  canonical one.\n* \"unmatched\" — the result carries no value for that component at all.",
      +  "properties": {
      +    "city": {
      +      "description": "Verdict on the supplied `city`.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "country": {
      +      "description": "Verdict on the supplied `country`.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "housenumber": {
      +      "description": "Verdict on the supplied `housenumber`.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "postcode": {
      +      "description": "Verdict on the supplied `postcode`.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "street": {
      +      "description": "Verdict on the supplied `street`.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    }
      +  },
      +  "type": "object"
      +}
  4. First observed

TDQS

A4.7/5.0
Behavior5/5

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

No annotations, but the description carries the full burden well: it explains that components are hard requirements rather than ranking hints, that an invalid country is refused not silently ignored, that a bare city name lists airports/stations first, and that match/score_gap must be read before acting on an address. These are precisely the non-obvious behavioral traits an agent needs.

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 core verb and resource, then builds through input modes and output interpretation. Dense but every sentence earns its place; slightly long, but the compression is intentional and mostly readable.

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

Completeness4/5

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

Given 9 params and output schema present, the description covers input semantics, result interpretation (match, score_gap, backend), and language behavior. It does not detail every output field, but the output schema covers that. Complete enough for an agent to call correctly.

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 baseline is 3, but the description adds real semantic value beyond the schema: it explains the two input modes combine, that components are REQUIREMENTS not hints, the country format, and that bare city names surface airports/stations. The match/score_gap guidance is output-level, but limit/x default behavior is confirmed too.

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?

Specific verb+resource: 'Turn a place (address, POI, town) into coordinates.' Explicitly distinguishes itself from reverse_geocode (opposite direction) and points the agent at verify_places for checking addresses. No ambiguity against siblings.

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?

Gives concrete when-to-use: pass components when the address already arrives in parts (form, CRM row, manifest); use verify_places instead when the address came from a model or user and needs verification. Also explains when to prefer query over components based on whether the input is free text or already structured.

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