Phase 13: Tools & Protocols

Contratos e conteúdo das ferramentas de MCP

Uma ferramenta é segura para automatizar apenas quando a descoberta, os argumentos, os resultados, a paginagem e o transporte de metadados concordam em um contrato.

Type: Build

Languages: Python

Prerequisites: Phase 13, Lessons 07, 09, and 10

Time: ~120 minutes

Objetivos de aprendizagem

  • Defina as entradas e saídas das ferramentas com JSON Schema 2020-12.
  • Validar resultados estruturados sem supor que sejam objetos JSON.
  • Escolha entre texto, imagem, áudio, links de recursos e recursos incorporados.
  • Rejeitar inseguros .x-mcp-headerdefinições antes de uma ferramenta chegar ao modelo.
  • Encodear valores de parâmetro-título e verificar a paridade exata de cabeçalho-corpo.
  • Paginação do cursor transversal sem interpretar os valores do cursor.
  • Dependência e autorizaçãocompletion/completeSugestões.

O problema

Chamando uma função Python é fácil. Chamando uma capacidade remota através de um host de IA é um problema de contrato.

O servidor publica um descritivo. O cliente transforma esse descritivo em contexto de modelo e interface de usuário. O modelo cria argumentos. Um gateway pode encaminhar a solicitação de cabeçalhos espelhados. O servidor executa a ferramenta. O cliente decide se o resultado é seguro e válido o suficiente para retornar ao modelo.

Uma fronteira fraca corrompe toda a cadeia.

Consideremos cinco falhas:

  • O descritivo diz que o resultado é um objeto, mas o servidor retorna uma matriz.
  • O cliente deixa de fazer páginas quando nextCursorÉ uma corda vazia.
  • Um parâmetro de token é espelhado em um cabeçalho HTTP e torna-se visível aos intermediários.
  • Um valor de roteamento Unicode é enviado como um cabeçalho bruto, então o gateway e a origem interpretam diferentes bytes.
  • Um ponto final de conclusão sugere um ambiente de produção para um telefonista que não pode acessá-lo.

Nenhuma destas falhas é corrigida por um melhor incentivo, pois exigem contratos explícitos de protocolo e aplicação.

O gasoduto de contrato

Trata cada chamada de ferramenta como cinco portas:

  1. Discover.Leia uma lista determinista de ferramentas.
  2. Admit.Validar cada descriptório e aplicar a política de segurança local.
  3. Invoke.Validar argumentos e criar metadados de transporte.
  4. Execute.Execute o manual e classifique as falhas corretamente.
  5. Consume.Validar os blocos de conteúdo e as saídas estruturadas antes da utilização do modelo.

O host é o proprietário dos portões de entrada e consumo. Um servidor não pode forçar um cliente a confiar em suas anotações, esquemas ou saídas.

JSON Schema é um limite de tempo de execução

Em MCP 2026-07-28- Não .inputSchemaE ...outputSchemausar JSON Schema. Quando $schemaNão existe, o dialeto padrão é 2020-12.

O esquema de entrada deve ser um objeto de esquema. Uma ferramenta sem argumentos deve ainda dizer exatamente o que aceita:

json{
  "type": "object",
  "additionalProperties": false
}

Isto é mais rigoroso do que ...{ "type": "object" }, que aceita propriedades arbitrárias.

Um esquema de saída é opcional. Uma vez que um servidor publica um, cada ferramenta completa

Resultado compromete-se a retornar conforme structuredContent, incluindo os resultados

comisError: true. A bandeira de erro classifica o resultado da execução; não

O contrato de saída publicado deve ser revogado pelo cliente.

de confiar no descrito.

Conteúdo estruturado é qualquer valor JSON

Não codifique .structuredContentComo um dicionário.

  • um objeto;
  • uma matriz;
  • uma corda;
  • um número;
  • um booleano;
  • null- Não .

Esta ferramenta retorna uma matriz:

json{
  "name": "tag_catalog",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false
  },
  "outputSchema": {
    "type": "array",
    "items": {"type": "string"}
  }
}

O seu resultado bem sucedido é válido:

json{
  "resultType": "complete",
  "content": [
    {
      "type": "text",
      "text": "[\"contracts\", \"mcp\", \"stateless\"]"
    }
  ],
  "structuredContent": ["contracts", "mcp", "stateless"],
  "isError": false
}

