MCP in 2026

The MCP specification has evolved significantly since FastMCP was first built. This covers the spec changes that affect how you build and deploy MCP servers.

Governance Change

MCP was donated to the Agentic AI Foundation (AAIF), a Linux Foundation directed fund, in December 2025. Co-founded by Anthropic, Block, and OpenAI. Spec changes now go through an open RFC process with multi-vendor consensus.

This matters for FastMCP because:

  • The spec is now vendor-neutral, reducing risk of Anthropic-specific drift
  • New features are designed for cross-platform compatibility
  • Enterprise adoption is accelerating, increasing demand for production-ready servers

Streamable HTTP Transport

The original remote transport was SSE (Server-Sent Events). The new standard is streamable HTTP:

from fastmcp import FastMCP

mcp = FastMCP("MyServer")

# New recommended transport for remote servers
mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

Why the Change

SSEStreamable HTTP
ConnectionLong-lived, statefulRequest-response with optional streaming
Load balancingDifficult (sticky sessions required)Standard HTTP load balancers
FirewallsOften blocked (long-lived connections)Standard HTTPS, universally allowed
ResumabilityManual reconnection logicBuilt into the protocol
Server complexityManage connection stateStateless by default

Migration

# Before (SSE)
mcp.run(transport="sse", host="0.0.0.0", port=8000)

# After (streamable HTTP)
mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

For local development, stdio remains the default and recommended transport.

Tasks Primitive

Long-running operations that don’t fit the request-response model:

@mcp.tool
async def process_dataset(path: str, context: Context) -> str:
    """Process a large dataset. May take several minutes."""
    task = await context.create_task(
        name="process-dataset",
        timeout=3600,
        retry={"max_attempts": 3, "backoff_ms": 1000},
    )

    for i, chunk in enumerate(read_chunks(path)):
        await task.report_progress(i / total_chunks)
        process(chunk)

    await task.complete()
    return f"Processed {total_chunks} chunks"

Tasks support:

  • Progress reporting - clients show progress bars or status updates
  • Cancellation - clients can cancel running tasks
  • Retry semantics - automatic retry with exponential backoff
  • Expiry policies - tasks auto-cancel after a timeout
  • Status polling - clients check task state without blocking

MCP Apps

Tools can return interactive UI components instead of plain text:

@mcp.tool
def show_metrics(service: str) -> dict:
    """Show service metrics in an interactive dashboard."""
    data = fetch_metrics(service)
    return {
        "type": "app",
        "component": "data-table",
        "props": {
            "columns": ["Metric", "Value", "Trend"],
            "rows": data,
            "sortable": True,
            "filterable": True,
        }
    }

The client renders the component natively. Currently supported component types vary by client, but common ones include data tables, charts, and forms.

Elicitation

Servers can request structured input from users during tool execution:

@mcp.tool
async def deploy(service: str, context: Context) -> str:
    """Deploy a service to the target environment."""
    env = await context.elicit(
        message="Which environment?",
        type="select",
        options=["staging", "production"],
    )

    if env == "production":
        confirmed = await context.elicit(
            message=f"Confirm production deployment of {service}?",
            type="confirm",
        )
        if not confirmed:
            return "Deployment cancelled"

    return await run_deployment(service, env)

Supported elicitation types:

  • text - free-form text input
  • select - single choice from options
  • multi-select - multiple choices
  • confirm - yes/no confirmation

Enterprise Features

Audit Trails

mcp = FastMCP("MyServer", audit=True)

# Every tool call is logged with:
# - Timestamp, caller identity
# - Input parameters, output summary
# - Duration, success/failure

SSO Integration

from fastmcp.auth import OAuthProvider

mcp = FastMCP("MyServer", auth=OAuthProvider(
    provider="okta",
    scopes=["read:data", "write:data"],
))

Gateway Compatibility

FastMCP servers work behind MCP gateways that provide rate limiting, access control, and usage metering at the infrastructure level.

Cross-Reference

For Claude-specific MCP integration patterns (how Claude Code discovers and uses MCP servers, how skills orchestrate MCP tools), see claude/deep-dives/mcp-ecosystem.md.