Shelf Watch #3: What good looks like on a hosted enterprise MCP server A developer behind the open-source mcp-ship-check scanner completed a static code audit of 300 MCP servers, finding 10 with verified code-level vulnerabilities, one of which (atlas-mcp-server, GHSA-w3gh-28jp-2hmv) has been fixed and published while the rest are being disclosed privately to maintainers. A separate sweep of 116 registry-listed servers documenting mcp-remote found 284 invocations across 87 repos, 94% of which don't pin a version. The project also published an Enterprise MCP Reference Blueprint of four controls for multi-tenant MCP servers, and the device-code HTTPS fix for CVE-2026-108716 shipped in mcp-remote v0.16.6. Originally published in the mcp-ship-check https://github.com/bot2botlabs/mcp-ship-check repo, home of the free, offline scanner this post describes. Update 2026-11-11 . Since this post first ran, we've finished a static code audit of 300 MCP servers : 10 had a verified code-level vulnerability. One is fixed and published atlas-mcp-server , GHSA-w3gh-28jp-2hmv https://github.com/IamNishant51/atlas-mcp-server/security/advisories/GHSA-w3gh-28jp-2hmv ; the rest are being disclosed privately to their maintainers, and we name a project only after its fix ships. Separately, a bridge sweep of 116 registry-listed servers that document mcp-remote found 284 invocations across 87 repos, and 94% of them don't pin a version . And the device-code HTTPS fix for CVE-2026-108716 has shipped in mcp-remote v0.16.6 https://github.com/punkpeye/mcp-remote/commit/e4dc3713b0d6a727cbeb21f38324d20a6692dc5f e4dc371 : if you use --device-code , pin 0.16.6 or later. In Shelf Watch 2 we read the code of 194 MCP servers and found the usual failure modes: a tool argument reaching a shell, a database "read-only" guard that only checked the first keyword, an HTTP transport listening on every network interface. That post was about what goes wrong. This one is about the other end of the shelf: what a well-guarded hosted MCP server should look like, especially one that runs for many tenants at once, like the servers MSPs and security vendors are starting to ship. Below is our Enterprise MCP Reference Blueprint : four controls we'd want on any multi-tenant MCP server. None of them needs an enterprise budget. A two-person team can build every one. The blueprint draws on what we've seen in production hosted MCP architectures and on the MCP specification's 2025-11-25 Authorization https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization and Elicitation https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation sections. The specific limits and exclusions below are our design targets , not a description of any one product. Then we'll look at the part of the connection a server can't protect on its own: the client-side bridge that many setups use to reach a remote MCP server. The blueprint. Clients sign in with OAuth 2.1 and PKCE, as the MCP authorization spec https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization describes, not with a static API key. The token's scopes map onto the product's existing role-based access, with separate read and write grants per area of the product. An agent gets exactly the access its operator's role already has, and reading never implies writing. Why it matters. The MCP layer inherits the permission model your product has already battle-tested, instead of inventing a second, weaker one beside it. A leaked or over-shared token can only do what that user could already do. How a small team can copy it: yourapp:invoices:read , yourapp:invoices:write , and grant them from the roles you already have. The blueprint. Cap requests per token. We use 100 per minute as a starting point for an interactive agent. Let each call touch one resource, and scope every write tool to a single subject: one device, process, file, user or incident. There's no "apply to all" write path. Why it matters. Even with valid credentials, a confused or prompt-injected agent can't turn one bad call into a fleet-wide action. The worst case is bounded by design rather than by hoping the model behaves. all: true flag. maxItems , and paginate reads. The blueprint. Every write tool waits for synchronous, in-chat human approval before it runs. If the connecting client can't show that approval step, the call fails closed instead of running unapproved. Why it matters. This is the property the vulnerable servers in Shelf Watch 2 lacked. They ran dangerous operations with no human in the loop at all. "Refuse when we can't ask" is the safe default; "run anyway" is how a missing UI feature becomes an incident. readOnlyHint for reads, destructiveHint for anything that changes or deletes. In Shelf Watch 2, a third of the tools we could inspect declared neither. elicitation capability when they connect, so your server knows up front whether it can ask. The blueprint. Tools that move money or entitlements license allocation, trial changes, billing aren't exposed to external MCP clients at all. If a vendor's own first-party assistant needs them, it gets them on a separate internal surface. The external surface is deliberately a subset of the internal one. Why it matters. Not every tool belongs on a connector that any compatible client can reach. Anything that moves money, entitlements or billing state is a much bigger prize than a read-only query. msp-seat-reconcile All four controls above live on the server. But many clients reach a remote MCP server through a local bridge: most often the open-source mcp-remote https://www.npmjs.com/package/mcp-remote package, launched from the client's config with something like npx -y mcp-remote@