# What Is Shadow MCP? A Plain Definition

> Shadow MCP is any MCP server your AI tools can reach that security doesn't know about. Where it comes from, why it's risky, and how to find and stop it.

- Canonical URL: https://webofmike.com/what-is-shadow-mcp/
- Author: Mike Moore (https://webofmike.com/about/)
- Published: 2026-10-17
- Last modified: 2026-10-17
- Tags: MCP, Security, AI Agents, Platform Engineering
- Cite as: Mike Moore, "What Is Shadow MCP? A Plain Definition", Web of Mike (webofmike.com), 2026-10-17. https://webofmike.com/what-is-shadow-mcp/


Shadow MCP is any MCP server your AI tools can reach that your security or platform team doesn't know about, didn't approve, and can't see. It's shadow IT for AI agents: a server one developer adds to a config file, a connector someone signs into with a personal account, or a service a team stands up without telling anyone. This page is the definition. [Why shadow MCP servers are hard to track](/shadow-mcp-servers/) is the hub: why they hide, and how to stop them.

Disclosure: I work at Solo.io, which builds agentgateway.

## What shadow MCP means

MCP is a standard way for AI clients to call tools and read data. Claude, Cursor, and GitHub Copilot can all speak it. The client is the agent or the IDE. The server is whatever those tools are allowed to reach: a database, a tracker, a mailbox, a laptop folder.

Shadow does not mean malware. It means unknown to the people who own security. A well-built internal server is still shadow MCP if nobody registered it, reviewed it, or can see the calls.

OWASP lists this as [MCP09:2025 Shadow MCP Servers](https://owasp.org/www-project-mcp-top-10/) in its MCP Top 10. The name is the finding: servers in use that are outside inventory, approval, and visibility. If security cannot name the server, cannot say who approved it, and cannot see the tool calls, it is shadow MCP. That is true for a local stdio process, a URL behind a personal login, and an internal service on the VPN.

## Where shadow MCP servers come from

They do not all look the same. Four patterns cover almost every case I see.

### Local servers in a config file

A developer adds a server to a client config. The client launches it. [stdio](https://modelcontextprotocol.io/specification/latest/basic/transports) servers run as child processes of the IDE or agent and never open a port. There is no listener on the laptop and nothing on the corporate network that looks like MCP. Credentials often sit in `env` blocks next to the command.

A network scan will not find this. The process list looks like the IDE.

### Project files that arrive with git clone

A committed `.mcp.json` (or the equivalent for that client) brings servers to every clone. The person who opens the repo did not choose those servers. The file did. Approve the repo and you have approved the servers, unless something in the path filters them.

This is how a team inherits MCP it never asked for. One commit, every laptop.

### Connectors behind a personal login

Remote MCP can be a URL someone authorizes with OAuth using a personal account. That grant lives with the person, not with the company inventory.

[Claude custom connectors](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp) go further: they connect from Anthropic's cloud, not from the laptop, in every Claude client. A laptop sweep and a network scan can both be clean while that connector is still live.

### Internal services nobody registered

A team stands up an MCP server on the VPN because it is convenient. It answers on an internal hostname. It is not in a registry. Every agent on the network that can route to it can ask what it does. That is the pattern people expect when they hear "shadow," and it is only one of the four.

## Why shadow MCP is a security problem

An MCP server is not a document. It is a way for an AI client to act on real systems.

An open server answers `tools/list` for anyone who can reach it. Tool descriptions are written for a model, in prose, and they routinely carry internal detail. In the lab on the hub, a `run_query` tool discloses the warehouse hostname `warehouse-prod.internal:5439` and the service account name to an anonymous caller, before anything is invoked.

Credentials sit in `env` blocks of those config files. Copy the file and you copy the secret. A sweep that prints `env` values has made the inventory worse.

Tool lists can change while the server runs. The 2026-07-28 spec has `listChanged` and subscriptions, so yesterday's review does not cover today's tools. [Pin tool definitions](/mcp-tool-poisoning-pin-definitions/), not just names, or the next `tools/list` can rewrite what the model is told the tool does.

The public half of this is already measured. In July 2025, Trend Micro counted [492 internet-exposed MCP servers with no client authentication](https://www.trendaisecurity.com/en-us/resources-insights/research/mcp-security-network-exposed-servers-are-backdoors-to-your-private-data), exposing 1,402 tools. That report is from July 2025. It is still the census people cite. The servers on your VPN are not in that number, and they are the ones your agents will actually find.

## Shadow MCP, shadow IT and shadow AI

Shadow IT is any unapproved tech: a SaaS account, a laptop app, a server under a desk. Shadow AI is unapproved AI use: a model, a chatbot, a plugin someone signed into.

Shadow MCP is the part where an AI client can act on systems through tools. A policy memo can forbid it. The client will still call whatever it can reach. That is why this needs controls on the path, not only a rule in a wiki. Inventory without a chokepoint goes stale the next time someone edits a config file. A chokepoint without a definition of shadow MCP will gate the wrong thing.

## How to find shadow MCP

Look in three places. On the network, probe for `server/discover`, then `initialize`. On laptops, read the client config files. In vendor accounts, look for connectors that never wrote a local file. Those three cover local stdio, committed project files, personal OAuth, and internal HTTP servers.

<!-- TODO link S2 /find-shadow-mcp-servers/ when live: "find shadow MCP servers in your environment" -->

Finding them produces a timestamped list. It does not stop the next one. The find page is the walk of those three places. This page only names them so the definition has somewhere to go.

## How to stop shadow MCP with agentgateway

Put [agentgateway](https://agentgateway.dev) in the only MCP path, in [standalone](https://agentgateway.dev/docs/standalone/latest/) mode or on [Kubernetes](https://agentgateway.dev/docs/kubernetes/latest/). An [AI agent gateway](/what-is-an-ai-agent-gateway/) is the hop. Current open-source agentgateway is v1.6.0, released October 2, 2026 ([release notes](https://github.com/agentgateway/agentgateway/releases)). The control below is what that release documents in both modes.

Authorize each tool call with CEL rules. In standalone, [`mcpAuthorization`](https://agentgateway.dev/docs/standalone/latest/documentation/configuration/security/mcp-authz/) runs CEL on MCP methods and filters disallowed tools out of the list response. On Kubernetes, [`AgentgatewayPolicy`](https://agentgateway.dev/docs/kubernetes/latest/documentation/mcp/tool-access/) with JWT and CEL rules controls tool access. Kubernetes tool access is allowed by default until you attach a policy. A cluster with agentgateway in the path and no policy still offers every tool. Write the policy, then [test the CEL policy with a call you expect to fail](/agentgateway-cel-authorization-gotchas/). CEL policies can fail open silently. Only a refused call tells you the rule took.

Default-deny egress so agents cannot go around the gateway. If a workload can reach a remote MCP URL on its own, the gateway is a suggestion.

Allowlist by URL and command, never by name. Claude Code's [managed MCP](https://code.claude.com/docs/en/managed-mcp) controls key `allowedMcpServers` on `serverUrl` or `serverCommand`; a `serverName` entry is not a security control. Keep [a private MCP registry](/private-mcp-registry/) as the list of servers you actually meant to run, and reconcile scans against that list.

<!-- TODO link S4 /stop-shadow-mcp-servers/ when live: "stop shadow MCP servers" -->

