Skip to content
Closed
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
5 changes: 4 additions & 1 deletion examples/mcpserver/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@

from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.utilities.types import Image
from mcp.types import ToolAnnotations

# Create server
mcp = MCPServer("Screenshot Demo")


@mcp.tool()
# Both hints differ from the spec defaults, so they tell a client something:
# the tool only reads the local display and never reaches an external system.
@mcp.tool(annotations=ToolAnnotations(read_only_hint=True, open_world_hint=False))
def take_screenshot() -> Image:
"""Take a screenshot of the user's screen and return it as an image. Use
this tool anytime the user wants you to look at something they're doing.
Expand Down
4 changes: 4 additions & 0 deletions examples/mcpserver/text_me.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class SurgeSettings(BaseSettings):
surge_settings = SurgeSettings() # type: ignore


# No ToolAnnotations on purpose. This tool sends a real SMS, and the spec defaults
# (read_only_hint=False, destructive_hint=True, open_world_hint=True) already make a
# client treat it with the most caution. Declaring destructive_hint=False would be
# accurate but would only relax that, so leave the defaults in place.
@mcp.tool(name="textme", description="Send a text message to me")
def text_me(text_content: str) -> str:
"""Send a text message to a phone number via https://surgemsg.com/"""
Expand Down
12 changes: 12 additions & 0 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,15 @@ def test_docs_examples(example: CodeExample, eval_example: EvalExample):
eval_example.format_ruff(example)
else:
eval_example.lint_ruff(example)


@pytest.mark.anyio
async def test_screenshot_declares_tool_annotations():
"""The screenshot example shows annotations that differ from the spec defaults."""
from examples.mcpserver.screenshot import mcp

async with Client(mcp) as client:
(tool,) = (await client.list_tools()).tools
assert tool.annotations is not None
assert tool.annotations.read_only_hint is True
assert tool.annotations.open_world_hint is False
Loading