chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# /// 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())
|
||||
Reference in New Issue
Block a user