Spec Registry
Help your agents use open-source better. Learn more.
Find usage specs for your project’s dependencies
- Author
- tessl
- Last updated
- Spec files
pypi-fastmcp
Describes: pypi/fastmcp
- Description
- The fast, Pythonic way to build MCP servers and clients with minimal boilerplate code.
- Author
- tessl
- Last updated
context.md docs/
1# Context and Dependencies23Execution context providing capabilities like logging, LLM sampling, HTTP requests, and resource access to tools/resources/prompts. The Context system enables FastMCP components to interact with the broader MCP ecosystem and client capabilities.45## Capabilities67### Context Class89Main context class providing execution capabilities for tools, resources, and prompts.1011```python { .api }12class Context:13async def info(self, message: str) -> None:14"""15Log an info message to the client.1617Parameters:18- message: Info message to log19"""2021async def error(self, message: str) -> None:22"""23Log an error message to the client.2425Parameters:26- message: Error message to log27"""2829async def debug(self, message: str) -> None:30"""31Log a debug message to the client.3233Parameters:34- message: Debug message to log35"""3637async def warning(self, message: str) -> None:38"""39Log a warning message to the client.4041Parameters:42- message: Warning message to log43"""44```4546### LLM Sampling4748Request LLM completions from the connected client.4950```python { .api }51async def sample(52self,53messages: list[dict],54params: dict | None = None55) -> SamplingResult:56"""57Request LLM completion from the client.5859Parameters:60- messages: List of message objects for the LLM61- params: Optional sampling parameters (temperature, max_tokens, etc.)6263Returns:64Sampling result with generated text and metadata65"""66```6768### Resource Access6970Read resources from the server within tool/resource/prompt execution.7172```python { .api }73async def read_resource(self, uri: str) -> ResourceResult:74"""75Read a resource from the server.7677Parameters:78- uri: Resource URI to read7980Returns:81Resource content and metadata82"""83```8485### HTTP Requests8687Make HTTP requests to external services with authentication and headers.8889```python { .api }90async def http_request(91self,92method: str,93url: str,94headers: dict | None = None,95data: Any | None = None,96json: dict | None = None,97params: dict | None = None,98timeout: float = 30.099) -> HttpResponse:100"""101Make HTTP request to external service.102103Parameters:104- method: HTTP method (GET, POST, PUT, DELETE, etc.)105- url: Target URL106- headers: Optional request headers107- data: Request body as bytes/string108- json: Request body as JSON object109- params: URL query parameters110- timeout: Request timeout in seconds111112Returns:113HTTP response with status, headers, and content114"""115```116117### Progress Reporting118119Report progress to the client for long-running operations.120121```python { .api }122async def report_progress(123self,124progress: int,125total: int | None = None126) -> None:127"""128Report progress to the client.129130Parameters:131- progress: Current progress value132- total: Total progress value (optional)133"""134```135136### Dependency Injection Functions137138Helper functions for accessing context and request information within components.139140```python { .api }141def get_context() -> Context:142"""143Get the current execution context.144145Returns:146Current Context instance147"""148149def get_http_request() -> HttpRequest:150"""151Get the current HTTP request object (for HTTP transport).152153Returns:154Current HTTP request155"""156157def get_http_headers() -> dict[str, str]:158"""159Get the current HTTP request headers (for HTTP transport).160161Returns:162Dictionary of HTTP headers163"""164165def get_access_token() -> AccessToken | None:166"""167Get the current access token (if authenticated).168169Returns:170Access token or None if not authenticated171"""172```173174### Access Token175176Access token representation for authenticated requests.177178```python { .api }179class AccessToken:180token: str181token_type: str = "bearer"182expires_at: datetime | None = None183scope: list[str] | None = None184```185186## Usage Examples187188### Basic Context Usage189190```python191from fastmcp import FastMCP, Context192193mcp = FastMCP("Context Demo Server")194195@mcp.tool196async def analyze_data(data: str, ctx: Context) -> str:197"""Analyze data with context logging and progress."""198await ctx.info("Starting data analysis")199200# Report initial progress201await ctx.report_progress(0, 100)202203# Simulate processing steps204steps = ["validation", "parsing", "analysis", "formatting"]205206for i, step in enumerate(steps):207await ctx.info(f"Performing {step}")208209# Simulate work210import asyncio211await asyncio.sleep(0.1)212213# Report progress214progress = int((i + 1) / len(steps) * 100)215await ctx.report_progress(progress, 100)216217await ctx.info("Data analysis completed")218return f"Analysis complete: {len(data)} characters processed"219220@mcp.tool221async def safe_operation(input_data: str, ctx: Context) -> str:222"""Perform operation with error handling and logging."""223try:224await ctx.info("Starting safe operation")225226if not input_data:227await ctx.warning("Empty input data provided")228return "No data to process"229230# Process data231result = input_data.upper().strip()232await ctx.info(f"Processed {len(input_data)} characters")233234return result235236except Exception as e:237await ctx.error(f"Operation failed: {str(e)}")238raise239```240241### LLM Sampling with Context242243```python244from fastmcp import FastMCP, Context245246mcp = FastMCP("LLM Integration Server")247248@mcp.tool249async def intelligent_summary(250text: str,251max_words: int = 100,252ctx: Context = None253) -> str:254"""Generate intelligent summary using client's LLM."""255await ctx.info(f"Generating summary of {len(text)} character text")256257# Prepare messages for LLM258messages = [259{260"role": "system",261"content": f"You are a professional summarizer. Create concise summaries in exactly {max_words} words or less."262},263{264"role": "user",265"content": f"Please summarize the following text:\n\n{text}"266}267]268269# Request completion from client's LLM270result = await ctx.sample(271messages=messages,272params={273"temperature": 0.3,274"max_tokens": max_words * 2 # Buffer for token estimation275}276)277278await ctx.info("Summary generated successfully")279return result.text280281@mcp.tool282async def code_explanation(283code: str,284language: str,285ctx: Context286) -> str:287"""Explain code using LLM sampling."""288await ctx.info(f"Explaining {language} code")289290messages = [291{292"role": "system",293"content": f"You are a programming expert. Explain {language} code in clear, simple terms."294},295{296"role": "user",297"content": f"Explain this {language} code:\n\n```{language}\n{code}\n```"298}299]300301explanation = await ctx.sample(messages)302await ctx.info("Code explanation generated")303304return explanation.text305306@mcp.tool307async def creative_content(308prompt: str,309style: str = "professional",310ctx: Context = None311) -> str:312"""Generate creative content with LLM."""313await ctx.info(f"Generating {style} content")314315messages = [316{317"role": "system",318"content": f"You are a {style} content creator. Write engaging, high-quality content."319},320{321"role": "user",322"content": prompt323}324]325326# Use sampling parameters for creativity327params = {328"temperature": 0.8 if style == "creative" else 0.5,329"max_tokens": 1000330}331332content = await ctx.sample(messages, params)333await ctx.info("Content generated successfully")334335return content.text336```337338### HTTP Requests with Context339340```python341from fastmcp import FastMCP, Context342import json343344mcp = FastMCP("API Integration Server")345346@mcp.tool347async def fetch_weather(city: str, ctx: Context) -> dict:348"""Fetch weather data from external API."""349await ctx.info(f"Fetching weather for {city}")350351# Make HTTP request to weather API352response = await ctx.http_request(353method="GET",354url="https://api.weather.com/v1/current",355params={"city": city, "units": "metric"},356headers={357"Authorization": "Bearer weather-api-key",358"User-Agent": "FastMCP-Weather/1.0"359},360timeout=10.0361)362363if response.status_code == 200:364weather_data = response.json()365await ctx.info("Weather data retrieved successfully")366367return {368"city": city,369"temperature": weather_data.get("temp"),370"condition": weather_data.get("condition"),371"humidity": weather_data.get("humidity"),372"source": "weather.com"373}374else:375await ctx.error(f"Weather API error: {response.status_code}")376return {"error": "Failed to fetch weather data"}377378@mcp.tool379async def post_data(380endpoint: str,381data: dict,382ctx: Context383) -> dict:384"""Post data to external endpoint."""385await ctx.info(f"Posting data to {endpoint}")386387response = await ctx.http_request(388method="POST",389url=endpoint,390json=data,391headers={392"Content-Type": "application/json",393"Authorization": "Bearer api-token"394}395)396397if response.status_code in [200, 201]:398await ctx.info("Data posted successfully")399return {400"success": True,401"response": response.json(),402"status_code": response.status_code403}404else:405await ctx.error(f"POST failed: {response.status_code}")406return {407"success": False,408"error": response.text,409"status_code": response.status_code410}411412@mcp.tool413async def aggregate_apis(414endpoints: list[str],415ctx: Context416) -> dict:417"""Aggregate data from multiple API endpoints."""418await ctx.info(f"Aggregating data from {len(endpoints)} endpoints")419420results = {}421total_endpoints = len(endpoints)422423for i, endpoint in enumerate(endpoints):424await ctx.info(f"Fetching from endpoint {i+1}/{total_endpoints}")425await ctx.report_progress(i, total_endpoints)426427try:428response = await ctx.http_request("GET", endpoint, timeout=5.0)429430if response.status_code == 200:431results[endpoint] = {432"success": True,433"data": response.json()434}435else:436results[endpoint] = {437"success": False,438"error": f"HTTP {response.status_code}"439}440441except Exception as e:442await ctx.warning(f"Failed to fetch from {endpoint}: {str(e)}")443results[endpoint] = {444"success": False,445"error": str(e)446}447448await ctx.report_progress(total_endpoints, total_endpoints)449await ctx.info("API aggregation completed")450451# Summary statistics452successful = sum(1 for r in results.values() if r["success"])453454return {455"summary": {456"total_endpoints": total_endpoints,457"successful": successful,458"failed": total_endpoints - successful459},460"results": results461}462```463464### Resource Access with Context465466```python467from fastmcp import FastMCP, Context468469mcp = FastMCP("Resource Integration Server")470471@mcp.tool472async def process_config(setting_name: str, ctx: Context) -> dict:473"""Process configuration using resource access."""474await ctx.info(f"Processing configuration: {setting_name}")475476# Read configuration resource477config_resource = await ctx.read_resource("config://settings")478config_data = json.loads(config_resource.content)479480if setting_name not in config_data:481await ctx.warning(f"Setting '{setting_name}' not found in configuration")482return {"error": f"Setting '{setting_name}' not found"}483484setting_value = config_data[setting_name]485await ctx.info(f"Retrieved setting: {setting_name} = {setting_value}")486487return {488"setting": setting_name,489"value": setting_value,490"type": type(setting_value).__name__491}492493@mcp.tool494async def compile_report(report_type: str, ctx: Context) -> str:495"""Compile report using multiple resources."""496await ctx.info(f"Compiling {report_type} report")497498# Read multiple resources499resources_to_read = [500"data://users/summary",501"data://orders/recent",502"config://report_settings"503]504505report_data = {}506507for i, resource_uri in enumerate(resources_to_read):508await ctx.info(f"Reading resource: {resource_uri}")509await ctx.report_progress(i, len(resources_to_read))510511try:512resource = await ctx.read_resource(resource_uri)513report_data[resource_uri] = json.loads(resource.content)514except Exception as e:515await ctx.warning(f"Failed to read {resource_uri}: {str(e)}")516report_data[resource_uri] = {"error": str(e)}517518await ctx.report_progress(len(resources_to_read), len(resources_to_read))519520# Compile report521report = f"# {report_type.title()} Report\n\n"522523for uri, data in report_data.items():524if "error" in data:525report += f"## {uri}\nError: {data['error']}\n\n"526else:527report += f"## {uri}\n{json.dumps(data, indent=2)}\n\n"528529await ctx.info("Report compilation completed")530return report531```532533### Authentication and Dependency Access534535```python536from fastmcp import FastMCP, Context537from fastmcp.server.dependencies import get_access_token, get_http_headers538539mcp = FastMCP("Secure Server")540541@mcp.tool542async def secure_operation(data: str, ctx: Context) -> dict:543"""Perform secure operation with authentication info."""544await ctx.info("Starting secure operation")545546# Get access token547token = get_access_token()548if not token:549await ctx.error("No access token available")550return {"error": "Authentication required"}551552await ctx.info(f"Authenticated with token type: {token.token_type}")553554# Get HTTP headers if available555try:556headers = get_http_headers()557user_agent = headers.get("user-agent", "unknown")558await ctx.info(f"Request from: {user_agent}")559except:560await ctx.debug("No HTTP headers available (not HTTP transport)")561562# Process data securely563result = {564"processed_data": data.upper(),565"user_info": {566"token_type": token.token_type,567"has_scope": bool(token.scope),568"expires_at": token.expires_at.isoformat() if token.expires_at else None569},570"timestamp": "2024-01-01T00:00:00Z"571}572573await ctx.info("Secure operation completed")574return result575576@mcp.tool577async def user_specific_action(action: str, ctx: Context) -> str:578"""Perform action based on user authentication."""579token = get_access_token()580581if not token:582await ctx.error("Authentication required")583return "Error: Please authenticate to perform this action"584585# Check token scopes586required_scope = f"{action}_access"587if token.scope and required_scope not in token.scope:588await ctx.warning(f"Insufficient permissions for action: {action}")589return f"Error: Missing required scope '{required_scope}'"590591await ctx.info(f"Performing {action} for authenticated user")592593# Perform the action594return f"Successfully performed {action} with proper authentication"595```596597## Result Types598599```python { .api }600class SamplingResult:601"""Result from LLM sampling request."""602text: str603finish_reason: str | None604usage: dict | None605606class HttpResponse:607"""Result from HTTP request."""608status_code: int609headers: dict[str, str]610text: str611content: bytes612613def json(self) -> dict:614"""Parse response as JSON."""615```