Skip to main content
Glama
README.md
# MCP Agent Tools

Caja de herramientas **MCP** que extiende a **VS Code Copilot** (con tu modelo Qwen3 vía API OpenAI) con capacidades que VS Code no trae nativamente.

## 🔧 Tools disponibles

| Tool | Qué hace |
|------|---------|
| `memory_store(text, tags)` | Guarda un hecho en memoria semántica persistente. Devuelve un id opaco. |
| `memory_search(query, k)` | Busca en memoria por similitud semántica. |
| `memory_forget(id)` | Elimina un recuerdo. |
| `code_index(path?, force?)` | Indexa el código del workspace para búsqueda semántica. |
| `code_search(query, k)` | Busca código por similitud semántica (RAG). |
| `run_python(code, timeout=30)` | Ejecuta Python en sandbox. Devuelve stdout/stderr/exit/duration. |
| `run_shell(cmd, timeout=60)` | Ejecuta un comando shell en sandbox. |
| `web_fetch(url, timeout=15)` | Trae una URL y extrae el texto. |
| `web_search(query, k=5)` | Busca en la web (requiere TAVILY_API_KEY o BRAVE_API_KEY). |
| `think(step, step_number, is_last?)` | Razonamiento structured multi-paso. |

## 🚀 Subir

```bash
# Crear .env con las variables opcionales
cp .env.example .env

# Build y subir
docker compose up -d --build

# Verificar
curl http://localhost:8000/health
```

Primera vez: se descarga el modelo de embeddings (~80 MB) a `db/models/`.

## 🖥️ Conectar en VS Code

**Opción A — `.vscode/mcp.json` (ya incluido en el repo):**
Abre el workspace → VS Code detecta el server → diálogo de *trust* → **Connect**.

**Opción B — Command Palette:**
1. `Ctrl+Shift+P` → `MCP: Add Server`
2. Selecciona **Workspace**
3. Pega:
   ```json
   { "type": "http", "url": "http://localhost:8000/mcp" }
   ```
4. Nombre: `mcp-agent-tools`

**Opción C — `.mcp.json` portable (raíz del workspace):**
```json
{ "mcpServers": { "mcp-agent-tools": { "type": "http", "url": "http://localhost:8000/mcp" } } }
```

**Verificar:** `MCP: List Servers` → `mcp-agent-tools` debe mostrar **connected**.

## 🖥️ UI web de gestión de tools

Abre: **http://localhost:8000/admin/**

Permite **en runtime** (sin reiniciar el contenedor):
- **Listar** todas las tools (built-in + dinámicas)
- **Crear** tools nuevas (Python o HTTP)
- **Editar** / **Borrar** / **Habilitar** / **Deshabilitar**
- **Test** de tools con args antes de guardar
- **Live update**: VS Code se actualiza solo (`tools/list_changed` de FastMCP)

Las tools creadas por UI se persisten en `db/tools.json` y se cargan automáticamente al arrancar.

## 📁 Estructura

```
mcp/
├── src/server.py          # Punto de entrada — create_app() + run_http()
├── src/tools/             # Tools built-in (extensibilidad por código)
│   ├── memory.py          # memoria semántica
│   ├── rag.py             # RAG sobre código
│   ├── exec.py            # run_python / run_shell
│   ├── web.py             # web_fetch / web_search
│   └── thinking.py        # sequential thinking
├── src/admin/             # UI web de gestión (FastAPI + vanilla JS)
│   ├── tool_store.py      # persistencia en db/tools.json
│   ├── executor.py        # sandbox executor (subprocess)
│   ├── api_tools.py       # REST API
│   └── static/            # dashboard single-page
├── db/                    # volumen: agent.db, code_index.db, tools.json
├── pyproject.toml
├── Dockerfile
├── docker-compose.yml
├── .vscode/mcp.json
└── README.md
```

## ➕ Agregar una tool nueva

**Por código (permanente, versionada):**
1. Crea `src/tools/mi_tool.py`:
   ```python
   def setup(mcp):
       @mcp.tool(name="mi_tool", description="Qué hace mi tool")
       async def mi_tool(param: str) -> dict:
           return {"result": param}
   ```
2. Agrega en `src/tools/__init__.py` → `TOOLS = [..., "src.tools.mi_tool"]`
3. Rebuild: `docker compose up -d --build`

**Por UI web (efímera, en runtime):**
1. Abre `http://localhost:8000/admin/`
2. Click "Nueva tool"
3. Fill name, description, source_type (Python/HTTP), params, code
4. **Test** → **Save**
5. Aparece en VS Code inmediatamente (sin reconectar)

## 🌍 Variables de entorno

| Variable | Default | Descripción |
|----------|---------|-------------|
| `WORKSPACE_ROOT` | `/workspace` | Ruta base para `code_search` |
| `TAVILY_API_KEY` | _(vacío)_ | Key para `web_search` (opcional) |
| `BRAVE_API_KEY` | _(vacío)_ | Key alternativa para `web_search` |
| `MCP_ADMIN_TOKEN` | _(vacío)_ | Si se define, `/api/*` requiere Bearer token |
| `EXEC_TIMEOUT` | `30` | Timeout por defecto para `run_python` |

## 🔒 Seguridad

- **Sandbox**: `run_python` y tools Python dinámicas se ejecutan en subprocess aislado
- **Whitelist de módulos** (tools dinámicas): `httpx, json, re, math, datetime, os.path` — **sin** `subprocess, socket, sys, shutil, sqlite3`
- **`MCP_ADMIN_TOKEN`**: protege la UI admin en entornos no-localhost
- **Volume `db/`**: la memoria es local; borrar `db/agent.db` resetea la memoria

## 🧹 Resetear

```bash
# Resetear memoria semántica
rm db/agent.db

# Resetear índice de código
rm db/code_index.db

# Resetear tools dinámicas
rm db/tools.json

# Resetear todo
docker compose down -v
rm -rf db/
```

## 🐛 Troubleshooting

- **VS Code no conecta**: Verifica que `docker compose ps` muestre `running`, que el puerto 8000 no esté ocupado (`ss -tlnp | grep 8000`)
- **`web_search` devuelve error**: Configura `TAVILY_API_KEY` o `BRAVE_API_KEY` en `.env`
- **`code_search` devuelve vacío**: Ejecuta `code_index()` primero desde el chat o MCP Inspector
- **Modelo de embeddings no descarga**: Verifica internet en el contenedor; `HF_HOME=/app/db/models`
- **UI no se abre**: Verifica `http://localhost:8000/admin/` — debe servir `index.html`