FastMCP é um framework Python pra construir servidores (e clientes) do Model Context Protocol. É a camada “de produção” em cima do SDK oficial mcp — cuida de transporte, autenticação, e boilerplate que o protocolo exige, deixando só a lógica de negócio pro desenvolvedor.

O que ele resolve

Um servidor MCP puro (via SDK oficial) exige lidar manualmente com transporte (stdio, SSE, Streamable HTTP), roteamento de tools/resources/prompts, e — se for exposto publicamente — toda a parte de autenticação OAuth 2.1 que o spec do MCP exige (discovery metadata, PKCE, Dynamic Client Registration). FastMCP embrulha tudo isso em decorators e classes de alto nível.

Tools, Resources e Prompts

Os três tipos de primitiva que um servidor MCP expõe, todos declarados via decorator:

from fastmcp import FastMCP
 
mcp = FastMCP(name="Meu Servidor")
 
@mcp.tool
def somar(a: int, b: int) -> int:
    """Soma dois números"""
    return a + b
 
if __name__ == "__main__":
    mcp.run()
  • @mcp.tool — uma ação que o modelo pode chamar (o mais comum).
  • @mcp.resource — dado exposto por URI, tipo um arquivo ou registro.
  • @mcp.prompt — template de prompt reutilizável.

Transportes

mcp.run(transport=...) aceita stdio (padrão, processo local), sse (Server-Sent Events, mais antigo) ou http (Streamable HTTP, o recomendado atualmente para servidores remotos).

Proxy de outro servidor MCP

FastMCP.as_proxy(...) cria um servidor FastMCP que repassa todas as chamadas pra outro servidor MCP existente (local ou remoto), útil pra adicionar uma camada (como auth) na frente de um servidor que já existe:

mcp = FastMCP.as_proxy("http://127.0.0.1:8080/sse", name="Meu Proxy")

Autenticação

É a parte mais elaborada do framework, porque implementa o spec de auth do MCP (baseado em OAuth 2.1 + PKCE obrigatório + discovery via /.well-known/oauth-protected-resource e /.well-known/oauth-authorization-server).

Providers prontos (fastmcp.server.auth.providers.*): GitHub, Google, WorkOS, Auth0, Azure, entre outros. Cada um implementa um TokenVerifier que sabe validar tokens daquele provedor específico.

OAuthProxy — o padrão mais relevante quando o provedor upstream (ex: GitHub) não suporta Dynamic Client Registration (DCR), que o spec do MCP exige dos clientes. O OAuthProxy resolve isso fazendo de conta que é uma authorization server completa pra quem chega (aceita DCR de qualquer cliente MCP), mas por trás sempre usa um único client OAuth fixo (criado manualmente no provedor real) pra falar com ele.

Pontos importantes de como isso funciona:

  • O FastMCP não repassa o token do provedor upstream pro cliente MCP. Ele emite seu próprio JWT, e guarda o token upstream (criptografado) server-side, referenciado por um jti (JWT ID) embutido no JWT emitido.
  • Validação de cada requisição tem duas etapas: (1) verificação criptográfica do JWT próprio (assinatura, expiração), e (2) lookup do jti no storage, pra confirmar que o token upstream referenciado ainda é válido.
  • Isso significa que o OAuthProxy tem estado — não é um esquema puramente stateless. Por padrão o storage é em memória (adequado só pra dev/uso pessoal); produção com múltiplas réplicas precisa de um backend externo (Redis, etc.) via o protocolo AsyncKeyValue.
  • Reiniciar o processo com storage em memória invalida todas as sessões ativas de uma vez — não tem revogação seletiva de um único token sem storage persistente.

Middleware customizado pra regras de autorização além do que os providers prontos cobrem (ex: restringir por usuário específico) — via fastmcp.server.middleware.Middleware, com hooks como on_call_tool.

Contexto de uso

Documentei um setup real usando isso em Setup Obsidian MCP Publico - mcp-proxy e OAuth GitHub — GitHub como provedor upstream via GitHubProvider, restringindo acesso a um único usuário via middleware.

Referências