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

> Learn how MCP servers connect to Claude Managed Agents using the vault credential pattern. Discover how static bearer vault credentials bind relay secrets to server URLs.

- Repository: [Anthropic/cwc-workshops](https://github.com/anthropics/cwc-workshops)
- Tags: explanation
- Published: 2026-07-18

---

**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`](https://github.com/anthropics/cwc-workshops/blob/main/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.

```python

# 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`](https://github.com/anthropics/cwc-workshops/blob/main/my_agent.py)):

```python

# 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).

```javascript
// 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`](https://github.com/anthropics/cwc-workshops/blob/main/setup.sh), which writes a `.env.setup` file containing `BOT_MCP_URL` (the public relay URL).
2. **Agent launch** – [`my_agent.py`](https://github.com/anthropics/cwc-workshops/blob/main/my_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`](https://github.com/anthropics/cwc-workshops/blob/main/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`](https://github.com/anthropics/cwc-workshops/blob/main/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.