To use AgentPay’s consume() or validate_api_key() methods, your MCP server first needs to extract the User API Key sent by the client. By convention, AgentPay User API Keys are sent in the HTTP header.

Standard Header

The standard HTTP header for transmitting the AgentPay User API Key is: X-AGENTPAY-API-KEY Clients (like Cursor or Claude) should be configured to send the User API Key in this header when using remote MCP Servers.

Extraction in Python Web Frameworks

How you access this header depends on the web framework you are using to run your MCP server. We recommend using Starlette as your web framework, as it is simple, lightweight, and compatible with the official FastMCP framework. Example (Starlette with FastMCP):
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from mcp.server.fastmcp import FastMCP
from contextvars import ContextVar
from agentpay_sdk import AgentPayClient

# Initialize AgentPay client
agentpay_client = AgentPayClient(service_token="YOUR_SERVICE_TOKEN")

# Define context variable for API key
api_key_context: ContextVar[str | None] = ContextVar("api_key_context", default=None)

# Create FastMCP instance
mcp = FastMCP("your-server-name")

# Middleware to extract and validate API Key
class ApiKeyMiddleware(BaseHTTPMiddleware):
    async def dispatch(
        self, request: Request, call_next: RequestResponseEndpoint
    ) -> Response:
        api_key = request.headers.get("X-AGENTPAY-API-KEY")

        # Validate User API key if present (recommended placement)
        if api_key:
            try:
                is_valid = agentpay_client.validate_api_key(api_key=api_key)
                if not is_valid:
                    return JSONResponse(
                        {"error": "Unauthorized", "message": "Invalid API Key"},
                        status_code=401
                    )
            except Exception as e:
                return JSONResponse(
                    {"error": "Internal Server Error", "message": "API Key validation failed"},
                    status_code=500
                )

        # Set context var for use in route handlers
        token = api_key_context.set(api_key)
        try:
            response = await call_next(request)
        finally:
            api_key_context.reset(token)
        return response

# Example MCP tool using FastMCP decorator
@mcp.tool()
async def example_tool(param1: str) -> str:
    """Example tool that demonstrates API key usage.
    
    Args:
        param1: Example parameter
    """
    # Get API key from context
    user_api_key = api_key_context.get()
    
    if user_api_key is None:
        return "Error: API Key missing"
    
    # Now you have the user_api_key (which was validated earlier by our middleware), you can use it to consume usage.
    # For example:
    # COST_CENTS = 10
    # usage_id = str(uuid.uuid4())
    # consume_result = agentpay_client.consume(
    #     api_key=user_api_key,
    #     amount_cents=COST_CENTS,
    #     usage_event_id=usage_id
    # )
    # if not consume_result.success:
    #     return f"Error: {consume_result.error_message}"
    
    return f"Tool executed with parameter: {param1}"

# Create Starlette app with middleware and mount FastMCP
app = Starlette(
    middleware=[
        Middleware(ApiKeyMiddleware)
    ],
    routes=[
        Mount("/", app=mcp.sse_app())
    ]
)

Other Frameworks (e.g. Flask, Django, etc.)

If you’re using other Python web frameworks like Flask or Django (or even a standard library http.server), you’ll need to adapt the above Starlette + FastMCP pattern to work with your framework. Here are conceptual examples showing how to integrate User API Key extraction and validation with your framework’s routing: Example (Conceptual - Flask with FastMCP):
from flask import Flask, request, jsonify
from mcp.server.fastmcp import FastMCP
from contextvars import ContextVar
from agentpay_sdk import AgentPayClient

app = Flask(__name__)
agentpay_client = AgentPayClient(service_token="YOUR_SERVICE_TOKEN")
mcp = FastMCP("your-server-name")

# Define context variable for API key
api_key_context: ContextVar[str | None] = ContextVar("api_key_context", default=None)

# Flask middleware equivalent for API key validation
@app.before_request
def validate_api_key():
    user_api_key = request.headers.get("X-AGENTPAY-API-KEY")
    
    if not user_api_key:
        return jsonify({"error": "Unauthorized", "message": "API Key missing"}), 401
    
    try:
        is_valid = agentpay_client.validate_api_key(api_key=user_api_key)
        if not is_valid:
            return jsonify({"error": "Unauthorized", "message": "Invalid API Key"}), 401
    except Exception as e:
        return jsonify({"error": "Internal Server Error", "message": "API Key validation failed"}), 500
    
    # Set API key in context for use in route handlers
    api_key_context.set(user_api_key)

# Example MCP tool using FastMCP decorator
@mcp.tool()
async def example_tool(param1: str) -> str:
    """Example tool that demonstrates API key usage.
    
    Args:
        param1: Example parameter
    """
    user_api_key = api_key_context.get()
    if not user_api_key:
        return "Error: API Key missing"
    
    return f"Tool executed with parameter: {param1}"

# Mount FastMCP SSE endpoint
@app.route("/mcp/sse", methods=["GET"])
def mcp_sse():
    return mcp.sse_app()(request.environ, lambda: None, lambda: None)
Example (Conceptual - Django with FastMCP):
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from mcp.server.fastmcp import FastMCP
from contextvars import ContextVar
from agentpay_sdk import AgentPayClient

agentpay_client = AgentPayClient(service_token="YOUR_SERVICE_TOKEN")
mcp = FastMCP("your-server-name")

# Define context variable for API key
api_key_context: ContextVar[str | None] = ContextVar("api_key_context", default=None)

# Django middleware for API key validation
class ApiKeyMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        user_api_key = request.headers.get("X-Agentpay-Api-Key")
        
        if not user_api_key:
            return JsonResponse(
                {"error": "Unauthorized", "message": "API Key missing"},
                status=401
            )
        
        try:
            is_valid = agentpay_client.validate_api_key(api_key=user_api_key)
            if not is_valid:
                return JsonResponse(
                    {"error": "Unauthorized", "message": "Invalid API Key"},
                    status=401
                )
        except Exception as e:
            return JsonResponse(
                {"error": "Internal Server Error", "message": "API Key validation failed"},
                status=500
            )
        
        # Set API key in context for use in views
        token = api_key_context.set(user_api_key)
        try:
            response = self.get_response(request)
        finally:
            api_key_context.reset(token)
        return response

# Example MCP tool using FastMCP decorator
@mcp.tool()
async def example_tool(param1: str) -> str:
    """Example tool that demonstrates API key usage.
    
    Args:
        param1: Example parameter
    """
    user_api_key = api_key_context.get()
    if not user_api_key:
        return "Error: API Key missing"
    
    return f"Tool executed with parameter: {param1}"

# Mount FastMCP SSE endpoint
@csrf_exempt
def mcp_sse(request):
    return mcp.sse_app()(request.environ, lambda: None, lambda: None)
Consult your specific web framework’s documentation on how specifically to adapt these examples to your particular Server’s needs.

Best Practices

  • Case-Insensitivity: Remember that HTTP header names are generally case-insensitive. While X-AGENTPAY-API-KEY is the standard casing, your extraction logic should ideally handle variations if your framework doesn’t normalize them (most modern ones do).
  • Error Handling: Always check if the API key is present. If not, return an appropriate error response to the client (e.g. an appropriate error string, or HTTP 401 Unauthorized).
  • Security: Do not log the full API keys unless absolutely necessary for debugging and ensure logs are secure. Remember, the User API Key you receive will be specific to usage with your Server.

Next Steps

With the User API Key extracted, you can now effectively use: