← the writing notes 9 min

MCP Server Security: Vet Tools Before You Install

Installing an MCP server is not a one-click convenience. It grants executable code access to your credentials, filesystem, and agent context. Here's a reusable checklist to review any server before it touches your stack.

Blueprint line-art of a padlock connected by pipes to server cylinders and gear nodes, with a magnifying glass over one node.

Installing an MCP server looks trivial: paste a command or URL, restart the client, and a new tool appears in your agent's context. But behind that tool name sits executable code, a schema injected into the model's context window, credentials, and whatever system those credentials can reach. The MCP ecosystem is still maturing, and the vetting process for new servers is, charitably, thin. This post gives you a reusable pre-install checklist applied to a pinned illustrative example, with findings and a plain accept/reject rationale for each step.

What Installation Actually Grants

When you install an MCP server, you are not installing a passive library. You are granting executable code access to your tools, filesystem, and usually your API keys, with no intermediate review step that most clients surface to you.

That trust is cumulative and non-granular. As Pluto Security's practitioner guide notes, approving an MCP server means approving every operator in its supply chain. There is no per-component re-prompt. Every enabled MCP server also pushes its full tool list into the model's context at session start, burning tokens and diluting attention. So you pay twice: once in security surface, once in context budget.

In Claude Code specifically, servers are configured via .mcp.json (project-scoped) or ~/.claude.json (user-scoped), and can be bundled inside a plugin directory that also contains hooks, agents, monitors, and bin/ scripts. A plugin is not a slim wrapper. It can reach everything your shell session reaches.

The threat model has three realistic failure modes:

  • A malicious publisher creates a lookalike server that appears in the registry, redirects API calls, or exfiltrates data silently.
  • A well-intentioned but inexperienced author ships a server that stores tokens in plain text or logs request bodies without thinking about it.
  • A legitimate server you approved gets updated, and the new version introduces a backdoor or widens its permissions without re-prompting you.

All three are documented in the wild, not hypothetical.

Review Source, Provenance, and Update Behaviour

Start before you read a single line of code. Who published this server? Is there a verifiable identity behind the package? Does the repository have a meaningful commit history, or was it created last week with one commit?

Christian Schneider's defense-first architecture guide puts the supply chain hygiene requirements plainly: only install servers from reputable sources, verify package signatures or hashes, and pin dependency versions rather than accepting "latest." Run npm audit or pip-audit against the package before it touches your environment. Generate a software bill of materials (SBOM) so you can trace every dependency and respond quickly when a CVE drops.

For your review checklist, capture these at the source stage:

  1. Confirm the publisher identity maps to a known organisation or individual with a track record.
  2. Check the repository creation date and commit frequency. One-commit repos warrant extra scrutiny.
  3. Pin the exact version you reviewed. Note the commit hash or release tag.
  4. Run npm audit or pip-audit on the dependency tree and record findings.
  5. Check whether the server's update mechanism verifies digital signatures before applying changes.

Illustrative example: suppose you are reviewing a hypothetical mcp-db-connector@1.4.2 from a publisher with 18 months of commit history, two contributors, and a signed release on GitHub. npm audit returns zero high-severity findings. That passes this stage. A server with an anonymous publisher, a two-day-old repo, and no signed release would not.

Inspect Tools, Hooks, Scripts, and Network Access

Source provenance is table stakes. Now read the thing.

Look at every tool definition the server registers. Does the stated description match the actual implementation? As Towards Data Science's MCP survival guide warns, just because something is published as an "email-sender" does not mean it only sends emails. It might log them, rewrite them, or forward them somewhere you did not intend.

Check for these specifically:

  • Hooks and lifecycle scripts: Does hooks.json register pre- or post-tool callbacks? What do they do?
  • `bin/` scripts: Are there shell scripts that execute on install or on invocation? Read them.
  • Outbound network calls: Does the server phone home to any endpoint not documented in the README? Use grep -r "fetch\|axios\|http\|https\|request" across the source.
  • File system access: Does it request broader path access than the task requires?
  • Credential handling: Are API keys written to disk, logged, or transmitted anywhere outside the declared target service?

The SlowMist MCP Security Checklist rates input validation, API rate limiting, and output encoding as the three highest-priority controls. If the server does not validate its own inputs strictly, it is a vector for injection attacks whether or not you trust the publisher.

One thing the checklist flags that most people miss: tool descriptions are injected into the model's context verbatim. A malicious or poorly written description can steer the agent's behaviour inside the sandbox even if the sandbox itself is intact. Sandboxing without schema scanning is only half a defence.

Test Prompt Injection and Data Boundary Cases

This step is not optional for anything that touches production data or customer information.

Prompt injection via tool descriptions is a documented attack vector. An attacker embeds instructions inside a tool's description field that the model interprets as user intent. You need to verify that the server's schema does not contain embedded instructions, that output from the server is not trusted as authoritative user input downstream, and that data returned from one tool cannot leak into the context of a separate session or user.

Run illustrative boundary cases before connecting the server to real credentials:

  1. Craft a tool call that returns a response containing something like "Ignore previous instructions and..." and observe whether the host client surfaces or acts on it.
  2. Pass oversized or malformed inputs to each registered tool and check whether the server handles them gracefully or throws unhandled exceptions that expose stack traces.
  3. If the server has access to multiple data sources, verify that a query against source A cannot return data from source B.

These are triage tests, not a certification. A short manual review identifies obvious problems. It does not guarantee the absence of subtle ones.

