docs: refresh translations for recent English changes (#3379)

This commit is contained in:
Max 2026-08-24 19:29:54 +01:00 • committed by GitHub
commit c5d7d0b6d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 3149 additions and 1047 deletions

View file

@ -1,13 +1,13 @@
---
translation:
sections: [e33d441f12d50535, 7099694c603e0f5f, c1df4cf9673433e6, c9cd294541422e6e, 6cec073617bfd037, efa92b8f99e908c8, 6a22a29e27fb4601]
sections: [7be05607887e6853, e7375894888d9750, c36f73fc7e3af13b, 2fec2d7e129e62fe, 809b0e0a7c27295a, b4395a04d2a5d906, 1a436007f5f54779, c6b2078ed1e63ba5]
tool: 1
---
# Tratando erros {#handling-errors}
Uma ferramenta (tool) pode falhar de duas maneiras, e o SDK trata cada uma de forma bem diferente.
Uma ferramenta (tool) pode falhar de três maneiras, e o SDK trata cada uma de forma diferente.
Lance uma exceção comum e é o **modelo** que a vê. Lance `MCPError` e é o **protocolo** que a vê.
Lance `ToolError` e é o **modelo** que vê a sua mensagem. Lance `MCPError` e é o **protocolo** que a vê. Lance qualquer outra coisa e é um crash: o modelo só fica sabendo que a chamada falhou, e o seu log recebe o traceback.
Esta página é sobre essa escolha.
@ -15,11 +15,11 @@ Esta página é sobre essa escolha.
Pegue uma ferramenta que faz uma consulta e deixe a consulta não encontrar nada:
```python title="server.py" hl_lines="11-12"
```python title="server.py" hl_lines="2 12-13"
--8<-- "docs_src/handling_errors/tutorial001.py"
```
Não há nada de MCP nessas duas linhas. `get_author` lança um `ValueError` comum, como qualquer função Python faria.
`ToolError`, de `mcp.server.mcpserver.exceptions`, é como uma ferramenta avisa ao modelo que algo deu errado.
Chame a ferramenta com um título que não está no catálogo e veja o resultado:
@ -30,13 +30,15 @@ result.structured_content # None
```
* A requisição **foi bem-sucedida**. Há um resultado; nada foi lançado no lado de quem chamou.
* `is_error` é `True`, e a mensagem da sua exceção (prefixada com o nome da ferramenta) está em `content`, exatamente onde o modelo lê.
* `is_error` é `True`, e a sua mensagem (prefixada com o nome da ferramenta) está em `content`, exatamente onde o modelo lê.
* `structured_content` é `None`. Uma chamada que falhou não tem valor de retorno para estruturar.
Isso é um **erro de ferramenta**, e é o padrão para *qualquer* exceção que a sua ferramenta lançar. Também é, quase sempre, o que você quer.
Isso é um **erro de ferramenta**, e é quase sempre o que você quer.
Quem chama a sua ferramenta é o modelo. Foi ele que escolheu os argumentos. Então um erro de ferramenta é um turno na conversa: o modelo lê *"No book titled 'Nothing' in the catalog."*, percebe que chutou o título errado e chama de novo com um melhor. Você escreveu um `raise` e ganhou um agente que se corrige sozinho.
No servidor, um `ToolError` é uma linha `INFO` no log, sem traceback. Você já esperava por ele, então não há nada para investigar.
!!! tip
Nunca faça `return` de uma mensagem de erro em uma ferramenta. Uma string retornada tem `is_error=False`, então, para o
modelo (e para toda interface de cliente), parece que a ferramenta funcionou e que aquela string era a resposta.
@ -44,7 +46,7 @@ Quem chama a sua ferramenta é o modelo. Foi ele que escolheu os argumentos. Ent
## Um erro que o modelo não consegue corrigir {#an-error-the-model-cannot-fix}
Agora troque `ValueError` por `MCPError`.
Agora troque `ToolError` por `MCPError`.
```python title="server.py" hl_lines="1 3 14"
--8<-- "docs_src/handling_errors/tutorial002.py"
@ -77,10 +79,10 @@ Agora troque `ValueError` por `MCPError`.
Os dois caminhos respondem a duas perguntas diferentes.
* **Lance qualquer exceção** para uma falha de *execução*: aquilo que a sua ferramenta tentou fazer não funcionou. Foi o modelo que escolheu a chamada, então é o modelo que deve ver a consequência e ter a chance de se recuperar. Um título escrito errado, uma API upstream que deu timeout, uma linha que não existe: tudo erro de ferramenta.
* **Lance `ToolError`** para uma falha de *execução*: aquilo que a sua ferramenta tentou fazer não funcionou. Foi o modelo que escolheu a chamada, então é o modelo que deve ver a consequência e ter a chance de se recuperar. Um título escrito errado, uma API upstream que deu timeout, uma linha que não existe: tudo erro de ferramenta.
* **Lance `MCPError`** quando a *própria requisição* deve ser rejeitada: o cliente não tem uma capacidade da qual a sua ferramenta depende, o servidor não está em condições de atender ninguém, quem chamou pulou uma etapa obrigatória. Nenhuma nova tentativa do modelo corrige nada disso, então não há nada a ganhar entregando a mensagem a ele.
Uma pergunta decide: **um modelo mais esperto teria evitado isso?** Sim -> exceção comum. Não -> `MCPError`.
Uma pergunta decide: **um modelo mais esperto teria evitado isso?** Sim -> `ToolError`. Não -> `MCPError`.
Por esse critério, a segunda versão de `get_author` fez a escolha errada: um título melhor resolve, então o modelo merecia ver a mensagem. Ela está ali para mostrar o mecanismo, não para recomendá-lo.
@ -89,6 +91,25 @@ Por esse critério, a segunda versão de `get_author` fez a escolha errada: um t
`data` opcional. O que você colocar neles é o que o cliente recebe: o SDK repassa um
`MCPError` lançado tal e qual, em vez de sanitizá-lo.
## Qualquer outra exceção {#any-other-exception}
Agora tire a verificação e deixe a consulta ao dicionário falhar sozinha:
```python title="server.py" hl_lines="11"
--8<-- "docs_src/handling_errors/tutorial004.py"
```
`CATALOG[title]` lança `KeyError`. Você não planejou isso, então o SDK trata como um crash:
```python
result.is_error # True
result.content # [TextContent(text="Error executing tool get_author")]
```
A chamada ainda retorna `is_error=True`, então o modelo sabe que falhou e pode seguir em frente. O que ele não recebe é o texto da exceção: um `KeyError` do seu código, ou uma pilha de SQL vinda de um driver três bibliotecas abaixo, pode descrever o funcionamento interno do seu servidor, então nunca sai do servidor.
Quem recebe é você. O servidor registra o crash em `ERROR` com o traceback completo, como `Tool 'get_author' raised an unexpected exception`. Um log de produção em `WARNING`, portanto, fica quieto a cada `ToolError` e se manifesta no instante em que algo está de fato quebrado.
## Um recurso que não existe {#a-resource-that-doesnt-exist}
Recursos fazem a mesma distinção, e vêm com uma exceção nomeada para o caso mais comum.
@ -109,7 +130,7 @@ Quando não consegue, lance `ResourceNotFoundError`. O SDK a transforma no erro
}
```
Repare que aqui não existe um meio-resultado com `is_error=True`. A leitura de um recurso ou retorna conteúdo ou falha: recursos só têm o caminho do protocolo. Templates e todo o resto sobre recursos ficam em **[Recursos](resources.md)**.
Repare que aqui não existe um meio-resultado com `is_error=True`. A leitura de um recurso ou retorna conteúdo ou falha: recursos só têm o caminho do protocolo. `ResourceError` é a mesma coisa para uma falha que não é "não encontrado" (`-32603`, com a sua mensagem), e as duas são uma linha `INFO` no seu log. Qualquer outra exceção, exceto `MCPError`, é um crash: o cliente recebe `-32603` citando apenas a URI, e o traceback vai para o seu log em `ERROR`. Templates e todo o resto sobre recursos ficam em **[Recursos](resources.md)**.
## Erros que você nunca lança {#errors-you-never-raise}
@ -120,19 +141,21 @@ Mande para `get_author` um `title` que não seja uma string e o SDK o rejeita co
Isso significa uma classe inteira de instruções `raise` que você não escreve: não revalide as suas próprias anotações de tipo.
!!! info
Tudo nesta página é o que um **cliente** vê, e o `Client` em memória com o qual você vai escrever
seus testes vê exatamente a mesma coisa. Nem `raise_exceptions=True` transforma um erro de ferramenta
de volta em traceback: no momento em que essa flag poderia agir, a sua exceção já virou o
resultado com `is_error=True`. Faça o assert no resultado. **[Testes](../get-started/testing.md)** cobre o padrão.
Tudo o que um **cliente** vê nesta página, o `Client` em memória com o qual você vai escrever
seus testes também vê. Nem `raise_exceptions=True` devolve a exceção de uma ferramenta que falhou
a quem chamou: no momento em que essa flag poderia agir, a sua exceção já virou o
resultado com `is_error=True`. Faça o assert no resultado. Se você precisar do traceback de um crash, ele está no
log do servidor, e o `caplog` do pytest o captura. **[Testes](../get-started/testing.md)** cobre o padrão.
## Recapitulando {#recap}
* Lance **qualquer exceção** em uma ferramenta -> a chamada retorna `is_error=True` com a sua mensagem em `content`. O modelo lê e pode tentar de novo. Esse é o padrão.
* Lance **`ToolError`** em uma ferramenta -> a chamada retorna `is_error=True` com a sua mensagem em `content`. O modelo lê e pode tentar de novo.
* Lance **`MCPError`** -> a própria chamada falha com um erro JSON-RPC. O modelo não vê nada; quem lida com isso é o host. `code`, `message` e `data` sobrevivem intactos.
* A pergunta que decide: *um modelo mais esperto teria evitado isso?* Sim -> exceção. Não -> `MCPError`.
* A pergunta que decide: *um modelo mais esperto teria evitado isso?* Sim -> `ToolError`. Não -> `MCPError`.
* Qualquer **outra exceção** é um crash -> `is_error=True` só com `Error executing tool <name>` para o modelo, e um registro `ERROR` com o traceback para você.
* `ResourceNotFoundError` em um handler de recurso -> o `-32602` do protocolo, com a URI em `data`.
* Argumentos inválidos são rejeitados com base no schema antes de a sua função executar; você não dá `raise` para eles.
* `from mcp import MCPError`; as constantes de código de erro vêm de `mcp.types`.
* Imports: `from mcp import MCPError`, `from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundError`, e as constantes de código de erro de `mcp.types`.
Erros tratados. Isso é tudo o que um servidor *expõe*. O que cada handler pode ler, e fazer de volta ao cliente enquanto executa, é a próxima seção: **[Dentro do seu handler](../handlers/index.md)**.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [496394d24d221bf1, 4ceb4591180dc6c3, 0fd63e4682d02e0c, 969ede0bd3686a16, 043f526230dd243d, 6ee3e9bcfd24047a]
sections: [496394d24d221bf1, 4ceb4591180dc6c3, 0fd63e4682d02e0c, 969ede0bd3686a16, 864137b5e9c61e91, 043f526230dd243d, db1ef91db7d6b3f3]
tool: 1
---
# Mídia {#media}
@ -86,6 +86,24 @@ Um sufixo não reconhecido cai no padrão `application/octet-stream`.
`Audio` a partir de bytes MP3 desse jeito e o cliente recebe `mime_type="audio/wav"` e,
confiando nisso, falha ao decodificar. Quando você passar `data=`, passe `format=`.
## Embutindo um recurso {#embedding-a-resource}
Uma ferramenta também pode retornar um documento: algum texto ou bytes junto com a URI onde ele mora e um tipo MIME. Isso é um **`EmbeddedResource`**, outro tipo de bloco de conteúdo. Diferente de uma `str` simples, ele diz ao cliente o que é o conteúdo, então o cliente pode mostrá-lo como anexo ou reconhecer um recurso que já conhece.
```python title="server.py" hl_lines="7 14 16-18"
--8<-- "docs_src/media/tutorial005.py"
```
* `brand://guidelines` é um recurso comum (**[Recursos](resources.md)** trata deles). A ferramenta entrega o mesmo documento ao modelo quando pedido, e chamar `guidelines()` diretamente mantém uma única fonte da verdade.
* `EmbeddedResource` e `TextResourceContents` vêm de `mcp.types`. Não há um helper como há para imagens: o bloco que você monta entra no resultado sem alteração, e não há `structured_content`.
* Use a URI sob a qual o recurso está registrado, para que um cliente consiga perceber que o anexo e `brand://guidelines` são o mesmo documento. Qualquer URI é válida, registrada ou não.
```python
result.content # [EmbeddedResource(type="resource", resource=TextResourceContents(uri="brand://guidelines", mime_type="text/markdown", text="# Brand guidelines\n\n..."))]
```
Para conteúdo binário, use `BlobResourceContents(uri=..., mime_type=..., blob=...)` com os bytes codificados em base64 em `blob`, no lugar de `TextResourceContents`. Para enviar apenas um ponteiro que o cliente pode ler depois com `resources/read`, retorne um `ResourceLink(name=..., uri=...)`; ele também é um bloco de conteúdo.
## Ícones {#icons}
Um `Icon` é metadado, não conteúdo. Ele não carrega a imagem; aponta para uma por meio de uma URI, e um cliente pode buscá-la e mostrá-la ao lado do nome do seu servidor, de uma ferramenta, de um recurso ou de um prompt.
@ -115,6 +133,7 @@ Os ícones de uma ferramenta ficam no objeto `Tool` de `tools/list`; os de um re
* Retorne uma `Image` ou um `Audio` de uma ferramenta e o cliente recebe um bloco `ImageContent` / `AudioContent`: seus bytes codificados em base64, com um tipo MIME.
* Monte um a partir de um `path=` e deixe o sufixo decidir o tipo MIME, ou a partir de `data=` em memória mais um `format=` explícito.
* Retorne um `EmbeddedResource` para colocar um documento (texto ou um blob em base64, com sua URI e tipo MIME) no resultado, ou um `ResourceLink` para enviar só o ponteiro.
* Resultados de mídia não trazem `structured_content` nem schema de saída.
* Um `Icon` é um ponteiro: uma URI `src` mais `mime_type`, `sizes` e `theme` opcionais.
* `icons=[...]` funciona no servidor, em ferramentas, em recursos e em prompts, e os clientes os encontram nos objetos correspondentes.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [d65c098f37f5b6c3, dd0c2724d6f2877e, 6835bb3570c6714c, ffe823cb0fedd488, f33651add1b59094]
sections: [d65c098f37f5b6c3, dd0c2724d6f2877e, 6835bb3570c6714c, d30d3c20168b88b2, f5ef38dad59d6f76, 6e38a699ba57fbdf, 2b984a3bf37a0ddd]
tool: 1
---
# Prompts {#prompts}
@ -139,10 +139,55 @@ A entrada em `prompts/list` agora traz tudo de que um cliente precisa para desen
```
!!! info
Se você leu **[Ferramentas](tools.md)**, já sabe tudo o que está nesta página. O mesmo decorador, a mesma
Se você leu **[Ferramentas](tools.md)**, já sabe tudo até este ponto. O mesmo decorador, a mesma
docstring como descrição, o mesmo `Annotated`/`Field`. As únicas coisas que mudam são quem
dispara (o usuário) e para onde vai o resultado (para a conversa).
## Mais do que texto {#more-than-text}
`UserMessage` e `AssistantMessage` também aceitam um bloco de conteúdo, ou um helper `Image` / `Audio`, onde quer que aceitem uma `str`. Dois casos aparecem em prompts: anexar um documento e anexar uma imagem.
### Incorporando um arquivo {#embedding-a-file}
```python title="server.py" hl_lines="5 12 21 23"
--8<-- "docs_src/prompts/tutorial004.py"
```
* O guia de estilo é um recurso em `style://python` (**[Recursos](resources.md)** trata deles), lido de um `style-guide.md` ao lado de `server.py`. Coloque qualquer arquivo Markdown ali.
* `EmbeddedResource(resource=TextResourceContents(...))`, ambos de `mcp.types`, carrega o arquivo com sua URI e seu tipo MIME como a primeira mensagem; a instrução que faz referência a ele vem em seguida, como texto simples.
* Incorporar, em vez de colar o guia na f-string, permite que o cliente o mostre como um anexo e reabra `style://python` depois, e o modelo recebe o arquivo na íntegra. Para um arquivo binário, use `BlobResourceContents` com um `blob` em base64.
Renderizada, o `content` da primeira mensagem é um bloco `resource`:
```json
{"type": "resource", "resource": {"uri": "style://python", "mimeType": "text/markdown", "text": "* Prefer early returns.\n..."}}
```
### Anexando uma imagem {#attaching-an-image}
```python title="server.py" hl_lines="4 15"
--8<-- "docs_src/prompts/tutorial005.py"
```
* `Image` é o helper de **[Imagens, áudio e ícones](media.md)**. `UserMessage` o converte em um bloco `ImageContent` (o arquivo codificado em base64, o tipo MIME deduzido a partir de `.png`) quando o prompt é renderizado; `Audio` vira um `AudioContent` do mesmo jeito.
* Coloque qualquer PNG chamado `architecture.png` ao lado de `server.py`. Os argumentos de prompt são strings, então a imagem sempre vem do servidor; `component` só fornece as palavras.
```json
{"type": "image", "data": "iVBORw0KGgoAAAANSUhEUg...", "mimeType": "image/png"}
```
## Mudando a lista em tempo de execução {#changing-the-list-at-runtime}
Prompts podem ser adicionados enquanto clientes estão conectados, por exemplo para deixar um usuário salvar uma instrução como uma entrada de menu própria. Registre o prompt e depois notifique:
```python title="server.py" hl_lines="5 23-27"
--8<-- "docs_src/prompts/tutorial006.py"
```
* `mcp.add_prompt(Prompt.from_function(fn, name=..., description=...))` registra uma função exatamente como `@mcp.prompt()` faria, e `mcp.remove_prompt(name)` é o inverso. `add_prompt` mantém uma entrada existente com o mesmo nome em vez de sobrescrevê-la, então a ferramenta remove qualquer entrada antiga primeiro para que salvar seja uma substituição. `prompts/list` reflete a mudança imediatamente.
* `await ctx.notify_prompts_changed()` envia `notifications/prompts/list_changed` a todo cliente `2026-07-28` escutando em um stream `subscriptions/listen` (**[Assinaturas](../handlers/subscriptions.md)**). `await ctx.session.send_prompt_list_changed()` envia ao cliente que fez a chamada quando esse cliente é anterior a 2026 (**[Atendendo clientes legados](../run/legacy-clients.md)**). Chame os dois; cada um não faz nada quando não há ninguém para avisar.
* Um cliente que recebe a notificação chama `prompts/list` de novo. No `Client` Python isso é `async with client.listen(prompts_list_changed=True) as sub:`, que produz um evento `PromptsListChanged`.
## Recapitulando {#recap}
* `@mcp.prompt()` em uma função faz dela um prompt. O nome vem da função, a descrição vem da docstring.
@ -151,5 +196,7 @@ A entrada em `prompts/list` agora traz tudo de que um cliente precisa para desen
* Retorne uma `str` e ela vira uma mensagem de usuário. Retorne uma lista de `UserMessage` / `AssistantMessage` para iniciar uma conversa de vários turnos.
* `title=` e `Field(description=...)` são o que um cliente coloca na interface dele.
* Um argumento obrigatório ausente faz a requisição inteira falhar. Não existe um resultado de erro por prompt.
* Embrulhe um `EmbeddedResource` ou um `Image` em uma `UserMessage` para anexar um documento ou uma imagem.
* Adicione ou remova prompts em tempo de execução com `mcp.add_prompt(...)` / `mcp.remove_prompt(...)`, e depois `await ctx.notify_prompts_changed()` e `await ctx.session.send_prompt_list_changed()`.
O autocomplete do lado do servidor para os argumentos de um prompt (ou de um template de recurso) é assunto de **[Completions](completions.md)**.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [a838d57f003aed44, 857d03886a0137ed, 42d9efcb9f542867, 2290ff08435b5573, e866c192e11d1c14, 6cdbad079f7b47f0, d4b607372fb28b51, 18dbf726ac45e0b7, c6f7d2a148aa49f4, c851964bb3301907, d715db6f8dccc9cc, ef86634aa70498a7]
sections: [a838d57f003aed44, 857d03886a0137ed, 42d9efcb9f542867, 2290ff08435b5573, 91be9b73602abcf1, 6cdbad079f7b47f0, d4b607372fb28b51, 18dbf726ac45e0b7, c7eff2a5698225fa, c851964bb3301907, 8f296f1f09e4c400, d715db6f8dccc9cc, a0c344a48450dbe4]
tool: 1
---
# Saída estruturada {#structured-output}
@ -105,7 +105,7 @@ Nem toda forma merece uma classe. Um `TypedDict` produz o mesmo schema:
--8<-- "docs_src/structured_output/tutorial003.py"
```
Um `TypedDict` é um `dict` comum em tempo de execução, então é isso que você monta e retorna. O schema, a validação e o `structured_content` são idênticos aos da versão com `BaseModel` (menos as descrições, para as quais o `TypedDict` não tem lugar).
Um `TypedDict` é um `dict` comum em tempo de execução, então é isso que você monta e retorna. O schema, a validação e o `structured_content` seguem as mesmas regras da versão com `BaseModel`: adicione uma docstring à classe ou `Annotated[..., Field(description=...)]` e elas viram as descrições, e uma chave `NotRequired` que você deixa de fora do dict fica de fora do `structured_content`.
## Uma dataclass {#a-dataclass}
@ -187,18 +187,19 @@ Você não percebe enquanto monta o valor à mão: o Pydantic já garantiu que o
A anotação promete `WeatherData`. A resposta do serviço upstream parou de enviar `humidity`.
!!! check
Chame `get_weather` e ela não entrega discretamente ao cliente um objeto pela metade. A chamada falha,
e as primeiras linhas do erro dão o nome do campo:
Chame `get_weather` e ela não entrega discretamente ao cliente um objeto pela metade. A chamada falha:
o cliente recebe `is_error=True` com `Error executing tool get_weather`, então o modelo sabe que a
chamada falhou em vez de ler, com toda a confiança, um clima que não existe. O nome do campo é para você,
no log do servidor em nível `ERROR`:
```text
Error executing tool get_weather: 1 validation error for WeatherData
Tool 'get_weather' raised an unexpected exception
...
pydantic_core._pydantic_core.ValidationError: 1 validation error for WeatherData
humidity
Field required [type=missing, input_value={'temperature': 16.2, 'conditions': 'Overcast'}, input_type=dict]
```
Esse texto volta como o resultado da ferramenta com `is_error=True`, então o modelo sabe que a chamada
falhou em vez de ler, com toda a confiança, um clima que não existe.
Retornar um `dict` comum de uma ferramenta `-> WeatherData` não tem problema, aliás. É exatamente isso que `json.loads` produziu. A validação é feita sobre o valor, não sobre o tipo Python.
## Desativando {#opting-out}
@ -213,6 +214,10 @@ Sem `output_schema`, sem wrapper, sem validação. `structured_content` é `None
O oposto, `structured_output=True`, transforma a detecção automática em exigência: uma ferramenta cujo tipo de retorno não consegue produzir um schema levanta uma exceção no momento do import em vez de recair para texto.
## Blocos de conteúdo e mídia {#content-blocks-and-media}
Blocos de conteúdo e mídia (`TextContent`, `EmbeddedResource`, `Image`, `Audio` e companhia, sozinhos, como itens de uma `list`, `tuple` ou `Sequence`, ou como membros de uma união) já ficam de fora para você: eles são para o modelo ler, então a detecção automática não deriva nenhum schema deles (**[Imagens, áudio e ícones](media.md)** cobre `Image` e `Audio`). `structured_output=True` ainda força um para as classes de bloco de conteúdo.
## Uma classe sem anotações de tipo {#a-class-without-type-hints}
Existe um jeito de acabar sem estrutura sem ter pedido por isso: retornar uma classe que **não tem anotações no corpo**.
@ -245,6 +250,6 @@ Existe um jeito de acabar sem estrutura sem ter pedido por isso: retornar uma cl
* Escalares, listas, tuplas e uniões são envolvidos em `{"result": ...}`. Modelos, `TypedDict`s, dataclasses, classes anotadas e `dict[str, ...]` já são objetos e ficam como estão.
* Todo resultado carrega `content` (texto, para o modelo) **e** `structured_content` (dados, para a aplicação).
* O que você retorna é validado contra o schema. Uma divergência vira um erro de ferramenta, não um resultado corrompido.
* `structured_output=False` deixa uma ferramenta de fora. Uma classe sem anotações de tipo fica de fora em silêncio; fique atento a isso.
* `structured_output=False` deixa uma ferramenta de fora. Blocos de conteúdo, `Image` e `Audio` ficam de fora por padrão; uma classe sem anotações de tipo fica de fora em silêncio, então fique atento a isso.
Agora você domina tudo o que uma ferramenta pode dizer de volta. A seguir, a segunda primitiva: **[Recursos](resources.md)**.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [e4cc390d56573409, 8566e2b68594e9ad, 2c97b9f888398951, 048e5471dfa71aea, 3076b1e16ad95950, edbedf2a16e71311, 3d8ef8da89fa87c1, f6c0e02e6ea5a363]
sections: [e4cc390d56573409, f30cf8103a6e918c, 2c97b9f888398951, 048e5471dfa71aea, 3076b1e16ad95950, edbedf2a16e71311, 3d8ef8da89fa87c1, f6c0e02e6ea5a363]
tool: 1
---
# Ferramentas {#tools}
@ -39,6 +39,8 @@ A partir dessas anotações de tipo, o SDK gera um JSON Schema e o envia ao clie
Os dois argumentos estão em `required` porque nenhum deles tem valor padrão. Você vai resolver isso daqui a pouco. (As chaves `title` são artefatos do Pydantic; as propriedades, seus tipos e `required` são o contrato.)
Também não há chave `$schema`: o MCP trata um schema sem ela como **JSON Schema 2020-12**, que é o que o Pydantic gera. Então não há nada para escolher até você escrever schemas à mão no **[Server de baixo nível](../advanced/low-level-server.md#the-dialect-is-json-schema-2020-12)**.
!!! tip
Aqui, as anotações de tipo não são documentação. Elas são **o contrato**. Se um cliente enviar `"limit": "ten"`,
o SDK rejeita isso antes mesmo de a sua função executar.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [4a7033e1ed8ad602, 55dcbfff0c6271bf, 101ef9d14bf4ec46, 4b6c4a845438abc7, f98b46bafbee4acd]
sections: [4a7033e1ed8ad602, 55dcbfff0c6271bf, 317f4256a650cab6, 4b6c4a845438abc7, f98b46bafbee4acd]
tool: 1
---
# Templates de URI e segurança de caminhos {#uri-templates-and-path-safety}
@ -174,7 +174,7 @@ conhecer o limite do seu sandbox. Para acesso ao sistema de arquivos,
use `safe_join` para resolver o caminho e verificar que ele continua
dentro do seu diretório base:
```python title="server.py" hl_lines="4 14"
```python title="server.py" hl_lines="5 15"
--8<-- "docs_src/uri_templates/tutorial002.py"
```
@ -216,9 +216,10 @@ de arquivos, `safe_join` continua sendo a fronteira de contenção.
!!! tip
Se o seu handler não consegue atender à requisição (o arquivo não
existe, o id é desconhecido), levante uma exceção. O SDK a transforma
em uma resposta de erro. Veja **[Tratamento de erros](handling-errors.md)** para a
diferença entre um erro de protocolo e um erro de ferramenta.
existe, o id é desconhecido), levante `ResourceNotFoundError`, como
`read_manual` faz acima. O cliente recebe `-32602` com a sua mensagem
e a URI. Já uma exceção inesperada vira um `-32603` genérico. Veja
**[Tratamento de erros](handling-errors.md#a-resource-that-doesnt-exist)**.
## Recursos no Server de baixo nível {#resources-on-the-low-level-server}