Skip to content

Find the MCP servers employees have installed

No admin console lists the MCP servers employees have installed. The order that works: a device sweep, the vendor logs that exist, then a direct ask.

Nachi Raman 9 min read
A laptop file browser showing MCP configuration files for several AI clients side by side

Why no admin console lists the MCP servers employees have installed

Most of the MCP servers employees have installed are lines in a file on a laptop, and no client vendor documents an admin inventory of those files. MCP (Model Context Protocol) is the standard way an AI assistant calls tools in other apps. A server is either a local process the client starts on the device, or a remote HTTPS address the client calls (modelcontextprotocol.io, checked October 2026). Both are recorded the same way, as an entry in the client's own configuration file.

That is why network tooling finds so little. A local server never leaves the machine, so there is no request for a proxy to inspect. A remote one is an ordinary HTTPS call. For Claude's connectors, that call comes from Anthropic's cloud rather than the user's device, on every Claude client (claude.com/docs/connectors/custom/add-unlisted, checked October 2026). Inline inspection still earns its place for other reasons. It is not how you build this list.

Vendor consoles report what connects through the vendor's own surface, which is a different set from what sits in a file. So the order is: read the files, then read the logs, then ask the people.

A note on sourcing: every claim below traces to a vendor's own documentation, linked and dated. "Checked [month, year]" marks when we last reconciled the claim against that page, not a publication date. Vendor docs change without notice, and the config path below moved when Windsurf became Devin Desktop. Re-verify against the live link before you build unattended automation on a specific path or key.

Which file holds the server list on each client?

Each client keeps its MCP servers at a documented path, and usually there are two, one per user and one per project. These are the paths as of October 2026, read from each vendor's own page. This list covers the clients most likely to appear in a laptop fleet today: Claude Desktop, Claude Code, Cursor, VS Code with Copilot, Devin Desktop and Codex. JetBrains AI Assistant, Zed, and mobile or browser-based MCP clients aren't covered here; if your fleet includes them, find the equivalent path in that vendor's own docs before treating a sweep as complete.

  • Claude Desktop. ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows, with servers under the mcpServers key. Anthropic gives no Linux path. Server names also appear in the log directory, ~/Library/Logs/Claude or %APPDATA%\Claude\logs, as one mcp-server-SERVERNAME.log per server (modelcontextprotocol.io, checked October 2026).
  • Claude Code. Local and user scope live in ~/.claude.json. Project scope lives in .mcp.json at the repository root. On a device you can also run claude mcp list (code.claude.com/docs/en/mcp, checked October 2026).
  • Cursor. ~/.cursor/mcp.json globally and .cursor/mcp.json per project (cursor.com/docs/mcp, checked October 2026).
  • VS Code with GitHub Copilot. .vscode/mcp.json with a top-level servers key, plus a user-profile mcp.json. Both are now labeled deprecated in the Add Server flow, which steers new servers to .mcp.json at the project root and ~/.copilot/mcp-config.json. Sweep both generations (code.visualstudio.com, checked October 2026).
  • Devin Desktop, which was Windsurf. ~/.config/devin/mcp_config.json, or %APPDATA%\devin\mcp_config.json on Windows. Devin's docs still name the older ~/.codeium/windsurf/mcp_config.json, so check both (docs.devin.ai, checked October 2026).
  • Codex. ~/.codex/config.toml, one [mcp_servers.<name>] table per server, plus a project .codex/config.toml in trusted projects only. One file covers the ChatGPT desktop app, the Codex CLI and the IDE extension (learn.chatgpt.com, checked October 2026).

Desktop extensions in Claude are local servers too, installed from Settings and then Extensions. No vendor page gives their path on disk, so the allowlist is the control for them, not a file sweep.

Quick reference: paths, policy and log coverage by client

