{
  "$schema": "https://readbeforerun.ai/schema/entry.schema.json",
  "entry": {
    "id": "gitguardian-ggmcp",
    "name": "GitGuardian MCP Server",
    "summary": "MCP server that brings GitGuardian secret detection, incident triage and honeytokens into an AI agent.",
    "draft": "review",
    "type": "mcp-server",
    "mission": [
      "defensive"
    ],
    "task": [
      "dependencies-secrets",
      "alert-triage"
    ],
    "domain": [
      "application-security",
      "security-operations"
    ],
    "runtime": [
      "mcp-generic",
      "cursor"
    ],
    "tier": "tried",
    "last_checked": "2026-11-07",
    "next_check": "2027-05-06",
    "freshness": "fresh",
    "superseded": false,
    "in_my_kit": null,
    "advice": null,
    "code_shows": "can tunnel or exfiltrate · writes outside the project · reads broad tokens or the environment · changes config or installs globally · Approval: unknown",
    "source": {
      "repo": "https://github.com/GitGuardian/ggmcp",
      "subpath": null,
      "commit": "7a75a34bc553a8717c2a119d28f96843ac9d32f6",
      "version": "v0.7.3",
      "license": "MIT"
    },
    "install": {
      "skills_cli": null,
      "claude_code": null,
      "upstream": "{\n  \"mcpServers\": {\n    \"GitGuardian\": {\n      \"command\": \"uvx\",\n      \"args\": [\n        \"--from\",\n        \"git+https://github.com/GitGuardian/ggmcp.git\",\n        \"gg-mcp-server\"\n      ],\n      \"env\": {\n        \"ENABLE_LOCAL_OAUTH\": \"false\",\n        \"GITGUARDIAN_PERSONAL_ACCESS_TOKEN\": \"your_pat_here\",\n        \"GITGUARDIAN_URL\": \"https://dashboard.gitguardian.com\"\n      }\n    }\n  }\n}",
      "bundled": false
    },
    "scan": {
      "status": "static scan pending (not run)"
    },
    "reach": {
      "method": "reach-v0.1",
      "level": 3,
      "level_source": "static",
      "level_label": "privileged",
      "unknown_axes": 1,
      "verdict": "as-declared",
      "badge": "reach 3 · as declared",
      "long": "reach 3 from code (privileged); lab: as declared",
      "declared": {
        "fs": 2,
        "net": 3,
        "cred": 1,
        "persist": 2
      },
      "static": {
        "level": 3,
        "fs": 2,
        "net": 3,
        "exec": 1,
        "cred": 2,
        "persist": 2,
        "hitl": null,
        "unknown": [
          "hitl"
        ]
      },
      "observed": {
        "level": 2,
        "fs": 2,
        "net": 1,
        "exec": 0,
        "cred": 0,
        "persist": 1,
        "hitl": 0,
        "unknown": [],
        "run": "2026-11-07"
      },
      "surplus": {
        "axes": {
          "fs": 0,
          "net": 0,
          "exec": 0,
          "cred": 0,
          "persist": 0,
          "hitl": 0
        },
        "count": 0,
        "beyond_static": [],
        "headline": "Within declared on every right the lab could observe."
      },
      "fit": "fits",
      "exports": {
        "aivss": {
          "fs": 0.5,
          "net": 1,
          "exec": 0.5,
          "cred": 0.5,
          "persist": 0.5,
          "hitl": null
        },
        "usf_risk_tier": "L3"
      }
    },
    "profile": {
      "read_at": "7a75a34bc553a8717c2a119d28f96843ac9d32f6",
      "read_on": "2026-10-25",
      "overview": "GitGuardian MCP Server is an MCP server that brings GitGuardian's secret detection, incident management and honeytoken generation into an AI agent; the tools it exposes depend on the OAuth scopes of the access token.",
      "purpose": [
        "Lets an AI agent scan code for credentials, triage existing secret incidents, generate honeytokens and remediate findings from an IDE or chat client.",
        "Lets AI agents scan projects for secrets through the GitGuardian API, manage security incidents and create honeytokens."
      ],
      "use_cases": [
        {
          "text": "Scan files for leaked credentials",
          "task": "dependencies-secrets"
        },
        {
          "text": "List, filter, assign, resolve and tag internal and Public Monitoring secret incidents",
          "task": "alert-triage"
        },
        {
          "text": "Generate honeytokens and list existing ones",
          "task": "detection-engineering"
        },
        {
          "text": "Open pull requests that remediate secrets in repositories the workspace monitors",
          "task": "dependencies-secrets"
        }
      ],
      "maturity": "beta",
      "capabilities": [
        {
          "name": "Proactive Secret Scanning",
          "effects": [
            "reads",
            "sends-data"
          ],
          "enabled": "default"
        },
        {
          "name": "Incident Management",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default"
        },
        {
          "name": "Repository Analysis",
          "effects": [
            "reads",
            "runs-commands"
          ],
          "enabled": "default"
        },
        {
          "name": "Remediation",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default"
        },
        {
          "name": "Honeytoken Management",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default"
        },
        {
          "name": "user information and token management",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default"
        }
      ],
      "effects": [
        "reads",
        "changes",
        "runs-commands",
        "sends-data"
      ],
      "runs": "vendor-hosted",
      "listens": [
        {
          "mode": "optional",
          "bind": "configurable",
          "sign_in": "optional"
        },
        {
          "mode": "optional",
          "bind": "all-interfaces",
          "sign_in": "optional"
        },
        {
          "mode": "optional",
          "bind": "loopback",
          "sign_in": "none"
        }
      ],
      "sends_to": [
        {
          "to": "GitGuardian API",
          "kind": "vendor-api",
          "when": "always"
        },
        {
          "to": "GitGuardian /multiscan",
          "kind": "vendor-api",
          "when": "default"
        },
        {
          "to": "mcp.gitguardian.com",
          "kind": "vendor-api",
          "when": "default"
        },
        {
          "to": "Sentry",
          "kind": "telemetry",
          "when": "optional"
        },
        {
          "to": "GitGuardian dashboard login",
          "kind": "vendor-api",
          "when": "optional"
        },
        {
          "to": "github.com/GitGuardian/ggmcp",
          "kind": "download",
          "when": "optional"
        }
      ],
      "model": "client",
      "needs": [
        {
          "kind": "account",
          "text": "A GitGuardian workspace (US or EU SaaS, or self-hosted) where a personal access token can be created in the dashboard."
        },
        {
          "kind": "credentials",
          "text": "The code defines scan, incidents:read and sources:read as MINIMAL_SCOPES."
        },
        {
          "kind": "runtime",
          "text": "The ggmcp package requires Python 3.11 or later."
        },
        {
          "kind": "setting",
          "text": "Local stdio with a PAT sets ENABLE_LOCAL_OAUTH=false and GITGUARDIAN_PERSONAL_ACCESS_TOKEN in the client's env block."
        },
        {
          "kind": "authorization",
          "text": "create_code_fix_request needs Manager access level and the incidents:write scope."
        },
        {
          "kind": "setting",
          "text": "Self-hosted GitGuardian instances need IS_ON_PREM=true so the server uses the /exposed/v1 API path and the self-hosted scope set."
        },
        {
          "kind": "other",
          "text": "Claude Desktop versions that pre-date HTTP MCP support need the local stdio fallback instead of the hosted server."
        },
        {
          "kind": "setting",
          "text": "For Claude Desktop on macOS the local stdio configuration needs the absolute path to uvx in the command field, because Claude Desktop does not resolve $PATH for MCP servers."
        }
      ]
    },
    "urls": {
      "page": "/catalog/gitguardian-ggmcp/",
      "json": "/entries/gitguardian-ggmcp.json",
      "md": "/catalog/gitguardian-ggmcp.md",
      "badge": "/badge/gitguardian-ggmcp.svg"
    }
  },
  "data": {
    "schema_version": "0.5",
    "slug": "gitguardian-ggmcp",
    "name": "GitGuardian MCP Server",
    "summary": "MCP server that brings GitGuardian secret detection, incident triage and honeytokens into an AI agent.",
    "draft": "review",
    "in_my_kit": null,
    "type": "mcp-server",
    "mission": [
      "defensive"
    ],
    "task": [
      "dependencies-secrets",
      "alert-triage"
    ],
    "domain": [
      "application-security",
      "security-operations"
    ],
    "phase": [
      "def:protect",
      "def:respond"
    ],
    "role": [
      "appsec",
      "soc"
    ],
    "runtime": [
      "mcp-generic",
      "cursor"
    ],
    "auth": "oauth2",
    "autonomy": null,
    "addresses": [],
    "frameworks": {
      "owasp_ast": [],
      "owasp_asi": [],
      "attack_tactic": [],
      "atlas": []
    },
    "source": {
      "repo": "https://github.com/GitGuardian/ggmcp",
      "commit": "7a75a34bc553a8717c2a119d28f96843ac9d32f6",
      "version": "v0.7.3",
      "license": "MIT",
      "manifest": "server.json",
      "also_listed": {}
    },
    "upstream": {
      "checked_at": "2026-10-19",
      "updated_at": "2026-10-14",
      "current_release": "v0.7.3",
      "archived": false,
      "stars": 40,
      "commit_history": {},
      "releases_since_pin": 0
    },
    "install": {
      "upstream": "{\n  \"mcpServers\": {\n    \"GitGuardian\": {\n      \"command\": \"uvx\",\n      \"args\": [\n        \"--from\",\n        \"git+https://github.com/GitGuardian/ggmcp.git\",\n        \"gg-mcp-server\"\n      ],\n      \"env\": {\n        \"ENABLE_LOCAL_OAUTH\": \"false\",\n        \"GITGUARDIAN_PERSONAL_ACCESS_TOKEN\": \"your_pat_here\",\n        \"GITGUARDIAN_URL\": \"https://dashboard.gitguardian.com\"\n      }\n    }\n  }\n}",
      "upstream_evidence": "README.md#L161-177",
      "bundled": false
    },
    "scan": [
      {
        "tool": "cisco-skill-scanner",
        "version": "not-run",
        "llm_judge": false,
        "date": "2026-10-19",
        "result": "pending"
      }
    ],
    "privileges": {
      "method": "reach-v0.1",
      "declared": {
        "axes": {
          "fs": 2,
          "net": 3,
          "cred": 1,
          "persist": 2
        },
        "evidence": {
          "fs": "README.md#L21-22 code-fix automation opens pull requests in the repositories the workspace monitors, writing on the target",
          "net": "README.md#L207 the documented self-hosted container launch binds the StreamableHTTP server to every network interface on port 8000, a declared listener beyond the loopback default",
          "cred": "README.md#L180 the user creates one personal access token for the server",
          "persist": "README.md#L18-19 incident management assigns, resolves and tags incidents, which changes workspace state"
        }
      },
      "static": {
        "level": 3,
        "axes": {
          "fs": 2,
          "net": 3,
          "exec": 1,
          "cred": 2,
          "persist": 2,
          "hitl": null
        },
        "evidence": {
          "fs": "packages/gg_api_core/src/gg_api_core/oauth.py#L116 writes the token JSON to the user's configuration directory outside the working directory; packages/gg_api_core/src/gg_api_core/client.py#L307-310 only in the local OAuth flow, because a personal access token in the environment is used before any token file",
          "net": "Dockerfile#L76 the repository container image sets the HTTP bind host to all interfaces, so the server listens on every interface, while the stdio default is the loopback address; packages/gg_api_core/src/gg_api_core/settings.py#L63 outside Docker the HTTP host defaults to 127.0.0.1, and HTTP runs only when MCP_PORT is set",
          "exec": "packages/gg_api_core/src/gg_api_core/tools/find_current_source_id.py#L142 runs the fixed program git with fixed arguments in the stdio transport, with no free shell",
          "cred": "packages/gg_api_core/src/gg_api_core/settings.py#L157 unless scopes are set the OAuth flow requests the full scope list including write scopes, so the server holds a broadly privileged token; packages/gg_api_core/src/gg_api_core/mcp_server.py#L385-390 with ENABLE_LOCAL_OAUTH=false and a personal access token, as in the quoted install, the server uses that token and runs no OAuth flow",
          "persist": "packages/gg_api_core/src/gg_api_core/client.py#L1452 deletes workspace custom tags and other calls change incident state, i.e. target configuration",
          "hitl": "no evidence: the server code sets no approval configuration and carries no MCP tool safety annotations; the README only advises reviewing agent actions"
        },
        "unknown": [
          "hitl"
        ]
      },
      "observed": {
        "level": 2,
        "axes": {
          "fs": 2,
          "net": 1,
          "exec": 0,
          "cred": 0,
          "persist": 1,
          "hitl": 0
        },
        "unknown": [],
        "run": "runs/2026-11-07",
        "valid_for": {
          "commit": "7a75a34bc553a8717c2a119d28f96843ac9d32f6",
          "version": "v0.7.3"
        }
      },
      "surplus": {
        "axes": {
          "fs": 0,
          "net": 0,
          "exec": 0,
          "cred": 0,
          "persist": 0,
          "hitl": 0
        },
        "count": 0,
        "beyond_static": [],
        "headline": "Within declared on every right the lab could observe."
      },
      "fit": "fits",
      "min_config": {
        "status": "derived",
        "note": "derived from the code; of it, the lab ran stdio with a PAT from the environment and ENABLE_LOCAL_OAUTH=false against a stub of the API (runs/2026-11-07); prefer the stdio transport, pass a PAT through the environment and set ENABLE_LOCAL_OAUTH=false, set GITGUARDIAN_SCOPES to a read-only set rather than the default all-scopes, never run the HTTP container bound to 0.0.0.0 without TLS and auth in front, create the PAT with read scopes only, and do not run the HTTP mode with a PAT in the environment"
      },
      "override": null,
      "reviews": []
    },
    "status": {
      "tier": "tried",
      "last_checked": "2026-11-07",
      "next_check": "2027-05-06",
      "freshness": "fresh",
      "superseded": false,
      "superseded_by": null,
      "added": "2026-10-19",
      "added_by": "scout"
    },
    "evidence": {
      "label": "observation",
      "runs": [
        "runs/2026-11-07"
      ],
      "badge": "/badge/gitguardian-ggmcp.svg"
    },
    "changes": [
      {
        "date": "2026-11-07",
        "value": "tier",
        "from": "listed",
        "to": "tried",
        "reason": "First lab run published (runs/2026-11-07): gg-mcp-server over stdio with a PAT from the environment, against the lab's stub of the GitGuardian API; observed reach 2, within the declaration on every right."
      }
    ]
  },
  "profile": {
    "schema_version": "0.1",
    "entry": "gitguardian-ggmcp",
    "draft": "review",
    "commit": "7a75a34bc553a8717c2a119d28f96843ac9d32f6",
    "read_on": "2026-10-25",
    "check": {
      "date": "2026-10-25",
      "facts": 61,
      "confirmed": 61,
      "verified": 51
    },
    "overview": {
      "text": "GitGuardian MCP Server is an MCP server that brings GitGuardian's secret detection, incident management and honeytoken generation into an AI agent; the tools it exposes depend on the OAuth scopes of the access token.",
      "ev": "README.md#L3 author's one-line description"
    },
    "maturity": {
      "word": "beta",
      "text": "The package metadata classifies the project as Development Status 4 - Beta.",
      "ev": "pyproject.toml#L23 Python package classifier"
    },
    "purpose": [
      {
        "text": "Lets an AI agent scan code for credentials, triage existing secret incidents, generate honeytokens and remediate findings from an IDE or chat client.",
        "ev": "README.md#L4-6 author's statement of what it is for"
      },
      {
        "text": "Lets AI agents scan projects for secrets through the GitGuardian API, manage security incidents and create honeytokens.",
        "ev": "server.json#L4 MCP registry description"
      }
    ],
    "use_cases": [
      {
        "text": "Scan files for leaked credentials",
        "task": "dependencies-secrets",
        "ev": "README.md#L17 'What it does' list"
      },
      {
        "text": "List, filter, assign, resolve and tag internal and Public Monitoring secret incidents",
        "task": "alert-triage",
        "ev": "README.md#L18-19 'What it does' list"
      },
      {
        "text": "Generate honeytokens and list existing ones",
        "task": "detection-engineering",
        "ev": "README.md#L20 'What it does' list"
      },
      {
        "text": "Open pull requests that remediate secrets in repositories the workspace monitors",
        "task": "dependencies-secrets",
        "ev": "README.md#L21-22 'What it does' list"
      }
    ],
    "not_for": [],
    "capabilities": {
      "coverage": "complete",
      "groups": [
        {
          "name": "Proactive Secret Scanning",
          "does": "scan_secrets passes the documents the agent supplies to the GitGuardian API through the client's multiple_scan call and returns the scan results.",
          "effects": [
            "reads",
            "sends-data"
          ],
          "enabled": "default",
          "ev": "packages/gg_api_core/src/gg_api_core/tools/scan_secret.py#L84-85 tool passes the documents to the API client"
        },
        {
          "name": "Incident Management",
          "does": "Lists and filters internal and public incidents, and assigns, resolves, ignores, reopens and tags them.",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default",
          "ev": "packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L95-96 capability list in server instructions"
        },
        {
          "name": "Repository Analysis",
          "does": "In local stdio mode find_current_source_id runs git config --get remote.origin.url in the given repository path to identify the repository.",
          "effects": [
            "reads",
            "runs-commands"
          ],
          "enabled": "default",
          "ev": "packages/gg_api_core/src/gg_api_core/tools/find_current_source_id.py#L140-148 subprocess call to git in stdio transport"
        },
        {
          "name": "Remediation",
          "does": "Locates occurrences with list_remediation_targets, reads the workspace instructions with get_remediation_workflow, and create_code_fix_request opens automated pull requests.",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default",
          "ev": "packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L101-103 capability list in server instructions"
        },
        {
          "name": "Honeytoken Management",
          "does": "generate_honeytoken creates an AWS GitGuardian honeytoken with injection recommendations; names must be unique among the workspace's active honeytokens.",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default",
          "ev": "packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L220-225 tool registration"
        },
        {
          "name": "user information and token management",
          "does": "revoke_current_token revokes the current API token and cleans up stored credentials.",
          "effects": [
            "reads",
            "changes"
          ],
          "enabled": "default",
          "ev": "packages/gg_api_core/src/gg_api_core/mcp_server.py#L267-270 common tool registration"
        }
      ]
    },
    "architecture": {
      "summary": {
        "text": "gg-mcp-server picks its transport at start: StreamableHTTP when MCP_PORT is set, otherwise stdio.",
        "ev": "packages/gg_mcp_server/src/gg_mcp_server/run.py#L52-61 transport auto-detection"
      },
      "runs": {
        "where": "vendor-hosted",
        "text": "The README recommends the hosted server at mcp.gitguardian.com; the client handles OAuth and nothing is installed locally.",
        "ev": "README.md#L59-61 recommended deployment"
      },
      "modes": [
        {
          "where": "local-process",
          "mode": "local stdio with PAT",
          "switch": null,
          "text": "Runs the server locally over stdio with a PAT, for CI/CD, airgapped environments or older MCP clients.",
          "ev": "README.md#L157-158 local stdio mode"
        },
        {
          "where": "container",
          "mode": "self-hosted HTTP",
          "switch": null,
          "text": "Self-hosters run the ghcr.io/gitguardian/mcp-server image, which serves StreamableHTTP on port 8000 behind a TLS-terminating proxy.",
          "ev": "README.md#L192-194 self-hosting section"
        }
      ],
      "parts": [
        {
          "name": "MCP client configuration",
          "zone": "client",
          "does": "An mcpServers entry of type http in the client's mcp.json points to https://mcp.gitguardian.com/mcp.",
          "ev": "README.md#L75-84 client configuration example"
        },
        {
          "name": "Hosted MCP server",
          "zone": "outside",
          "does": "GitGuardian's hosted MCP endpoint: https://mcp.gitguardian.com/mcp for US SaaS or https://mcp.eu1.gitguardian.com/mcp for EU SaaS.",
          "ev": "README.md#L65-68 region URL table"
        },
        {
          "name": "gg-mcp-server (local stdio process)",
          "zone": "machine",
          "does": "Local process the MCP client starts with uvx --from git+https://github.com/GitGuardian/ggmcp.git gg-mcp-server.",
          "ev": "README.md#L163-168 stdio command configuration"
        },
        {
          "name": "GitGuardian API",
          "zone": "outside",
          "does": "GitGuardian public API that receives every call with the token in the Authorization header; SaaS or self-hosted.",
          "ev": "packages/gg_api_core/src/gg_api_core/client.py#L375-382 request headers"
        },
        {
          "name": "ghcr.io/gitguardian/mcp-server image",
          "zone": "container",
          "does": "Image that sets MCP_PORT=8000, MCP_HOST=0.0.0.0 and ENABLE_LOCAL_OAUTH=false and leaves the start command to the deployment.",
          "ev": "Dockerfile#L74-83 environment and entrypoint"
        },
        {
          "name": "Local OAuth token file",
          "zone": "machine",
          "does": "The local OAuth flow keeps tokens in mcp_oauth_tokens.json inside a gitguardian config directory it creates.",
          "ev": "packages/gg_api_core/src/gg_api_core/oauth.py#L91-92 token file path"
        }
      ],
      "listens": [
        {
          "what": "With MCP_PORT set, uvicorn serves the /mcp StreamableHTTP app on the host and port from the MCP_HOST and MCP_PORT settings.",
          "mode": "optional",
          "bind": "configurable",
          "sign_in": "optional",
          "ev": "packages/gg_mcp_server/src/gg_mcp_server/run.py#L38-46 uvicorn host and port from settings"
        },
        {
          "what": "The documented docker run publishes port 8000 and starts gunicorn bound to 0.0.0.0:8000, with the OAuth proxy enabled in that example.",
          "mode": "optional",
          "bind": "all-interfaces",
          "sign_in": "optional",
          "ev": "README.md#L198-207 docker run example"
        },
        {
          "what": "The local OAuth flow's callback HTTPServer binds explicitly to 127.0.0.1 on a free port.",
          "mode": "optional",
          "bind": "loopback",
          "sign_in": "none",
          "ev": "packages/gg_api_core/src/gg_api_core/oauth.py#L386-388 callback server bind"
        }
      ],
      "connections": [
        {
          "to": "GitGuardian API",
          "kind": "vendor-api",
          "when": "always",
          "what": "Every tool call goes to the GitGuardian API derived from GITGUARDIAN_URL (default dashboard.gitguardian.com) with the token in a header.",
          "ev": "packages/gg_api_core/src/gg_api_core/settings.py#L44 default instance URL"
        },
        {
          "to": "GitGuardian /multiscan",
          "kind": "vendor-api",
          "when": "default",
          "what": "scan_secrets posts the contents of the documents the agent passes to the /multiscan endpoint.",
          "ev": "packages/gg_api_core/src/gg_api_core/client.py#L1382 multiscan POST"
        },
        {
          "to": "mcp.gitguardian.com",
          "kind": "vendor-api",
          "when": "default",
          "what": "With the hosted server, requests transit mcp.gitguardian.com in addition to api.gitguardian.com.",
          "ev": "README.md#L128 deployment table"
        },
        {
          "to": "Sentry",
          "kind": "telemetry",
          "when": "optional",
          "what": "Sentry error reporting is enabled only when SENTRY_DSN is set.",
          "ev": "packages/gg_api_core/src/gg_api_core/sentry_integration.py#L8 Sentry opt-in variable"
        },
        {
          "to": "GitGuardian dashboard login",
          "kind": "vendor-api",
          "when": "optional",
          "what": "The local OAuth flow opens the GitGuardian authorization URL in the user's browser.",
          "ev": "packages/gg_api_core/src/gg_api_core/oauth.py#L572 browser launch"
        },
        {
          "to": "github.com/GitGuardian/ggmcp",
          "kind": "download",
          "when": "optional",
          "what": "The local stdio configuration makes uvx fetch the package from the GitHub repository's default branch.",
          "ev": "README.md#L167 uvx source URL"
        }
      ],
      "model": {
        "who": "client",
        "text": "Per the README, agents act on the user's behalf and under the user's responsibility when they use the server's tools.",
        "ev": "README.md#L9-10 caution about agents acting on the user's behalf"
      }
    },
    "needs": [
      {
        "kind": "account",
        "text": "A GitGuardian workspace (US or EU SaaS, or self-hosted) where a personal access token can be created in the dashboard.",
        "ev": "README.md#L180-181 PAT creation"
      },
      {
        "kind": "credentials",
        "text": "The code defines scan, incidents:read and sources:read as MINIMAL_SCOPES.",
        "ev": "packages/gg_api_core/src/gg_api_core/scopes.py#L5-9 MINIMAL_SCOPES"
      },
      {
        "kind": "runtime",
        "text": "The ggmcp package requires Python 3.11 or later.",
        "ev": "pyproject.toml#L35 Python requirement"
      },
      {
        "kind": "setting",
        "text": "Local stdio with a PAT sets ENABLE_LOCAL_OAUTH=false and GITGUARDIAN_PERSONAL_ACCESS_TOKEN in the client's env block.",
        "ev": "README.md#L170-173 env block of the stdio configuration"
      },
      {
        "kind": "authorization",
        "text": "create_code_fix_request needs Manager access level and the incidents:write scope.",
        "ev": "packages/gg_api_core/src/gg_api_core/tools/create_code_fix_request.py#L115-118 permission error message"
      },
      {
        "kind": "setting",
        "text": "Self-hosted GitGuardian instances need IS_ON_PREM=true so the server uses the /exposed/v1 API path and the self-hosted scope set.",
        "ev": "README.md#L210-214 IS_ON_PREM explanation"
      },
      {
        "kind": "other",
        "text": "Claude Desktop versions that pre-date HTTP MCP support need the local stdio fallback instead of the hosted server.",
        "ev": "README.md#L89-91 Claude Desktop note"
      },
      {
        "kind": "setting",
        "text": "For Claude Desktop on macOS the local stdio configuration needs the absolute path to uvx in the command field, because Claude Desktop does not resolve $PATH for MCP servers.",
        "ev": "README.md#L183-185 Claude Desktop macOS note in the local stdio section"
      }
    ],
    "installer": [
      {
        "text": "The local stdio configuration runs uvx --from git+https://github.com/GitGuardian/ggmcp.git gg-mcp-server, which builds from the default branch without a version pin.",
        "ev": "README.md#L164-168 uvx command and args"
      },
      {
        "text": "The self-hosting example runs the mutable tag ghcr.io/gitguardian/mcp-server:latest.",
        "ev": "README.md#L205 docker run image reference"
      },
      {
        "text": "The publish-to-pypi and publish-to-mcp-registry jobs are disabled, so the package is not published to PyPI or the MCP Registry; server.json is still version-synced.",
        "ev": "PUBLISHING.md#L126-130 publishing status"
      }
    ],
    "limits": [
      {
        "text": "Unless GITGUARDIAN_SCOPES is set, effective_scopes returns all of ALL_SCOPES, or SCOPES_SUPPORTED_IN_SELF_HOSTED on non-local self-hosted instances.",
        "ev": "packages/gg_api_core/src/gg_api_core/settings.py#L150-157 effective_scopes fallback"
      },
      {
        "text": "In PAT env mode, which needs ENABLE_LOCAL_OAUTH=false and no OAuth proxy, the server is built without an auth provider, so any caller of an HTTP listener acts with that PAT.",
        "ev": "packages/gg_api_core/src/gg_api_core/mcp_server.py#L385-390 PAT env mode constructed without auth"
      },
      {
        "text": "The deprecated local OAuth flow saves the issued token to a JSON file in the user's config directory with file mode 0600.",
        "ev": "packages/gg_api_core/src/gg_api_core/oauth.py#L110-119 save_token"
      },
      {
        "text": "Since 0.7.3 honeytoken values are returned unmasked to the agent.",
        "ev": "CHANGELOG.md#L8 0.7.3 bug fix entry"
      },
      {
        "text": "The model decides which files scan_secrets sends to GitGuardian; the tool description asks it to send codebase files and skip files listed in .gitignore.",
        "ev": "packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L144-145 scan_secrets description"
      },
      {
        "text": "The README warns that agents act on the user's behalf and says the server defaults to read-only-leaning permissions, with exposure set by the token's OAuth scopes.",
        "ev": "README.md#L8-13 caution block"
      },
      {
        "text": "manage_private_incident refuses to resolve an incident without secret_revoked and tells the model to ask the user whether the secret was revoked or rotated.",
        "ev": "packages/gg_api_core/src/gg_api_core/tools/manage_incident.py#L62-68 resolve guard"
      },
      {
        "text": "Browser-driven OAuth in stdio mode is deprecated but stays the stdio default; it opens a localhost callback and stores the PAT on disk.",
        "ev": "README.md#L146-153 authentication mode table row and deprecation note"
      },
      {
        "text": "In OAuth proxy mode the MCP client receives the real GitGuardian PAT, and the proxy class extends PassThroughTokenVerifier, so the server does not validate bearer tokens itself.",
        "ev": "packages/gg_api_core/src/gg_api_core/oauth_proxy_auth.py#L164-169 GitGuardianOAuthThinProxy class and docstring"
      },
      {
        "text": "GITGUARDIAN_TOKEN_LIFETIME sets the lifetime in days of OAuth-issued PATs, default 30, and accepts never.",
        "ev": "README.md#L231 configuration reference row"
      },
      {
        "text": "revoke_secret revokes a secret by its ID through the GitGuardian API, for internal and Public Monitoring incidents alike, and requires the secrets:write scope.",
        "ev": "packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L376-381 revoke_secret registration"
      },
      {
        "text": "In OAuth proxy mode the token lifetime setting defaults to 90 days, which the code comment says mirrors the server-side default and cap for DCR-issued tokens.",
        "ev": "packages/gg_api_core/src/gg_api_core/settings.py#L72-76 mcp_oauth_token_lifetime default"
      },
      {
        "text": "When neither the OAuth proxy, local OAuth nor GITGUARDIAN_PERSONAL_ACCESS_TOKEN is configured, the server falls back to Authorization-header mode with PassThroughTokenVerifier and takes the PAT from each request's bearer header.",
        "ev": "packages/gg_api_core/src/gg_api_core/mcp_server.py#L387-396 last branch of get_mcp_server selects the Authorization-header mode with a pass-through verifier"
      },
      {
        "text": "ALL_SCOPES, the scope list requested by default, includes write scopes such as honeytokens:write, incidents:write and api_tokens:write.",
        "ev": "packages/gg_api_core/src/gg_api_core/scopes.py#L13-22 HONEYTOKEN_SCOPES and ALL_SCOPES definitions with write scopes"
      },
      {
        "text": "In single-tenant mode the client takes the PAT from GITGUARDIAN_PERSONAL_ACCESS_TOKEN first, then from a stored OAuth token, and runs the interactive OAuth flow only when local OAuth is enabled.",
        "ev": "packages/gg_api_core/src/gg_api_core/client.py#L292-295 token source precedence in acquire_single_tenant_token"
      },
      {
        "text": "Write tools such as revoke_secret are registered with a description and required_scopes only; the code sets no MCP tool annotations such as readOnlyHint or destructiveHint.",
        "ev": "packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L376-381 revoke_secret registration without annotations"
      }
    ],
    "not_found": [
      {
        "field": "not_for",
        "searched": "README.md, server.json, DEVELOPMENT.md and tool descriptions in register_tools.py for out-of-scope, authorised-use-only or do-not-use statements"
      },
      {
        "field": "capability_count",
        "searched": "README.md, server.json, pyproject.toml for a stated number of tools; only '500+ detectors' is stated"
      },
      {
        "field": "autonomy",
        "searched": "not applicable: entry type is mcp-server, not agent"
      }
    ]
  },
  "verdict": null,
  "runs": [
    {
      "schema_version": "0.5",
      "run_id": "20261107T180211Z-gitguardian-ggmcp",
      "entry": "gitguardian-ggmcp",
      "draft": "review",
      "label": "observation",
      "method_version": "0.1",
      "reach_method": "reach-v0.1",
      "published": "2026-11-07",
      "run_by": "Ilja Schlak",
      "disclaimer": "One run is an observation, not a benchmark. Observed reach holds for exactly this configuration: gg-mcp-server over stdio with a personal access token from the environment and local OAuth off, driven by Claude Code with Haiku, against a lab stub of the GitGuardian API with a dummy token.",
      "tool": {
        "name": "GitGuardian MCP Server",
        "commit": "7a75a34bc553a8717c2a119d28f96843ac9d32f6",
        "version": "v0.7.3",
        "install_source": "upstream",
        "declared_file": "declared.json"
      },
      "runtime": {
        "client": "claude-code",
        "client_version": "2.1.311",
        "permission_mode": "dontAsk with the lab approver: every tool call asks, the task list below allows, everything else is denied",
        "allow_list": [
          "mcp__gitguardian__list_detectors"
        ],
        "sandbox": {
          "lab_vm": true,
          "external_allowlist_empty": true,
          "dns_via_lab_resolver": true,
          "target_only": true
        },
        "user": "tool (uid 1001), no sudo"
      },
      "model": {
        "id": "claude-haiku-5-5",
        "dated": "2026-11-07",
        "route": "direct",
        "virtual_key": "tool",
        "inference_region": "global"
      },
      "target": {
        "name": "Lab stub of the GitGuardian API (fixtures/api-stub, plain HTTP on the lab target)",
        "version": "0.1.0",
        "ground_truth": "n/a: the stub answers with fixed, empty results; no planted findings",
        "contamination": "written for the lab; no vendor data; the credentials given to the tool are lab dummies"
      },
      "access_mode": "white-box",
      "task_given": "Lab measurement task. Use only the tools of the MCP server gitguardian. Call list_detectors once without arguments. Then answer in one sentence what the call returned. Do not call any other tool.",
      "timebox_minutes": 6,
      "overnight": false,
      "phases": {
        "install": {
          "start": "2026-11-07T18:02:11Z",
          "end": "2026-11-07T18:04:35Z",
          "egress_hosts": [
            "files.pythonhosted.org",
            "pypi.org"
          ]
        },
        "run": {
          "start": "2026-11-07T18:04:48Z",
          "end": "2026-11-07T18:07:02Z",
          "egress_hosts": []
        }
      },
      "duration_seconds": 134,
      "budget_cap_usd": 0.5,
      "cost": {
        "cost_source": "tool-reported",
        "total_cost": 0.0067,
        "input_tokens": 63533,
        "output_tokens": 71,
        "duration_seconds": 134,
        "cost_per_hour": 0.1805,
        "file": "cost.json"
      },
      "result": {
        "score": "Task done: list_detectors returned the empty list the lab stub serves. Nothing to score: this run measures reach, not detection.",
        "findings_reported": 0,
        "sample_validated": 0,
        "true_positives": 0,
        "false_positives": 0,
        "scope_violations": [],
        "file": "findings.jsonl",
        "notes": "ggmcp reads its token's scopes from the API's /api_tokens/self to decide which tools to offer (packages/gg_api_core/src/gg_api_core/mcp_server.py line 225 at the pinned commit). The lab points GITGUARDIAN_URL at its own stub of the API, which reports a token with only the scan scope (tool-cmd.sh). The server made three requests, all to the stub: two token look-ups and one detector list (target-access.txt lines 3 to 5). While it ran, the beartype library it depends on wrote 30 bytecode cache files with its own optimization tag into the tool's virtual environment, outside the working directory (fs-diff.json); that is what files 2 and persistence 1 read here, and nothing else was written. No credential store was read, and the runner made no DNS query and no connection outside the lab. The install took the 70 locked packages with their hashes from the workspace's uv.lock through the lab proxy and built the two workspace packages from the pinned tree."
      },
      "reach_observed": {
        "level": 2,
        "axes": {
          "fs": {
            "value": 2,
            "evidence": "fs-diff.json#L1 write outside /home/tool/work: /home/tool/.local/ggmcp-venv/lib/python3.13/site-packages/beartype/_util/os/__pycache__/utilostty.cpython-313.opt-beartype0v22v9.pyc"
          },
          "net": {
            "value": 1,
            "evidence": "target-access.txt#L3-5 connection to the declared target (run->tgt)"
          },
          "exec": {
            "value": 0,
            "evidence": "none found: no execve besides the tool itself (tool start host-events.jsonl#L3: python3); harness starts L1, L2 (timeout, start wrapper, preparation) are not counted for the tool"
          },
          "cred": {
            "value": 0,
            "evidence": "none found: no reads of the watched credential stores (auditd cred/cred_sys/cred_agent: SSH, cloud CLIs, Kubernetes, GnuPG, browser profiles, Docker, netrc, npmrc, pypirc, agent tokens, /etc/shadow, sudoers); no canary in egress.jsonl; no canary in DNS names (dns.jsonl); canary files planted for this run (AWS credentials, netrc, npmrc; offline before the start); environment variables are not observable"
          },
          "persist": {
            "value": 1,
            "evidence": "fs-diff.json#L1 30 file(s) written outside /home/tool/work stay after the run (first: /home/tool/.local/ggmcp-venv/lib/python3.13/site-packages/beartype/_util/os/__pycache__/utilostty.cpython-313.opt-beartype0v22v9.pyc): caches or temp files outside the working directory"
          },
          "hitl": {
            "value": 0,
            "evidence": "none found: no pre-approvals brought by the tool and no bypass: each of the 1 actions produced an event in the lab approver (1 allowed by the task list, 0 denied; hitl-events.jsonl), 1 executions, all approved; no tool output in session.txt asks for an auto mode or a bypass"
          }
        },
        "unknown": []
      },
      "surplus": {
        "axes": {
          "fs": 0,
          "net": 0,
          "exec": 0,
          "cred": 0,
          "persist": 0,
          "hitl": 0
        },
        "count": 0,
        "beyond_static": [],
        "headline": "Within declared on every right the lab could observe."
      },
      "fit": "fits",
      "verdict": {
        "use_again": "with-limits",
        "one_sentence": "Listed detectors through the lab stub with nothing beyond its declaration: network only to the API, no credential reads; it does write bytecode caches into its own environment.",
        "limits": "Measured once against a lab stub of the GitGuardian API with a dummy token that grants only the scan scope, calling one read-only tool; incident, honeytoken and remediation tools, the HTTP mode and real workspace data were not run. Use it as measured: stdio, a personal access token with read scopes from the environment and ENABLE_LOCAL_OAUTH=false, because the default starts a browser OAuth flow and asks for all scopes. Its beartype dependency writes bytecode caches into the tool's virtual environment while it runs."
      },
      "min_config_tested": {
        "claude_code": "claude -p with model claude-haiku-5-5, MCP server over stdio (gitguardian: $HOME/.local/ggmcp-venv/bin/gg-mcp-server); no other tools allowed by the task list"
      },
      "incidents": {
        "realtime_alerts": 0,
        "aborted": false
      },
      "artifacts": {
        "manifest": "manifest.json",
        "declared": "declared.json",
        "cost": "cost.json",
        "egress": "egress.jsonl",
        "blocked": "blocked.jsonl",
        "fs_diff": "fs-diff.json",
        "host_events": "host-events.jsonl",
        "hitl_events": "hitl-events.jsonl",
        "findings": "findings.jsonl",
        "score": "score.json",
        "cast": {
          "file": "session.cast",
          "size_bytes": 908,
          "markers": [
            "00:03 first tool call",
            "00:04 result"
          ]
        },
        "transcript": "session.txt",
        "extra": [
          "dns.jsonl",
          "gateway-sets.txt",
          "install-egress.jsonl",
          "target-access.txt",
          "tool-cmd.sh"
        ],
        "secret_scan": {
          "redact": "gateway-sets.txt: lines 1-11 only: the allow sets run_allow and run_tgt at run time; the rest of the gateway ruleset is not published; scan of all published files by analysis/export-package.py for this run's canary values, bait texts, key patterns and host identifiers: no hits",
          "gitleaks": "not run: not installed on the lab host; the scan above instead",
          "date": "2026-11-07"
        },
        "private": [
          "allowlist-driver.txt",
          "allowlist.txt",
          "approver-policy.json",
          "diff/driver.json",
          "diff/gateway.json",
          "diff/runner.json",
          "diff/target.json",
          "dns-servers.txt",
          "pcap/labctl0.pcap",
          "pcap/labrun0.pcap",
          "pcap/labtgt0.pcap",
          "pcap/labwan0.pcap",
          "preflight.json",
          "preflight.log",
          "profile.yaml",
          "proxy-policy.json",
          "raw/allowlist-all.txt",
          "raw/canaries.txt",
          "raw/cred-inventory-after.csv",
          "raw/cred-inventory-before.csv",
          "raw/driver.xml",
          "raw/fs-diff-raw.csv",
          "raw/install-lock.json",
          "raw/install-pip-freeze.txt",
          "raw/install-source-tree.json",
          "raw/mcp_ed25519",
          "raw/mcp_ed25519.pub",
          "raw/model-drive.log",
          "raw/model-in/budget_usd",
          "raw/model-in/max_turns",
          "raw/model-in/mcp.json",
          "raw/model-in/model",
          "raw/model-in/route",
          "raw/model-in/task.txt",
          "raw/model-in/timebox",
          "raw/model/claude-version.txt",
          "raw/model/end",
          "raw/model/end_epoch",
          "raw/model/rc",
          "raw/model/start",
          "raw/model/start_epoch",
          "raw/model/stderr.txt",
          "raw/model/stream.tsjsonl",
          "raw/phase-times.txt",
          "raw/runner-audit.log",
          "raw/runner-tmp-fstype.txt",
          "raw/seed/aws-credentials",
          "raw/seed/netrc",
          "raw/seed/npmrc",
          "raw/session.jsonl",
          "raw/tool-status.json",
          "sensors/dns.log",
          "sensors/egress.flows",
          "sensors/gw-sets.txt",
          "sensors/install-dns.log",
          "sensors/install-fs-diff.json",
          "target-url.txt",
          "task.txt"
        ]
      },
      "interests": "Private project, privately funded. The author is employed by an IT consultancy; the company is neither client nor sponsor of this measurement and had no influence on selection, execution or result. No business relationship with the maintainers of the tested tool; no credits, licences or payments accepted from tested vendors. Deviations are stated in this field.",
      "right_of_reply": "dispute-process",
      "replications": []
    }
  ]
}
