Skip to main content
Golf v0.2.0 introduces powerful built-in utilities that enhance your tool development experience.

Overview

Golf utilities provide four core capabilities:
  1. Context Access - Direct access to FastMCP context without manual parameter passing
  2. Elicitation - Interactive user prompting and input collection
  3. Sampling - LLM interactions and text generation with multiple modes
  4. Authentication Integration - Seamless token extraction
All utilities automatically handle context management using Python’s contextvars for thread-safe, async-aware access to FastMCP features.

Context access

Get current context

The get_current_context() function provides direct access to the FastMCP context without requiring explicit context parameter passing.
from golf.utilities import get_current_context

async def context_aware_tool():
    # Get the current FastMCP context
    context = get_current_context()
    
    # Access request information
    request_id = getattr(context, 'request_id', None)
    
    return {
        "request_id": request_id,
        "context_available": True
    }

Context with logging

from golf.utilities import get_current_context

async def logging_tool(message: str):
    context = get_current_context()
    
    # Use context for structured logging
    context.logger.info(f"Processing message: {message}")
    
    return {"status": "logged", "message": message}

Error handling

from golf.utilities import get_current_context

async def safe_context_tool():
    try:
        context = get_current_context()
        return {"context_available": True}
    except RuntimeError as e:
        # Context not available (e.g., called outside MCP tool)
        return {
            "context_available": False, 
            "error": str(e)
        }
    except ImportError as e:
        # FastMCP not available or incompatible version
        return {
            "context_available": False,
            "error": "FastMCP >=2.11.0 required"
        }

Elicitation utilities

Elicitation utilities enable your tools to interact with users, collect additional information, and create dynamic conversational experiences.

Basic elicitation

from golf.utilities import elicit

async def interactive_tool():
    # Simple text prompt
    color = await elicit("What's your favorite color?")
    
    # Use the response in your tool logic
    return {"message": f"Great choice! {color} is a beautiful color."}

Type-safe elicitation

from golf.utilities import elicit
from pydantic import BaseModel

class UserInfo(BaseModel):
    name: str
    email: str
    age: int

async def user_registration_tool():
    # Collect structured data with validation
    user_info = await elicit("Please provide your information:", UserInfo)
    
    return {
        "name": user_info.name,
        "email": user_info.email,
        "age": user_info.age
    }

Confirmation dialogs

from golf.utilities import elicit_confirmation

async def deletion_tool(file_path: str):
    # Ask for confirmation before destructive action
    confirmed = await elicit_confirmation(
        f"Are you sure you want to delete {file_path}?"
    )
    
    if confirmed:
        # Perform deletion
        return {"status": "deleted", "file": file_path}
    else:
        return {"status": "cancelled", "file": file_path}

Advanced elicitation with error handling

from golf.utilities import elicit, elicit_confirmation

async def configuration_tool():
    try:
        # Collect multiple pieces of information
        name = await elicit("What's your name?")
        email = await elicit("What's your email address?")
        
        # Confirm before saving
        confirmed = await elicit_confirmation(
            f"Save configuration for {name} ({email})?"
        )
        
        if confirmed:
            config = {"name": name, "email": email}
            return {"configuration": config, "saved": True}
        else:
            return {"configuration": None, "saved": False}
            
    except RuntimeError as e:
        # User declined or cancelled
        return {"error": f"Configuration failed: {str(e)}"}

Sampling utilities

Sampling utilities provide direct access to LLM capabilities within your tools, enabling text generation, analysis, and AI-powered processing with multiple modes.

Basic sampling

from golf.utilities import sample

async def explanation_tool(topic: str):
    # Generate an explanation using the default model
    explanation = await sample(f"Explain {topic} in simple terms")
    
    return {"topic": topic, "explanation": explanation}

Structured sampling

The sample_structured() function uses a lower temperature (0.1) for more consistent, formatted outputs.
from golf.utilities import sample_structured

async def entity_extraction_tool(text: str):
    # Use structured sampling for formatted outputs
    entities = await sample_structured(
        f"Extract entities from this text: {text}",
        format_instructions="Return as JSON with keys: persons, organizations, locations"
    )
    
    return {"text": text, "entities": entities}

