MCP 文件系统和 git 工具使 AI 代理可以直接访问您的代码库,这很强大,但没有护栏也很危险。本教程构建了一个安全代理,可以读取文件、搜索代码库和管理 git 操作,同时强制执行路径沙箱、只读默认值和操作白名单。搜索基础确保任何生成的代码都基于当前文档而不是过时的训练数据。
前置条件
- 安装克劳德代码
- 已安装 Node.js 18+
- 一个可以使用的 git 存储库
- 用于搜索基础的 Scavio API 密钥
操作指南
步骤 1: 使用沙箱配置文件系统和 git MCP
设置具有受限路径的 MCP 服务器。文件系统服务器仅访问允许的目录; git 服务器仅在指定的存储库上运行。
Python
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)')步骤 2: 构建路径验证中间件
添加一个验证层,在任何路径遍历尝试到达文件系统 MCP 服务器之前拒绝它们。
Python
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}')步骤 3: 添加基于搜索的代码帮助
当代理需要生成或修改代码时,请先搜索当前文档,以避免幻觉过时的 API。
Python
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')Python 示例
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])JavaScript 示例
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')); // false预期输出
JSON
/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