Para compatibilidade, os resultados estruturados também devem incluir JSON serializado em um bloco de texto. O texto não é a fonte de validação. structuredContent- Não, não.

Um pequeno validador ainda ensina a fronteira

A lição usa um subconjunto deliberado de JSON Schema porque fica dentro da biblioteca padrão Python.

  • Tipo de objeto, matriz, cadeia, número inteiro, número, booleano e zero;
  • Propriedades exigidas;
  • additionalProperties: falseO artigo 2.o
  • elementos de matriz;
  • Valores enum;
  • comprimento mínimo da corda.

A lição reutiliável é onde a validação ocorre: após a descoberta dos descritivos, antes da execução dos argumentos e antes do consumo para resultados estruturados.

Os blocos de conteúdo têm custos diferentes

O contentA matriz pode combinar vários tipos de conteúdo.

TypeUse it forMain boundary
textHuman and model-readable summariesTreat text as untrusted output
imageVisual evidence encoded as base64Validate media type and size
audioSpoken or recorded output encoded as base64Validate media type and duration limits
resource_linkA URI the client may fetch laterReauthorize the later resource read
resourceData embedded directly in the resultEnforce payload and content limits now

Um link de recurso não é prova de que o recurso aparece em resources/listO cliente ainda aplica a sua política de recursos quando segue o URI.

Um recurso embucado evita outra viagem de ida e volta, mas aumenta o tamanho da resposta atual. Use links para artefatos grandes ou que mudam de forma independente. Use recursos embutidos para pequenas evidências que devem viajar atômicamente com o resultado.

A lição é:evidence_bundleO cliente valida cada bloco antes de aceitar o resultado.

x-mcp-headerEstá encaminhando metadados

Uma propriedade lá dentro .inputSchemapode declarar x-mcp-header. Em Streamable HTTP, o cliente reflete esse argumento em Mcp-Param-{name}- Não .

json{
  "region": {
    "type": "string",
    "x-mcp-header": "Region"
  }
}

Com oregion: "eu-west", o transporte pode emitir:

httpMcp-Param-Region: eu-west

A anotação existe para que um balanceador de carga, gateway ou motor de política possa encaminhar sem analisar o corpo JSON.

O protocolo limita a anotação:

  • O nome do cabeçalho não é vazio e segue a sintaxe do token de nome de campo HTTP;
  • Os nomes dos cabeçalhos são únicos, independentemente do caso;
  • O tipo de propriedade é string, inteiro ou booleano;
  • numberNão é permitido;
  • A anotação aparece apenas num membro direto de inputSchema.propertiesO artigo 2.o
  • Os valores inteiros permanecem dentro de -9007199254740991através de9007199254740991- Não .

A regra de localização é sintática e fechada.

Não apenas as propriedades que o seu validador entende.

anotação sob o objeto aninhado properties, a oneOframo, items, a

definição alcançada por $refResolver uma referência faz

Não transformar o nó referenciado em uma propriedade direta de nível superior.

Esta lição acrescenta uma política de implantação: rejeitar descriptórios que refletem nomes como password- Não .secret- Não .token- Não .api_key, ou authorizationA especificação oficial aconselha os autores do servidor a não refletir parâmetros sensíveis.

Verifique o nome da cabeçalha, não o seu valor.Mcp-Param-Region- Sim .eu-westfora do evento de auditoria.

Valores de codificação antes de criar cabeçalhos HTTP

Um valor de parâmetro só pode viajar como texto plano quando é uma cadeia não vazia

de caracteres ASCII visíveis de !através de~e não se assemelha ao

Tudo o resto usa esta forma exata:

text=?base64?{Base64UTF8}?=

Base64UTF8É base 64 padrão sobre os bytes UTF-8 exatos. Não cortar,

Encode Unicode, cadeias vazias, espaços,

Os elementos de controlo devem ser identificados em conformidade com o artigo 10.o, n.o 1, do Regulamento (UE) n.o 1095/2011.

Valor a partir de =?base64?Encoder um valor que parece sentinela novamente é

o que permite ao receptor recuperar o texto original literal em vez de decodificar

  • Como uma sintaxe de transporte.

Booleans traduzir como minúsculas trueou false- Inteiros em base 10 e