Client User/global config Project config Policy control Admin log / audit coverage
Claude Desktop macOS: ~/Library/Application Support/Claude/claude_desktop_config.json; Windows: %APPDATA%\Claude\claude_desktop_config.json (mcpServers key) n/a (extensions use an allowlist, not a file) macOS domain com.anthropic.claudefordesktop; Windows HKLM:\SOFTWARE\Policies\Claude Per-server logs at ~/Library/Logs/Claude or %APPDATA%\Claude\logs
Claude.ai connectors n/a, server-side n/a Enterprise admin console Compliance API: integration_user_connected / _disconnected, mcp_server_created, mcp_tool_policy_updated
Claude Code ~/.claude.json .mcp.json at repo root allowedMcpServers / deniedMcpServers in managed settings (deny wins) OpenTelemetry claude_code.mcp_server_connection, server names only with OTEL_LOG_TOOL_DETAILS=1
Cursor ~/.cursor/mcp.json .cursor/mcp.json Enterprise allowlist (does not push servers) Enterprise audit log: mcp_server_config, mcp_authentication; beforeMCPExecution hook per call
VS Code + Copilot user-profile mcp.json (deprecated), now ~/.copilot/mcp-config.json .vscode/mcp.json (deprecated), now .mcp.json at root chat.mcp.access (all/registry/none) + per-server allow/deny (deny wins) Usage metrics report MCP use for Copilot CLI only
Devin Desktop ~/.config/devin/mcp_config.json; legacy ~/.codeium/windsurf/mcp_config.json n/a Team admin on/off + allowlist (one allowlisted server blocks all others) None documented
Codex (app/CLI/IDE) ~/.codex/config.toml .codex/config.toml (trusted projects only) requirements.toml approved mcp_servers list (empty key disables all) None documented

How to collect only the server entries

Parse each file and emit the server objects alone. Never ship the whole file to your inventory.

The reason is concrete. ~/.claude.json holds the Claude Code sign-in session alongside its mcpServers object, so a script that uploads the file uploads a credential. Read the mcpServers object out and discard the rest. Do the same for servers in VS Code's files and the [mcp_servers.*] tables in Codex's TOML. Use a real JSON or TOML parser rather than a regular expression, and when a file will not parse, log the path and move on.

Per entry, record five fields: the device, the user, the client, the server name, and either its url or its command with arguments. For an env block, record the key names and not the values. Those values are often long-lived API tokens, and a sweep that copies them creates a second place they live.

Project files are the part most sweeps miss. .mcp.json, .cursor/mcp.json, .vscode/mcp.json and .codex/config.toml sit inside repository checkouts, not in the home directory, so the script needs a path glob across developer working directories. Run the whole sweep twice, a week apart. The delta tells you whether the list is growing, which matters more than the first snapshot.

Which admin logs show an MCP connection?

Three exist today, and each covers connections made through the vendor's surface rather than files on disk.

Anthropic's Compliance API, on Enterprise, emits integration_user_connected and integration_user_disconnected with integration_type set to mcp, carrying the server's id and name. It also carries admin events such as mcp_server_created and mcp_tool_policy_updated. The Primary Owner enables it and there is no backfill, so turn it on before you need the history (platform.claude.com, checked October 2026). It covers connectors on the claude.ai side, not local config files.

Claude Code can emit claude_code.mcp_server_connection over OpenTelemetry, with server names present only when OTEL_LOG_TOOL_DETAILS=1 (code.claude.com, checked October 2026). Cursor's Enterprise audit log carries mcp_server_config and mcp_authentication events (cursor.com/docs/enterprise/compliance-and-monitoring, checked October 2026). Cursor does not say that an edit to a member's own mcp.json emits either, so treat it as coverage of connections rather than of files. Cursor also documents MDM-deployed hooks, where beforeMCPExecution sees the server name and its URL or command on every call and can allow, deny or ask (cursor.com/docs/hooks, checked October 2026). GitHub's usage metrics report MCP use for Copilot CLI only (docs.github.com, checked October 2026). OpenAI and Devin document nothing comparable, so the file sweep is the whole answer for Codex and Devin Desktop.

