Skip to content

Security

mcp-devtools is designed for AI agents operating on developer machines. Every tool operates within enforced boundaries.

Filesystem Scope

All file paths are resolved to absolute and compared against config.scope. Both the resolved path and any symlink target must stay inside the scope root.

A symlink that points outside scope returns SCOPE_VIOLATION — even if the symlink itself is inside scope.

Command Allowlist

run_command only executes binaries whose basename is in config.allowedCommands. Commands run with spawn(file, args)no shell — so shell injection via the command argument is structurally impossible.

Shell metacharacters (;, |, &, backtick, $() in arguments are rejected.

The child process receives a minimal environment (PATH, HOME, SystemRoot) — the parent's env is never leaked.

Database Read-Only

When readOnly: true (the default), writes are blocked at two layers:

  1. SQL parser guard — rejects INSERT, UPDATE, DELETE, DROP, CREATE, GRANT, and multi-statement queries before they reach the engine.
  2. Engine-level enforcementBEGIN READ ONLY on PostgreSQL, START TRANSACTION READ ONLY on MySQL, readonly: true on SQLite.

Result sets are capped at maxRows (default 200). Queries time out after queryTimeoutMs (default 10s).

HTTP Bearer Auth

When auth.token is configured and the transport is HTTP, every request must include:

Authorization: Bearer <token>

Token comparison uses crypto.timingSafeEqual to prevent timing attacks. The token supports env:VAR indirection so it never needs to be in the config file.

Requests without a valid token receive 401 Unauthorized.

Secret Masking

get_env automatically masks values for keys matching common secret patterns: SECRET, TOKEN, PASSWORD, KEY, API_KEY, PRIVATE, CREDENTIAL (case-insensitive).

Audit Log

When audit.enabled: true, every tool invocation is logged to an NDJSON file:

json
{
  "timestamp": "2026-04-28T12:00:00.000Z",
  "tool": "read_file",
  "inputSummary": { "path": "src/index.ts" },
  "durationMs": 12,
  "ok": true
}

Input summaries are sanitized: secrets are masked, long strings are truncated.

OpenAPI Host Restriction

call_api only sends HTTP requests to hosts listed in the spec's servers array. Requests to unlisted hosts are rejected. This prevents an AI agent from using the tool as a proxy to arbitrary endpoints.

Output Capping

All tools cap their output to prevent context window flooding:

Tool typeCap
File reads1 MB
Command output100 KB per stream
Database queries200 rows
API responses100 KB body
Log reads500 lines

Released under the MIT License.