deve permanecer dentro da faixa inteira segura do JavaScript. Valores fora dessa faixa

são rejeitadas em vez de arredondadas por um intermediário.

O servidor verifica a cópia espelhada

A geração de cabeçalhos é apenas a metade do cliente.

O servidor deve:

  1. Encontrar reconhecido .Mcp-Param-*Nomes sem consideração do caso de cabeçalho-nome;
  2. Decodificar a forma exacta base64 sentinela quando presente;
  3. Compare exatamente o texto decodificado com o argumento corpóreo JSON correspondente;
  4. rejeitar uma falta, duplicação, inesperada, malformada ou incompatível

- O cabeçalho reconhecido antes do envio.

A rejeição é HTTP 400com código de erro JSON-RPC -32020Nem o

O valor do corpo nem a forma do cabeçalho codificado pertencem ao registo de auditoria.

apenas o nome do cabeçalho reconhecido e a categoria de rejeição.

code/main.pyModela este limite diretamente. Lesson 09

abrange a ordem de validação HTTP Streamable mais ampla, incluindo o método e

Paridade de protocolo versão.

Os curadores de páginas são opacos

As operações de lista MCP usam pagination do cursor. O servidor seleciona o tamanho da página e formato do cursor. O cliente recebe uma decisão:

pythonif result.get("nextCursor") is None:
    break
cursor = result["nextCursor"]

Não escreva isto:

pythonif not result.get("nextCursor"):
    break

Uma cadeia vazia é um cursor válido.

Os clientes não devem decodificar um cursor, incrementá-lo, compará-lo com um cursor anterior para encomendar ou inferir um número de página. Um servidor pode assinar um cursor, ligá-lo a uma versão de catálogo ou mapeá-lo para estado privado. Esse é o detalhe de implementação do servidor.

O servidor de amostra retorna deliberadamente ""O cliente deve enviar esse valor exato na segunda solicitação.

text<first request with no cursor>
<second request with cursor "">

Cursores inválidos produzem parâmetros inválidos JSON-RPC, código -32602- Não .

A conclusão é uma superfície autorizada

completion/completeO sistema de listagem de recursos é útil para formulários interativos, mas pode filtrar nomes que os métodos de listagem comuns protegem.

Um pedido de conclusão indica uma referência e o argumento a ser concluído:

json{
  "method": "completion/complete",
  "params": {
    "ref": {
      "type": "ref/prompt",
      "name": "deployment_review"
    },
    "argument": {
      "name": "environment",
      "value": "st"
    }
  }
}

O resultado retorna no máximo 100 valores e pode relatar total- E mais .hasMore- Não .

Aplicar o mesmo limite de autorização utilizado pelo prompt ou recurso referenciado.developmentE ...stagingSó um operador pode receber .production- Não .

A conclusão da produção também requer:

  • A validação de entrada;
  • Filtragem de informação para o telefonista;
  • Solicitar desaconselho no cliente;
  • Limitação de taxa no servidor;
  • Contas de resultados limitados;
  • registos que não exporem valores sensíveis de sugestão.

A conclusão é assistência, não descoberta de contorno.

Duas camadas de erro

Mantenha os erros de protocolo separados dos erros de execução da ferramenta.

Utilize um erro JSON-RPC quando a solicitação MCP não pode ser enviada corretamente:

  • Nome desconhecido da ferramenta;
  • Forma de pedido malformada;
  • Os metadados do pedido faltantes;
  • Cursor inválido.

Use um resultado completo de ferramenta com isError: trueQuando a invocação chegar à ferramenta e a ferramenta relatar uma falha a ser aplicada:

  • Não está disponível uma fonte de relatório;
  • Uma data está fora do intervalo suportado;
  • Uma regra empresarial rejeita a operação solicitada.

Os modelos podem muitas vezes reparar um erro de execução da ferramenta. Eles não podem reparar um servidor que violeu seu próprio esquema de saída.

Se a ferramenta declarar um esquema de saída, modelar uma falha acionável dentro desse

O esquema.route_reportA falha retorna a região solicitada com

accepted: false, ao lado de texto de erro legível por humanos e isError: true- Não .

Construí-lo

code/main.pyconstrui ambos os lados da fronteira com a biblioteca padrão Python.