What to ask people directly

Send a short message to the teams most likely to have built something, and make it a question about their work rather than a compliance notice. Scripts miss anything written outside a standard directory. An engineer who wrote a local server to read a staging database will say so if nothing bad happens when they do.

Four questions is enough. Which MCP servers do you have configured, in any client. Which of them reach a company system, as opposed to local files. Which did you write yourself. Which would break your week if it stopped working on Friday.

That last question sorts the list. It separates a tool somebody tried once from a tool that is now part of a process, and the second kind has to be replaced rather than removed. State up front that the goal is to keep the useful ones working. An audit that reads as punishment pushes the next one further out of sight.

Keep, replace, remove: sorting the inventory

Sort every entry into one of three buckets, and resist inventing a fourth.

Keep is a local server that touches nothing but the developer's own machine and holds no company credential. A filesystem reader over a local checkout is the usual case. Record it, scope it so it cannot reach a production environment, and move on.

Replace is any server that reaches a company SaaS account: the Jira server with a personal API token in an env block, the Slack server somebody pasted a bot token into, the internal API wrapper running on one laptop. These are the entries a leaver takes with them, and they sit outside whatever sign-in rules govern everything else on the device, which is the practical case for OAuth rather than API keys.

The replace pattern has the same shape regardless of vendor: one shared endpoint behind OAuth, so no server URL or token lives in a per-user config file; a catalog of maintained connectors, so engineering time isn't spent patching a Jira or Slack MCP server; and a restriction layer, a rule naming which connectors and which individual tools a role or person may reach, enforced at browse, connect, advertise and execute, plus a final check on the fully substituted outbound URL, not only at connect.

Disclosure: Elaichi, which publishes this post, is one implementation of that pattern. It serves 600+ connectors through a single organization-wide endpoint, POST https://api.elaichi.ai/mcp, behind OAuth, with no per-user URLs and no embedded tokens. A restriction change takes effect within about two minutes. Elaichi writes one entry per tool-call attempt, succeeded or failed. If you're evaluating this category rather than this vendor, four questions apply to any product in it: single endpoint or per-user URLs, who authors and maintains the catalog, where restrictions are enforced (connect only, or also at execute), and how fast a change propagates.

Remove is everything with no owner, plus anything built on a shared long-lived token. Deleting the config entry is not the whole job. Rotate the credential it held, because the entry was only one copy of it.

Write the limit down next to the list. A governed endpoint controls access through itself and nothing upstream of it. It does not govern a server somebody else runs. GitHub's own MCP server, for instance, stays governed by GitHub's policy and your identity provider, regardless of catalog. Removing access through the gateway also ends there: the person's account inside each downstream app still exists and is deprovisioned through that app or your identity provider, which is the harder half of offboarding when an agent holds access.

Which managed policy keeps the list from growing again

Each client ships its own, and each binds only that client. Set them after the sweep, so you know in advance what the policy will break.

Claude Desktop reads device policy from the macOS domain com.anthropic.claudefordesktop and from HKLM:\SOFTWARE\Policies\Claude on Windows, where isLocalDevMcpEnabled, isDesktopExtensionEnabled and isDesktopExtensionDirectoryEnabled all default to true. The Desktop extension allowlist in Organization settings is off by default, and turning it on removes existing installs (support.claude.com, checked October 2026). Claude Code uses allowedMcpServers and deniedMcpServers in managed settings, where the denylist always wins and an unset allowlist allows everything. Anthropic states that matching by serverName is not a security control; the reason is that users choose the names, since the name is the key a person types in their own config. Match on serverUrl or serverCommand instead (code.claude.com, checked October 2026). A newly blocked server disappears from /mcp with no reason shown, so tell people before you apply it.

