docs: publish translated docs in twelve languages and the tool that maintains them (#3280)
This commit is contained in:
parent
14aa889992
commit
52ad0a8876
5 changed files with 89737 additions and 54 deletions
144
i18n/pt/pages/get-started/first-steps.md
Normal file
144
i18n/pt/pages/get-started/first-steps.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
---
|
||||
translation:
|
||||
sections: [0d6c05bcbf836bf3, 59a7b14eeefc68c1, 7114d8d6daba203f, e8bbb56a98ba7bc9, 5138010f6159901c, f78da7c7c363d4c6, 220a939cab348686]
|
||||
tool: 1
|
||||
---
|
||||
# Primeiros passos {#first-steps}
|
||||
|
||||
A **[página inicial](../index.md)** anda rápido: escrever um servidor, executá-lo, chamar uma ferramenta.
|
||||
|
||||
Esta página vai com calma, passando pelas três coisas que um servidor pode expor e dando nome a tudo pelo caminho.
|
||||
|
||||
## Host, cliente e servidor {#host-client-and-server}
|
||||
|
||||
Três palavras que você vai ver em todas as páginas daqui em diante:
|
||||
|
||||
* Um **host** é a aplicação de LLM: o Claude, uma IDE, um runtime de agentes. É com ele que o usuário conversa.
|
||||
* Um **cliente** vive dentro do host e fala MCP. O host executa um cliente para cada servidor ao qual está conectado.
|
||||
* Um **servidor** é o que você constrói com este SDK. Ele expõe coisas aos clientes. Nunca fala diretamente com o modelo.
|
||||
|
||||
Você escreve o servidor. Os hosts são produto de terceiros. O SDK também traz um `Client`. Você vai usá-lo para testar seus servidores, e ele aparece mais adiante nesta página.
|
||||
|
||||
## As três primitivas {#the-three-primitives}
|
||||
|
||||
Um servidor expõe exatamente três tipos de coisa. O que as distingue é **quem decide usá-las**:
|
||||
|
||||
| Primitiva | Quem controla | O que é | Exemplo |
|
||||
|-----------------|-----------------|-----------------------------------------------------------------|----------------------------------------------------|
|
||||
| **Ferramentas** | O modelo | Uma função que o modelo chama para executar uma ação | Uma chamada de API, uma escrita no banco de dados |
|
||||
| **Recursos** | A aplicação | Dados que o host carrega no contexto do modelo | O conteúdo de um arquivo, uma resposta de API |
|
||||
| **Prompts** | O usuário | Um template de mensagem reutilizável que o usuário invoca pelo nome | Um comando de barra, um item de menu |
|
||||
|
||||
"Quem controla" é justamente o sentido da divisão. Uma ferramenta roda porque o **modelo** decidiu chamá-la. Um recurso é anexado porque a **aplicação** decidiu que o modelo precisava dele. Um prompt roda porque o **usuário** o escolheu.
|
||||
|
||||
!!! info
|
||||
Se você já construiu uma API web, já tem quase toda a intuição: um **recurso** é um `GET`
|
||||
(carrega dados e não altera nada) e uma **ferramenta** é um `POST` (realiza trabalho e pode ter
|
||||
efeitos colaterais). Um **prompt** não tem equivalente em HTTP; está mais para uma consulta salva
|
||||
que o usuário executa pelo nome.
|
||||
|
||||
## Um servidor, as três {#one-server-all-three}
|
||||
|
||||
```python title="server.py" hl_lines="6 12 18"
|
||||
--8<-- "docs_src/first_steps/tutorial001.py"
|
||||
```
|
||||
|
||||
Três funções simples, três decoradores. Cada decorador já é o registro completo:
|
||||
|
||||
* `@mcp.tool()` transforma `add` em uma **ferramenta**.
|
||||
* `@mcp.resource("greeting://{name}")` transforma `greeting` em um **template de recurso**: o `{name}` na URI é o parâmetro da função.
|
||||
* `@mcp.prompt()` transforma `summarize` em um **prompt**. A string que ela retorna vira uma mensagem de usuário.
|
||||
|
||||
Todo o resto (o nome, a descrição, o schema dos argumentos) o SDK lê da própria função: o nome dela, a docstring, as anotações de tipo. Você nunca declarou nada disso separadamente.
|
||||
|
||||
!!! tip
|
||||
As duas metades do SDK têm dois caminhos de importação: `from mcp import Client` e
|
||||
`from mcp.server import MCPServer`. Não existe `from mcp import MCPServer`.
|
||||
|
||||
### Experimente {#try-it}
|
||||
|
||||
Execute com o MCP Inspector:
|
||||
|
||||
```console
|
||||
uv run mcp dev server.py
|
||||
```
|
||||
|
||||
Abra a URL que ele imprime. O Inspector tem uma aba por primitiva; passe por elas na ordem.
|
||||
|
||||
**Ferramentas.** Uma entrada: `add`, descrita como *Add two numbers.* O formulário tem um campo inteiro obrigatório para `a` e outro para `b`. Preencha, chame, e o resultado é `3`. O Inspector montou esse formulário a partir de `a: int, b: int`. Qualquer outro cliente faz o mesmo.
|
||||
|
||||
**Recursos.** A lista *Resources* está vazia. `greeting` fica em **Resource Templates**, porque `greeting://{name}` tem um parâmetro: não existe um recurso concreto para listar até alguém fornecer um `name`. Passe `World` e leia:
|
||||
|
||||
```text
|
||||
Hello, World!
|
||||
```
|
||||
|
||||
**Prompts.** Uma entrada: `summarize`, com um único argumento obrigatório, `text`. Obtenha-o com algum texto e você recebe uma mensagem com `role: user` e sua string renderizada como conteúdo. Um prompt é só isso: uma função que monta mensagens.
|
||||
|
||||
O Inspector executou seu servidor via **stdio**, um dos transportes que um servidor MCP sabe falar. Por enquanto você não escolhe um; **[Executando seu servidor](../run/index.md)** é a página para isso.
|
||||
|
||||
## Capacidades {#capabilities}
|
||||
|
||||
Você viu três abas no Inspector. Como ele sabia que eram três?
|
||||
|
||||
Quando um cliente se conecta, o servidor declara suas **capacidades**: quais famílias de requisições ele vai responder. O cliente usa essa declaração para decidir o que faz sentido pedir. Você nunca escreveu isso; o `MCPServer` declara por você.
|
||||
|
||||
Veja você mesmo. O `Client` do SDK aceita o objeto do servidor diretamente e se conecta a ele **em memória** (sem subprocesso, sem porta):
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from mcp import Client
|
||||
|
||||
from server import mcp
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with Client(mcp) as client:
|
||||
print(client.server_capabilities.model_dump(exclude_none=True))
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
```text
|
||||
{'prompts': {'list_changed': True}, 'resources': {'subscribe': True, 'list_changed': True}, 'tools': {'list_changed': True}}
|
||||
```
|
||||
|
||||
Esse dicionário é a declaração de **capacidades** do seu servidor. É a primeira coisa que todo cliente aprende ao se conectar:
|
||||
|
||||
| Capacidade | O cliente agora pode chamar |
|
||||
|-------------|---------------------------------------------------------------|
|
||||
| `tools` | `tools/list`, `tools/call` |
|
||||
| `resources` | `resources/list`, `resources/templates/list`, `resources/read` |
|
||||
| `prompts` | `prompts/list`, `prompts/get` |
|
||||
|
||||
O `MCPServer` serve as três primitivas, então as três são sempre declaradas.
|
||||
|
||||
Repare no que não aparece ali. `completions` (autocompletar de argumentos para templates de recurso e prompts) precisa de um handler escrito por você; este servidor não tem nenhum, então a capacidade fica de fora e um cliente bem-comportado nem pede. Essa é a regra para tudo que é opcional: registre a coisa e a capacidade aparece; **[Completions](../servers/completions.md)** comprova isso.
|
||||
|
||||
!!! info
|
||||
`Client(mcp)` é o mesmo cliente em memória com que todos os exemplos desta documentação são
|
||||
testados, e é assim que você vai testar os seus. Ele ganha uma página inteira: **[Testes](testing.md)**.
|
||||
|
||||
## O que você não escreveu {#what-you-did-not-write}
|
||||
|
||||
Olhe de novo esta página. Você escreveu três funções Python pequenas. Você **não** escreveu:
|
||||
|
||||
* Um JSON Schema. `a: int, b: int` *é* o schema de `add`.
|
||||
* Um handler de requisição. `tools/list`, `resources/read`, `prompts/get`: o SDK atende todos por você.
|
||||
* Uma declaração de capacidades. O `MCPServer` fez isso por você.
|
||||
* Uma linha de protocolo. A negociação de versão, o enquadramento JSON-RPC, a troca de capacidades: tudo isso aconteceu dentro de `mcp dev` e `Client(mcp)`, e você nunca viu.
|
||||
|
||||
Essa proporção é a razão de ser do SDK.
|
||||
|
||||
## Recapitulando {#recap}
|
||||
|
||||
* Um **host** é o app de LLM, um **cliente** é a metade dele que fala MCP, um **servidor** é o que você constrói.
|
||||
* Ferramentas são controladas pelo **modelo**, recursos pela **aplicação**, prompts pelo **usuário**.
|
||||
* Um decorador por primitiva: `@mcp.tool()`, `@mcp.resource(uri)`, `@mcp.prompt()`. Nome, descrição e schema vêm da função.
|
||||
* Uma URI com um `{param}` cria um **template** de recurso, listado separadamente dos recursos concretos.
|
||||
* As **capacidades** do servidor já vêm declaradas para você, e um cliente só pede o que o servidor declara.
|
||||
* `Client(mcp)` se conecta ao objeto do servidor em memória: seu ambiente de testes desde o primeiro dia.
|
||||
|
||||
A seguir vem **[Conecte a um host real](real-host.md)**: este servidor dentro do Claude Desktop ou de uma IDE, de verdade. Depois, **[Testes](testing.md)**: uma página, um cliente em memória, e você nunca mais fica adivinhando se funciona. Depois disso, cada primitiva ganha sua própria página, começando pela que o modelo comanda: **[Ferramentas](../servers/tools.md)**.
|
||||
57
i18n/pt/pages/get-started/index.md
Normal file
57
i18n/pt/pages/get-started/index.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
translation:
|
||||
sections: [ed4a756b4c53c585, 97e2fb315b7fe398, 4d04f1c6f4bf6c1d, 577d73078fc62baf]
|
||||
tool: 1
|
||||
---
|
||||
# Comece por aqui {#get-started}
|
||||
|
||||
Novo no MCP, ou novo neste SDK? Comece aqui. Estas páginas levam você do zero a um
|
||||
servidor funcional e testado: [instale o SDK](installation.md), construa seu
|
||||
[primeiro servidor](first-steps.md), [conecte-o a um host real](real-host.md) e
|
||||
[teste-o](testing.md) com um cliente em memória.
|
||||
|
||||
## Execute o código {#run-the-code}
|
||||
|
||||
Todos os blocos de código podem ser copiados e usados diretamente: são arquivos completos e funcionais.
|
||||
|
||||
Para acompanhar, cole um bloco em um `server.py` e abra-o no MCP Inspector:
|
||||
|
||||
```console
|
||||
uv run mcp dev server.py
|
||||
```
|
||||
|
||||
É **ALTAMENTE recomendado** que você escreva (ou copie) o código, edite-o e execute-o localmente. Usá-lo no seu próprio editor é o que mostra de verdade qual é a ideia: o pouco que você escreve, o autocompletar, a checagem de tipos pegando erros antes de executar qualquer coisa.
|
||||
|
||||
## Você não vai precisar adivinhar {#you-will-not-be-guessing}
|
||||
|
||||
Cada exemplo nesta documentação é um arquivo completo em [`docs_src/`](https://github.com/modelcontextprotocol/python-sdk/tree/main/docs_src) no próprio repositório do SDK, e a suíte de testes do SDK exercita cada um deles por meio de um **cliente em memória**:
|
||||
|
||||
```python
|
||||
import pytest
|
||||
from mcp import Client
|
||||
|
||||
from server import mcp
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_add() -> None:
|
||||
async with Client(mcp) as client:
|
||||
result = await client.call_tool("add", {"a": 1, "b": 2})
|
||||
assert result.structured_content == {"result": 3}
|
||||
```
|
||||
|
||||
Sem subprocesso, sem porta, sem transporte. `Client(mcp)` se conecta diretamente ao objeto do servidor.
|
||||
|
||||
Se uma mudança no SDK quebrar um exemplo de uma destas páginas, o CI fica vermelho antes que a página quebre. O código que você lê aqui é o código que roda.
|
||||
|
||||
Você mesmo vai usar isso em [Testes](testing.md); é assim que você testa seus próprios servidores também.
|
||||
|
||||
## Para onde ir agora {#where-to-go-next}
|
||||
|
||||
Depois que você tiver um servidor rodando, o resto desta documentação é uma referência, não um curso.
|
||||
Cada página se sustenta sozinha, então pule direto para o que você precisa:
|
||||
|
||||
* O que um servidor expõe (ferramentas, recursos, prompts) está em **[Servidores](../servers/index.md)**.
|
||||
* O que está disponível dentro das funções que você registra está em **[Dentro do seu handler](../handlers/index.md)**.
|
||||
* Levar o servidor até os clientes (stdio, HTTP, o app FastAPI que você já tem) está em **[Executando seu servidor](../run/index.md)**.
|
||||
* Construir o outro lado, uma aplicação que *usa* servidores MCP, está em **[Clientes](../client/index.md)**.
|
||||
47
i18n/pt/pages/get-started/installation.md
Normal file
47
i18n/pt/pages/get-started/installation.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
translation:
|
||||
sections: [6e2f9bab94d5ed36, 8cf653388f69e28b, 6fd9ea2f65de0df6]
|
||||
tool: 1
|
||||
---
|
||||
# Instalação {#installation}
|
||||
|
||||
O SDK Python está no PyPI como [`mcp`](https://pypi.org/project/mcp/). Ele requer **Python 3.10+**.
|
||||
|
||||
Esta documentação descreve a **v2**, a linha de versões estável atual:
|
||||
|
||||
=== "uv"
|
||||
|
||||
```bash
|
||||
uv add "mcp[cli]"
|
||||
```
|
||||
|
||||
=== "pip"
|
||||
|
||||
```bash
|
||||
pip install "mcp[cli]"
|
||||
```
|
||||
|
||||
!!! note "Vindo da v1?"
|
||||
A v2 é uma versão major com quebras de compatibilidade; o **[Guia de migração](../migration.md)**
|
||||
cobre todas elas. Se o seu *pacote* depende de `mcp` e ainda não está pronto para migrar, mantenha um
|
||||
limite superior `<2` (por exemplo `mcp>=1.28,<2`) para que uma resolução sem versão fixada continue na linha 1.x.
|
||||
|
||||
## O que é instalado {#what-gets-installed}
|
||||
|
||||
Você não precisa saber nada disso para usar o SDK, mas, se quiser saber para que serve cada dependência:
|
||||
|
||||
* `mcp-types`: todos os tipos do protocolo (requisições, resultados, blocos de conteúdo) em um pacote próprio, versionado em sincronia com o SDK. O código que depende de `mcp` o importa pelo alias `mcp.types` (todo `from mcp.types import ...` nesta documentação); importe `mcp_types` diretamente apenas em um projeto que instala `mcp-types` sem o SDK.
|
||||
* [`anyio`](https://anyio.readthedocs.io/): o runtime assíncrono. O SDK inteiro é escrito sobre o anyio, então roda tanto com `asyncio` quanto com `trio`.
|
||||
* [`pydantic`](https://docs.pydantic.dev/): a base de todos os modelos de `mcp.types`, além de toda a geração e validação de schemas.
|
||||
* [`httpx2`](https://pypi.org/project/httpx2/): o cliente HTTP por trás dos transportes de *cliente* Streamable HTTP e SSE, com suporte embutido a server-sent events.
|
||||
* [`starlette`](https://www.starlette.io/), [`uvicorn`](https://www.uvicorn.org/), [`sse-starlette`](https://pypi.org/project/sse-starlette/) e [`python-multipart`](https://pypi.org/project/python-multipart/): os transportes HTTP de *servidor*.
|
||||
* [`jsonschema`](https://pypi.org/project/jsonschema/): valida a saída estruturada de uma ferramenta (tool) contra o schema de saída declarado por ela.
|
||||
* [`pyjwt[crypto]`](https://pyjwt.readthedocs.io/): tratamento de tokens OAuth para autorização.
|
||||
* [`opentelemetry-api`](https://opentelemetry-python.readthedocs.io/): apenas a API leve, então o middleware de tracing do SDK não custa nada, a menos que você mesmo instale um SDK e um exporter do OpenTelemetry.
|
||||
* [`typing-extensions`](https://typing-extensions.readthedocs.io/) e [`typing-inspection`](https://pypi.org/project/typing-inspection/): funcionalidades modernas de tipagem no Python 3.10.
|
||||
* [`pywin32`](https://pypi.org/project/pywin32/): somente no Windows, usado para o gerenciamento de subprocessos `stdio`.
|
||||
|
||||
## Extras opcionais {#optional-extras}
|
||||
|
||||
* `mcp[cli]` adiciona [`typer`](https://typer.tiangolo.com/) e [`python-dotenv`](https://pypi.org/project/python-dotenv/) para a ferramenta de linha de comando `mcp` (`mcp dev`, `mcp run`, `mcp install`). Você vai querer isso durante o desenvolvimento; talvez não precise dele em um servidor depois do deploy.
|
||||
* `mcp[rich]` adiciona [`rich`](https://rich.readthedocs.io/) para logs de servidor mais bonitos.
|
||||
185
i18n/pt/pages/get-started/real-host.md
Normal file
185
i18n/pt/pages/get-started/real-host.md
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
---
|
||||
translation:
|
||||
sections: [3c4f2f06b4e978b6, 22520eecae3d1961, f4e1709db18d635a, 2eb57992049671d9, 1ba83e9af37cc1b4, 4822586344b08d9e, 1c93afef72478992, b6b448f9eddd51dc, fe55370fd931815b]
|
||||
tool: 1
|
||||
---
|
||||
# Conecte-se a um host de verdade {#connect-to-a-real-host}
|
||||
|
||||
Um **host** é a aplicação dentro da qual seu servidor acaba rodando: Claude Desktop, Claude Code, uma IDE. O host é aquilo com que o usuário conversa. Dentro dele, um **cliente** MCP inicia seu servidor como um processo filho e fala com ele pelo stdin e stdout desse processo.
|
||||
|
||||
Ou seja, conectar a um host é um ato só: você informa a ele **o comando que inicia seu servidor**. Tudo nesta página (dois comandos de CLI, três arquivos JSON) é um lugar diferente para colocar esse mesmo comando.
|
||||
|
||||
## Um servidor, todos os hosts {#one-server-every-host}
|
||||
|
||||
```python title="server.py" hl_lines="3 33-34"
|
||||
--8<-- "docs_src/real_host/tutorial001.py"
|
||||
```
|
||||
|
||||
Duas ferramentas (tools) e um recurso, um arquivo só. Três coisas sobre esse arquivo importam para todos os hosts abaixo:
|
||||
|
||||
* `mcp.run()` sem argumentos inicia um servidor **stdio**: ele bloqueia, lê mensagens do protocolo no stdin e as escreve no stdout. Esse é o transporte que todos os hosts desta página falam. O host inicia seu arquivo como um processo filho e é dono desses dois pipes, e é por isso que conectar nunca passa de "aqui está o comando". Você nunca escolhe uma porta, e nada fica escutando em uma.
|
||||
* `run()` fica dentro de `if __name__ == "__main__":`. Tudo abaixo **importa** este arquivo em vez de executá-lo, então um `run()` sem essa proteção iniciaria um servidor no instante em que qualquer coisa carregasse o módulo.
|
||||
* O objeto do servidor é uma global de nível de módulo chamada `mcp`. É esse o nome que `mcp run` procura (`server` e `app` também funcionam). Dê outro nome a ele e você precisa informá-lo explicitamente: `mcp run server.py:bookshop`.
|
||||
|
||||
Essa é a última linha de Python nesta página. Daqui para baixo é tudo configuração de host.
|
||||
|
||||
## O comando de inicialização {#the-launch-command}
|
||||
|
||||
Todos os hosts abaixo recebem o mesmo comando:
|
||||
|
||||
```bash
|
||||
uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
|
||||
```
|
||||
|
||||
Um comando só para todos eles porque `uv run --with` resolve o SDK em um ambiente novo na hora: funciona a partir de qualquer diretório e não precisa de projeto nem de ambiente virtual para ativar. Isso importa aqui mais do que em qualquer outro lugar, porque um host inicia seu servidor a partir do diretório de trabalho *dele*, com um ambiente quase vazio, e não a partir do seu shell.
|
||||
|
||||
É também o comando que `mcp install` grava na configuração do Claude Desktop para você (abaixo), então o que você digita à mão e o que o utilitário gera coincidem, fora o pin exato de versão que o utilitário adiciona.
|
||||
|
||||
!!! tip "Se um host não encontrar o `uv`"
|
||||
Um host inicia seu servidor com um `PATH` mínimo, e o `uv` pode não estar nele. Troque o
|
||||
`uv` sozinho pelo caminho absoluto que `which uv` (macOS/Linux) ou `where uv` (Windows)
|
||||
retorna. É exatamente isso que `mcp install` grava.
|
||||
|
||||
!!! note "Esta página é o cenário local"
|
||||
Tudo aqui executa seu servidor na máquina em que o host está: o host inicia seu
|
||||
arquivo, via stdio. Isso é exatamente o certo para uma ferramenta pessoal ou de uma máquina
|
||||
só. Para entregar um servidor a pessoas que *não* têm seu arquivo, você distribui uma
|
||||
**URL**, não um comando: o mesmo objeto `mcp` servido via Streamable HTTP.
|
||||
**[Executando seu servidor](../run/index.md)** é essa decisão em uma tabela só, e
|
||||
**[Deploy e escala](../run/deploy.md)** é o caminho dali até um hostname de verdade.
|
||||
|
||||
E um host nada mais é que uma aplicação com um cliente MCP dentro, então seu próprio
|
||||
código Python pode fazer o papel do host: **[Transportes do cliente](../client/transports.md)**
|
||||
inicia este mesmo arquivo como subprocesso com `stdio_client(...)`, e **[Testes](testing.md)**
|
||||
se conecta a ele em memória, sem processo nenhum.
|
||||
|
||||
## Claude Desktop {#claude-desktop}
|
||||
|
||||
O único host que o SDK consegue configurar para você:
|
||||
|
||||
```bash
|
||||
uv run mcp install server.py
|
||||
```
|
||||
|
||||
É só isso. `mcp install` importa o arquivo para ler o nome do servidor, encontra o arquivo de configuração do Claude Desktop e grava o comando de inicialização nele. De passagem, já converte o caminho para absoluto, então você não precisa fazer isso.
|
||||
|
||||
Não há mistério nenhum. Esta é a entrada que ele grava:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"Bookshop": {
|
||||
"command": "/absolute/path/to/uv",
|
||||
"args": [
|
||||
"run",
|
||||
"--frozen",
|
||||
"--with",
|
||||
"mcp[cli]==2.0.0",
|
||||
"mcp",
|
||||
"run",
|
||||
"/absolute/path/to/server.py"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
É o comando de inicialização da seção acima com três acréscimos: o caminho absoluto do `uv`, `--frozen` para que o `uv` nunca reescreva um lockfile que por acaso esteja por perto, e um pin exato na versão do `mcp` que você tem instalada. Ele vai parar em `claude_desktop_config.json`, que fica em:
|
||||
|
||||
* **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||
* **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
||||
|
||||
Você pode escrever esse arquivo à mão. `mcp install` existe para você não cometer o erro clássico (um caminho relativo) ao fazer isso.
|
||||
|
||||
Encerre o Claude Desktop por completo (não só a janela) e abra-o de novo.
|
||||
|
||||
!!! warning
|
||||
`mcp install` falha com `Claude app not found` se o *diretório* de configuração do Claude
|
||||
Desktop ainda não existir. Instale o Claude Desktop e execute-o uma vez: é isso que cria o
|
||||
diretório.
|
||||
|
||||
!!! tip
|
||||
O Claude Desktop inicia seu servidor em um processo próprio, então as variáveis de ambiente do
|
||||
seu shell não estão lá. `uv run mcp install server.py -v API_KEY=abc123` (ou `-f .env`) as
|
||||
registra no campo `env` da entrada. `--name` sobrescreve o nome da entrada; o padrão é o
|
||||
`name` do servidor.
|
||||
|
||||
## Claude Code {#claude-code}
|
||||
|
||||
Não há arquivo para editar. Registre o servidor com a CLI `claude`; tudo depois de `--` é o comando de inicialização.
|
||||
|
||||
```bash
|
||||
claude mcp add bookshop -- uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
|
||||
```
|
||||
|
||||
Execute `/mcp` dentro de uma sessão do Claude Code para confirmar que `bookshop` está conectado e que suas ferramentas aparecem listadas.
|
||||
|
||||
## Cursor {#cursor}
|
||||
|
||||
Crie `.cursor/mcp.json` na raiz do seu projeto.
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"bookshop": {
|
||||
"command": "uv",
|
||||
"args": ["run", "--with", "mcp[cli]", "mcp", "run", "/absolute/path/to/server.py"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Os mesmos `command` e `args`, sob a mesma chave `mcpServers` que o Claude Desktop usa. O servidor aparece nas configurações de MCP do Cursor com as duas ferramentas listadas.
|
||||
|
||||
## VS Code {#vs-code}
|
||||
|
||||
Crie `.vscode/mcp.json` na raiz do seu projeto.
|
||||
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"bookshop": {
|
||||
"type": "stdio",
|
||||
"command": "uv",
|
||||
"args": ["run", "--with", "mcp[cli]", "mcp", "run", "/absolute/path/to/server.py"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Duas diferenças em relação ao arquivo do Cursor, e são as únicas duas: a chave externa é `servers`, não `mcpServers`, e cada entrada declara seu `type`. Confirme o diálogo de confiança e, em seguida, **MCP: List Servers** na paleta de comandos mostra `bookshop` rodando.
|
||||
|
||||
!!! note
|
||||
Você precisa do VS Code 1.99 ou posterior, com login feito na extensão **GitHub Copilot**
|
||||
(o Copilot Free basta), e o Copilot Chat precisa estar no modo **Agent**, porque nenhum
|
||||
outro modo chama ferramentas.
|
||||
|
||||
## Não aparece {#it-doesnt-show-up}
|
||||
|
||||
Antes de mexer em qualquer configuração de host, execute você mesmo o comando de inicialização:
|
||||
|
||||
```bash
|
||||
uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
|
||||
```
|
||||
|
||||
Nada é impresso, e ele não retorna. Esse silêncio está certo: um servidor stdio está esperando um host falar primeiro no stdin (`Ctrl-C` para pará-lo). Um traceback ou uma saída imediata é o bug de verdade, e agora você consegue lê-lo em vez de tentar adivinhá-lo através de um host.
|
||||
|
||||
Uma vez que esse comando fica parado esperando, o que sobra é quase sempre uma de três coisas:
|
||||
|
||||
* **Um caminho relativo.** O host inicia seu servidor a partir do diretório de trabalho *dele*, não daquele de onde você fez o registro. `server.py` onde é preciso `/absolute/path/to/server.py` é, de longe, a falha mais comum. Se o host também não encontrar o `uv`, esse caminho precisa ser absoluto também.
|
||||
* **O host ainda está rodando a configuração antiga.** Os hosts leem a configuração ao iniciar. O Claude Desktop, em particular, precisa ser *encerrado por completo* (não basta fechar a janela) e reaberto para que uma edição em `claude_desktop_config.json` tenha efeito.
|
||||
* **Algo chegou ao stdout fora do intervalo de desvio.** No stdio, o stdout *é* o protocolo. O SDK desvia para o stderr a saída avulsa descarregada (com flush) enquanto está servindo, mas uma saída descarregada no stdout antes disso (um script wrapper que ecoa algo, um `print()` em tempo de importação em um processo sem buffer), ou um `print()` em buffer que só é descarregado quando o interpretador encerra, entrega ao host uma mensagem corrompida, e ele derruba a conexão. Registre os logs usando a configuração padrão do `logging`, cujo handler de stderr faz flush de cada registro; handlers personalizados também precisam evitar o stdout. **[Logging](../handlers/logging.md)** tem a história completa.
|
||||
|
||||
O Claude Desktop mantém um log por servidor: `mcp-server-<NAME>.log` é o stderr do seu servidor, ao lado de `mcp.log` para as conexões, em `~/Library/Logs/Claude` no macOS e `%APPDATA%\Claude\logs` no Windows.
|
||||
|
||||
Para qualquer coisa além dessas três, a página é **[Solução de problemas](../troubleshooting.md)**.
|
||||
|
||||
## Recapitulando {#recap}
|
||||
|
||||
* Um **host** (Claude Desktop, uma IDE) executa um cliente MCP que inicia seu servidor como processo filho via stdio. Conectar significa dar a ele um comando de inicialização.
|
||||
* Esse comando é `uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py`: nenhum venv para ativar, funciona a partir de qualquer diretório.
|
||||
* **Claude Desktop** é o único host que `mcp install` configura para você. Ele grava esse mesmo comando (mais o caminho absoluto do `uv`, `--frozen` e um pin exato na versão que você tem instalada) em `claude_desktop_config.json`, para você nunca precisar fazer isso.
|
||||
* **Claude Code** é `claude mcp add bookshop -- <launch command>`. **Cursor** é `.cursor/mcp.json` sob `mcpServers`. **VS Code** é `.vscode/mcp.json` sob `servers`, cada entrada com um `type`.
|
||||
* Caminhos absolutos em todo lugar, reinicie o host depois de editar a configuração dele, e nunca deixe nada além do SDK escrever no stdout.
|
||||
|
||||
Todos os hosts desta página se conectaram ao mesmo arquivo, com o mesmo comando. O que esse arquivo pode *expor* é o resto desta documentação: **[Ferramentas](../servers/tools.md)**, **[Recursos](../servers/resources.md)** e todos os transportes além do stdio em **[Executando seu servidor](../run/index.md)**.
|
||||
115
i18n/pt/pages/get-started/testing.md
Normal file
115
i18n/pt/pages/get-started/testing.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
---
|
||||
translation:
|
||||
sections: ['4926721070127497', c52a1de2b6b32f40, 2e410b412c25f314, 627195f7159e24ef]
|
||||
tool: 1
|
||||
---
|
||||
# Testes {#testing}
|
||||
|
||||
O SDK Python traz uma classe `Client` com um **transporte em memória**: passe a ela o objeto do seu servidor e ela se conecta diretamente a ele.
|
||||
|
||||
Sem subprocesso. Sem porta. Sem transporte nenhum. É a mesma ideia do `TestClient` do FastAPI.
|
||||
|
||||
## Uso básico {#basic-usage}
|
||||
|
||||
Vamos supor que você tenha um servidor simples com uma única ferramenta (tool):
|
||||
|
||||
```python title="server.py"
|
||||
--8<-- "docs_src/testing/tutorial001.py"
|
||||
```
|
||||
|
||||
Para executar o teste abaixo, você vai precisar de duas dependências extras (de desenvolvimento):
|
||||
|
||||
=== "uv"
|
||||
|
||||
```bash
|
||||
uv add --dev pytest inline-snapshot
|
||||
```
|
||||
|
||||
=== "pip"
|
||||
|
||||
```bash
|
||||
pip install pytest inline-snapshot
|
||||
```
|
||||
|
||||
!!! info
|
||||
Esta documentação pressupõe que você já conhece o [`pytest`](https://docs.pytest.org/en/stable/).
|
||||
|
||||
O [`inline-snapshot`](https://15r10nk.github.io/inline-snapshot/latest/) é o que o teste abaixo
|
||||
usa para fazer a asserção sobre o objeto de resultado inteiro em uma única linha. Ele grava a saída
|
||||
de um teste como o literal `snapshot(...)` que você vê. Se preferir não usá-lo, remova o import e
|
||||
faça as asserções sobre os campos que interessam (`result.content[0].text == "3"`), como em
|
||||
qualquer outro teste.
|
||||
|
||||
Agora o teste:
|
||||
|
||||
```python title="test_server.py"
|
||||
import pytest
|
||||
from inline_snapshot import snapshot
|
||||
from mcp import Client
|
||||
from mcp.types import CallToolResult, TextContent
|
||||
|
||||
from server import mcp
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def anyio_backend(): # (1)!
|
||||
return "asyncio"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def client(): # (2)!
|
||||
async with Client(mcp, raise_exceptions=True) as c:
|
||||
yield c
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_call_add_tool(client: Client):
|
||||
result = await client.call_tool("add", {"a": 1, "b": 2})
|
||||
# Drop the server identity stamp in `_meta`; it is not what this test is about.
|
||||
result.meta = None
|
||||
assert result == snapshot(
|
||||
CallToolResult(
|
||||
content=[TextContent(type="text", text="3")],
|
||||
structured_content={"result": 3},
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
1. Se você estiver usando `trio`, retorne `"trio"` no lugar. Veja a [documentação do anyio](https://anyio.readthedocs.io/en/stable/testing.html#specifying-the-backends-to-run-on) para os detalhes.
|
||||
2. A fixture entrega um cliente já conectado. Todo teste que recebe `client` ganha uma conexão em memória nova com o mesmo servidor.
|
||||
|
||||
Pronto! Agora você pode estender seus testes para cobrir mais cenários.
|
||||
|
||||
## Por que `raise_exceptions=True`? {#why-raise_exceptionstrue}
|
||||
|
||||
Duas coisas diferentes podem dar errado, e essa flag só mexe em uma delas.
|
||||
|
||||
Uma exceção dentro de uma das **suas ferramentas** não é uma falha de protocolo. Ela vira um resultado normal com
|
||||
`is_error=True`, e o modelo lê a mensagem. `raise_exceptions` não muda isso: com ou
|
||||
sem ela, `call_tool` retorna o mesmo resultado com `is_error=True`. Há uma página inteira sobre isso:
|
||||
**[Tratamento de erros](../servers/handling-errors.md)**.
|
||||
|
||||
Uma falha **fora** do corpo de uma ferramenta é diferente. Na conexão que `Client(mcp)` entrega, o
|
||||
servidor a sanitiza em um genérico `"Internal server error"` antes que o cliente a veja. Você nunca
|
||||
deve vazar os detalhes de um crash inesperado para um chamador remoto. Em um teste, isso é exatamente o que
|
||||
você *não* quer, e é isso que `raise_exceptions=True` muda: seu teste vê a mensagem real
|
||||
em vez da sanitizada.
|
||||
|
||||
Deixe-a ligada nos testes. Em código de produção, ela não significa nada.
|
||||
|
||||
## No mesmo processo por padrão {#in-process-by-default}
|
||||
|
||||
!!! note
|
||||
`Client(mcp)` se conecta no mesmo processo e é **neutro quanto à era** por padrão: ele sonda o servidor e
|
||||
escolhe o caminho de protocolo adequado. Fixe `mode="legacy"` se o seu teste exercita semântica
|
||||
específica do modo legado (push de amostragem (sampling) ou de elicitação (elicitation), `message_handler`), e remova `raise_exceptions=True`
|
||||
nesse caso: uma conexão legada nem sequer sanitiza, e a flag relança a
|
||||
falha dentro da task do servidor em vez de no seu teste.
|
||||
|
||||
Essa única linha é também o motivo pelo qual esta documentação pode prometer que os exemplos funcionam: cada
|
||||
arquivo de exemplo é exercitado pela própria suíte de testes do SDK, quase todos exatamente por meio deste
|
||||
cliente. Você está usando a mesma ferramenta que o SDK usa em si mesmo.
|
||||
|
||||
Você tem um servidor funcionando e testado. Colocá-lo dentro de uma aplicação real (Claude Desktop, uma
|
||||
IDE) é o tema de **[Conecte-se a um host real](real-host.md)**; todas as outras formas de servi-lo estão em
|
||||
**[Executando seu servidor](../run/index.md)**.
|
||||
Loading…
Reference in a new issue