ATALAIA
  1. Home
  2. Resources
  3. Blog
  4. What an MCP server can reach
AI & tooling · Deep dive

What an MCP server can reach

An MCP server runs with your tokens, your filesystem and your network. Here is what that means, and how to inventory and scope it.

4 min readAtalaia team

MCPAI agentsDeveloper laptops

The Model Context Protocol made it easy to give an AI assistant hands. You add a few lines of JSON, restart your editor or chat client, and the assistant can now read tickets, query a database or open pull requests. That convenience is the point. It is also why it is worth asking, plainly, what each of those servers can actually reach.

The short answer: a local MCP server is just a program running as you. It reaches whatever you can reach, plus whatever you explicitly pass into it.

Anatomy of an MCP server

Most MCP servers on developer laptops are launched by the client as a child process over stdio. The client reads a JSON config, runs a command such as npx, uvx or a local binary, and passes environment variables. Remote servers exist too, reached over HTTP, but the local pattern is the common one today.

Four things define the blast radius:

  • Tools. The functions the server advertises to the model: read_file, run_query, create_issue. The model decides when to call them.
  • Tokens. API keys and personal access tokens passed in env. A server given a broad token can do anything that token allows, whatever its tool list says.
  • Filesystem. A stdio server runs with your user permissions. Unless it is sandboxed, it can read your SSH keys, cloud credentials and shell history.
  • Network. It can open outbound connections to anywhere your laptop can, including internal services on the VPN.

Note that the advertised tools are a promise, not a boundary. The process itself is the boundary, and by default that boundary is your whole account.

Prompt injection through tool output

The less obvious risk is not the server misbehaving. It is the data the server returns. Tool output is fed back into the model as context, and the model cannot reliably tell instructions from content.

  1. PlantAn attacker writes text into something a tool will read: an issue comment, a README, a web page, a database row.
  2. FetchA developer asks the assistant to summarise open issues. The ticketing server returns the planted text.
  3. SteerThe text tells the model to call another tool, for example to read a credentials file or push a branch.
  4. ActIf a second server with broad access is connected, the model may follow the instruction using the developer's identity.
  5. ExfiltrateResults leave via any tool that can write outward: a comment, a commit, an HTTP fetch.

The dangerous combination is a server that reads untrusted input sitting alongside a server that can write or reach secrets. Each one alone may be fine. Together they form a line from attacker text to your credentials.

Inventory MCP configs on a laptop

MCP clients store their server lists as JSON, usually under a top-level mcpServers key, in the user's home directory, an application support folder, or inside a project as a dotfile. You do not need to know every client. Search for the key.

# macOS / Linux: find JSON files that declare MCP servers
grep -rl --include="*.json" '"mcpServers"' \
  ~/.config ~/Library/Application\ Support ~ 2>/dev/null \
  | sort -u

# Also check project-level configs in your source tree
find ~/src -maxdepth 4 -name "*mcp*.json" -not -path "*/node_modules/*"

Then list what each one runs and what it is given:

jq -r '.mcpServers | to_entries[] |
  [.key, .value.command, ((.value.args // []) | join(" ")),
   ((.value.env // {}) | keys | join(","))] | @tsv' path/to/config.json

A typical entry looks like this. Note the token sitting in plain text in the config.

{
  "mcpServers": {
    "tickets": {
      "command": "npx",
      "args": ["-y", "example-tickets-mcp"],
      "env": { "TICKETS_TOKEN": "PLACEHOLDER_NOT_A_REAL_TOKEN" }
    }
  }
}

Three things to flag: npx -y or similar with no pinned version (you run whatever is latest at launch), tokens stored inline, and servers nobody on the team can explain.

Scope tokens and allowlist servers

Treat each MCP server as a new dependency with credentials attached.

  • One token per server. Create a dedicated, fine-grained token with the minimum scopes and an expiry. Never reuse your main personal access token.
  • Read-only by default. Most assistant use is lookup. Grant write scopes only to servers that genuinely need them, and keep confirmation prompts on.
  • Pin versions. Replace npx -y package with npx -y package@1.4.2, or install a reviewed build locally.
  • Keep secrets out of the JSON. Load tokens from the OS keychain or a secrets manager wrapper rather than inline env values.
  • Publish an allowlist. A short list of approved servers, their pinned versions and permitted scopes. Anything else is a conversation, not a block on sight.
  • Separate sessions. Avoid connecting a server that reads public input in the same session as one that can touch production or secrets.

Check yours in 10 minutes

  1. Run the grep above on your own laptop and count the configs.
  2. For each server, write down: command, version pinned or not, token scopes, and whether it can write.
  3. Revoke any broad token found inline and reissue a scoped one.
  4. Remove servers you do not use. Fewer stations on the line means fewer places for a fault to start.
  5. Share the result with your team and start the allowlist from what people actually use.

None of this requires banning assistants. It just applies the same thinking you already use for dependencies and CI tokens to a newer kind of tool.

Where this sits on the line

In the tower (in development):

Talk it through

A 30-minute call. No slides, no price list, and a next step either way.