VS Code has chat.mcp.access, set to all, registry or none, plus per-server allow and deny lists where deny beats allow (code.visualstudio.com, checked October 2026). Cursor's allowlist is Enterprise only and does not push servers to anyone (cursor.com/docs/enterprise/model-and-integration-management, checked October 2026). Devin Desktop lets a team admin turn MCP off or allowlist servers, and once any server is allowlisted every other server is blocked for the team (docs.devin.ai, checked October 2026). Codex reads an approved mcp_servers list from requirements.toml, where a key that is present but empty disables every MCP server (learn.chatgpt.com, checked October 2026).

When the inventory is the whole job

If the sweep returns four local servers on two laptops and none of them holds a company credential, you are done. Set the client policies, keep the script on a monthly schedule, and spend the budget elsewhere. A governed endpoint earns its place when people are reaching company SaaS accounts from an assistant, not when two developers are reading local files.

The decision changes when the same list shows a personal token in a config file, or a server nobody can name the owner of, or one app connected from three different clients. At that point the work is consolidation, and the case for waiting no longer holds.

For the replacement step in detail, see how to swap personal servers on laptops for one endpoint. For what the browser-side evidence does and does not prove, read the shadow AI browser extension log, and for the layer above it, what CASB and DLP can see. The architecture behind the single address is covered in the MCP control plane explainer. Check which servers on your list have a maintained equivalent in the connector catalog.

FAQ

Frequently asked questions

Where does each AI client store its MCP server list?

As of October 2026: Claude Desktop uses ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows, under the mcpServers key. Claude Code uses ~/.claude.json for local and user scope and .mcp.json at a repository root for project scope. Cursor uses ~/.cursor/mcp.json and .cursor/mcp.json. VS Code with Copilot uses .vscode/mcp.json and a user-profile mcp.json, both now deprecated in favor of .mcp.json at the project root and ~/.copilot/mcp-config.json. Devin Desktop, formerly Windsurf, uses ~/.config/devin/mcp_config.json or %APPDATA%\devin\mcp_config.json, with the older ~/.codeium/windsurf/mcp_config.json still named in its docs. Codex uses ~/.codex/config.toml with one [mcp_servers.<name>] table per server.

Can an admin console show which MCP servers employees added on their own laptops?

No client vendor documents an admin inventory of the servers in members' local configuration files. Admin consoles report servers that connect, or are used, through the vendor's own surface. Anthropic's Compliance API emits integration_user_connected events with integration_type mcp, Claude Code can emit claude_code.mcp_server_connection over OpenTelemetry, and Cursor's Enterprise audit log carries mcp_server_config and mcp_authentication events. Finding local servers means reading the configuration files on each device with an MDM or EDR script.

Is it safe for an inventory script to upload the whole config file?

No. Parse the file and collect only the server entries. Claude Code's ~/.claude.json holds the sign-in session alongside its mcpServers object, so uploading the whole file uploads a credential. For an env block inside a server entry, record the key names and not the values, since those values are often long-lived API tokens.

Does removing an MCP server revoke the person's access to the third-party app?

No. Removing a server or a connector ends access through the AI client and nothing more. The person's account inside each app still exists, and it is deprovisioned in that app or through your identity provider. Rotate any credential the server config held, because deleting the entry does not invalidate the token it contained.

What should replace an MCP server that holds a personal API token?

A governed endpoint where the credential is not in the client at all. Elaichi serves every connected SaaS account through one organization-wide MCP endpoint at https://api.elaichi.ai/mcp, behind OAuth, with no per-user URL and no token to paste into a config file. Each member connects once and signs in with their own grant, and revoking that grant, removing the member or suspending them takes effect on the next call.

Put agents to work on your own systems

14 days on Gold, no credit card. Start with one app and one team.

Works with
Claude ChatGPT Cursor and any other MCP client, or the Elaichi Agent.
When the trial ends
Nothing is deleted. Connections, roles and the audit log stay where they are, so subscribing picks up exactly where you left off.