Help us shape the future of Go! Take the 2026 Go Developer Survey

iap-mcp-proxy

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: Apache-2.0

README

iap-mcp-proxy

A client-side bridge that lets generic MCP clients (Claude Desktop, Claude Code, Cursor, ...) connect to remote MCP servers protected by Google Cloud Identity-Aware Proxy (IAP).

The Google Cloud counterpart to aws/mcp-proxy-for-aws.

┌──────────────┐        stdio          ┌───────────────┐   HTTPS + ID token   ┌─────┐      ┌────────────┐
│  MCP client  │ ────────────────────► │ iap-mcp-proxy │ ───────────────────► │ IAP │ ───► │ MCP server │
│ (Claude etc.)│                       │  (this tool)  │  Proxy-Authorization │     │      │ (Cloud Run)│
└──────────────┘                       └───────────────┘                      └─────┘      └────────────┘

IAP expects a Google-issued OIDC ID token; the MCP spec's OAuth 2.1 flow can't produce one, so generic clients get a 401/redirect and stop. This proxy runs locally, obtains and refreshes Google credentials, attaches them as Proxy-Authorization (IAP consumes and strips this header), and forwards MCP traffic (Streamable HTTP) upstream.

Install

go install github.com/knwoop/iap-mcp-proxy/cmd/iap-mcp-proxy@latest

or grab a binary from Releases (darwin/linux/windows, amd64/arm64).

Quick start

  1. Make sure you have credentials IAP will accept (see Credentials):

    gcloud auth application-default login
    
  2. Add the proxy to your MCP client config. Claude Desktop:

    {
      "mcpServers": {
        "internal-tools": {
          "command": "iap-mcp-proxy",
          "args": [
            "--audience", "1234567890-abc.apps.googleusercontent.com",
            "https://mcp.internal.example.com/mcp"
          ]
        }
      }
    }
    

    Claude Code:

    claude mcp add internal-tools -- iap-mcp-proxy \
      --audience 1234567890-abc.apps.googleusercontent.com \
      https://mcp.internal.example.com/mcp
    

Usage

iap-mcp-proxy [flags] <UPSTREAM_URL>
Flag Env var Default Description
--audience IAP_MCP_AUDIENCE origin of UPSTREAM_URL OIDC token audience. LB-backed IAP: the IAP OAuth client ID (NNN.apps.googleusercontent.com). Direct Cloud Run IAP: depends on the OAuth client — see Supported IAP configurations.
--credentials IAP_MCP_CREDENTIALS auto auto, adc, impersonate, oauth, signjwt.
--impersonate-service-account IAP_MCP_IMPERSONATE_SA — Target SA email. impersonate mints an ID token as it; signjwt signs a self-signed JWT as it.
--downstream-auth IAP_MCP_DOWNSTREAM_AUTH — Value forwarded as the upstream Authorization header. Supports env:VAR_NAME indirection so secrets stay out of client config files.
--refresh-margin IAP_MCP_REFRESH_MARGIN 5m Refresh the ID token this long before expiry.
--timeout IAP_MCP_TIMEOUT 120s Upstream timeout: total for JSON responses, idle (time between reads) for SSE streams — so long-running streaming tool calls are not killed while data or keepalives keep arriving.
--log-level IAP_MCP_LOG warn debug / info / warn / error. Logs go to stderr only.
--version — — Print version and exit.

Credentials

With --credentials=auto (the default), sources are tried in this order:

  1. Impersonation — if --impersonate-service-account is set, mint ID tokens via the IAM Credentials API (generateIdToken) using your ADC as the base identity. Requires roles/iam.serviceAccountTokenCreator on the target SA. Best for CI and shared team setups.
  2. ADC — if Application Default Credentials are a service account key or workload credential, mint an ID token directly.
  3. Desktop OAuth — gcloud user credentials can't mint arbitrary-audience ID tokens, so the proxy falls back to an installed-app OAuth flow: first run opens a browser for Google sign-in; the refresh token is stored in your OS keychain (fallback: 0600 file under your user config dir). Requires a desktop OAuth client in the same project as the IAP resource, supplied via IAP_MCP_OAUTH_CLIENT_ID / IAP_MCP_OAUTH_CLIENT_SECRET — see Google's docs on programmatic IAP authentication.

These OIDC modes need IAP to use a custom OAuth client (LB-backed IAP, or a managed-client service with a separate allow-listed OAuth client). For modern managed-client direct Cloud Run IAP, --credentials=signjwt is the simplest route — it needs no OAuth client (see Supported IAP configurations).

The principal must hold roles/iap.httpsResourceAccessor on the IAP resource.

