# GitGuardian MCP Server

> Draft · awaiting review.

> MCP server that brings GitGuardian secret detection, incident triage and honeytokens into an AI agent.

- Badge: `reach 3 · as declared`
- Type: MCP server; tier: tried
- Tasks: Dependencies and secrets, Alert triage; mission: Defensive; works with: Any MCP client, Cursor
- Source: https://github.com/GitGuardian/ggmcp, pinned to `7a75a34` (v0.7.3), licence MIT
- Last checked: 2026-11-07; next check: 2027-05-06; method v0.1, reach-v0.1

## At a glance

- **What it is:** 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. An MCP server is a program that gives your AI client extra tools; the client's model decides when to call them.
- **Made for:** Lets an AI agent scan code for credentials, triage existing secret incidents, generate honeytokens and remediate findings from an IDE or chat client. +1 more
- **Runs:** On the vendor's servers. Other modes: local stdio with PAT (on your machine, started by your AI client); self-hosted HTTP (in a container on your machine). Listens only in an optional mode: 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 (sign-in optional); 3 listeners in all.
- **Sends data to:** GitGuardian API (always), GitGuardian /multiscan (by default), mcp.gitguardian.com (by default), Sentry (if you turn it on), GitGuardian dashboard login (if you turn it on), github.com/GitGuardian/ggmcp (if you turn it on). Other connections not ruled out: read in the documentation and the cited code, not searched in full.
- **Can change things:** Changes, runs commands, sends data out, according to the capabilities read.
- **Needs:** A GitGuardian workspace (US or EU SaaS, or self-hosted) where a personal access token can be created in the dashboard · The code defines scan, incidents:read and sources:read as MINIMAL_SCOPES · The ggmcp package requires Python 3.11 or later · +5 more

Profile read at commit `7a75a34` on 2026-10-25; every fact cites a file and line at that commit.

