Frameworks de agente
Conecte um agente feito com LangGraph, ADK ou código próprio, do arquivo da chave à primeira tool call conferida.
Um agente feito com LangGraph, ADK ou Python puro chega às tools por clients MCP. Para que cada tool call passe pela nossa verificação, aponte esses clients para as MCP URLs que entregamos e envie o nosso access token no header Authorization. O framework continua igual: mudam só o endereço e o header.
Esta página vai da configuração no Admin até a primeira chamada conferida.
O que o administrador prepara
A configuração acontece no Admin, muitas vezes feita por outra pessoa, nesta ordem:
- Um provedor de identidade está conectado, para verificarmos a pessoa por quem o agente age.
- Cada MCP server que o agente usa está registrado, com as tools revisadas (Servers do cliente, Revisão de tools).
- O agente existe, com as pessoas ou serviços que delegam a ele e as tools que pode chamar, e o acesso está publicado (Criar um agente).
Depois disso, quem desenvolve recebe três coisas:
- O arquivo da chave,
<agent>.chokepoint.json. Ele sai de Generate key and download, na aba Identity do agente (Identidade do agente). O arquivo guarda a chave privada do agente; mantenha-o num cofre de segredos. - A MCP URL de cada server, listada na mesma aba em MCP URL for developers, no formato
<origin>/api/v1/mcp/<workspace>/<ambiente>/<server_id>. - O token da pessoa para quem o agente trabalha. O seu provedor de identidade emite esse token no login da pessoa na sua aplicação. Um job sem pessoa usa o token de uma service account que delega ao agente (Quem pode delegar).
Obter o access token
O agente não manda o token do provedor de identidade para as tools. Ele troca esse token pelo nosso e assina o pedido com a chave do arquivo: um token exchange OAuth (RFC 8693) autenticado por uma client assertion assinada (RFC 7523). Em Python, com requests e pyjwt[crypto]:
import json, time, uuid
import jwt
import requests
agent = json.load(open("issues-agent.chokepoint.json"))
def exchange_token(person_token: str) -> str:
now = int(time.time())
assertion = jwt.encode(
{"iss": agent["client_id"], "sub": agent["client_id"], "aud": agent["token_endpoint"],
"jti": str(uuid.uuid4()), "iat": now, "exp": now + 60},
jwt.PyJWK(agent["private_key"]).key,
algorithm="ES256",
headers={"kid": agent["kid"]},
)
response = requests.post(agent["token_endpoint"], data={
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token": person_token,
"subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
"client_id": agent["client_id"],
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
})
response.raise_for_status()
return response.json()["access_token"]Cada assertion precisa de um jti novo: um jti repetido é recusado. O access token dura no máximo 5 minutos.
Um exchange recusado responde invalid_client quando a chave não corresponde ao agente, e invalid_grant quando o token da pessoa é inválido ou expirou, ou quando a pessoa não delega ao agente. O error_description traz um código Reference. A resposta nunca diz o motivo; o administrador cola o código no Quick incident para ver a causa. Integrar o agente descreve cada campo do exchange.
Carregar as tools
O access token vai no header de cada conexão MCP. Um agente com vários servers abre uma conexão por server, cada uma com a sua URL e o mesmo token.
LangGraph
O LangGraph carrega tools MCP com o langchain-mcp-adapters:
from langchain_mcp_adapters.client import MultiServerMCPClient
token = exchange_token(person_token)
client = MultiServerMCPClient({
"issues": {
"transport": "streamable_http",
"url": "<MCP URL do server issues>",
"headers": {"Authorization": f"Bearer {token}"},
},
})
tools = await client.get_tools()A lista tools entra no grafo como qualquer outra tool do LangChain.
ADK
O ADK carrega tools MCP com o McpToolset:
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
token = exchange_token(person_token)
issues = McpToolset(connection_params=StreamableHTTPConnectionParams(
url="<MCP URL do server issues>",
headers={"Authorization": f"Bearer {token}"},
))
agent = LlmAgent(model="<model>", name="issues_agent", tools=[issues])Tools que rodam dentro do agente
Uma tool escrita no código do próprio agente, como uma função @tool no LangGraph ou uma function tool no ADK, roda no processo do agente e nunca atravessa uma conexão MCP. Por isso não temos como conferi-la. O mesmo vale para um MCP server que o agente chama no endereço original, sem a URL que entregamos.
Para colocar uma tool assim sob controle, mova-a para um MCP server seu:
- Escreva a tool num server FastMCP que valida o nosso token (Validar o token).
- Registre o server no Admin como server do cliente e revise as tools.
- Carregue o server no agente como os outros, pela MCP URL dele.
A partir daí a tool só roda depois que a chamada é permitida, e o token que ela recebe informa a pessoa (sub) e o agente (act.sub).
Execuções longas e chamadas negadas
Os exemplos definem o token uma vez, ao criar o client MCP. Uma execução de mais de 5 minutos precisa de um novo exchange e de um novo client.
Uma tool call negada volta como erro JSON-RPC, com a mensagem Access denied. Reference <code>. e o código em data.reference. Trate o erro como resposta, não como falha de rede, e registre o código no log (As tool calls).