El sistema de archivos MCP y las herramientas git brindan a los agentes de inteligencia artificial acceso directo a su código base, que es poderoso pero peligroso sin barreras de seguridad. Este tutorial crea un agente seguro que puede leer archivos, buscar bases de código y administrar operaciones de git mientras aplica la zona de pruebas de ruta, los valores predeterminados de solo lectura y las listas de operaciones permitidas. La base de búsqueda garantiza que cualquier código generado se base en documentación actual en lugar de datos de entrenamiento obsoletos.
Requisitos previos
- Código Claude instalado
- Node.js 18+ instalado
- Un repositorio de git con el que trabajar
- Una clave API de Scavio para la base de búsqueda
Guia paso a paso
Paso 1: Configurar el sistema de archivos y git MCP con sandboxing
Configure los servidores MCP con rutas restringidas. El servidor del sistema de archivos sólo accede a un directorio permitido; el servidor git solo opera en repositorios específicos.
import json
from pathlib import Path
mcp_config = {
'mcpServers': {
'filesystem': {
'command': 'npx',
'args': ['-y', '@anthropic/mcp-filesystem',
'--allowed-dir', '/home/user/projects',
'--read-only'],
'env': {}
},
'git': {
'command': 'npx',
'args': ['-y', '@anthropic/mcp-git',
'--repo-path', '/home/user/projects/my-repo',
'--allow-operations', 'status,log,diff,branch'],
'env': {}
}
}
}
Path('.mcp.json').write_text(json.dumps(mcp_config, indent=2))
print('Filesystem MCP: read-only, sandboxed to /home/user/projects')
print('Git MCP: status, log, diff, branch only (no push, no force)')Paso 2: Construir middleware de validación de ruta
Agregue una capa de validación que rechace cualquier intento de atravesar la ruta antes de que llegue al servidor MCP del sistema de archivos.
import os
ALLOWED_ROOT = '/home/user/projects'
BLOCKED_PATTERNS = ['.env', '.ssh', 'credentials', 'secrets', '.git/config']
def validate_path(requested_path: str) -> dict:
resolved = os.path.realpath(requested_path)
# Check sandbox
if not resolved.startswith(ALLOWED_ROOT):
return {'allowed': False, 'reason': f'Path escapes sandbox: {resolved}'}
# Check blocked patterns
for pattern in BLOCKED_PATTERNS:
if pattern in resolved.lower():
return {'allowed': False, 'reason': f'Blocked pattern: {pattern}'}
# Check symlink attacks
if os.path.islink(requested_path):
target = os.readlink(requested_path)
if not os.path.realpath(target).startswith(ALLOWED_ROOT):
return {'allowed': False, 'reason': f'Symlink escapes sandbox'}
return {'allowed': True, 'resolved': resolved}
# Test cases
test_paths = [
'/home/user/projects/src/main.py', # allowed
'/home/user/projects/../.ssh/id_rsa', # blocked
'/home/user/projects/.env', # blocked
'/etc/passwd', # blocked
]
for p in test_paths:
result = validate_path(p)
status = 'ALLOWED' if result['allowed'] else f'BLOCKED ({result["reason"]})'
print(f' {p}: {status}')Paso 3: Agregar asistencia de código basada en búsquedas
Cuando el agente necesite generar o modificar código, busque primero la documentación actual para evitar alucinar con API obsoletas.
import requests
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def ground_code_generation(language: str, task: str) -> str:
"""Search for current docs before generating code."""
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': f'{language} {task} documentation 2026',
'country_code': 'us', 'num_results': 3})
results = resp.json().get('organic_results', [])
context = '\n'.join(f'- {r["title"]}: {r.get("snippet", "")}' for r in results)
return context
# Example: before generating Next.js code, check current API
context = ground_code_generation('Next.js', 'app router server components')
print('Grounding context for code generation:')
print(context)
print(f'\nCost: $0.005')Ejemplo en Python
import os, json, requests
from pathlib import Path
ALLOWED_ROOT = '/home/user/projects'
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def validate_path(path):
resolved = os.path.realpath(path)
if not resolved.startswith(ALLOWED_ROOT):
return False
blocked = ['.env', '.ssh', 'credentials', 'secrets']
return not any(b in resolved.lower() for b in blocked)
def search_docs(query):
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': 3})
return [r.get('snippet', '') for r in resp.json().get('organic_results', [])]
print(validate_path('/home/user/projects/src/main.py')) # True
print(validate_path('/etc/passwd')) # False
print(search_docs('python pathlib best practices 2026')[0][:80])Ejemplo en JavaScript
const ALLOWED_ROOT = '/home/user/projects';
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const path = require('path');
function validatePath(p) {
const resolved = path.resolve(p);
if (!resolved.startsWith(ALLOWED_ROOT)) return false;
const blocked = ['.env', '.ssh', 'credentials'];
return !blocked.some(b => resolved.toLowerCase().includes(b));
}
async function searchDocs(query) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us', num_results: 3 })
});
return (await resp.json()).organic_results?.map(r => r.snippet) || [];
}
console.log(validatePath('/home/user/projects/src/main.py')); // true
console.log(validatePath('/etc/passwd')); // falseSalida esperada
/home/user/projects/src/main.py: ALLOWED
/home/user/projects/../.ssh/id_rsa: BLOCKED (Path escapes sandbox)
/home/user/projects/.env: BLOCKED (Blocked pattern: .env)
/etc/passwd: BLOCKED (Path escapes sandbox)
Grounding context for code generation:
- Next.js App Router Docs: Server Components run on the server...
- Vercel Blog: Next.js 16 App Router updates...
Cost: $0.005