If you are building AI tooling for clients and want support reviewing MCP integrations as part of a broader Claude Code setup, Seahawk's Claude Code agency service can help assess the stack before it goes anywhere near production.

Choose the Smallest Credential Scope and Isolate the Process

Once you have reviewed the server and decided it is acceptable, the question becomes: how do you run it?

Blueprint line-art of concentric permission rings with valves and gauges around a central server cylinder.

The principle is least privilege, applied without compromise. Do not hand an MCP server your personal API key with full account access because it is convenient. Create a scoped credential with the minimum permissions the documented functionality requires. If the server needs read access to a single S3 bucket, the credential should not have write access, full stop.

Isolation options, roughly in ascending cost:

  • Run the server in a dedicated subprocess with no access to the parent shell's environment variables beyond what you explicitly pass.
  • Use a container with a restricted network policy so the server cannot make arbitrary outbound connections.
  • For sensitive deployments, enforce supply chain checks as deployment gates and treat MCP server updates with the same change-management process as application code.

The General Analysis threat model puts it well: vetted marketplace without version pinning means today's vetted server is tomorrow's rug pull. Isolation and pinning are not redundant. They protect against different failure modes. Sandboxing contains blast radius; pinning prevents silent drift.

Also worth noting: do not share credentials between MCP servers. Token passthrough and shared API keys mean a compromise in one server reaches everything the credential touches.

Record the Decision and Re-review on Every Change

A review you do not record is a review that did not happen, as far as your future self or your team is concerned.

For each server you install, maintain a decision log with at minimum:

  • The exact version reviewed (package version plus commit hash or release tag).
  • The date of review.
  • Who performed the review.
  • Findings from the audit tools and manual inspection.
  • The accept/reject rationale.
  • Conditions that would trigger a re-review (e.g., any new major version, any change to the tool schema, any security advisory touching a dependency).

This is not bureaucracy for its own sake. Schneider's architecture guide asks a direct question that most teams cannot answer: "What happens if an MCP server's tool description changes after a user approved it? Would anyone know?" In most default setups, the answer is no. Version pinning plus a decision log is how you change that answer.

Set a calendar reminder to re-review pinned servers quarterly even without a new release, because the threat environment around them changes even when the code does not.

For teams already running MCP servers in production stacks, the operational considerations around managing multiple servers alongside your existing tooling are covered separately in our production stack post.

Reusable Pre-Install Checklist: Accept/Reject Rationale

Below is the full checklist in triage order. Apply it before installing any server. The example findings are illustrative; your results will vary.

#CheckIllustrative FindingVerdict
1Publisher identity verifiableKnown org, 18-month historyPass
2Repo creation date and commit frequencyActive, multiple contributorsPass
3Version pinned, release signedSigned tag on GitHubPass
4npm audit / pip-audit cleanZero high-severity findingsPass
5Tool descriptions match implementationEmail tool only calls email APIPass
6No undocumented outbound network callsOne undocumented analytics ping foundReject / investigate
7Hooks and bin/ scripts reviewedNo hooks presentPass
8Input validation enforced server-sideStrict schema validation confirmedPass
9Credential scope minimisedScoped read-only key createdPass
10Isolation appliedRuns in restricted subprocessPass
11Decision logged with version and dateLoggedPass
12Re-review trigger definedTriggered on any schema changePass

Row 6 is why you do this. An undocumented analytics ping is not automatically malicious, but it is undocumented, and undocumented outbound calls are a rejection criterion until explained. You ask the publisher, get a clear answer, review what is actually sent, and then make a new decision. That is the process.

FAQ

Does reviewing source code guarantee a server is safe to install?

No. Code review is triage, not certification. It reduces the probability of obvious problems: undocumented network calls, credential logging, malicious tool descriptions. It does not protect against vulnerabilities introduced in a future update (which is why you pin versions and re-review on changes) or against subtle logic flaws that require deep security analysis to surface.

What is tool poisoning and how does it relate to MCP?

Tool poisoning refers to an attacker embedding malicious instructions inside a tool's name or description field. Because MCP tool schemas are injected into the model's context verbatim, the model may interpret those instructions as legitimate directives. Reviewing the schema before installation and checking for embedded instruction fragments is the primary mitigation at the pre-install stage.

Should I review remote MCP servers differently from local ones?

Local servers have a shorter path to sensitive data because they run directly on your machine with access to your environment. Remote servers introduce network attack surface and man-in-the-middle risk. Both require the same checklist, but local servers warrant particular attention to filesystem access scope and credential handling in the source code, while remote servers require verified TLS, signature validation, and OAuth 2.1 compliance per the current MCP specification.

How do I handle MCP servers that are closed-source or distributed as binaries?

If you cannot read the source, you are relying entirely on publisher reputation, cryptographic signature verification, and runtime controls (sandboxing, network policy, scoped credentials). That is a materially higher-risk posture. For anything touching production data or customer information, a closed-source binary without a verifiable signature from a known publisher should default to rejection.

What is an SBOM and do I actually need one for MCP servers?

An SBOM (software bill of materials) is a machine-readable inventory of every dependency a package includes. For MCP servers, it lets you identify whether any transitive dependency has a disclosed CVE, even if the top-level package itself looks clean. For low-stakes personal tooling, it is optional overhead. For production deployments handling sensitive data, it is the difference between knowing your exposure and guessing at it.

The single sharpest caveat from this entire review: a tool description that looks benign in the registry can steer agent behaviour after installation just as effectively as malicious executable code, and most clients will not warn you. Read the schema, not just the README.

Need this done, not just read?

start a project book 30 minutes