O servidor implementa:

  • Avalidação de metadados do MCP por pedido;
  • server/discoverCom ferramentas e capacidades de conclusão;
  • Deterministatools/listPaginação;
  • Quatro descrições de ferramentas, incluindo uma que deve ser rejeitada;
  • saída estruturada de matriz;
  • Todos os tipos de blocos de conteúdo atuais da ferramenta;
  • um portal de paridade HTTP streamable que decodifica cabeçalhos de parâmetros reconhecidos e

retorna HTTP 400+ JSON-RPC -32020em caso de desajuste;

  • A conclusão autorizada e limitada.

O cliente implementa:

  • Admissão de descriptórios;
  • árvore cheiax-mcp-headerA validação da colocação e a política de campo sensível;
  • A codificação exacta do valor ASCII ou base64 UTF-8 de forma simples e visível;
  • um circuito de cursor opaco que segue uma cadeia vazia;
  • A validação de argumentos e resultados;
  • Avalidação do bloco de conteúdo;
  • Eventos de auditoria de cabeçalhos que contenham nomes, mas não valores.

O descritivo deliberadamente inseguro é o ensino de dados.

Usá-lo

A partir da raiz do repositório:

bashcd phases/13-tools-and-protocols/28-mcp-tool-contracts-and-content/code
python3 main.py
python3 -m unittest discover tests -v

As impressões demo admitidas ferramentas, o descrito rejeitado, ambos pagination

Requisitos, conteúdo estruturado de matriz, tipos de blocos de conteúdo, cabeçalho espelhado

nomes, quer seja o valor exigido de codificação, o status de paridade HTTP, e

Valores de conclusão filtrados pelo chamador.

Laboratório Interativo

Abre .code/main.pye localizaçãoTOOLS- Não .

  1. Mudança .tag_catalog.outputSchema.typedearray- Não .object- Não .
  2. A demo deve ser executada, o cliente deve rejeitar o array devolvido.
  3. Restaurar o esquema.
  4. Mantenha a primeira página.nextCursorComo "", então fazer a última página de volta

nextCursor: NoneEm vez de omitir o campo.

  1. Faça os testes e compare o rastro do cursor.
  2. Adicionarx-mcp-header: "Authorization"para uma propriedade de corda.
  3. A admissão do descrito de confirmação o rejeita antes da invocação.
  4. Tente .regionvalores que contenham Unicode, uma linha nova, espaços circundantes e

O texto literal =?base64?SGVsbG8=?=Decodificar cada cabeçalho emitido e provar

O valor original sobrevive exatamente.

  1. Mover a anotação para baixo oneOf- Não .items, ou um $refDefinição.

Cada descriptor é rejeitado mesmo que esse ramo nunca seja usado pela demonstração.

  1. Remova o cabeçalho reconhecido ou altere o seu valor decodificado.

status dos retornos de limites 400e código JSON-RPC -32020- Não .

O ponto não é memorizar uma forma JSON, é ver cada porta falhar na fronteira que a possui.

Laboratório de Prática

Expandir o laboratório de contrato com umsearch_evidence- Uma ferramenta.

Requisitos:

  1. O seu esquema de entrada aceita query- Não .limit, e um cofre .regionCampo de roteamento.
  2. O seu esquema de saída é uma matriz de objetos com uri- Não .title, e score- Não .
  3. O resultado inclui texto de compatibilidade e um link de recursos por item.
  4. Os argumentos rejeitam propriedades desconhecidas.
  5. limité limitada pela validação do pedido.
  6. Um chamador sem acesso a um URI nunca vê esse URI através da conclusão ou saída da ferramenta.
  7. Os testes incluem uma pontuação não conforme, uma anotação de cabeçalho inválida e uma lista de duas páginas.
  8. Os testes de valor de cabeçalho abrangem os caracteres visíveis ASCII, Unicode, controles,

espaço em branco, texto semelhante a sentinela, e ambos os limites inteiros seguros para JavaScript.

  1. O dispositivo HTTP aceita nomes de cabeçalhos insensiveis para casos, mas rejeita falta

ou valores reconhecidos incompatíveis com status 400e código -32020- Não .

Artigo enviado

outputs/skill-mcp-contract-reviewer.mdÉ uma habilidade de revisão plana e reutilizável. Dê-lhe um descrito de ferramenta, resultados de amostra, comportamento de pagination e política de conclusão. Retorna uma decisão de admissão, plano de validação de resultados, política de cabeçalho e testes de falha concretos.

Verifique

A lição é completa quando estas declarações são verdadeiras:

  • tools/listRetorna a mesma ordem lógica em chamadas repetidas.
  • O cliente realiza um segundo pedido quando nextCursorÉ o que é""- Não .
  • O descritivo de cabeçalhos sensíveis inseguros é excluído, enquanto restam disponíveis outras ferramentas.
  • Uma matriz passa o esquema de saída da matriz.
  • Um objeto falha no mesmo esquema de matriz.
  • Os resultados de erro não podem omitir ou violar um esquema de saída publicado.
  • O texto, imagem, áudio, link de recurso e blocos de recursos incorporados validam.
  • Os eventos de auditoria de cabeçalhos contêm nomes e não valores.
  • ASCII simples visível permanece simples; Unicode, controle, enchido, vazio e

Valores sentinela-parecem viagem de ida e volta através base64 UTF-8 codificação exata.

  • Os números inteiros espelhados fora do alcance seguro do JavaScript são rejeitados.
  • Anotativas nooneOf- Não .items, objetos aninhados, $refdefinições, ou

Os regimes de saída são rejeitados durante a admissão.

  • Os nomes de cabeçalhos reconhecidos não sensíveis ao caso passam apenas quando o valor decodificado

correspondem exatamente ao corpo; cópias faltantes ou incompatíveis produzem HTTP 400

e JSON-RPC -32020- Não .

  • A conclusão do analista nunca volta .production- Não .
  • Uma falha de ferramenta utiliza isError: trueUma chamada de protocolo mal formada utiliza JSON-RPC error- Não .

Modos de falha de produção

FailureWhat the learner seesCorrect response
Client assumes object outputValid arrays fail or are silently wrappedValidate against the published schema without object-only types
Empty cursor treated as falseFinal pages disappearContinue whenever nextCursor is present and non-null
Sensitive value mirroredSecret appears in proxy, WAF, or trace dataReject the descriptor and keep secrets in protected request data
Raw Unicode or whitespace mirroredGateway and origin disagree or the value is normalizedUse exact base64 UTF-8 sentinel encoding and compare after decoding
Annotation hidden in a schema branchA client misses routing metadata during admissionTraverse the entire schema tree and allow only direct top-level properties
Large integer mirroredJavaScript intermediary rounds the routing valueReject values outside the JavaScript safe integer range
Header and body disagreeGateway routes one target while the origin executes anotherReject before dispatch with HTTP 400 and JSON-RPC -32020
Output schema ignoredDownstream code consumes corrupt structureValidate before model or application use
Resource link trusted automaticallyCaller follows an unauthorized URIReauthorize every resource read
Completion shares global suggestionsHidden tenant names leakFilter by caller, reference, and authorization
Tool annotations treated as policyDestructive operation bypasses confirmationEnforce authorization and approval outside annotations
One malformed tool breaks discoveryEntire server becomes unavailableReject the bad descriptor and admit valid tools independently

Conexão Capstone

A pedra final da Fase 13 precisa de um gateway que possa fundir ferramentas de vários servidores.

Usar o artefato para classificar quatro peças de evidências de pedra:

  • Descoberta determinista e completa em páginas;
  • A validação do descrito antes da exposição do modelo;
  • Output estruturado validado mais blocos de conteúdo limitados;
  • Completar e encaminhar metadados que preservam os limites de autorização.

Não reivindique a compatibilidade do gateway com um sucesso tools/callCapture o descriptor, o rastreamento de página, o conjunto de ferramentas admitidas, o conjunto de ferramentas rejeitadas e um resultado validado.

Termos-chave

TermMeaning
inputSchemaJSON Schema object defining accepted tool arguments
outputSchemaOptional JSON Schema defining structuredContent
structuredContentAny JSON value produced by a tool result
Content blockTyped text, image, audio, resource link, or embedded resource
x-mcp-headerSchema annotation that mirrors a primitive argument into Streamable HTTP metadata
Opaque cursorServer-issued pagination token whose value the client does not interpret
Completion referencePrompt name or resource URI/template whose argument is being completed
AdmissionClient decision to expose or reject a discovered descriptor

Mais leitura

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.