Criando Agents Customizados: do subagent ao MCP
Gerenciar agents é metade do jogo. A outra metade é criar os seus próprios: subagents especializados que seu time usa todo dia, MCP servers que conectam seu sistema a qualquer agent compatível, e uma biblioteca interna de agents que reduz o custo marginal de automação perto de zero. Neste módulo, construímos exemplos reais — não demos.
Três formas de criar um agent
| Forma | O que é | Quando usar |
|---|---|---|
| Subagent | Agent definido em arquivo (.md com frontmatter) invocado por agent principal | Tarefa repetida no time: review, research, test writing |
| MCP server | Servidor stdio/HTTP que expõe tools/resources/prompts | Conectar agent a sistema externo (Jira, GitHub, DB, API interna) |
| SDK custom | Agent programático usando Anthropic SDK / Agent SDK | Produto ou pipeline onde agent é parte do código, não do editor |
Subagent: anatomia (Claude Code)
Um subagent no Claude Code vive em .claude/agents/<nome>.md (por projeto) ou em ~/.claude/agents/ (global). Frontmatter declara metadados; corpo é o system prompt.
---
name: security-review
description: >
Use para revisar PRs com foco em vulnerabilidades e supply chain.
Invoque proativamente antes de merges em módulos de auth, pagamento ou IO externo.
model: sonnet
tools:
- Read
- Grep
- Glob
- Bash
---
# Security Review Agent
Você é revisor de segurança sênior. Seu trabalho é revisar um conjunto
de mudanças (diff ou PR) e produzir um relatório curto e acionável.
## Missão
Encontrar: (a) vulnerabilidades classe OWASP Top 10 (injection, authz,
broken auth, IDOR, XSS, SSRF, deserialization); (b) secrets vazados;
(c) dependência suspeita (typosquat, sem manutenção, fork malicioso);
(d) pattern anti-security (shell=True, eval, pickle de input externo,
subprocess com input não sanitizado).
## Método
1. Leia o diff/PR completo antes de comentar.
2. Para cada arquivo tocado, considere: entrada do usuário? sanitização?
output encoding? uso de crypto? I/O com sistema?
3. Procure strings suspeitas: "password", "token", "secret",
"private_key" em código (não em .env ou vault ref).
4. Verifique dependências adicionadas em package.json/requirements.txt:
autor, última versão, popularidade.
5. Produza um relatório: [CRITICAL/HIGH/MEDIUM/LOW] arquivo:linha -
descrição e mitigação.
## Regras
- Seja específico: aponte linha e trecho.
- Se não achar nada, diga com convicção.
- Não re-analise código não tocado pelo PR.
- Nunca rode comando destrutivo.
## Saída esperada
Relatório em Markdown: resumo executivo + lista de achados por severidade.Por que funciona. (1) Nome e descrição deixam o agent principal saber quando invocar. (2) Model declara qual modelo usar — Haiku pra tarefas leves, Sonnet pra balanço, Opus pra raciocínio pesado. (3) Tools restringem capacidades (read-only aqui — não precisa escrever). (4) System prompt é curto, focado e termina com formato de saída claro.
Subagent de pesquisa (paralelo e ágil)
---
name: research
description: >
Explore o repositório para responder perguntas técnicas.
Ótimo para "como funciona X?", "onde é Y definido?", "quais impactos de mudar Z?".
model: haiku
tools:
- Read
- Grep
- Glob
---
# Research Agent
Você é um explorador de código. Sua missão é entender partes do
repositório e retornar SUMÁRIOS CURTOS ao invés de arquivos completos.
## Método
1. Planeje 2-3 queries Grep/Glob antes de abrir arquivo.
2. Abra só os arquivos relevantes (não leia tudo).
3. Para cada arquivo, cite caminho e linhas específicas.
4. Seu output final deve ter <= 400 palavras.
## Formato da resposta
- Resposta direta (1 parágrafo)
- Evidências (bullet list com file.ts:LL)
- Próximos passos sugeridos (opcional)
## Nunca
- Listar arquivo inteiro sem necessidade.
- Responder "li tudo" sem evidência.
- Sair da pergunta do orquestrador.Como agent principal invoca subagents
MCP: protocolo de ferramentas
MCP padroniza como modelos conectam a sistemas externos. Um MCP server expõe tools (funções chamáveis), resources (dados consultáveis) e prompts (templates). Qualquer agent compatível (Claude Code, Claude.ai, Cursor, VS Code com plugin) consome o mesmo server.
MCP server mínimo em Node/TypeScript
// mcp-jira-server.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
const server = new Server(
{ text: 'jira-bridge', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'get_issue',
description: 'Recupera uma issue do Jira por chave (ex: INGEST-123).',
inputSchema: {
type: 'object',
properties: {
key: { type: 'string', description: 'Chave da issue' },
},
required: ['key'],
},
},
{
name: 'list_sprint_issues',
description: 'Lista issues do sprint ativo de um board.',
inputSchema: {
type: 'object',
properties: {
boardId: { type: 'number' },
},
required: ['boardId'],
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (req) => {
const { name, arguments: args } = req.params;
if (name === 'get_issue') {
const res = await fetch(`${process.env.JIRA_URL}/rest/api/3/issue/${args.key}`, {
headers: {
Authorization: `Bearer ${process.env.JIRA_TOKEN}`,
Accept: 'application/json',
},
});
if (!res.ok) {
return { content: [{ type: 'text', text: `Erro: ${res.status}` }], isError: true };
}
const data = await res.json();
return {
content: [{ type: 'text', text: JSON.stringify({
key: data.key,
summary: data.fields.summary,
status: data.fields.status.name,
assignee: data.fields.assignee?.displayName ?? 'unassigned',
description: data.fields.description,
}, null, 2) }],
};
}
if (name === 'list_sprint_issues') {
// ... lógica análoga
}
return { content: [{ type: 'text', text: 'Tool não encontrada' }], isError: true };
});
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('jira-bridge MCP server running');# package.json
{
"name": "mcp-jira-server",
"bin": { "mcp-jira": "dist/mcp-jira-server.js" },
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0"
}
}
# Build e registro no agent
npm run build
# Em .claude/mcp.json ou ~/.claude/mcp_settings.json
{
"mcpServers": {
"jira": {
"command": "node",
"args": ["/path/mcp-jira-server/dist/mcp-jira-server.js"],
"env": {
"JIRA_URL": "https://empresa.atlassian.net",
"JIRA_TOKEN": "${JIRA_TOKEN}"
}
}
}
}MCP na prática: um agente que fecha PR com issue
Com MCP Jira + MCP GitHub (oficial), o agent faz sozinho:
- 1. Usuário: “Resolve INGEST-123”.
- 2. Agent chama → lê título, descrição, critério de aceite.
- 3. Research subagent mapeia arquivos relevantes.
- 4. Agent implementa, escreve testes, abre PR via MCP GitHub ().
- 5. Agent atualiza issue no Jira () com link do PR.
- 6. Humano revisa PR em 10 min — foca no que importa.
Agent via SDK (programático)
Quando o agent é parte do seu produto (não do editor), use o SDK. Exemplo com o Anthropic SDK em TypeScript:
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
const tools = [
{
name: 'get_order',
description: 'Retorna detalhes de um pedido.',
input_schema: {
type: 'object',
properties: { orderId: { type: 'string' } },
required: ['orderId'],
},
},
{
name: 'refund_order',
description: 'Reembolsa pedido. Requer confirmação humana antes de chamar.',
input_schema: {
type: 'object',
properties: {
orderId: { type: 'string' },
amount: { type: 'number' },
},
required: ['orderId', 'amount'],
},
},
];
async function runAgent(userMessage: string) {
const messages: Anthropic.MessageParam[] = [
{ role: 'user', content: userMessage },
];
while (true) {
const res = await client.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 2048,
tools,
messages,
});
messages.push({ role: 'assistant', content: res.content });
if (res.stop_reason === 'end_turn') return res.content;
if (res.stop_reason === 'tool_use') {
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of res.content) {
if (block.type !== 'tool_use') continue;
// Gate humano em ações destrutivas
if (block.name === 'refund_order') {
const ok = await askHumanApproval(block.input);
if (!ok) {
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: 'Reembolso negado pelo humano.',
is_error: true,
});
continue;
}
}
const result = await executeTool(block.name, block.input);
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: JSON.stringify(result),
});
}
messages.push({ role: 'user', content: toolResults });
}
}
}Sandbox e ciclo de vida
Bibliotecas de agents: como o time escala
Times maduros constroem um catálogo interno. Um repo ou pasta no monorepo com:
infra/agents/
├── agents/
│ ├── security-review.md # subagent para PR review
│ ├── research.md # exploração rápida
│ ├── architect.md # design de feature
│ ├── test-writer.md # escreve testes
│ ├── migration-executor.md # migrations SQL seguras
│ └── runbook-responder.md # responde incident seguindo runbook
├── mcp-servers/
│ ├── jira-bridge/ # MCP server de Jira
│ ├── sentry-bridge/ # MCP server de Sentry (ler erros prod)
│ ├── grafana-bridge/ # consulta dashboards
│ └── feature-flag-bridge/ # GrowthBook toggle
├── policies/
│ ├── CLAUDE.md # regras globais para agents
│ └── security-policy.md # o que nunca fazer
└── README.md # como usarEfeito. Onboarding de novo dev dobra de velocidade: agent já entende o repo, já sabe abrir PR do jeito certo, já tem runbook de incidente conectado. “Como faço X aqui?” vira “qual agent uso?”.
Dois cenários reais
📋 Time faz ~40 PRs/semana e review de segurança atrasa tudo
Subagent roda no PR quando há arquivos sensíveis (auth, pagamento, IO). Publica comentário com findings. Reviewer humano focaliza nos HIGH/CRITICAL. PRs sem finding mergeiam mais rápido.
📋 Product quer que IA abra tickets completos a partir de feedback de cliente no Intercom
Pipeline programático (não agent de editor). Agent lê ticket, gera spec, cria issue no Jira, abre PR draft com esqueleto. Humano ajusta.
Alt: Só subagent —
Perguntas típicas
❓ Diferença entre subagent e MCP?
❓ Preciso hospedar MCP server em algum lugar?
❓ Posso rodar agent 100% offline?
❓ Quantos subagents é demais?
❓ Como versiono agents?
Take-aways. (1) Subagent = especialista. Prompt curto + tools mínimas + modelo barato quando cabe. (2) MCP = USB-C dos LLMs. Escreva 1 server, use em todo agent compatível. (3) SDK quando agent vira produto. (4) Sandbox e permissões não são opcionais. (5) Catálogo interno de agents multiplica produtividade do time. (6) Próxima trilha: testes profissionais que dão rede para agent e humano.
Próximos passos sugeridos
Discussão
Carregando…