Skip to content

Commit fb9e22e

Browse files
Merge pull request #14 from planetlabs/steve/geojson-types
simplify geom inputs for tools
2 parents d53c994 + a9e5a12 commit fb9e22e

File tree

2 files changed

+49
-16
lines changed

2 files changed

+49
-16
lines changed

src/planet_mcp/models.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from typing import Any
2+
from typing_extensions import TypedDict
3+
4+
5+
class Geometry(TypedDict):
6+
type: str
7+
coordinates: Any
8+
content: str | None

src/planet_mcp/servers/sdk.py

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import functools
22
import inspect
3+
from types import NoneType
4+
import typing
35

6+
from planet_mcp import models
47
from planet_mcp.clients import session
58
from . import descriptions
69
from fastmcp import FastMCP
710
import planet
8-
from typing import Union, Optional
9-
10-
from pydantic import PydanticSchemaGenerationError
11+
from typing import Union
1112

1213

1314
# tools we don't want enabled at all.
@@ -30,6 +31,19 @@
3031
"subscriptions_update_subscription",
3132
}
3233

34+
# tools with signatures we want to simplify for LLM usage
35+
TOOL_SIG_OVERRIDE = {
36+
"features_add_items",
37+
"data_get_item_coverage",
38+
"data_search",
39+
"mosaics_download_quad",
40+
"mosaics_download_quads",
41+
"mosaics_get_quad",
42+
"mosaics_list_quads",
43+
"mosaics_list_series_mosaics",
44+
"mosaics_summarize_quads",
45+
}
46+
3347
SDK_CLIENTS = [
3448
(planet.FeaturesClient, "features"),
3549
(planet.DataClient, "data"),
@@ -85,15 +99,12 @@ def make_tools(mcp: FastMCP, client_class: type, prefix: str):
8599
if tag in full_name:
86100
opts["tags"].add(tag)
87101

88-
try:
89-
mcp.tool(func, name=full_name, **opts)
90-
except PydanticSchemaGenerationError:
91-
# there's a few functions we need to modify again because of custom types.
92-
modified_func = _create_param_modified_wrapper(func)
93-
try:
94-
mcp.tool(modified_func, name=full_name, **opts)
95-
except Exception as e:
96-
print("Unable to add tool", full_name, e)
102+
# some tools have function signatures that need to be
103+
# modified/simplified.
104+
if full_name in TOOL_SIG_OVERRIDE:
105+
func = _create_param_modified_wrapper(func)
106+
107+
mcp.tool(func, name=full_name, **opts)
97108

98109

99110
def _async_get_wrapper(f, prefix):
@@ -120,9 +131,14 @@ async def wrapper(*args, **kwargs):
120131

121132
def _create_param_modified_wrapper(original_func):
122133
"""
123-
Some functions that accept special types (typing.Protocol) fail during
124-
FastMCP tool registration. This wrapper modifies the function's signature,
125-
replacing the type hints with simple types that FastMCP can handle.
134+
Create a wrapper function with a modified signature using types that
135+
are compatible with FastMCP and/or easier for LLMs to work with.
136+
137+
* FastMCP tool registration doesn't support Protocol types.
138+
* the Planet SDK is flexible with geometry inputs (accepting either feature ref
139+
strings, geojson dicts or shapely-like geometries), but for LLM tool usage
140+
we generally want geojson as an object/dict. Our tests have shown better
141+
and more consistent results when tool inputs use dicts only.
126142
"""
127143

128144
@functools.wraps(original_func)
@@ -139,7 +155,16 @@ async def wrapper(*args, **kwargs):
139155
if param_name in ("feature", "quad", "mosaic", "series"):
140156
wrapper.__annotations__[param_name] = dict
141157
elif param_name == "geometry" and "planet.models" in str(param.annotation):
142-
wrapper.__annotations__[param_name] = Optional[Union[dict, str]] | None
158+
# llms should always submit geometry inputs as a geojson geometry
159+
hint = models.Geometry
160+
161+
# add None if originally used (NoneType will be an arg
162+
# within a Union type)
163+
if typing.get_origin(
164+
param.annotation
165+
) is Union and NoneType in typing.get_args(param.annotation):
166+
hint = hint | None
167+
wrapper.__annotations__[param_name] = hint
143168

144169
except Exception as e:
145170
print(f"Error modifying signature: {e}")

0 commit comments

Comments
 (0)