Context-enhanced sampling

The sample_with_context() function automatically appends context data to prompts.
from golf.utilities import sample_with_context

async def personalized_report_tool(data: str):
    # Sample with automatic context enhancement
    report = await sample_with_context(
        f"Generate a personalized report based on this data: {data}",
        context_data={
            "user_preferences": "detailed analysis",
            "report_format": "executive summary"
        }
    )
    
    return {"data": data, "report": report}

Advanced sampling with parameters

from golf.utilities import sample

async def creative_writing_tool(prompt: str, style: str):
    # Advanced sampling with custom parameters
    story = await sample(
        f"Write a short story in {style} style based on: {prompt}",
        model="gpt-4",
        max_tokens=500,
        temperature=0.8
    )
    
    return {
        "prompt": prompt,
        "style": style,
        "story": story
    }

Sampling error handling

from golf.utilities import sample, sample_structured

async def robust_analysis_tool(text: str):
    try:
        # Attempt structured analysis
        analysis = await sample_structured(
            f"Analyze the sentiment and themes in: {text}",
            format_instructions="Return JSON with sentiment and themes"
        )
        return {"analysis": analysis, "method": "structured"}
        
    except RuntimeError as e:
        # Fall back to basic sampling
        try:
            analysis = await sample(f"Analyze: {text}")
            return {"analysis": analysis, "method": "basic"}
        except RuntimeError:
            return {
                "error": "Analysis failed", 
                "text": text
            }

Authentication integration

Golf utilities seamlessly integrate with the authentication system for secure API forwarding.

Basic token forwarding

from golf.utilities import sample
from golf.auth import get_auth_token

async def api_analysis_tool(data: str):
    # Get authentication token
    auth_token = get_auth_token()
    
    if not auth_token:
        return {"error": "Authentication required"}
    
    # Use token for upstream API call
    import httpx
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "https://api.example.com/analyze",
            headers={"Authorization": f"Bearer {auth_token}"},
            json={"data": data}
        )
        
        # Enhance results with LLM sampling
        summary = await sample(
            f"Summarize this API response: {response.text}"
        )
        
        return {
            "api_response": response.json(),
            "summary": summary
        }

Combined context and auth

from golf.utilities import get_current_context, sample
from golf.auth import get_auth_token

async def secure_personalized_tool(request: str):
    # Get both context and auth
    context = get_current_context()
    auth_token = get_auth_token()
    
    if not auth_token:
        return {"error": "Authentication required"}
    
    # Log request with context
    context.logger.info(f"Processing request: {request}")
    
    # Generate personalized response
    response = await sample(
        f"Respond to this request personally: {request}",
        context_data={
            "user_authenticated": True,
            "request_id": getattr(context, 'request_id', None)
        }
    )
    
    return {
        "request": request,
        "response": response,
        "authenticated": True
    }

Error handling best practices

Comprehensive error handling

from golf.utilities import get_current_context, sample, elicit
from golf.auth import get_auth_token

async def production_ready_tool(task: str):
    try:
        # Verify context availability
        context = get_current_context()
        
        # Check authentication
        auth_token = get_auth_token()
        if not auth_token:
            confirmation = await elicit_confirmation(
                "No authentication found. Continue with limited functionality?"
            )
            if not confirmation:
                return {"error": "Authentication required"}
        
        # Perform main task
        result = await sample(f"Complete this task: {task}")
        
        # Log success
        context.logger.info(f"Task completed: {task}")
        
        return {
            "task": task,
            "result": result,
            "authenticated": bool(auth_token)
        }
        
    except ImportError:
        return {
            "error": "FastMCP >=2.11.0 required",
            "task": task
        }
    except RuntimeError as e:
        if "Context" in str(e):
            return {
                "error": "Must be called from MCP tool context",
                "task": task
            }
        elif "declined" in str(e):
            return {
                "error": "User declined operation",
                "task": task
            }
        else:
            return {
                "error": f"Operation failed: {str(e)}",
                "task": task
            }