Search places

Discover places by name or traveler intent in an explicit geographic scope.

Availability

search_places is available through GoVisit page WebMCP and the stateless HTTP JSON endpoint POST https://govisit.ai/api/tools/v1/search_places. The matching Agent Skill packages the same versioned request contract.

HTTP requests do not inherit browser page context. Supply the traveler-established scope and language supported by this tool. No authentication, cookies, SSE connection, or persistent session are required.

On a GoVisit page in a compatible browser, use the registered WebMCP tool. Pass a destination code returned by search_destinations when the traveler has selected a destination:

const context = document.modelContext;
if (!context) throw new Error('This browser does not expose WebMCP on this page.');
const tool = (await context.getTools()).find((item) => item.name === 'search_places');
if (!tool) throw new Error('search_places is not registered on this page.');
const result = await context.executeTool(tool, {
  query: 'Cafe Slavia', mode: 'name', destination: 'cz_prague', language: 'en', limit: 5
});
console.log(result.data.items);

Call over HTTP

curl

curl --fail-with-body --silent --show-error https://govisit.ai/api/tools/v1/search_places \
  -H 'Content-Type: application/json' \
  --data '{"query":"Cafe Slavia","mode":"name","destination":"cz_prague","language":"en","limit":5}'

JavaScript

const response = await fetch('https://govisit.ai/api/tools/v1/search_places', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({"query": "Cafe Slavia", "mode": "name", "destination": "cz_prague", "language": "en", "limit": 5}),
});
let result;
try {
  result = await response.json();
} catch {
  throw new Error(`GoVisit returned a non-JSON response (HTTP ${response.status})`);
}
if (!response.ok) {
  const retryAfter = response.headers.get('Retry-After');
  throw new Error(`GoVisit returned HTTP ${response.status}${retryAfter ? `; retry after ${retryAfter}s` : ''}: ${JSON.stringify(result)}`);
}
if (result.completeness !== 'search-index-release') {
  throw new Error(`Search did not complete: ${result.error ?? result.warnings?.join('; ') ?? result.completeness}`);
}
console.log(result.data.items);

Python

import json
from urllib.error import HTTPError
from urllib.request import Request, urlopen

url = 'https://govisit.ai/api/tools/v1/search_places'
payload = {'query': 'Cafe Slavia', 'mode': 'name', 'destination': 'cz_prague', 'language': 'en', 'limit': 5}
request = Request(url, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json'}, method='POST')
try:
    with urlopen(request) as response:
        result = json.load(response)
except HTTPError as error:
    body = error.read().decode('utf-8', 'replace')
    retry_after = error.headers.get('Retry-After')
    raise RuntimeError(f'GoVisit returned HTTP {error.code}; Retry-After={retry_after}: {body}') from error
if result.get('completeness') != 'search-index-release':
    raise RuntimeError(result.get('error') or result.get('warnings') or result.get('completeness'))
for item in result.get('data', {}).get('items', []):
    print(item.get('name'), item.get('url'))

The response is the same result object exposed by WebMCP. Inspect data.items, data.scope, and data.count; preserve any release, completeness, warnings, and truncated fields returned.

Read a returned place

Each item includes a canonical profile url and a bounded set of preview fields. Treat a search match as a candidate, then read the profile before presenting factual details in a planner. This schema-shaped response example shows the required envelope and an item; the place ID and canonical URL are placeholders, and optional release metadata or warnings may also be present:

{
  "schemaVersion": "2",
  "locale": "en",
  "completeness": "search-index-release",
  "data": {
    "scope": { "kind": "destination", "code": "cz_prague" },
    "count": 1,
    "items": [
      {
        "id": "<returned-place-id>",
        "entityType": "place",
        "name": "<returned place name>",
        "url": "<canonical profile URL returned by GoVisit>",
        "match": "intent",
        "score": null
      }
    ]
  }
}

The place overview tool can read additional published facts through WebMCP when a compatible browser is on that place page; it has no stateless HTTP endpoint. An HTTP-only app can show the returned preview fields and link to the canonical profile, but should not assume the full profile is available as JSON. The score is a ranking signal, not a suitability probability.

Input and output contract

Input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 2,
      "maxLength": 200,
      "description": "Place or destination name, or the traveler's intent."
    },
    "mode": {
      "type": "string",
      "enum": [
        "auto",
        "name",
        "intent"
      ],
      "default": "auto",
      "description": "Name lookup, intent retrieval, or name-first auto discovery."
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 20,
      "default": 10
    },
    "language": {
      "type": "string",
      "enum": [
        "en",
        "cs"
      ],
      "description": "Requested response language; defaults to the page language."
    },
    "destination": {
      "type": "string",
      "maxLength": 64,
      "pattern": "^[A-Za-z0-9][A-Za-z0-9_]*$",
      "description": "Stable destination code or all. Defaults to the current destination, otherwise all."
    },
    "country": {
      "type": "string",
      "pattern": "^[A-Za-z]{2}$",
      "description": "ISO country scope; intersects destination and proximity where the public geography projection is available."
    },
    "near": {
      "type": "object",
      "properties": {
        "placeId": {
          "type": "string",
          "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
          "description": "Reference GERS Place resolved from the same public release."
        },
        "coordinates": {
          "type": "object",
          "properties": {
            "latitude": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            },
            "longitude": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          "required": [
            "latitude",
            "longitude"
          ],
          "additionalProperties": false
        },
        "radiusMeters": {
          "type": "number",
          "minimum": 1,
          "maximum": 100000
        }
      },
      "required": [
        "radiusMeters"
      ],
      "additionalProperties": false,
      "oneOf": [
        {
          "required": [
            "placeId"
          ],
          "not": {
            "required": [
              "coordinates"
            ]
          }
        },
        {
          "required": [
            "coordinates"
          ],
          "not": {
            "required": [
              "placeId"
            ]
          }
        }
      ]
    }
  },
  "required": [
    "query"
  ],
  "additionalProperties": false,
  "allOf": [
    {
      "if": {
        "properties": {
          "mode": {
            "const": "intent"
          }
        },
        "required": [
          "mode"
        ]
      },
      "then": {
        "properties": {
          "query": {
            "minLength": 3
          }
        }
      }
    },
    {
      "if": {
        "properties": {
          "mode": {
            "const": "name"
          }
        },
        "required": [
          "mode"
        ]
      },
      "then": {
        "properties": {
          "query": {
            "maxLength": 120
          },
          "limit": {
            "maximum": 10
          }
        }
      }
    }
  ]
}
Output schema
{
  "type": "object",
  "properties": {
    "schemaVersion": {
      "type": "string",
      "const": "2"
    },
    "locale": {
      "type": "string",
      "enum": [
        "en",
        "cs"
      ]
    },
    "completeness": {
      "type": "string",
      "enum": [
        "search-index-release",
        "partial-geography",
        "invalid-input",
        "unavailable"
      ]
    },
    "release": {
      "type": "string"
    },
    "error": {
      "type": "string"
    },
    "warnings": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "truncated": {
      "type": "boolean"
    },
    "retryAfter": {
      "type": "number"
    },
    "data": {
      "type": "object",
      "properties": {
        "scope": {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "enum": [
                "all",
                "country",
                "destination"
              ]
            },
            "code": {
              "type": "string"
            },
            "country": {
              "type": "string",
              "pattern": "^[A-Z]{2}$"
            },
            "near": {
              "type": "object",
              "description": "Resolved proximity constraint; never interpreted as travel time."
            }
          },
          "required": [
            "kind",
            "code"
          ],
          "additionalProperties": false
        },
        "items": {
          "type": "array",
          "maxItems": 20,
          "items": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "category": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "locality": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Street address, for example \"Pobřežní 311/1\"; null when the place has none."
              },
              "coordinates": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "The place's point (WGS 84); null when it has none.",
                "properties": {
                  "latitude": {
                    "type": "number"
                  },
                  "longitude": {
                    "type": "number"
                  }
                },
                "required": [
                  "latitude",
                  "longitude"
                ]
              },
              "url": {
                "type": "string",
                "description": "The place's canonical GoVisit page."
              },
              "score": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Engine-specific ranking signal; compare only within the same match method, not a suitability probability."
              },
              "entityType": {
                "type": "string",
                "const": "place"
              },
              "id": {
                "type": "string",
                "format": "uuid",
                "description": "Public GERS Place identity."
              },
              "match": {
                "type": "string",
                "enum": [
                  "name",
                  "intent"
                ]
              },
              "profileQuality": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Published profile completeness signal; not guest fit."
              },
              "categoryCode": {
                "type": "string",
                "description": "Published canonical category, not an amenity or suitability verdict."
              },
              "destinationCodes": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                },
                "description": "Canonical membership; null is unestablished and an empty array is known empty."
              },
              "operatingStatus": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "operational",
                  "temporarily_closed",
                  "permanently_closed",
                  null
                ],
                "description": "Published lifecycle status, not open-now or booking availability."
              },
              "distanceMeters": {
                "type": "number",
                "minimum": 0,
                "description": "Straight-line geographic distance from the explicit proximity reference, not travel time."
              }
            },
            "required": [
              "id",
              "entityType",
              "name",
              "url",
              "match",
              "score"
            ]
          }
        },
        "count": {
          "type": "integer",
          "minimum": 0
        },
        "coverage": {
          "type": "object",
          "description": "Bounded candidate observation, not exhaustive market coverage.",
          "properties": {
            "candidatesRetrieved": {
              "type": "integer",
              "minimum": 0,
              "maximum": 200
            },
            "examined": {
              "type": "integer",
              "minimum": 0,
              "maximum": 200
            },
            "unestablished": {
              "type": "integer",
              "minimum": 0,
              "maximum": 200
            },
            "eligible": {
              "type": "integer",
              "minimum": 0,
              "maximum": 200
            },
            "returned": {
              "type": "integer",
              "minimum": 0,
              "maximum": 20
            },
            "candidateBudget": {
              "const": 200
            },
            "indexRowsScanned": {
              "type": "integer",
              "minimum": 0
            },
            "truncated": {
              "type": "boolean"
            }
          },
          "required": [
            "candidatesRetrieved",
            "examined",
            "unestablished",
            "eligible",
            "returned",
            "candidateBudget",
            "indexRowsScanned",
            "truncated"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "scope",
        "items",
        "count"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "schemaVersion",
    "locale",
    "completeness",
    "data"
  ]
}
HTTP input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 2,
      "maxLength": 200,
      "description": "Place or destination name, or the traveler's intent."
    },
    "mode": {
      "type": "string",
      "enum": [
        "auto",
        "name",
        "intent"
      ],
      "default": "auto",
      "description": "Name lookup, intent retrieval, or name-first auto discovery."
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 20,
      "default": 10
    },
    "language": {
      "type": "string",
      "enum": [
        "en",
        "cs"
      ],
      "description": "Requested response language; defaults to the page language."
    },
    "destination": {
      "type": "string",
      "maxLength": 64,
      "pattern": "^[A-Za-z0-9][A-Za-z0-9_]*$",
      "description": "Stable destination code or all. Defaults to the current destination, otherwise all."
    },
    "country": {
      "type": "string",
      "pattern": "^[A-Za-z]{2}$",
      "description": "ISO country scope; intersects destination and proximity where the public geography projection is available."
    },
    "near": {
      "type": "object",
      "properties": {
        "placeId": {
          "type": "string",
          "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
          "description": "Reference GERS Place resolved from the same public release."
        },
        "coordinates": {
          "type": "object",
          "properties": {
            "latitude": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            },
            "longitude": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          "required": [
            "latitude",
            "longitude"
          ],
          "additionalProperties": false
        },
        "radiusMeters": {
          "type": "number",
          "minimum": 1,
          "maximum": 100000
        }
      },
      "required": [
        "radiusMeters"
      ],
      "additionalProperties": false,
      "oneOf": [
        {
          "required": [
            "placeId"
          ],
          "not": {
            "required": [
              "coordinates"
            ]
          }
        },
        {
          "required": [
            "coordinates"
          ],
          "not": {
            "required": [
              "placeId"
            ]
          }
        }
      ]
    }
  },
  "required": [
    "query"
  ],
  "additionalProperties": false,
  "allOf": [
    {
      "if": {
        "properties": {
          "mode": {
            "const": "intent"
          }
        },
        "required": [
          "mode"
        ]
      },
      "then": {
        "properties": {
          "query": {
            "minLength": 3
          }
        }
      }
    },
    {
      "if": {
        "properties": {
          "mode": {
            "const": "name"
          }
        },
        "required": [
          "mode"
        ]
      },
      "then": {
        "properties": {
          "query": {
            "maxLength": 120
          },
          "limit": {
            "maximum": 10
          }
        }
      }
    }
  ]
}

The schemas above are rendered server-side from config/webmcp-tools.json, the canonical reviewed tool catalog. The WebMCP manifest also publishes the machine-readable contract; native RegisteredTool entries advertise an output-contract URL because that interface does not provide an inline outputSchema field.

Interpretation limits

Search returns candidates, not verified recommendations. Constraints intersect and never silently widen. Name-mode and geography constraints have release-specific availability; inspect completeness, warnings, counts, and truncation. Distance is straight-line meters, not travel time.

For the full current contract and linked context, see the WebMCP manifest and the WebMCP overview.

Last updated: October 10, 2026