SafetyCard Request a review

mcp-agent

Python framework for building agents and workflows on the Model Context Protocol, with a CLI scaffolder and Temporal-backed durable execution.

github.com/lastmile-ai/mcp-agent · 2026-10-04 · f62d849

Defense-in-depth score

1.7 / 10

mcp-agent is a thin orchestration layer: as shipped it adds no approval gate, no sandbox, and no argument validation between the model and its MCP tools. The scaffolded default gives one unattended session web fetch, a filesystem server over the project directory, and the plaintext secrets file in that same directory, so a prompt injection can read API keys and overwrite files. Sub-agent specs and config are also auto-loaded from the working directory, where they can trigger Python module imports. Opt-in OAuth scoping and OpenTelemetry tracing are the strongest controls on offer.

Safest setup

mcp-agent ships with few protections on: it adds no approval step, no sandbox and no argument checks between the model and its tools, and the scaffolded config gives one unattended session web fetch and write access to the project folder. The safest setup turns on the OAuth scoping, tracing and hooks the framework offers and builds containment around the process yourself.

SetupHowWhat it gives you
Scoped, low-limit keysPass only the model and tool keys this app needs through environment variables, each scoped with a spending limit set at the providerWhatever the agent does, it reaches only the systems and spend you chose C1
OAuth for HTTP serversUnder each HTTP server's auth: block, set oauth: with enabled: true and only the scopes the task needsEach server's token is limited to the scopes you requested for that one server C1
A dedicated task folderRoot the filesystem server at a folder holding only the task's files, outside the folder with your secrets file, config and logsThe model reads and writes only the task's files, never your API keys or settings C8
Sub-agent discovery offSet enabled: false under agents: and define sub-agents in your own codeOnly agents you wrote run, so spec files in a folder can't add agents or import code C6
A clean working directoryStart the app from a directory whose config, secrets and .env files you wrote yourselfServers, keys and the model endpoint come only from you, not from a folder you happen to run in C6
Per-call approvalOverride pre_tool_call on your LLM class to ask a person and return False to refuseA person sees each tool and its arguments before a consequential call runs C2
Its own container or VMRun the app and its MCP servers in a container or VM whose network reaches only the hosts the task needsAn outer boundary around servers and tools that otherwise run as you, and a narrow path for data to leave C4
OpenTelemetry tracingSet enabled: true under otel: with an otlp exporter to a collector outside the agent's reachA record of each tool call with its arguments, kept where the agent can't edit it C9

Approving with confidence

  • Read each prompt and approve calls one at a time; the hook sees the exact tool name and arguments.

Handling data

  • The scaffolded file log is written inside the project; set path under logger: to a location the filesystem server can't reach.
  • Leave LOG_SECRETS unset so values under sensitive keys stay partly masked in logs.
  • Traces carry tool arguments and results unredacted; store them like the data the agent read.

Key gaps (4)

  1. Configured stdio MCP servers and local tools run unsandboxed as the user, with the default filesystem server rooted at the project that holds the plaintext secrets file. C4 · Code-execution isolation
  2. Rule of Two is broken by the default template: fetch, a filesystem server over the project (including the secrets file), and file write combine in one unattended session. C5 · Untrusted input blast radius
  3. Sub-agent auto-discovery is on by default and imports Python modules named in .claude/agents files from the working directory; config and .env are also discovered from the working directory with no trust prompt. C6 · Memory, context & configuration integrity
  4. The plaintext secrets file lives inside the directory the default filesystem MCP server exposes, so the model can read long-lived API keys. C8 · Secrets & sensitive-data protection

Criteria

C1 Identity & least privilege

0.40 / 1.00

By default an mcp-agent app runs with the developer's own authority: LLM API keys come from env vars or a plaintext secrets file, and stdio MCP servers are launched as the same OS user. The one narrowing step is that stdio servers get a minimal default environment plus their configured variables rather than the full parent environment. For HTTP MCP servers the framework offers an opt-in OAuth client whose tokens are cached per user identity and per requested scope set, which is a real per-capability scoping primitive but is off unless configured per server.

C2 Approval gates

0.00 / 1.00

The framework has no approval gate for tool calls. The hook that runs before each tool call simply returns the request unchanged unless a developer subclasses it, and the human-input tool is something the model chooses to call, not a checkpoint on actions. The only built-in human approval covers MCP sampling requests, not tool execution. In the scaffolded default config the agent can overwrite project files and fetch arbitrary URLs with no human in the loop.

C3 Tool & action scoping

0.25 / 1.00

Tool arguments are passed through to MCP servers without framework-side validation; only local Python function tools get typed pydantic parsing. Enforcement of the per-server allowed_tools setting does not cover every path. The default template enables filesystem write and unrestricted web fetch.

C4 Code-execution isolation

0.00 / 1.00

mcp-agent has no isolation mechanism. Configured stdio MCP servers, including the default filesystem server launched with npx, run as ordinary subprocesses of the same OS user, and local function tools run in the agent's own process. Any code those paths execute can reach the user's home directory, network, and the project's secrets file.

C5 Untrusted input blast radius

0.00 / 1.00

Tool and MCP results are appended to the conversation as ordinary tool messages with no untrusted marking, and nothing in the framework changes what the agent may do after reading external content. In the scaffolded default, one session combines web fetch (untrusted input and an exfiltration channel), the project directory including the secrets file, and file write. A successful prompt injection can therefore both leak keys and overwrite files without any human involvement.

C6 Memory, context & configuration integrity

0.10 / 1.00

Conversation memory is in-process and session-scoped, but configuration is not. At startup the app searches the current directory and every parent for its config and secrets files, reads a .env file from the working directory (which can set values such as the OpenAI base URL), and auto-loads sub-agent definitions from .claude/agents and .mcp-agent/agents in the working directory. Those definition files can name Python callables, which the loader imports by module name, so files in the workspace can trigger code import without any trust prompt. Because the default filesystem server is rooted at the same directory, the agent itself can write these files for the next run.

C7 Third-party extensions

0.05 / 1.00

MCP servers are whatever the config names, and the scaffolded template launches them with npx -y and uvx with no version pins, so the latest package is fetched and executed at each launch. There is no integrity check or re-approval when a server changes. stdio servers do get a reduced default environment, but they run as the same user, and function references in sub-agent spec files are imported into the agent's own process.

C8 Secrets & sensitive-data protection

0.25 / 1.00

API keys come from env vars or a plaintext, gitignored secrets file that sits in the project directory. The log serializer masks values under sensitive-looking keys, but leaves the first ten characters visible, and an environment variable turns masking off entirely. Usage telemetry is flagged on but currently sends nothing. The biggest problem is placement: the default filesystem server is rooted at the same directory as the secrets file, so the model can read the long-lived keys.

C9 Audit & traceability

0.35 / 1.00

By default the aggregator logs each MCP tool call at info level with tool, server, and agent names but not the arguments, and the scaffolded config writes these logs to a file inside the project directory that the agent's own filesystem tool can edit. Logs are batched and flushed every two seconds. Opt-in OpenTelemetry tracing records tool arguments and results under agent-named spans and can export over OTLP, which is a much better record but is off by default.

C10 Limits & kill switch

0.30 / 1.00

Each LLM generate call is limited to 10 tool-use iterations and 2048 output tokens per completion. There is no wall-clock limit, no cost cap, and tool calls have no timeout by default, so a hanging MCP server blocks indefinitely. Orchestrator, router, and swarm patterns create sub-agents that each get their own fresh iteration budget. A budgeted deep-orchestrator workflow exists but applies only to that workflow.