Skip to main content
Glama
prompts.py26.8 kB
"""Prompt registrations for the STAC MCP server. This module exposes a single function `register_prompts(app)` which attaches all prompt definitions to the provided FastMCP app. Keeping prompts in a separate module avoids making the server module too large and prevents import cycles. Each prompt definition includes both the human-readable content and the machine-readable payload schema and example. They aim to be epistemically transparent about their purpose and usage - guiding users on geospatial data tool interactions. """ from __future__ import annotations import json from typing import Any from fastmcp.prompts.prompt import PromptMessage, TextContent def register_prompts(app: Any) -> None: """Register all prompt definitions on the provided FastMCP `app`.""" _common_required = ["collections", "datetime", "bbox", "limit"] @app.prompt( name="sensor_registry_info_prompt", description="Information about the STAC sensor registry", meta={}, ) def _prompt_sensor_registry_info() -> PromptMessage: human = ( "The internal STAC sensor registry maps collection ids to native " "dtypes and provider-specific aliases. Use it as a fallback " "when a collection id cannot be found by searching the target " "catalog. It is not exhaustive; always confirm with " "search_collections or get_collection when available." ) payload = { "name": "sensor_registry_info", "description": ( "Return the internal sensor registry mapping of collection ids " "to dtype info." ), "parameters": {"type": "object", "properties": {}, "required": []}, "example": {}, } return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="stac_tool_overview_prompt", description="Overview of STAC tools available", meta={}, ) def _prompt_stac_tool_overview() -> PromptMessage: human = ( "Available STAC tools: get_root, get_conformance, search_collections, " "get_collection, get_queryables, search_items, get_item, and " "estimate_data_size." ) payload = { "name": "stac_tool_overview", "description": "Overview of STAC tools available", "parameters": {}, "example": {}, } return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_get_root_prompt", description="Usage for get_root tool", meta={ "schema": {"type": "object", "properties": {}, "required": []}, "example": {}, }, ) def _prompt_get_root() -> PromptMessage: schema = {"type": "object", "properties": {}, "required": []} payload = { "name": "get_root", "description": "Return the STAC root document for a catalog.", "parameters": schema, "example": {}, } human = ( f"Tool: get_root\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_get_conformance_prompt", description="Usage for get_conformance tool", meta={ "schema": {"type": "object", "properties": {}, "required": []}, "example": {}, }, ) def _prompt_get_conformance() -> PromptMessage: schema = {"type": "object", "properties": {}, "required": []} payload = { "name": "get_conformance", "description": "Return server conformance classes.", "parameters": schema, "example": {}, } human = ( f"Tool: get_conformance\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_search_collections_prompt", description="Usage for search_collections tool", meta={ "schema": { "type": "object", "properties": { "limit": {"type": "integer", "default": 10}, "catalog_url": {"type": "string"}, }, "required": [], }, "example": {"limit": 5}, }, ) def _prompt_search_collections() -> PromptMessage: schema = { "type": "object", "properties": { "limit": {"type": "integer", "default": 10}, "catalog_url": {"type": "string"}, }, "required": [], } payload = { "name": "search_collections", "description": "Return a page of STAC collections.", "parameters": schema, "example": {"limit": 5}, } human = ( f"Tool: search_collections\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_get_collection_prompt", description="Usage for get_collection tool", meta={ "schema": { "type": "object", "properties": { "collection_id": {"type": "string"}, "catalog_url": {"type": "string"}, }, "required": ["collection_id"], }, "example": {"collection_id": "my-collection"}, }, ) def _prompt_get_collection() -> PromptMessage: schema = { "type": "object", "properties": { "collection_id": {"type": "string"}, "catalog_url": {"type": "string"}, }, "required": ["collection_id"], } payload = { "name": "get_collection", "description": "Fetch a single STAC Collection by id.", "parameters": schema, "example": {"collection_id": "my-collection"}, } human = ( f"Tool: get_collection\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_get_item_prompt", description="Usage for get_item tool", meta={ "schema": { "type": "object", "properties": { "collection_id": {"type": "string"}, "item_id": {"type": "string"}, "output_format": { "type": "string", "enum": ["text", "json"], "default": "text", }, "catalog_url": {"type": "string"}, }, "required": ["collection_id", "item_id"], }, "example": { "collection_id": "c1", "item_id": "i1", "output_format": "json", }, }, ) def _prompt_get_item() -> PromptMessage: schema = { "type": "object", "properties": { "collection_id": {"type": "string"}, "item_id": {"type": "string"}, "output_format": { "type": "string", "enum": ["text", "json"], "default": "text", }, "catalog_url": {"type": "string"}, }, "required": ["collection_id", "item_id"], } payload = { "name": "get_item", "description": "Retrieve a single STAC Item.", "parameters": schema, "example": { "collection_id": "c1", "item_id": "i1", "output_format": "json", }, } human = ( f"Tool: get_item\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_search_items_prompt", description="Usage for search_items tool", meta={ "schema": { "type": "object", "properties": { "collections": {"type": "array", "items": {"type": "string"}}, "bbox": { "type": "array", "items": {"type": "number"}, "minItems": 4, "maxItems": 4, }, "datetime": {"type": "string"}, "limit": {"type": "integer", "default": 10}, "query": {"type": "object"}, "output_format": { "type": "string", "enum": ["text", "json"], "default": "text", }, }, "required": _common_required, }, "example": {"collections": ["c1"], "limit": 3}, }, ) def _prompt_search_items() -> PromptMessage: schema = { "type": "object", "properties": { "collections": {"type": "array", "items": {"type": "string"}}, "bbox": { "type": "array", "items": {"type": "number"}, "minItems": 4, "maxItems": 4, }, "datetime": {"type": "string"}, "limit": {"type": "integer", "default": 10}, "query": {"type": "object"}, "output_format": { "type": "string", "enum": ["text", "json"], "default": "text", }, }, "required": _common_required, } payload = { "name": "search_items", "description": "Search for STAC Items.", "parameters": schema, "example": {"collections": ["c1"], "limit": 3}, } human = ( f"Tool: search_items\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}\n\n" "Notes:\n" "If get_collections has not been run yet for the target catalog, " "run it first to populate the collection list.\n" "On responses with zero items, validate that the collection IDs " "are correct.\n" "If using 'bbox', ensure coordinates are in [minLon, minLat, maxLon, " "maxLat] order.\n" "Datetime should be in ISO 8601 format, e.g., '2020-01-01/2020-12-31'.\n" "Limit should be a positive integer.\n" "Unlike `pystac-client`, this `limit` is a hard cutoff on the number " "of items returned post-search, not a page size.\n" "If a user specifies 'latest' for datetime, interpret it as the " "most recent available data for the specified collections and " "use a limit=1.\n" "To prevent excessive data retrieval, enforce a maximum limit of 10. " "Requests exceeding this limit should be adjusted down to 10 and batched.\n" "If 'query' is provided, ensure it conforms to the STAC API " "filter specification." ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_estimate_data_size_prompt", description="Usage for estimate_data_size tool", meta={ "schema": { "type": "object", "properties": { "collections": {"type": "array", "items": {"type": "string"}}, "bbox": { "type": "array", "items": {"type": "number"}, "minItems": 4, "maxItems": 4, }, "datetime": {"type": "string"}, "query": {"type": "object"}, "aoi_geojson": {"type": "object"}, "limit": {"type": "integer", "default": 10}, "force_metadata_only": {"type": "boolean", "default": False}, "output_format": { "type": "string", "enum": ["text", "json"], "default": "text", }, }, "required": _common_required, }, "example": {"collections": ["c1"], "limit": 10, "output_format": "json"}, }, ) def _prompt_estimate_data_size() -> PromptMessage: schema = { "type": "object", "properties": { "collections": {"type": "array", "items": {"type": "string"}}, "bbox": { "type": "array", "items": {"type": "number"}, "minItems": 4, "maxItems": 4, }, "datetime": {"type": "string"}, "query": {"type": "object"}, "aoi_geojson": {"type": "object"}, "limit": {"type": "integer", "default": 100}, "force_metadata_only": {"type": "boolean", "default": False}, "output_format": { "type": "string", "enum": ["text", "json"], "default": "text", }, }, "required": _common_required, } payload = { "name": "estimate_data_size", "description": "Estimate data size for a STAC query.", "parameters": schema, "example": {"collections": ["c1"], "limit": 10, "output_format": "json"}, } human = ( f"This tool should be run only after search_items has been used to " "validate collection IDs and sampling parameters.\n\n" f"Tool: estimate_data_size\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Note: The response may include 'reported_bytes' and 'registry_bytes'\n" "for per-variable estimates. Prefer 'registry_bytes' when a sensor " "registry provides an instrument-native dtype.\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_get_queryables_prompt", description="Usage for get_queryables tool", meta={ "schema": { "type": "object", "properties": { "collection_id": {"type": "string"}, "catalog_url": {"type": "string"}, }, "required": [], }, "example": {"collection_id": "my-collection"}, }, ) def _prompt_get_queryables() -> PromptMessage: schema = { "type": "object", "properties": { "collection_id": {"type": "string"}, "catalog_url": {"type": "string"}, }, "required": [], } payload = { "name": "get_queryables", "description": "Fetch STAC API (or collection) queryables.", "parameters": schema, "example": {"collection_id": "my-collection"}, } human = ( f"Tool: get_queryables\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_get_aggregations_prompt", description="Usage for get_aggregations tool", meta={ "schema": { "type": "object", "properties": { "collections": {"type": "array", "items": {"type": "string"}}, "bbox": { "type": "array", "items": {"type": "number"}, "minItems": 4, "maxItems": 4, }, "datetime": {"type": "string"}, "query": {"type": "object"}, "catalog_url": {"type": "string"}, }, "required": _common_required, }, "example": {"collections": ["c1"], "datetime": "2020-01-01/2020-12-31"}, }, ) def _prompt_get_aggregations() -> PromptMessage: schema = { "type": "object", "properties": { "collections": {"type": "array", "items": {"type": "string"}}, "bbox": { "type": "array", "items": {"type": "number"}, "minItems": 4, "maxItems": 4, }, "datetime": {"type": "string"}, "query": {"type": "object"}, "catalog_url": {"type": "string"}, }, "required": _common_required, } payload = { "name": "get_aggregations", "description": "Return aggregations for STAC Items in a collection.", "parameters": schema, "example": {"collections": ["c1"], "datetime": "2020-01-01/2020-12-31"}, } human = ( f"Tool: get_aggregations\nDescription: {payload['description']}\n\n" "Parameters:\n" f"{json.dumps(schema, indent=2)}\n\n" "Example:\n" f"{json.dumps(payload['example'], indent=2)}" ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="tool_ordering_info_prompt", description="Information on tool ordering and usage", meta={}, ) def _prompt_tool_ordering_info() -> PromptMessage: human = ( "Preferred order: get_root -> get_conformance -> search_collections -> " "get_collection -> get_queryables -> search_items -> get_item -> " "estimate_data_size. Use caching and sampling (limit) when " "estimating." ) payload = { "name": "tool_ordering_info", "description": "Preferred order and usage guidance for STAC tools", "parameters": {}, "example": {}, } return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="catalog_discovery_prompt", description="Steps to discover what a STAC catalog supports", meta={}, ) def _prompt_catalog_discovery() -> PromptMessage: human = ( "Discovery steps:\n" "1) Call get_root to locate the catalog root and entrypoints.\n" "2) Call get_conformance to list supported STAC extensions.\n" "3) Run search_collections (limit=50) to inspect available " "collection IDs and titles.\n" "4) Sample get_collection for candidate collections to validate " "assets and links.\n\n" "Parameters:\n" "- None\n\n" "Example:\n" '{"catalog_url": "https://planetarycomputer.microsoft.com/api/stac/v1"}\n\n' "Notes:\n" "Use these steps before searching items to avoid mismatched " "collection IDs." ) payload = { "name": "catalog_discovery", "description": "Checklist for discovering catalog capabilities", "parameters": {}, "example": {}, } return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="collection_alias_resolution_prompt", description="How to resolve collection id aliases across catalogs", meta={}, ) def _prompt_collection_alias_resolution() -> PromptMessage: human = ( "Alias resolution strategy:\n" "1) When a collection ID lookup returns no result, normalize case " "and punctuation.\n" "2) Try provider-specific aliases (for example: 'sentinel-2-l2a' " "vs 'sentinel-2-c1-l2a').\n" "3) For each candidate alias call get_collection to verify presence " "and canonical metadata.\n" "4) If still unresolved, call the sensor_registry_info tool as a " "fallback to map known aliases.\n\n" "Parameters:\n" "- collection_id: string (optional)\n\n" "Example:\n" '{"collection_id": "sentinel-2-c1-l2a"}\n' ) payload = { "name": "collection_alias_resolution", "description": "Steps to resolve collection id aliases across providers", "parameters": {}, "example": {}, } return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="estimate_size_strategy_prompt", description="Safe strategies for estimating data size at scale", meta={}, ) def _prompt_estimate_size_strategy() -> PromptMessage: human = ( "Estimation strategy:\n" "1) Sample a modest number of items (N=10-100) across the " "requested timeframe.\n" "2) Prefer 'registry_bytes' when the sensor registry provides an " "instrument-native dtype.\n" "3) Aggregate per-band sizes and scale by item counts; persist " "detailed per-sample results as fixtures.\n" "4) Avoid downloading full assets; use metadata-only measurements " "whenever possible.\n\n" "Parameters:\n" "- collections: list[string]\n" "- limit: integer (samples per collection)\n\n" "Example:\n" '{"collections": ["sentinel-2-l2a"], "limit": 20}\n' ) payload = { "name": "estimate_size_strategy", "description": "Guidance for safely estimating dataset sizes", "parameters": {}, "example": {}, } return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, ) @app.prompt( name="explain_tool_output_prompt", description="Summarize and explain tool outputs for humans", meta={ "schema": { "type": "object", "properties": { "tool": {"type": "string"}, "payload": {"type": "object"}, }, "required": ["tool", "payload"], }, "example": {"tool": "get_collection", "payload": {}}, }, ) def _prompt_explain_tool_output() -> PromptMessage: schema = { "type": "object", "properties": {"tool": {"type": "string"}, "payload": {"type": "object"}}, "required": ["tool", "payload"], } payload = { "name": "explain_tool_output", "description": "Summarize and explain tool outputs", "parameters": schema, "example": {"tool": "get_collection", "payload": {}}, } human = ( "Explain tool output:\n" "- Give a 2-4 sentence human summary of the tool output.\n" "- Highlight 3 most important fields and why they matter.\n" "- Provide 1-2 concrete next steps (e.g., call ordering or " "validation checks).\n\n" "Parameters:\n" "- tool: string\n" "- payload: object (the tool response)\n\n" "Example:\n" '{"tool": "get_collection", "payload": {}}\n' ) return PromptMessage( role="user", content=TextContent(type="text", text=human), _meta={"machine_payload": payload}, )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/BnJam/stac-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server