## What it does

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. (README.md#L3)

Made for (the author says):

- Lets an AI agent scan code for credentials, triage existing secret incidents, generate honeytokens and remediate findings from an IDE or chat client. (README.md#L4-6)
- Lets AI agents scan projects for secrets through the GitGuardian API, manage security incidents and create honeytokens. (server.json#L4)

Documented uses:

- Scan files for leaked credentials [Dependencies and secrets] (README.md#L17)
- List, filter, assign, resolve and tag internal and Public Monitoring secret incidents [Alert triage] (README.md#L18-19)
- Generate honeytokens and list existing ones [Detection engineering] (README.md#L20)
- Open pull requests that remediate secrets in repositories the workspace monitors [Dependencies and secrets] (README.md#L21-22)

## What it can do

| Group | What it covers | Effect | On by default |
|---|---|---|---|
| Proactive Secret Scanning | scan_secrets passes the documents the agent supplies to the GitGuardian API through the client's multiple_scan call and returns the scan results. (packages/gg_api_core/src/gg_api_core/tools/scan_secret.py#L84-85) | reads, sends data out | yes |
| Incident Management | Lists and filters internal and public incidents, and assigns, resolves, ignores, reopens and tags them. (packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L95-96) | reads, changes | yes |
| Repository Analysis | In local stdio mode find_current_source_id runs git config --get remote.origin.url in the given repository path to identify the repository. (packages/gg_api_core/src/gg_api_core/tools/find_current_source_id.py#L140-148) | reads, runs commands | yes |
| Remediation | Locates occurrences with list_remediation_targets, reads the workspace instructions with get_remediation_workflow, and create_code_fix_request opens automated pull requests. (packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L101-103) | reads, changes | yes |
| Honeytoken Management | generate_honeytoken creates an AWS GitGuardian honeytoken with injection recommendations; names must be unique among the workspace's active honeytokens. (packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L220-225) | reads, changes | yes |
| user information and token management | revoke_current_token revokes the current API token and cleans up stored credentials. (packages/gg_api_core/src/gg_api_core/mcp_server.py#L267-270) | reads, changes | yes |

## How it runs

gg-mcp-server picks its transport at start: StreamableHTTP when MCP_PORT is set, otherwise stdio. (packages/gg_mcp_server/src/gg_mcp_server/run.py#L52-61)

- Starts: On the vendor's servers. The README recommends the hosted server at mcp.gitguardian.com; the client handles OAuth and nothing is installed locally. (README.md#L59-61)
- Can also run: On your machine, started by your AI client (local stdio with PAT). Runs the server locally over stdio with a PAT, for CI/CD, airgapped environments or older MCP clients. (README.md#L157-158)
- Can also run: In a container on your machine (self-hosted HTTP). Self-hosters run the ghcr.io/gitguardian/mcp-server image, which serves StreamableHTTP on port 8000 behind a TLS-terminating proxy. (README.md#L192-194)
- Your AI client: **MCP client configuration**: An mcpServers entry of type http in the client's mcp.json points to https://mcp.gitguardian.com/mcp. (README.md#L75-84)
- Your machine: **gg-mcp-server (local stdio process)**: Local process the MCP client starts with uvx --from git+https://github.com/GitGuardian/ggmcp.git gg-mcp-server. (README.md#L163-168)
- Your machine: **Local OAuth token file**: The local OAuth flow keeps tokens in mcp_oauth_tokens.json inside a gitguardian config directory it creates. (packages/gg_api_core/src/gg_api_core/oauth.py#L91-92)
- Container on your machine: **ghcr.io/gitguardian/mcp-server image**: 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. (Dockerfile#L74-83)
- Outside your machine: **Hosted MCP server**: GitGuardian's hosted MCP endpoint: https://mcp.gitguardian.com/mcp for US SaaS or https://mcp.eu1.gitguardian.com/mcp for EU SaaS. (README.md#L65-68)
- Outside your machine: **GitGuardian API**: GitGuardian public API that receives every call with the token in the Authorization header; SaaS or self-hosted. (packages/gg_api_core/src/gg_api_core/client.py#L375-382)
- Listens: With MCP_PORT set, uvicorn serves the /mcp StreamableHTTP app on the host and port from the MCP_HOST and MCP_PORT settings.: an address you choose, sign-in optional, in an optional mode (packages/gg_mcp_server/src/gg_mcp_server/run.py#L38-46)
- Listens: 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.: all network interfaces, sign-in optional, in an optional mode (README.md#L198-207)
- Listens: The local OAuth flow's callback HTTPServer binds explicitly to 127.0.0.1 on a free port.: this machine only (loopback), no sign-in, in an optional mode (packages/gg_api_core/src/gg_api_core/oauth.py#L386-388)
- Sends data to GitGuardian API (vendor API, always): Every tool call goes to the GitGuardian API derived from GITGUARDIAN_URL (default dashboard.gitguardian.com) with the token in a header. (packages/gg_api_core/src/gg_api_core/settings.py#L44)
- Sends data to GitGuardian /multiscan (vendor API, by default): scan_secrets posts the contents of the documents the agent passes to the /multiscan endpoint. (packages/gg_api_core/src/gg_api_core/client.py#L1382)
- Sends data to mcp.gitguardian.com (vendor API, by default): With the hosted server, requests transit mcp.gitguardian.com in addition to api.gitguardian.com. (README.md#L128)
- Sends data to Sentry (telemetry, if you turn it on): Sentry error reporting is enabled only when SENTRY_DSN is set. (packages/gg_api_core/src/gg_api_core/sentry_integration.py#L8)
- Sends data to GitGuardian dashboard login (vendor API, if you turn it on): The local OAuth flow opens the GitGuardian authorization URL in the user's browser. (packages/gg_api_core/src/gg_api_core/oauth.py#L572)
- Sends data to github.com/GitGuardian/ggmcp (download, if you turn it on): The local stdio configuration makes uvx fetch the package from the GitHub repository's default branch. (README.md#L167)

## What you need

- Account: A GitGuardian workspace (US or EU SaaS, or self-hosted) where a personal access token can be created in the dashboard. (README.md#L180-181)
- Credentials: The code defines scan, incidents:read and sources:read as MINIMAL_SCOPES. (packages/gg_api_core/src/gg_api_core/scopes.py#L5-9)
- Runtime: The ggmcp package requires Python 3.11 or later. (pyproject.toml#L35)
- Setting: Local stdio with a PAT sets ENABLE_LOCAL_OAUTH=false and GITGUARDIAN_PERSONAL_ACCESS_TOKEN in the client's env block. (README.md#L170-173)
- Authorisation: create_code_fix_request needs Manager access level and the incidents:write scope. (packages/gg_api_core/src/gg_api_core/tools/create_code_fix_request.py#L115-118)
- Setting: Self-hosted GitGuardian instances need IS_ON_PREM=true so the server uses the /exposed/v1 API path and the self-hosted scope set. (README.md#L210-214)
- Other: Claude Desktop versions that pre-date HTTP MCP support need the local stdio fallback instead of the hosted server. (README.md#L89-91)
- Setting: 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. (README.md#L183-185)
- Installer: 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. (README.md#L164-168)
- Installer: The self-hosting example runs the mutable tag ghcr.io/gitguardian/mcp-server:latest. (README.md#L205)
- Installer: 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. (PUBLISHING.md#L126-130)

## Limits and risks

- Unless GITGUARDIAN_SCOPES is set, effective_scopes returns all of ALL_SCOPES, or SCOPES_SUPPORTED_IN_SELF_HOSTED on non-local self-hosted instances. (packages/gg_api_core/src/gg_api_core/settings.py#L150-157)
- 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. (packages/gg_api_core/src/gg_api_core/mcp_server.py#L385-390)
- The deprecated local OAuth flow saves the issued token to a JSON file in the user's config directory with file mode 0600. (packages/gg_api_core/src/gg_api_core/oauth.py#L110-119)
- Since 0.7.3 honeytoken values are returned unmasked to the agent. (CHANGELOG.md#L8)
- 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. (packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L144-145)
- 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. (README.md#L8-13)
- 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. (packages/gg_api_core/src/gg_api_core/tools/manage_incident.py#L62-68)
- Browser-driven OAuth in stdio mode is deprecated but stays the stdio default; it opens a localhost callback and stores the PAT on disk. (README.md#L146-153)
- 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. (packages/gg_api_core/src/gg_api_core/oauth_proxy_auth.py#L164-169)
- GITGUARDIAN_TOKEN_LIFETIME sets the lifetime in days of OAuth-issued PATs, default 30, and accepts never. (README.md#L231)
- 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. (packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L376-381)
- 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. (packages/gg_api_core/src/gg_api_core/settings.py#L72-76)
- 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. (packages/gg_api_core/src/gg_api_core/mcp_server.py#L387-396)
- ALL_SCOPES, the scope list requested by default, includes write scopes such as honeytokens:write, incidents:write and api_tokens:write. (packages/gg_api_core/src/gg_api_core/scopes.py#L13-22)
- 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. (packages/gg_api_core/src/gg_api_core/client.py#L292-295)
- 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. (packages/gg_mcp_server/src/gg_mcp_server/register_tools.py#L376-381)

## Rights in plain language

- Declared: files 2 (writes outside the project), network 3 (can tunnel or exfiltrate), secrets 1 (uses one scoped token), persistence 2 (changes config or installs globally).
- Code: reach 3 (privileged): files 2 (writes outside the project), network 3 (can tunnel or exfiltrate), secrets 2 (reads broad tokens or the environment), persistence 2 (changes config or installs globally); unknown: approval.
- Lab: Within declared on every right the lab could observe.

Why three columns? Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

## Privilege Reach

Reach level 3 (privileged).

| Right | Declared | Code | Lab |
|---|---|---|---|
| Files: where does it read and write? | 2 writes outside the project | 2 writes outside the project | 2 writes outside the project |
| Network: whom does it talk to? | 3 can tunnel or exfiltrate | 3 can tunnel or exfiltrate | 1 talks only to declared hosts |
| Execution: what does it run? | not declared | 1 runs only declared programs | 0 runs no programs |
| Secrets: which credentials does it touch? | 1 uses one scoped token | 2 reads broad tokens or the environment | 0 touches no credentials |
| Persistence: what survives the run? | 2 changes config or installs globally | 2 changes config or installs globally | 1 leaves cache or temp files |
| Approval: does it ask before acting? | not declared | ? unknown | 0 asks each time |

0 contained · 1 scoped · 2 open · 3 privileged · ? no evidence · 0 never means safe

## Install

### Upstream

Quoted from `README.md#L161-177` at the pinned commit (not a command to copy): `{
  "mcpServers": {
    "GitGuardian": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/GitGuardian/ggmcp.git",
        "gg-mcp-server"
      ],
      "env": {
        "ENABLE_LOCAL_OAUTH": "false",
        "GITGUARDIAN_PERSONAL_ACCESS_TOKEN": "your_pat_here",
        "GITGUARDIAN_URL": "https://dashboard.gitguardian.com"
      }
    }
  }
}`


### Run it with least privilege

- 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`

- derived, not tested: proposed from the code analysis

## Lab runs

### 2026-11-07

One run is an observation, not a benchmark.

- Run and written by Ilja Schlak, 2026-11-07
- Target: Lab stub of the GitGuardian API (fixtures/api-stub, plain HTTP on the lab target) 0.1.0; model claude-haiku-5-5; claude-code mode dontAsk with the lab approver: every tool call asks, the task list below allows, everything else is denied; white-box
- Verdict: Within declared on every right the lab could observe.
- Use again: with-limits; 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.
- Artifacts: https://readbeforerun.ai/catalog/gitguardian-ggmcp/runs/2026-11-07/

## Questions and answers

**Why compare declared, code and lab?**

Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

**What rights does GitGuardian MCP Server declare?**

files 2 (writes outside the project), network 3 (can tunnel or exfiltrate), secrets 1 (uses one scoped token), persistence 2 (changes config or installs globally).

**What does its code suggest?**

reach 3 (privileged): files 2 (writes outside the project), network 3 (can tunnel or exfiltrate), secrets 2 (reads broad tokens or the environment), persistence 2 (changes config or installs globally); unknown: approval.

**What did it use when it ran in the lab?**

Within declared on every right the lab could observe.

**Was it tried, and when?**

Yes: 2026-11-07.

**What changed since the last check?**

Upstream last pushed 2026-10-14; 0 release(s) since the pinned version.

**How do I run it with least privilege?**

Derived, not tested: 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

Method: https://readbeforerun.ai/method/
