How MCP Servers Connect to Claude Managed Agents: The Vault Credential Pattern Explained

MCP servers connect to Claude Managed Agents (CMAs) through header-authenticated endpoints using static-bearer vault credentials that bind relay secrets to MCP server URLs, falling back to URL-keyed endpoints when vault provisioning fails.

Managed Control Program (MCP) servers serve as the bridge enabling Claude Managed Agents to invoke external tools, but securing these connections requires a specific vault credential pattern. The anthropics/cwc-workshops repository demonstrates how the agent runtime provisions static-bearer credentials in a named vault, ensuring secrets remain out of URLs while maintaining backward compatibility with legacy URL-keyed endpoints.

MCP Server Connection Architecture

The connection pipeline supports two authentication strategies for the MCP server endpoints. The header-authenticated endpoint is the preferred route, sending an Authorization: Bearer <relay-key> header injected from a static-bearer vault credential. The URL follows the pattern:


https://<public-base>/bot/<participant-name>/mcp

When header authentication cannot be provisioned—such as when the vault API is unavailable—the system falls back to the legacy URL-keyed endpoint:


https://<public-base>/p/<relay-key>/mcp

This dual-mode design ensures secret safety by keeping the bearer token out of infrastructure logs while supporting local development scenarios.

Agent-Side MCP URL Resolution

The resolution logic lives in agent-battle/my_agent.py within the _bot_mcp_url function (lines 28-38). This function detects whether the environment provides a legacy URL-keyed endpoint and attempts to upgrade it to the header-authenticated variant.


# my_agent.py – Resolve the MCP URL for the bot (prefers header auth)

def _bot_mcp_url(client, cache):
    relay_key = os.environ.get("RELAY_KEY", "")
    m = (re.match(rf"(.+?)/p/{re.escape(relay_key)}/mcp/?$", BOT_MCP_URL)
         if relay_key else None)
    if not m:
        return BOT_MCP_URL                     # legacy URL‑key fallback

    public_base = m.group(1)
    header_url = f"{public_base}/bot/{quote(PARTICIPANT, safe='')}/mcp"
    try:
        _ensure_vault_credential(client, cache, header_url, relay_key)
        return header_url                      # header‑auth ready

    except Exception:
        return BOT_MCP_URL                      # fallback if vault fails

The function extracts the public_base from the legacy URL using a regex, constructs the header-authenticated URL with the participant name, and attempts to provision a vault credential. If provisioning fails, it returns the original URL to maintain connectivity.

The Vault Credential Pattern

The static-bearer credential binds the relay secret (<relay-key>) to the MCP server URL and stores it within a CMA vault named agent-battle. The _ensure_vault_credential function (called from _bot_mcp_url) first searches for an existing vault, creates one if necessary, then either reuses an existing credential for the same URL or creates a new one.

The helper _write_credential handles SDK version differences by attempting two possible credential shapes—some deployments accept the token inside the auth object, while others require it under extra_body (lines 84-92 in my_agent.py):


# my_agent.py – Create / update a static‑bearer vault credential

def _write_credential(creds, vault_id, cred_id, token, mcp_server_url,
                      display_name):
    shapes = [
        dict(auth={"type": "static_bearer", "token": token,
                   "mcp_server_url": mcp_server_url}),
        dict(auth={"type": "static_bearer", "token": token},
             extra_body={"mcp_server_url": mcp_server_url}),
    ]
    for kw in shapes:
        try:
            if cred_id:
                return creds.update(cred_id, vault_id=vault_id,
                                    display_name=display_name, **kw).id
            return creds.create(vault_id=vault_id,
                                display_name=display_name, **kw).id
        except anthropic.BadRequestError as e:
            if "extra_inputs" not in str(e).lower():
                raise
    raise last_err

This implementation provides idempotent credential handling by checking cached credential IDs and token hashes, avoiding unnecessary recreation on agent restarts.

MCP Server Implementation

The event server exposes two distinct MCP endpoints in agent-battle/event/server.mjs. The Wiki MCP (/wiki/mcp) provides a read-only knowledge interface with a single lookup(query) tool (lines 50-60). The Bot MCP mounts two routes: the preferred header-auth version at /bot/:name/mcp and the legacy URL-keyed version at /p/:key/mcp (lines 63-71 and 84-90).

// event/server.mjs – Mount the preferred header‑auth bot MCP endpoint
mountMcp('/bot/:name/mcp', (req) => buildBotMcp(bearerKey(req)),
         botMcpRateKey(bearerKey));

The Bot MCP acts as a dynamic relay that forwards tool calls to a participant’s bot over a WebSocket. When a request arrives, the server authenticates the bearer token, looks up the stored tool set in the relay, forwards the call to the participant’s bot, and returns the result.

End-to-End Connection Flow

The complete connection lifecycle follows four stages:

  1. Setup – The participant runs setup.sh, which writes a .env.setup file containing BOT_MCP_URL (the public relay URL).
  2. Agent launchmy_agent.py reads the environment file, resolves the MCP URL via _bot_mcp_url, and ensures a vault credential exists via _ensure_vault_credential.
  3. Session creation – The CMA SDK includes the resolved MCP URL in the session spec under the mcp_servers field (constructed in _build_spec around lines 30-35).
  4. Tool call – When Claude invokes an MCP tool, the request is sent to the resolved URL with the bearer token from the vault. The event server authenticates the token and forwards the call.

Summary

  • MCP servers use header-authenticated endpoints by default, falling back to URL-keyed endpoints only when vault provisioning fails.
  • The vault credential pattern stores static-bearer tokens in a named CMA vault (agent-battle), binding relay secrets to MCP server URLs without exposing them in URL paths.
  • The _bot_mcp_url function in my_agent.py (lines 28-38) handles URL resolution and credential provisioning with idempotent checks.
  • _write_credential (lines 84-92) accommodates SDK version differences by attempting two credential payload shapes.
  • Security is maintained by keeping bearer tokens out of infrastructure logs while preserving backward compatibility for local development.

Frequently Asked Questions

What is the difference between header-authenticated and URL-keyed MCP endpoints?

Header-authenticated endpoints (/bot/:name/mcp) receive the relay secret via an Authorization: Bearer <token> header extracted from a vault credential, keeping secrets out of URLs and logs. URL-keyed endpoints (/p/:key/mcp) embed the secret directly in the path, which is less secure but requires no vault infrastructure.

How does the vault credential pattern prevent secret exposure?

The pattern stores the relay secret as a static-bearer credential inside a CMA vault rather than in environment variables or URLs. When the agent creates a session, it references the credential ID; the SDK injects the header server-side. This ensures the secret never transits through client-side logs or memory outside the secure vault context.

What happens if vault credential provisioning fails?

If _ensure_vault_credential raises an exception—such as when the vault API is unreachable—the _bot_mcp_url function catches the error and returns the original BOT_MCP_URL, which uses the legacy URL-keyed format. This graceful degradation ensures the agent remains functional even when credential services are unavailable.

Where is the MCP server URL resolved in the agent code?

URL resolution occurs in agent-battle/my_agent.py within the _bot_mcp_url function (lines 28-38). This function parses the environment-provided URL, attempts to upgrade it to a header-authenticated variant, and returns the appropriate URL for inclusion in the session's mcp_servers specification.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →