Search destinations

Discover destinations by name or traveler intent, returning stable codes for subsequent searches.

Availability

search_destinations is available through GoVisit page WebMCP and the stateless HTTP JSON endpoint POST https://govisit.ai/api/tools/v1/search_destinations. 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:

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_destinations');
if (!tool) throw new Error('search_destinations is not registered on this page.');
const result = await context.executeTool(tool, { query: 'Prague', mode: 'name', 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_destinations \
  -H 'Content-Type: application/json' \
  --data '{"query":"Prague","mode":"name","language":"en","limit":5}'

JavaScript

const response = await fetch('https://govisit.ai/api/tools/v1/search_destinations', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({"query": "Prague", "mode": "name", "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_destinations'
payload = {'query': 'Prague', 'mode': 'name', '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.

Continue with the selected destination

Let the traveler choose a destination when the search returns multiple candidates. Pass that result's stable code as destination to search places; do not silently choose the first match for them.

For example, a matching item can provide the cz_prague code shown in the place-search request below. This schema-shaped response example shows the full required envelope; optional fields such as release metadata and warnings may also be present:

{
  "schemaVersion": "2",
  "locale": "en",
  "completeness": "search-index-release",
  "data": {
    "scope": { "kind": "all", "code": "all" },
    "count": 1,
    "items": [
      {
        "code": "cz_prague",
        "entityType": "destination",
        "name": "Prague",
        "url": "https://govisit.ai/en/destinations/cz/prague/",
        "match": "name",
        "score": null
      }
    ]
  }
}

In application code, carry the selected code forward:

const selectedDestination = destinationResult.data.items.find(
  (item) => item.code === travelerSelection.destinationCode,
);
if (!selectedDestination) throw new Error('The selected destination is not in this result.');

const placeSearch = {
  query: 'quiet cafes with outdoor seating',
  mode: 'intent',
  destination: selectedDestination.code,
  language: 'en',
  limit: 5,
};

Input and output contract

Input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 2,
      "maxLength": 120,
      "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."
    },
    "within": {
      "type": "string",
      "maxLength": 64,
      "pattern": "^[A-Za-z0-9][A-Za-z0-9_]*$",
      "not": {
        "pattern": "^[aA][lL][lL]$"
      },
      "description": "Canonical destination code to explore within; all is reserved for an explicit unrestricted place search, never a containing-destination filter."
    },
    "types": {
      "type": "array",
      "minItems": 1,
      "maxItems": 5,
      "uniqueItems": true,
      "items": {
        "enum": [
          "country",
          "region",
          "district",
          "city",
          "highlight"
        ]
      },
      "description": "Match any of these published classifications; not a size/tier filter."
    }
  },
  "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
          }
        }
      }
    }
  ]
}
Output schema
{
  "type": "object",
  "properties": {
    "schemaVersion": {
      "type": "string",
      "const": "2"
    },
    "locale": {
      "type": "string",
      "enum": [
        "en",
        "cs"
      ]
    },
    "completeness": {
      "type": "string",
      "enum": [
        "search-index-release",
        "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",
                "destination"
              ]
            },
            "code": {
              "type": "string"
            }
          },
          "required": [
            "kind",
            "code"
          ],
          "additionalProperties": false
        },
        "items": {
          "type": "array",
          "maxItems": 20,
          "items": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "type": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "country",
                  "region",
                  "district",
                  "city",
                  "highlight",
                  null
                ]
              },
              "region": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The region it lies in; null for a country or a region."
              },
              "country": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The country it lies in; null for a country."
              },
              "places": {
                "type": "integer",
                "minimum": 0,
                "description": "Indexed places in the destination."
              },
              "match": {
                "type": "string",
                "enum": [
                  "name",
                  "intent"
                ]
              },
              "score": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Engine-specific ranking signal; compare only within the same match method, not a suitability probability."
              },
              "url": {
                "type": "string",
                "description": "The destination's canonical GoVisit page."
              },
              "entityType": {
                "type": "string",
                "const": "destination"
              },
              "code": {
                "type": "string",
                "description": "Stable code accepted by search_places.destination."
              },
              "classifications": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Published classifications; highlight is not a geographic size or tier."
              },
              "containmentMethod": {
                "enum": [
                  "identity",
                  "division-coverage",
                  "parent-chain"
                ],
                "description": "Canonical relation used to establish within scope; parent-chain is disclosed fallback when coverage is absent."
              }
            },
            "required": [
              "code",
              "entityType",
              "name",
              "url",
              "match",
              "score"
            ]
          }
        },
        "count": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "scope",
        "items",
        "count"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "schemaVersion",
    "locale",
    "completeness",
    "data"
  ]
}
HTTP input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 2,
      "maxLength": 120,
      "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."
    },
    "within": {
      "type": "string",
      "maxLength": 64,
      "pattern": "^[A-Za-z0-9][A-Za-z0-9_]*$",
      "not": {
        "pattern": "^[aA][lL][lL]$"
      },
      "description": "Canonical destination code to explore within; all is reserved for an explicit unrestricted place search, never a containing-destination filter."
    },
    "types": {
      "type": "array",
      "minItems": 1,
      "maxItems": 5,
      "uniqueItems": true,
      "items": {
        "enum": [
          "country",
          "region",
          "district",
          "city",
          "highlight"
        ]
      },
      "description": "Match any of these published classifications; not a size/tier filter."
    }
  },
  "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
          }
        }
      }
    }
  ]
}

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 a judgment that a destination fits a trip. Geographic filters require a capable index release; unknown containment is never assumed. Scores are ranking signals, not suitability probabilities.

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

Last updated: October 10, 2026