MCP Owl

MCP Owl

Build npm version npm downloads License: MIT Node.js

Servidor MCP que dá à sua AI a capacidade de entender código sem ler arquivos inteiros — via AST + LLM.

## 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: 1. **Explica** — recebe o nome de uma classe ou método e devolve um resumo semântico compacto (propósito, dependências, side effects) 2. **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). | ```json {"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`](docs/TOOLS-REFERENCE.md) ## Quick Install ### Via npm (recomendado) ```bash npm install -g mcp-owl ``` Após instalar, veja as instruções de configuração: ```bash npx mcp-owl --help ``` Adicione ao `mcp.json` da sua IDE (Kiro, Claude Code, Cursor, etc.): ```json { "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) ```bash 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 pronta ``` ### Nota 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 `peerOptional` pelo `@nestjs/core` mas 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 `read` em `.php` para entender código — use `explain_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/`](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: ```bash # 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: 1. **Proibir leitura direta de código para "entender"** — forçar uso de `explain_symbol` 2. **Priorizar batch** (`explain_symbols`) sobre chamadas sequenciais 3. **Usar `explain_flow`** para fluxos de execução (substitui 4-7 reads) 4. **Aceitar `found:false`** como definitivo (classe não existe, não insistir com grep) 5. **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/`](instructions/claude/) | `.mcp.json` + skill + hook de enforcement | | **Kimi** | [`instructions/kimi/`](instructions/kimi/) | Skill v1-v4 (use v4) | | **Kiro** | [`instructions/kiro/`](instructions/kiro/) | Steering + mcp.json | > Veja [`instructions/README.md`](instructions/README.md) para 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): ```json { "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.json` estiver versionado, separe API keys no `.env` do 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`](.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//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, DTOs ``` ## All Tools Reference Documentação completa de todas as 11 tools (params, responses, exemplos): [`docs/TOOLS-REFERENCE.md`](docs/TOOLS-REFERENCE.md) ## Cache & Session Logs ### Cache (3 camadas) 1. **AST Cache** (memória, LRU) — evita re-parsear. Invalida por mtime. 2. **LLM Response Cache** (memória + SQLite) — evita re-chamar LLM. Invalida por hash do código. 3. **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). ```bash MCP_SESSIONS_PATH=/home/user/mcp-sessions MCP_CLIENT_NAME=kiro ``` Organizados por projeto: `mcp-sessions//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 ```bash 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 # ESLint ``` Protocolo: STDIO/JSON-RPC 2.0 via `@rekog/mcp-nest`. Sem HTTP, sem portas abertas. ## Licença MIT