MCP tools give your IDE agent access to external APIs, databases, and services. An unaudited configuration can expose API keys, allow unintended writes, or rack up charges. This tutorial walks through auditing which MCP tools are connected, classifying them by risk level, checking for plaintext API keys, and monitoring usage.
Prerequisites
- An IDE with MCP support (Cursor, VS Code, Windsurf)
- At least one MCP server configured
- Basic understanding of MCP
Walkthrough
Step 1: List all configured MCP servers
Read IDE config files to see connected servers.
import json, os
def list_mcp():
for path in ['.mcp.json', os.path.expanduser('~/.cursor/mcp.json')]:
if os.path.exists(path):
config = json.load(open(path))
servers = config.get('mcpServers', config.get('servers', {}))
print(f'\n{path}:')
for name, srv in servers.items():
url = srv.get('url', srv.get('command', '?'))
print(f' {name}: {url}')
for k in srv.get('env', {}):
safe = '***' if any(s in k.lower() for s in ['key', 'secret', 'token']) else srv['env'][k]
print(f' {k}: {safe}')
list_mcp()Step 2: Classify tools by risk
Categorize each tool as read-only, write, or destructive.
def classify(tool_name):
t = tool_name.lower()
if any(w in t for w in ['delete', 'remove', 'drop']): return 'HIGH'
if any(w in t for w in ['create', 'update', 'send', 'write']): return 'MEDIUM'
if any(w in t for w in ['search', 'get', 'list', 'fetch', 'read']): return 'LOW'
return 'REVIEW'
for tool in ['scavio_search', 'gmail_send_email', 'db_delete_record', 'list_files']:
print(f' [{classify(tool):6}] {tool}')Step 3: Check for plaintext API keys
Verify keys use env vars, not raw values.
def audit_keys(path='.mcp.json'):
config = json.load(open(path))
issues = []
for name, srv in config.get('mcpServers', {}).items():
for k, v in srv.get('env', {}).items():
if any(s in k.lower() for s in ['key', 'secret', 'token']):
if not v.startswith('$') and len(v) > 10:
issues.append(f'{name}.{k}: plaintext key detected')
if issues:
for i in issues: print(f' WARNING: {i}')
else:
print(' No plaintext keys found.')
audit_keys()Step 4: Monitor MCP usage
Track which tools your agent calls.
from collections import Counter
class MCPMonitor:
def __init__(self): self.calls = Counter()
def log(self, tool): self.calls[tool] += 1
def report(self):
for tool, count in self.calls.most_common():
print(f' {tool:30} {count:4} calls [{classify(tool)}]')
m = MCPMonitor()
m.log('scavio_search'); m.log('scavio_search'); m.log('gmail_send_email')
m.report()Python Example
import json, os
def audit(path='.mcp.json'):
if not os.path.exists(path): print('Not found'); return
for name, srv in json.load(open(path)).get('mcpServers', {}).items():
url = srv.get('url', srv.get('command', '?'))
print(f'{name}: {url}')
for k, v in srv.get('env', {}).items():
print(f' {k}: {"***" if "key" in k.lower() else v}')
audit()JavaScript Example
const fs = require('fs');
function audit(path = '.mcp.json') {
if (!fs.existsSync(path)) return console.log('Not found');
const config = JSON.parse(fs.readFileSync(path, 'utf8'));
for (const [name, srv] of Object.entries(config.mcpServers || {})) {
console.log(`${name}: ${srv.url || srv.command || '?'}`);
for (const [k, v] of Object.entries(srv.env || {}))
console.log(` ${k}: ${/key|secret|token/i.test(k) ? '***' : v}`);
}
}
audit();Expected Output
.mcp.json:
scavio: https://mcp.scavio.dev/mcp
SCAVIO_API_KEY: ***
[LOW ] scavio_search
[MEDIUM] gmail_send_email
[HIGH ] db_delete_record
No plaintext keys found.