Supported IAP configurations

Which credential the proxy must present depends on how IAP is deployed — above all on whether IAP uses a custom OAuth client or Google's managed one. The token type is what matters, not just the audience.

IAP deployment OAuth client Token the proxy sends --audience Status
Behind an external HTTPS load balancer Custom OIDC ID token (impersonate / adc / oauth) IAP OAuth client ID (NNN.apps.googleusercontent.com) ✅ Supported — OIDC acceptance verified against a live IAP
Direct Cloud Run IAP Google-managed (the default when you enable IAP today) Self-signed service-account JWT (signjwt) exact *.run.app endpoint (or + /*) ✅ Supported — IAP rejects OIDC tokens here, so use --credentials=signjwt
Direct Cloud Run IAP Custom / allow-listed OIDC ID token OAuth client ID ⚠️ Expected to work, not yet verified
  • Since Google shut down the IAP OAuth Admin API (March 2026), newly-secured apps default to a Google-managed OAuth client, and that configuration rejects Google-issued OIDC ID tokens (Invalid IAP credentials: Invalid bearer token. Invalid JWT audience.) for every audience. The simplest programmatic access is a self-signed service-account JWT (iss=sub=SA email, signed via the IAM signJwt API), audience set to the canonical run.app URL with a path or /* wildcard. Use --credentials=signjwt --impersonate-service-account=<SA>; --audience defaults to the exact upstream endpoint (pass <origin>/* to cover all paths). Requires the Service Account Credentials API (gcloud services enable iamcredentials.googleapis.com).
  • Managed-client IAP can also accept OIDC ID tokens via a separate allow-listed OAuth client (console-created; see custom OAuth configuration) — then --credentials=impersonate/adc work with that client ID as --audience. New custom clients are console-only (no API); existing ones keep working.

Notes

  • The IAP token travels in Proxy-Authorization, which IAP consumes and strips — your app never sees it. If your app has its own auth, pass it with --downstream-auth and it is forwarded verbatim as Authorization.
  • On a 401 (or a 302 into Google sign-in) the proxy refreshes the token and retries once; a second failure is surfaced to the MCP client as a JSON-RPC error with an actionable message on stderr.
  • If the upstream reports the session expired (HTTP 404 — e.g. after a Cloud Run redeploy), the proxy transparently replays the cached initialize handshake to obtain a fresh session and retries the request; the stdio client never notices.
  • If a streaming (SSE) response drops mid-tool-call and the server tags events with IDs, the proxy resumes it with Last-Event-ID instead of losing the response.
  • After initialize, the proxy opens the standalone GET SSE stream so server-initiated messages (notifications/tools/list_changed, sampling/elicitation requests, log notifications) reach the client, reconnecting with Last-Event-ID if the stream drops. Servers that respond 405 (no standalone stream) are handled silently.
  • Exit codes: 0 clean shutdown, 1 fatal error (bad configuration or unrecoverable runtime failure), 2 auth bootstrap failure.

See docs/setup-gcp.md for setting up IAP in both deployment modes (direct Cloud Run IAP and IAP behind a global external Application Load Balancer).

License

Apache-2.0

Directories

Path Synopsis
cmd
iap-mcp-proxy command
Command iap-mcp-proxy bridges a stdio MCP client to a remote MCP server protected by Google Cloud Identity-Aware Proxy.
Command iap-mcp-proxy bridges a stdio MCP client to a remote MCP server protected by Google Cloud Identity-Aware Proxy.
internal
auth
Package auth provides credential sources for authenticating to Google Cloud IAP — Google-issued OIDC ID tokens (adc/impersonate/oauth) and self-signed service-account JWTs (signjwt) — plus an http.RoundTripper that attaches them.
Package auth provides credential sources for authenticating to Google Cloud IAP — Google-issued OIDC ID tokens (adc/impersonate/oauth) and self-signed service-account JWTs (signjwt) — plus an http.RoundTripper that attaches them.
bridge
Package bridge implements the stdio ⇄ Streamable HTTP bridge: it reads newline-delimited JSON-RPC messages from stdin, POSTs them to the upstream MCP endpoint, and writes responses (plain JSON or SSE streams) back to stdout as single lines.
Package bridge implements the stdio ⇄ Streamable HTTP bridge: it reads newline-delimited JSON-RPC messages from stdin, POSTs them to the upstream MCP endpoint, and writes responses (plain JSON or SSE streams) back to stdout as single lines.
iap
Package iap classifies upstream responses as IAP-origin auth failures vs.
Package iap classifies upstream responses as IAP-origin auth failures vs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL