{
  "question": "How do I inventory MCP servers with scope, owner, and revocation?",
  "slug": "how-to-inventory-mcp-servers-with-scope-owner-and-revocation",
  "url": "https://www.rightshold.com/answers/how-to-inventory-mcp-servers-with-scope-owner-and-revocation",
  "short_answer": "Treat every MCP server as infrastructure that holds credentials, not as a browser extension: give each one a named owner, the exact host and transport it listens on, the token or OAuth grant it holds (scopes, expiry, issuer), the tools that grant exposes, and a tested revocation path. SC Media's November 3, 2026 perspective on CVE-2026-61560 in @zereight/mcp-gitlab (CVSS 9.8) describes the failure mode: a developer-run GitLab MCP server never reached the asset inventory, held a broad personal access token, and — before 2.1.27 — accepted unauthenticated SSE traffic that could read /proc/self/environ and steal that token. A spreadsheet of package names is not enough; you need a live grant record you can revoke, and a tools/list fingerprint you can re-check when the server changes.",
  "checklist": [
    "Find every MCP server your agents can reach: IDE configs (Claude Desktop, Cursor, VS Code, ChatGPT connectors), CI/CD, docker-compose, and any host publishing /sse, /messages or /mcp. Ask \"which MCP servers can reach our GitLab (or Slack, GitHub, prod DB)?\" and treat a blank answer as a gap.",
    "For each server record: owner (person or team), purpose, package name and pinned version, listen address and transport (stdio vs HTTP/SSE), whether auth is required on the transport, and the downstream system it talks to.",
    "Inventory the credential separately from the package: personal/project/group access token or OAuth client, owner of that credential, scopes, expiry, last-used, and the revoke action (GitLab Credentials inventory Revoke; IdP connected-app revoke; npm token delete).",
    "Map tools to grants: run tools/list, keep the name/description/inputSchema set, and write which scope or role each write/pay/delete tool needs. Prefer separate tokens when read and write scopes are different (GitLab token guidance).",
    "Prefer short-lived, least-privilege credentials: fine-grained or project-scoped tokens with expiry; MCP OAuth with resource-bound tokens and challenged scopes (MCP Authorization, July 2026 revision — authorization remains OPTIONAL for implementations).",
    "Register the server somewhere outside the agent's editable session (your CMDB, GitLab Credentials inventory for tokens, or an external MCP registry that stores a tools/list fingerprint) so definition drift is visible.",
    "Test revocation: revoke the grant, then confirm the next tools/call fails (401/403), including refresh paths and any second process that cached the token. Rotate any token that was ever exposed on a network-reachable unauthenticated transport.",
    "Watch package releases and security advisories for the servers you run, not only published CVEs — SC Media notes the gitlab-mcp fix shipped June 22, 2026 while the CVE record landed about twelve weeks later."
  ],
  "sections": [
    {
      "heading": "Why inventory beats a spreadsheet of package names",
      "points": [
        "CVE-2026-61560 (@zereight/mcp-gitlab before 2.1.27) chained an unauthenticated SSE transport with an upload_markdown tool that read arbitrary file_path values. GitLab's advisory and the maintainer changelog put the upgrade floor at 2.1.27 with SSE_AUTH_TOKEN for SSE deployments; impact is CVSS 9.8 with PAT exfiltration and account takeover.",
        "SC Media's point is operational: the server arrived through a developer laptop, skipped change control, never entered the asset inventory, and held a developer PAT with more access than the task needed. Detection that waits for a CVE id would have waited ~12 weeks after the fix.",
        "The MCP Authorization spec (2026-07-28) still marks authorization OPTIONAL. Defaults favor getting started, so your inventory — not the protocol — has to answer who owns each listener and how you cut it off."
      ]
    },
    {
      "heading": "What a verifiable grant record looks like",
      "points": [
        "One row (or ledger event) per live grant: server id, owner, credential id (not the secret), scopes, audience/resource, issued_at, expires_at, last_used, revoke_url or procedure, and the tools/list fingerprint version you approved.",
        "GitLab's Credentials inventory shows ownership, access scopes, usage, expiration and revocation dates for personal, project and group access tokens, and supports Revoke from that view — use it for GitLab-backed MCP tokens rather than a private wiki table.",
        "On the MCP side, challenge only the scopes the current operation needs (WWW-Authenticate scope), keep previously granted scopes when stepping up, and bind tokens to the resource (RFC 8707) so a stolen token for server A is refused at server B.",
        "Re-probe tools/list on a cadence. A changed fingerprint is a reason to re-approve scopes and re-read descriptions before the agent keeps calling the server — that is grant hygiene, not a safety certification."
      ]
    },
    {
      "heading": "What can go wrong",
      "points": [
        "The only inventory is a spreadsheet of npm package names with no owner, listen address, or revoke button.",
        "One classic or full-api token shared by several MCP servers; revoking for one outage breaks everything, and a single leak opens everything.",
        "Assuming \"read-only\" tool annotations or a narrow MCP scope string are enforced when the downstream API never checks them (separate GitLab MCP-scoped-token authorization bugs have required patches for exactly that class of gap).",
        "Leaving SSE or Streamable HTTP on 0.0.0.0 without auth \"just for a demo,\" including escape-hatch env vars that disable authentication."
      ]
    }
  ],
  "checks": [],
  "ask_rightshold": {
    "start": "https://www.rightshold.com/start?ref=seo",
    "mcp_endpoint": "https://www.rightshold.com/mcp",
    "ask": "Before I keep this MCP server in our inventory, is it registered, what tools does it expose now, and have its tool definitions changed since they were recorded?",
    "mcp_call": {
      "tool": "precall_check",
      "arguments": {
        "url": "<the MCP server's https URL>"
      }
    },
    "also": [
      "Free, no key. precall_check combines the external-registry entry (if any), a live integrity probe against the recorded tools/list fingerprint, and any security flags — facts about the probe, not a finding that the server is safe.",
      "register_external_server (account key) probes initialize + tools/list and stores what the server answered so later check_tool_integrity calls can show a plain diff when definitions change.",
      "list_mcp_health shows probe receipts over time for listed servers. revoke_agent kills a Rightshold agent credential that should no longer call anything; still revoke the downstream GitLab/IdP token in that system's own inventory.",
      "How to revoke an AI agent's access immediately and How to detect MCP tool description changes (rug pull) cover the kill-switch and fingerprint-diff steps."
    ],
    "scope": "Rightshold can register and re-probe external MCP servers and record agent credential revocations for agents that use it. It does not discover undeclared listeners on your network, revoke GitLab or IdP tokens for you, or certify any server as safe. Not legal advice."
  },
  "sources": [
    {
      "title": "SC Media: The MCP server nobody inventoried (Ashish Pulivarthy, Nov 3, 2026)",
      "url": "https://www.scworld.com/perspective/the-mcp-server-nobody-inventoried"
    },
    {
      "title": "GitLab Advisory Database: CVE-2026-61560 (@zereight/mcp-gitlab)",
      "url": "https://advisories.gitlab.com/npm/@zereight/mcp-gitlab/CVE-2026-61560/"
    },
    {
      "title": "zereight/gitlab-mcp CHANGELOG (GHSA-cv3r-c5h8-f4g5 / CVE-2026-61560)",
      "url": "https://github.com/zereight/gitlab-mcp/blob/main/CHANGELOG.md"
    },
    {
      "title": "GitLab Docs: Credentials inventory",
      "url": "https://docs.gitlab.com/administration/credentials_inventory/"
    },
    {
      "title": "GitLab Docs: Token overview (least privilege, separate tokens per scope)",
      "url": "https://docs.gitlab.com/security/tokens/"
    },
    {
      "title": "Model Context Protocol specification 2026-07-28: Authorization",
      "url": "https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization"
    }
  ],
  "related": [
    {
      "title": "How to vet an MCP server before installing it",
      "url": "https://www.rightshold.com/answers/how-to-vet-an-mcp-server-before-installing-it"
    },
    {
      "title": "How to detect MCP tool description changes (rug pull)",
      "url": "https://www.rightshold.com/answers/how-to-detect-mcp-tool-description-changes-rug-pull"
    },
    {
      "title": "How to revoke an AI agent's access immediately",
      "url": "https://www.rightshold.com/answers/how-to-revoke-an-ai-agents-access-immediately"
    },
    {
      "title": "How to give an MCP server least-privilege access to GitHub",
      "url": "https://www.rightshold.com/answers/how-to-give-an-mcp-server-least-privilege-access-to-github"
    }
  ],
  "computed_from": "Curated guidance; license verdicts computed from Rightshold's license profiles at render time. Not legal advice.",
  "updated": "2026-11-06"
}