Files
wehub-resource-sync 60e0ffc959
Upgrade checks / Notify on failure (push) Has been cancelled
Upgrade checks / Close issue on success (push) Has been cancelled
Schema Crash Test / Real-world schema crash test (232K schemas) (push) Has been cancelled
Run static analysis / static_analysis (push) Has been cancelled
Tests / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Tests / Tests with lowest-direct dependencies (push) Has been cancelled
Tests / MCP conformance tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
Tests / Package install smoke (push) Has been cancelled
Upgrade checks / Static analysis (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Upgrade checks / Integration tests (push) Has been cancelled
Update MCPServerConfig Schema / update-config-schema (push) Has been cancelled
Update SDK Documentation / update-sdk-docs (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:59 +08:00

126 lines
4.0 KiB
Python

# /// script
# dependencies = ["anthropic", "fastmcp", "rich"]
# ///
"""
Sampling with Tools
Demonstrates giving an LLM tools to use during sampling. The LLM can call
helper functions to gather information before responding.
Run:
uv run examples/sampling/tool_use.py
"""
import asyncio
import random
from datetime import datetime
from pydantic import BaseModel, Field
from rich.console import Console
from rich.panel import Panel
from fastmcp import Client, Context, FastMCP
from fastmcp.client.sampling import SamplingMessage, SamplingParams
from fastmcp.client.sampling.handlers.anthropic import AnthropicSamplingHandler
console = Console()
class LoggingAnthropicHandler(AnthropicSamplingHandler):
async def __call__(
self, messages: list[SamplingMessage], params: SamplingParams, context
): # type: ignore[override]
console.print(" [bold blue]SAMPLING[/] Calling Claude API...")
result = await super().__call__(messages, params, context)
console.print(" [bold blue]SAMPLING[/] Response received")
return result
# Define tools available to the LLM during sampling
def add(a: float, b: float) -> str:
"""Add two numbers together."""
result = a + b
console.print(f" [bold magenta]TOOL[/] add({a}, {b}) = {result}")
return str(result)
def multiply(a: float, b: float) -> str:
"""Multiply two numbers together."""
result = a * b
console.print(f" [bold magenta]TOOL[/] multiply({a}, {b}) = {result}")
return str(result)
def get_current_time() -> str:
"""Get the current date and time."""
console.print(" [bold magenta]TOOL[/] get_current_time()")
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def roll_dice(sides: int = 6) -> str:
"""Roll a die with the specified number of sides."""
result = random.randint(1, sides)
console.print(f" [bold magenta]TOOL[/] roll_dice({sides}) = {result}")
return str(result)
# Structured output for the response
class AssistantResponse(BaseModel):
answer: str = Field(description="The answer to the user's question")
tools_used: list[str] = Field(description="List of tools that were used")
reasoning: str = Field(
description="Brief explanation of how the answer was determined"
)
# Create the MCP server
mcp = FastMCP("Smart Assistant")
@mcp.tool
async def ask_assistant(question: str, ctx: Context) -> dict:
"""Ask the assistant a question. It can use tools to help answer."""
console.print(" [bold cyan]SERVER[/] Processing question...")
result = await ctx.sample(
messages=question,
system_prompt="You are a helpful assistant with access to tools. Use them when needed to answer questions accurately.",
tools=[add, multiply, get_current_time, roll_dice],
result_type=AssistantResponse,
)
console.print(" [bold cyan]SERVER[/] Response ready")
return result.result.model_dump() # type: ignore[attr-defined]
async def main():
console.print(Panel.fit("[bold]MCP Sampling Flow Demo[/]", subtitle="tool_use.py"))
console.print()
handler = LoggingAnthropicHandler(default_model="claude-sonnet-4-5")
async with Client(mcp, sampling_handler=handler) as client:
questions = [
"What is 15 times 7, plus 23?",
"Roll a 20-sided dice for me",
"What time is it right now?",
]
for question in questions:
console.print(f"[bold green]CLIENT[/] Question: {question}")
console.print()
result = await client.call_tool("ask_assistant", {"question": question})
data = result.data
console.print(f"[bold green]CLIENT[/] Answer: {data['answer']}") # type: ignore[index]
console.print(
f" Tools used: {', '.join(data['tools_used']) or 'none'}"
) # type: ignore[index]
console.print(f" Reasoning: {data['reasoning']}") # type: ignore[index]
console.print()
if __name__ == "__main__":
asyncio.run(main())