Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/planet_mcp/servers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from . import sdk
from . import tiles
from . import search

all = [
sdk,
tiles,
search,
]
5 changes: 4 additions & 1 deletion src/planet_mcp/servers/descriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
}
```

search_filter: a Planet Data API filter for advanced searches.
start_date: An optional datestring to use as the start date for the search. Use ISO 8601 format, e.g. 2022-04-14T00:00:00Z.
end_date: An optional datestring to use as the end date for the search. Use ISO 8601 format. If not provided, searches from start_date onwards.

If the user does not ask for specific item types, default to ["PSScene", "SkySatScene", "SkySatCollect"].

Avoid using search_filter unless the user has asked for specific date ranges or other advanced parameters. If a
user asks for a scene from "today", do a search as normal and present the first (most recent) result.

Note: The search automatically filters for cloud_cover <= 0.2 (20%).
"""
}
3 changes: 1 addition & 2 deletions src/planet_mcp/servers/sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import planet
from typing import Union


# tools we don't want enabled at all.
# they simply don't work well in an AI context.
_DEFAULT_IGNORE = {
Expand All @@ -19,6 +18,7 @@
"data_get_search",
"data_get_stats",
"data_list_searches",
"data_search",
"data_update_search",
"data_wait_asset",
"destinations_patch_destination",
Expand All @@ -35,7 +35,6 @@
TOOL_SIG_OVERRIDE = {
"features_add_items",
"data_get_item_coverage",
"data_search",
"mosaics_download_quad",
"mosaics_download_quads",
"mosaics_get_quad",
Expand Down
57 changes: 57 additions & 0 deletions src/planet_mcp/servers/search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from datetime import datetime

from fastmcp import FastMCP
from planet import Planet
from planet_mcp import models
from planet_mcp.servers import descriptions

# technically not using the sdk to make the tool but we can add it to that

mcp = FastMCP("sdk")


@mcp.tool(
name="data_search",
description=descriptions.overrides["data_search"],
tags={"data", "search"},
)
async def data_search(
item_types: list[str],
start_date: str,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
start_date: str,
start_date: str | None,

the type hint (used for validation) still requires a value

end_date: str | None,
geometry: models.Geometry,
):

planet = Planet()
cloud_filter = {
"type": "RangeFilter",
"field_name": "cloud_cover",
"config": {"lte": 0.2},
}
filter = {
"type": "AndFilter",
"config": [cloud_filter],
}
if start_date is not None or end_date is not None:
datefilter_config = {}
if start_date is not None:
datefilter_config["gte"] = datetime.fromisoformat(
start_date.replace("Z", "+00:00")
).isoformat()
if end_date is not None:
datefilter_config["lte"] = datetime.fromisoformat(
end_date.replace("Z", "+00:00")
).isoformat()
datefilter = {
"type": "DateRangeFilter",
"field_name": "acquired",
"config": datefilter_config,
}
filter["config"].append(datefilter)

results = planet.data.search(
item_types=item_types,
geometry=dict(geometry),
search_filter=filter,
)
return results
12 changes: 10 additions & 2 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ async def test_search_tool():
)
async with client:
result = await client.call_tool(
"sdk_data_search", {"item_types": ["SkySatScene"]}
"sdk_data_search",
{
"item_types": ["SkySatScene"],
"start_date": "2023-01-01",
"end_date": "2023-01-02",
"geometry": {"type": "Point", "coordinates": [0, 0], "content": None},
},
)
assert result.structured_content == {"result": [{"type": "Feature"}]}
assert len(result.content) == 1
assert result.content[0].type == "text"
assert result.content[0].text == '[{"type":"Feature"}]'