f/hold docs

Public remote MCP deployment

This deployment is optional. fhold does not add a proxy, tunnel, certificate manager, or identity provider to the managed stack. Operators bring an HTTPS reverse proxy and an OAuth/OIDC authorization server; Guardian remains the MCP resource server and policy boundary.

Use this path when fhold should be available as a Claude custom connector or to another internet MCP client. Claude remote connectors originate from Anthropic's cloud—even when configured in Claude Desktop—so the MCP URL must be publicly reachable. See Anthropic's remote connector network requirements.

Required topology

MCP client
  -> public HTTPS reverse proxy
  -> 127.0.0.1:3830 Guardian
  -> Assistant

MCP client <-> external OAuth authorization server
Guardian -> authorization server JWKS

Keep Guardian loopback-bound. Publish only the exact MCP and OAuth metadata paths through the proxy. Do not expose Assistant's native API. The examples use Guardian's default port, 3830. Fresh setup may choose another port when defaults are in use; run fhold connect mcp for the actual address and use its port in the proxy and health-check examples below.

Configure the authorization server

The external authorization server must:

For Claude, allow the current callback URL https://claude.ai/api/mcp/auth_callback. Anthropic notes that the hostname may move to claude.com, so allow the successor shown by Claude or its current custom connector documentation.

fhold deliberately does not store the OAuth client registration. If the authorization server does not support dynamic/metadata registration, enter its pre-registered client ID and secret in Claude's Advanced settings when adding the connector.

Configure fhold

Create a named credential for each policy class you need, then map each OAuth subject to one of them:

fhold guardian enable
fhold credential add claude-read read
fhold credential add claude-full full

fhold config oauth \
  --resource https://agent.example.com/mcp \
  --issuer https://identity.example.com/ \
  --jwks-url https://identity.example.com/.well-known/jwks.json \
  --audience https://agent.example.com/mcp \
  --scopes fhold

fhold credential map oauth \
  https://identity.example.com/ subject-for-alice claude-read
fhold credential map oauth \
  https://identity.example.com/ subject-for-operator claude-full

config oauth recreates the stack by default because Guardian loads the resource-server configuration at startup. Use --no-apply to stage changes. Identity mappings are read on each request and do not require a restart.

Inspect or revoke mappings with:

fhold credential mappings oauth
fhold credential unmap oauth \
  https://identity.example.com/ subject-for-alice
fhold config oauth --disable

An OAuth identity receives exactly the mapped credential's chat, read, or full policy. Scopes prove that the token was issued for fhold; they do not grant an fhold policy. Unknown issuers, subjects, audiences, algorithms, or missing scopes fail closed.

Reverse proxy

Example Caddy site:

agent.example.com {
    @fhold path /mcp /.well-known/oauth-protected-resource /.well-known/oauth-protected-resource/mcp
    handle @fhold {
        reverse_proxy 127.0.0.1:3830
    }
    handle {
        respond 404
    }
}

Example Nginx locations inside an HTTPS server block:

location = /mcp {
    proxy_pass http://127.0.0.1:3830;
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_read_timeout 130s;
}

location = /.well-known/oauth-protected-resource {
    proxy_pass http://127.0.0.1:3830;
}

location = /.well-known/oauth-protected-resource/mcp {
    proxy_pass http://127.0.0.1:3830;
}

Terminate TLS with a publicly trusted certificate. Preserve the Authorization, Mcp-Protocol-Version, Mcp-Session-Id, Last-Event-ID, and Accept headers; standard Caddy and Nginx proxy behavior does this unless an operator override removes them. Disable response buffering on /mcp so streamed responses are delivered promptly.

Verify before adding a client

curl --fail http://127.0.0.1:3830/health
curl --fail https://agent.example.com/.well-known/oauth-protected-resource
curl --include --request POST https://agent.example.com/mcp

The metadata response must name the exact public resource and issuer. The unauthenticated MCP request must return 401 with a WWW-Authenticate header whose resource_metadata URL is public HTTPS. Use the MCP Inspector to complete the OAuth flow and verify the policy-filtered tools before enabling a production client.

For Claude Pro/Max, open Customize → Connectors → Add custom connector and enter https://agent.example.com/mcp. Team/Enterprise owners add it under organization connector settings. Claude supports tools, prompts, and resources on remote MCP connectors, so this uses the complete Guardian MCP catalog rather than a chat-only subset.

Operational guidance