Executando seu servidor
Tradução automática
Esta página foi traduzida automaticamente a partir da documentação em inglês, e a página em inglês é a versão de referência. Se algo parecer errado, Traduções explica como avisar.
mcp.run() inicia o servidor.
A única decisão que você toma é o transporte: como os bytes entre seu servidor e o cliente realmente trafegam.
Escolha um transporte
| Transporte | O que é | Quando |
|---|---|---|
stdio |
O host inicia seu arquivo como um subprocesso e conversa pelo stdin e stdout dele. | Servidores locais. O padrão. |
streamable-http |
Um servidor HTTP de verdade, escutando em uma porta. | Tudo o que você faz deploy. |
sse |
O transporte HTTP antigo. | Nunca. |
Warning
O SSE foi substituído pelo Streamable HTTP na revisão 2025-03-26 do protocolo.
mcp.run(transport="sse") ainda funciona, com suas próprias opções sse_path= e message_path=,
mas existe apenas para clientes que ainda não migraram. Não construa nada novo em cima dele.
mcp.run()
from mcp.server import MCPServer
mcp = MCPServer("Bookshop")
@mcp.tool()
def search_books(query: str) -> str:
"""Search the catalog by title or author."""
return f"Found 3 books matching {query!r}."
if __name__ == "__main__":
mcp.run()
run()é síncrono. Ele bloqueia durante toda a vida do servidor.- Sem argumentos, o transporte é
stdio. - Ele fica sob
if __name__ == "__main__":porque tudo o que carrega seu servidor (mcp dev,mcp run,mcp install, seus testes) importa este arquivo. A guarda impede que um import vire um servidor em execução.
stdio
Não há nada para configurar. O host inicia seu arquivo como processo filho, escreve requisições no stdin dele e lê respostas do stdout.
Execute você mesmo e veja a consequência:
python server.py
Nada é impresso, e ele não retorna. Está esperando no stdin que um host fale primeiro.
Isso também significa que o stdout é o canal de comunicação. Enquanto serve, o SDK move esse canal para um descritor privado e desvia para o stderr a saída que é descarregada (flushed) no stdout (um subprocesso escrevendo no stdout herdado, um print() com flush), onde ela não pode corromper o fluxo. A saída descarregada no stdout antes de o servidor começar a servir (um script wrapper fazendo echo, um print sem buffer em tempo de import) ainda cai no canal, assim como um print() que fica no buffer até o interpretador esvaziá-lo na saída. Para a saída que você realmente quer, o módulo logging é a ferramenta certa: o handler dele descarrega cada registro no stderr assim que acontece. Essa história está em Logging.
Experimente
uv run mcp dev server.py
O Inspector faz exatamente o que um host de verdade faz: inicia server.py como subprocesso e se conecta a ele via stdio.
Você nunca informou uma porta. Não existe nenhuma.
Streamable HTTP
Para colocar o mesmo servidor em uma porta, nomeie o transporte (e suas opções) em run():
from mcp.server import MCPServer
mcp = MCPServer("Bookshop")
@mcp.tool()
def search_books(query: str) -> str:
"""Search the catalog by title or author."""
return f"Found 3 books matching {query!r}."
if __name__ == "__main__":
mcp.run(transport="streamable-http", port=3001)
Essa única linha monta um app Starlette e o serve com uvicorn. Os clientes se conectam em http://127.0.0.1:3001/mcp.
Cada transporte tem seus próprios argumentos nomeados, todos em run():
host/port: onde escutar. Padrões127.0.0.1e8000.streamable_http_path: onde fica o endpoint MCP. Padrão/mcp.json_response=True: responde a cada POST com um único corpo JSON em vez de um fluxo SSE. Esse corpo tem espaço para a resposta e nada mais, então uma ferramenta que chama o cliente de volta no meio da requisição (ctx.elicit(), amostragem (sampling)) lançaNoBackChannelErrornesse trecho, e as notificações ligadas à chamada em andamento (progresso dectx.report_progress(), mensagens de log por chamada) são descartadas; o fluxoGETavulso continua transportando as que não têm relação.stateless_http=True: um transporte novo por requisição, sem rastreamento de sessão.max_request_body_size: maior corpo de POST aceito, em bytes. O padrão é 4 MiB; requisições maiores recebem HTTP 413 antes do parsing ou da criação da sessão. Aumente apenas quando mensagens MCP legítimas ultrapassarem esse tamanho.event_store,retry_interval,transport_security: retomada e proteção contra DNS rebinding. Podem esperar até você fazer o deploy em algum lugar que não seja o localhost; Deploy e escala cobretransport_security.
Warning
As opções de transporte vão para run(), não para MCPServer(...). O construtor descreve o que
seu servidor é: nome, versão, instruções. run() descreve como ele é servido. Inverta isso
e o Python responde antes mesmo de o MCP entrar em cena:
TypeError: MCPServer.__init__() got an unexpected keyword argument 'port'
run() é o caminho curto. No momento em que você precisar de mais (seu servidor montado dentro de um app existente, dois servidores em um só processo, CORS para clientes no navegador), monte o app ASGI você mesmo e entregue a qualquer host ASGI. Isso está em Adicione a um app existente.
Configurações do servidor
Algumas coisas relacionadas à execução não dizem respeito ao transporte. São argumentos do construtor:
from mcp.server import MCPServer
mcp = MCPServer("Bookshop", log_level="DEBUG")
@mcp.tool()
def search_books(query: str) -> str:
"""Search the catalog by title or author."""
return f"Found 3 books matching {query!r}."
if __name__ == "__main__":
mcp.run()
log_level: passado paralogging.basicConfig()no momento em queMCPServer(...)é construído. Isso configura o logger raiz, então define o nível dos seus próprios loggers também, não só os do SDK. Padrão"INFO".debug: repassado ao app Starlette que os transportes HTTP montam. PadrãoFalse.
Ambos vão parar em mcp.settings, que você pode ler de volta em tempo de execução.
O comando mcp
O extra [cli] instala uma pequena ferramenta de linha de comando em torno de tudo isso.
mcp dev executa seu servidor sob o MCP Inspector:
uv run mcp dev server.py
uv run mcp dev server.py --with pandas --with numpy
uv run mcp dev server.py --with-editable .
--with adiciona pacotes ao ambiente que ele monta; --with-editable instala seu próprio pacote nele. Ele precisa de npx no seu PATH: o Inspector é um app Node.js.
mcp run importa o arquivo, encontra o objeto do servidor (um mcp, server ou app no nível do módulo) e chama run() nele:
uv run mcp run server.py
uv run mcp run server.py:bookshop
O sufixo : nomeia o objeto quando ele não se chama mcp, server ou app.
Seu bloco if __name__ == "__main__": nunca executa aqui: o próprio mcp run chama run(), e a única opção que ele repassa é --transport.
mcp install registra o servidor no Claude Desktop, para que o app o inicie por você:
uv run mcp install server.py --name "Bookshop"
uv run mcp install server.py -v API_KEY=abc123 -f .env
-v KEY=VALUE e -f .env gravam variáveis de ambiente nessa entrada. O Claude Desktop inicia seu servidor em um processo próprio. O ambiente do seu shell não está lá.
O Claude Desktop é o único host que mcp install conhece. Todos os outros hosts (Claude Code, Cursor, VS Code) aceitam o mesmo comando de inicialização no próprio arquivo de configuração, e Conecte a um host de verdade tem cada um deles.
mcp version imprime a versão do SDK instalada.
Tip
mcp dev e mcp run só entendem MCPServer. Se você constrói com o Server de baixo nível,
você mesmo o executa. Veja O Server de baixo nível.
Recapitulando
- Um transporte é como os bytes chegam ao seu servidor:
stdiopara um subprocesso local,streamable-httppara uma porta. O SSE foi substituído. mcp.run()escolhe o transporte. Sem argumentos éstdio, e ele bloqueia.- Toda opção de transporte (
host,port,streamable_http_path, ...) é um argumento derun(), nunca deMCPServer(...). - Mantenha
run()sobif __name__ == "__main__":. Tudo o que carrega seu servidor importa o arquivo primeiro. log_level=edebug=são argumentos do construtor; eles vão parar emmcp.settings.mcp devpara o Inspector,mcp runpara executar um arquivo,mcp installpara o Claude Desktop,mcp versionpara a versão.- O transporte nunca muda o que seu servidor é: os três arquivos desta página expõem exatamente a mesma ferramenta.
Quando o próprio run() é o limite (seu servidor dentro de um app que já existe), o caminho é Adicione a um app existente. Um hostname de verdade e mais de um worker é Deploy e escala. E se alguns dos seus clientes ainda estão na versão 2025-11-25 da especificação ou anterior, Servindo clientes legados traz as boas notícias.