mcp-owl
v0.2.6
Published
MCP server for codebase navigation — explains symbols, traces execution flows, and searches references via AST parsing and LLM. Supports PHP and TypeScript projects.
Maintainers
Readme
A dor
Você pede ao Claude/Kimi/Cursor: "crie um plano para implementar uma nova feature complexa". O que acontece por baixo:
Sem MCP Owl: A AI cria subagentes que leem 25+ arquivos inteiros, fazem 23 grep, gastam 3-5M de tokens de contexto — e o resultado pode demorar 6 minutos mas funciona.
Com MCP Owl: A AI pergunta ao servidor "o que faz PaymentService.processCharge?" e recebe um resumo semântico de 200 tokens em vez de ler o arquivo de 1500 tokens. Em 12 perguntas dessas, monta o mesmo plano com 1.7M de contexto (-41%) e zero leitura de arquivo.
A qualidade do plano é a mesma. A diferença é que a AI trabalha com summaries inteligentes em vez de código bruto.
Como funciona
O MCP Owl é um braço para a LLM que o consome — ele não raciocina, não decide, não implementa. Quem raciocina é a AI (Claude, Kimi, DeepSeek). O MCP apenas:
- Explica — recebe o nome de uma classe ou método e devolve um resumo semântico compacto (propósito, dependências, side effects)
- Conecta — sugere classes e métodos relacionados que compartilham o mesmo contexto, ajudando a AI a montar o mapa completo sem ler dezenas de arquivos
A AI continua fazendo o trabalho pesado (interpretar a tarefa, raciocinar sobre impacto, montar o plano). O MCP só alimenta esse raciocínio com informação estruturada e comprimida.
Cache inteligente
O MCP Owl usa uma LLM barata como backend para gerar os summaries — nos benchmarks, DeepSeek Flash (~$0.001/request) funcionou bem, mas qualquer provider suportado serve (OpenAI, Claude, OpenRouter). Na segunda vez que alguém pergunta sobre o mesmo símbolo, a resposta vem do cache SQLite em <10ms, custo $0 — sem chamar nenhum LLM.
O cache sabe quando invalidar: se o arquivo foi editado (hash do código mudou), ele re-analisa automaticamente. Se não mudou, serve instantâneo. Progressivamente, quanto mais você usa, mais rápido fica:
- Sessão 1: 0% cache hit (tudo é novo)
- Sessão 3: ~44% cache hit
- Sessão 6+: ~100% cache hit — respostas instantâneas, custo zero
Num time de 5 devs usando a mesma codebase, o cache é compartilhado — o que um explorou beneficia todos.
Por que usar
| Cenário | O que acontece | Resultado | |---------|---------------|-----------| | Sem MCP | AI cria 1-4 sub-agentes, lê arquivos inteiros, duplica system prompts | 3-5M tokens contexto | | Com MCP (core) | API semântica no agente principal — sem sub-agentes, sem file reads | 1.7-2.5M tokens contexto |
Resumo cross-model
| Modelo | Economia de context tokens | Eliminação de file reads | Custo | |--------|---------------------------|--------------------------|-------| | Kimi-K2.6 | -64% (2.9x) | ✅ Sub-agentes eliminados | -52% | | Claude Sonnet 5 | -41% (core tools) | -94% (25→1.5 reads) | -30% context | | DeepSeek v4 Pro | -41% input | N/A (sem sub-agentes) | -40% |
Achado crítico: Habilitar todas as 12 tools é pior que sem MCP. Com apenas 7 core tools, a economia chega a 41-48%. Use
TOOLS_MODE=core(default).
Core Tools (recomendado: TOOLS_MODE=core)
| Tool | O que faz |
|------|-----------|
| get_explored_symbols | Retorna símbolos já analisados no cache + sugestões por co-ocorrência. Use no início de toda investigação. |
| explain_symbol | Localiza símbolo via AST + retorna explicação semântica estruturada (~400 tokens). |
| explain_symbols | Batch de explain_symbol (até 30 símbolos, processamento paralelo). |
| explain_flow | Mapeia cadeia completa de execução a partir de um entry point. Substitui 4-7 explain_symbol. |
| inspect_symbol | Retorna código raw de um símbolo (signature ou full_code). Zero LLM, instantâneo. |
| find_references | Busca reversa: quem importa/usa/chama um símbolo. Word boundary, retorna file+line+text. |
| search_text | Discovery por termo: quais arquivos mencionam um texto. Case-insensitive, retorna só file+count (max 15). |
{"symbol": "OrderService.create", "context": {"intention": "como sincroniza relações?"}, "detail_level": "intention_answer", "include_snippet": false, "follow_depth": 0}Documentação completa de todas as tools:
docs/TOOLS-REFERENCE.md
Quick Install
Via npm (recomendado)
npm install -g mcp-owlApós instalar, veja as instruções de configuração:
npx mcp-owl --helpAdicione ao mcp.json da sua IDE (Kiro, Claude Code, Cursor, etc.):
{
"mcpServers": {
"codebase": {
"command": "npx",
"args": ["-y", "mcp-owl"],
"env": {
"TARGET_PROJECT_PATH": "/caminho/do/seu/projeto",
"TARGET_LANGUAGE": "php",
"LLM_PRIMARY_PROVIDER": "deepseek",
"DEEPSEEK_ENABLED": "true",
"DEEPSEEK_API_KEY": "sk-sua-chave",
"DEFAULT_FRAMEWORK": "laravel",
"TOOLS_MODE": "core",
"LLM_CACHE_ENABLED": "true",
"AST_CACHE_ENABLED": "true",
"CO_OCCURRENCE_TRACKING_ENABLED": "true"
},
"autoApprove": ["explain_symbol", "explain_symbols", "explain_flow", "get_explored_symbols", "clear_cache", "warmup_provider"]
}
}
}Nota: Com
npx -y mcp-owl, a IDE baixa e executa automaticamente — não precisa de install global.
Via clone (desenvolvimento/contribuição)
git clone https://github.com/lucianopalhares/mcp-owl.git
cd mcp-owl
npm install
npm run build
npx mcp-owl --help # Exibe a configuração prontaNota sobre vulnerabilidades do npm audit
Ao instalar, o npm audit pode reportar vulnerabilidades em dependências transitivas (multer, body-parser, express, qs). Essas não afetam o MCP Owl porque:
- O servidor usa exclusivamente transporte STDIO (stdin/stdout) — não expõe nenhuma porta HTTP
- As dependências vulneráveis (express, multer) nunca são carregadas em runtime
- São arrastadas como
peerOptionalpelo@nestjs/coremas nunca importadas no código
Para eliminar completamente seria necessário migrar para NestJS 11+ (breaking change planejada para versão futura). Até lá, podem ser ignoradas com segurança.
Configuração por AI
⚠️ Importante: a Skill é obrigatória
Instalar o MCP não basta. A IA precisa de uma Skill — um documento que ensina COMO e QUANDO usar as tools do MCP Owl. Sem skill, a IA ignora o MCP e volta a ler arquivos inteiros.
A skill define regras como:
- "Nunca use
readem.phppara entender código — useexplain_symbol" - "Use
explain_symbols(batch) quando tiver 3+ símbolos" - "
found:false= classe nova a criar, não é motivo para grep" - "Dispare todas as tool calls independentes na mesma mensagem"
Sem a skill: a IA tem as ferramentas mas não sabe quando usá-las. Com a skill: ela segue o protocolo e a economia de tokens acontece de verdade.
Configuração referência: Claude Code (a mais testada)
A configuração do Claude Code em instructions/claude/ é a mais validada por benchmarks e inclui 3 componentes:
| Arquivo | Propósito |
|---------|-----------|
| .mcp.json | Registro do servidor MCP com env vars |
| .claude/skills/codebase/SKILL.md | Skill completa com workflow, regras e checklist |
| .claude/hooks/php_grep_guard.sh | Hook que bloqueia grep/find/cat em código PHP (enforcement mecânico) |
| .claude/settings.local.json | Configuração do hook PreToolUse |
Para usar com Claude Code, copie a pasta instructions/claude/ para a raiz do seu projeto:
# Após npm install -g mcp-owl:
cp -r $(npm root -g)/mcp-owl/instructions/claude/.claude /seu-projeto/
cp $(npm root -g)/mcp-owl/instructions/claude/.mcp.json /seu-projeto/Adaptando para outras IAs e linguagens
A skill do Claude (instructions/claude/.claude/skills/codebase/SKILL.md) é um template que pode ser adaptado para qualquer AI e linguagem. Os princípios são universais:
- Proibir leitura direta de código para "entender" — forçar uso de
explain_symbol - Priorizar batch (
explain_symbols) sobre chamadas sequenciais - Usar
explain_flowpara fluxos de execução (substitui 4-7 reads) - Aceitar
found:falsecomo definitivo (classe não existe, não insistir com grep) - Agrupar tool calls independentes na mesma mensagem (economia de turns)
Para TypeScript/Next.js/NestJS, ajuste a skill:
- Troque "
.php" por ".ts/.tsx" - Troque "grep em código PHP" por "grep em código TypeScript"
- O resto do protocolo é idêntico
Configurações disponíveis
| AI | Pasta | Conteúdo |
|----|-------|----------|
| Claude Code | instructions/claude/ | .mcp.json + skill + hook de enforcement |
| Kimi | instructions/kimi/ | Skill v1-v4 (use v4) |
| Kiro | instructions/kiro/ | Steering + mcp.json |
Veja
instructions/README.mdpara detalhes de cada IDE.
Configuração genérica (qualquer AI/IDE)
Substitua LLM_PRIMARY_PROVIDER e a respectiva API key pelo provider que preferir (DeepSeek, OpenAI, Claude, OpenRouter):
{
"mcpServers": {
"codebase": {
"command": "npx",
"args": ["-y", "mcp-owl"],
"env": {
"TARGET_PROJECT_PATH": "/caminho/do/projeto",
"TARGET_LANGUAGE": "php",
"LLM_PRIMARY_PROVIDER": "deepseek",
"DEEPSEEK_ENABLED": "true",
"DEEPSEEK_API_KEY": "sk-sua-chave",
"DEFAULT_FRAMEWORK": "laravel",
"TOOLS_MODE": "core",
"LLM_CACHE_ENABLED": "true",
"AST_CACHE_ENABLED": "true",
"LLM_FALLBACK_ENABLED": "true",
"CO_OCCURRENCE_TRACKING_ENABLED": "true"
},
"autoApprove": ["explain_symbol", "explain_symbols", "explain_flow", "get_explored_symbols", "clear_cache", "warmup_provider"]
}
}
}⚠️ Se o
mcp.jsonestiver versionado, separe API keys no.envdo MCP server (gitignored). Veja.env.example.
Linguagens & Frameworks
| Linguagem | TARGET_LANGUAGE | Parser | Extensões |
|-----------|-------------------|--------|-----------|
| PHP | php (default) | php-parser | .php |
| TypeScript/JS | typescript | TS Compiler API | .ts, .tsx, .js, .jsx |
| Framework | DEFAULT_FRAMEWORK | Linguagem | Funcionalidade |
|-----------|---------------------|-----------|----------------|
| Laravel | laravel | PHP | Resolve Facades, detecta relações Eloquent, prioriza app/Models/ |
| Symfony | symfony | PHP | Funcionalidade mínima |
| Next.js | nextjs | TypeScript | Prioriza src/app, src/pages, src/components, src/hooks |
| NestJS | nestjs | TypeScript | Prioriza src/modules, src/common, src/guards, libs/ |
| Generic | generic | Qualquer | Sem priorização |
Combinações válidas: php → laravel/symfony/generic · typescript → nextjs/nestjs/generic
Variáveis de Ambiente
Configuráveis via .env ou bloco env no mcp.json (precedência: mcp.json > .env). Referência completa: .env.example.
| Variável | Default | Descrição |
|----------|---------|-----------|
| TARGET_PROJECT_PATH | — | Caminho do projeto (Laravel: app/, Next.js: raiz) |
| TARGET_LANGUAGE | php | php ou typescript |
| DEFAULT_FRAMEWORK | laravel | Framework do projeto |
| LLM_PRIMARY_PROVIDER | — | deepseek · ollama · openrouter · openai · gemini · claude |
| TOOLS_MODE | core | core (7 tools) ou all (12 tools) |
| LLM_CACHE_ENABLED | true | Cache LLM persistente (SQLite) |
| LLM_FALLBACK_ENABLED | true | Fallback automático entre providers |
| AST_CACHE_ENABLED | true | Cache AST em memória |
| AST_TIMEOUT_MS | 10000/30000 | Timeout busca AST (PHP/TS) |
| LOG_LEVEL | info | debug · info · warn · error |
| LOG_FILE | — | Path para log em arquivo |
| MCP_SESSIONS_PATH | auto | Pasta para session logs |
| MCP_CLIENT_NAME | — | Identifica qual AI usou (kiro, claude, kimi) |
Benchmarks
Kimi-K2.6 (15 sessões, tarefa de planejamento Laravel)
| Métrica | Sem MCP | Com MCP (skill calibrada) | Delta | |---------|---------|--------------------------|-------| | Tokens caros (input+output) | 140,614 avg | 48,740-51,014 | -64% (2.9x) | | Custo estimado/sessão | ~$0.178 | ~$0.082-0.087 | -52% | | Sub-agentes criados | 1-4 (83%) | 0 | Eliminados | | Qualidade do plano | ✅ Completo | ✅ Completo | Mesma |
Claude Sonnet 5 (18 sessões, 2 tarefas Laravel)
| Métrica | Sem MCP (N=4) | Com MCP — core (N=10) | Com MCP — all (N=4) | |---------|---------------|----------------------|---------------------| | Context tokens (média) | ~3.8M | ~2.5M | ~5.9M ⚠️ | | File reads (média) | 25 | 0.5 | 0 | | Turns totais (média) | 77 | 35 | 72 | | Tool calls (média) | 53 | 16 | 50 | | Qualidade | ★★★★★ | ★★★★★ | ★★★★★ |
Cenários:
- Core (4 tools), cache frio: 1.7M context — melhor configuração (-41% vs no-MCP)
- All (12 tools), sem skill: 5.6-7.4M context — pior que no-MCP
DeepSeek v4 Pro (18 sessões, tarefa Laravel)
| Métrica | Sem MCP | Com MCP (skill v2) | Delta | |---------|---------|---------------------|-------| | Tokens prompt | ~1.920K | ~1.130K | -41% | | Custo/sessão | ~$0.05 | ~$0.03 | -40% | | Qualidade vs referência | 70/100 | 73/100 | +4% | | Over-engineering | 5/9 testes | 1/9 testes | -80% |
Relatórios completos em
benchmarks/<model>/reports/
O papel da skill
| Skill | Tokens caros | vs sem-MCP | |-------|-------------|-----------| | Sem skill (sem MCP) | 140,614 | baseline | | Skill básica (v1) | 49,093 | 2.9x melhor | | Skill mal calibrada (v3) | 109,245 | 1.3x (quase anulou o ganho) | | Skill otimizada (v4) | 48,740 | 2.9x melhor |
Uma skill mal escrita pode anular o ganho do MCP. Use as skills validadas em instructions/.
Modelos testados
| Modelo | Data | Sessões | Resultado principal | |--------|------|---------|---------------------| | Kimi-K2.6 | 2026-07-26 | 15 | -64% tokens, -52% custo | | Claude Sonnet 5 | 2026-08-01 | 13 | -30% context, -94% reads | | Claude Sonnet 5 | 2026-08-02 | 5 | Core: -41%. All: +97% ⚠️ | | DeepSeek v4 Pro | 2026-07-28/29 | 18 | -40% custo, +4 pts qualidade |
Arquitetura
MCP Client (IDE/AI) ──STDIO──▶ NestJS Server (no HTTP)
│
┌──────────────┼──────────────┐
▼ ▼ ▼
AST Parser Framework LLM Provider
(php/ or typescript/) Strategy (DeepSeek/Ollama/...)
│ │ │
▼ ▼ ▼
Symbol Resolver ◄───────────────────┘
│
▼
Response (JSON-RPC via stdout)src/
├── mcp/handlers/ # Tool handlers (entry points MCP)
├── symbol/services/ # SymbolResolver, FileScanner, FlowTracer
├── parser/php/ # PHP parser (php-parser)
├── parser/typescript/ # TS parser (TypeScript Compiler API)
├── llm/providers/ # GenericCloud, Ollama, ProviderRegistry
├── llm/services/ # LlmService, PromptLoader, SqliteCache
├── framework/strategies/ # Laravel, Symfony, NextJs, NestJs, Generic
└── shared/ # AppConfig, Logger, interfaces, DTOsAll Tools Reference
Documentação completa de todas as 11 tools (params, responses, exemplos): docs/TOOLS-REFERENCE.md
Cache & Session Logs
Cache (3 camadas)
- AST Cache (memória, LRU) — evita re-parsear. Invalida por mtime.
- LLM Response Cache (memória + SQLite) — evita re-chamar LLM. Invalida por hash do código.
- Snippet Cache (SQLite) — reutiliza análises para perguntas diferentes sobre mesmo código.
Persiste em TARGET_PROJECT_PATH/.mcp-cache/llm-cache.sqlite. Hit rate observado: 0% (sessão 1) → 58% → 100% (sessão 6+).
Session Logs
Cada conexão gera JSON com métricas (calls, tokens, custo, reasoning trace).
MCP_SESSIONS_PATH=/home/user/mcp-sessions
MCP_CLIENT_NAME=kiroOrganizados por projeto: mcp-sessions/<project>/2026-07-28_143638.json
LLM Providers
| Provider | Status | Modelo default | Custo |
|----------|--------|----------------|-------|
| DeepSeek | ✅ Primário | deepseek-v4-flash | ~$0.001/req |
| Ollama | ✅ Local | qwen2.5-coder:3b | $0 |
| OpenRouter | ✅ Validado | Configurável | Varia |
| OpenAI | ✅ Validado | gpt-4o-mini | ~$0.002/req |
| Claude | ✅ Validado | claude-sonnet-4-20250514 | ~$0.003/req |
| Gemini | ⚠️ Não validado | gemini-2.0-flash | ~$0.001/req |
Fallback automático (LLM_FALLBACK_ENABLED=true): deepseek → openrouter → openai → gemini → claude → ollama.
Development
npm run build # Compila para dist/
npm run start # Inicia servidor MCP (STDIO)
npm run start:dev # Watch mode
npm test # Unit tests (471+)
npm run test:e2e # End-to-end
npm run lint # ESLintProtocolo: STDIO/JSON-RPC 2.0 via @rekog/mcp-nest. Sem HTTP, sem portas abertas.
Licença
MIT
