> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.hoop.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server Configuration

> Connect an MCP client to Hoop's gateway, enable OAuth, and run your first tool calls

<Note>
  For an introduction to what the MCP server does and the controls it enforces, see the [MCP Server overview](/learn/features/mcp-server).
</Note>

## Prerequisites

* Either [create an account in our managed instance](https://use.hoop.dev) or [deploy your own hoop.dev instance](/setup/deployment/overview)
* Have admin access to your hoop.dev instance
* An MCP-compatible client (Claude Code, Cursor, Devin, or any client that supports streamable HTTP transport with OAuth)
* A user account in Hoop with access to at least one resource role

## Endpoint

The MCP server is mounted at:

```
https://<your-gateway>/api/mcp
```

Two authentication methods are supported — a **Bearer token** (always available) and **OAuth 2.0** (must be enabled by an administrator). Both result in the agent acting as the authenticated user with the same RBAC, masking, guardrails, and review controls. See the [authentication overview](/learn/features/mcp-server#endpoint-and-authentication) for how each method works.

## Add the MCP Server to Your Client

Configure your MCP client to point at your gateway. The exact format varies by client.
Refer to the client's (e.g., Claude Code, Cursor, Devin) documentation for details.

### Oauth Enabled

In this mode, the client negotiates the token automatically

```json theme={"dark"}
{
  "mcpServers": {
    "hoop": {
      "url": "https://<your-gateway>/api/mcp"
    }
  }
}
```

On first connect, the client opens a browser window to complete the OAuth flow against your IdP (Google, Okta, Azure, etc., depending on your gateway configuration).

### Bearer Token

You add the bearer token manually to the client configuration. The token is obtained by running `hoop login` and copying the value of the `HOOP_TOKEN` environment variable.

<Steps>
  <Step title="Expose the required environment variables">
    ```sh theme={"dark"}
    export HOOP_URL=$(hoop config view api_url)
    export HOOP_TOKEN=$(hoop config view token)
    ```
  </Step>

  <Step title="Configure the Bearer token in your client">
    The example below shows a JSON configuration file.

    ```json theme={"dark"}
      {
        "mcpServers": {
          "hooplocal": {
            "type": "http",
            "url": "${HOOP_URL}/api/mcp",
            "headers": {
              "Authorization": "Bearer ${HOOP_TOKEN}"
            }
          }
        }
      }
    ```

    <Note>
      Once the token expires, you can refresh it by running `hoop login` again and updating the `HOOP_TOKEN` environment variable.
    </Note>
  </Step>
</Steps>

## Enabling OAuth via the CLI

OAuth on the `/api/mcp` endpoint is **off by default** and is managed by an administrator with the `hoop admin mcp auth` command group. When enabled, the endpoint accepts JWTs issued by the gateway's configured OIDC issuer **in addition** to regular Hoop bearer tokens — so existing Bearer-token clients keep working.

When enabled, discovery metadata is published at:

```
https://<your-gateway>/.well-known/oauth-protected-resource/api/mcp
```

Most MCP clients (Claude Code, Cursor, Devin) detect this metadata and handle the OAuth flow without manual configuration — you only need to provide the `/api/mcp` URL.

<Note>
  These commands require an authenticated admin session (run `hoop login` first as an admin user).
</Note>

### Enable OAuth

```bash theme={"dark"}
hoop admin mcp auth enable
```

Optional flags let you override the defaults at the same time:

```bash theme={"dark"}
hoop admin mcp auth enable \
  --resource-uri https://<your-gateway>/api/mcp \
  --groups-claim groups
```

| Flag             | Default             | Purpose                                                                                                                                      |
| ---------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `--resource-uri` | `<api-url>/api/mcp` | Canonical [RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707) audience binding. Inbound JWTs must carry this value as the `aud` claim. |
| `--groups-claim` | `groups`            | The JWT claim from which user groups are extracted.                                                                                          |

### Check current status

```bash theme={"dark"}
hoop admin mcp auth status
```

Prints the current state, resource URI, and groups claim:

```text theme={"dark"}
MCP OAuth Status:
  State:        enabled
  Resource URI: https://<your-gateway>/api/mcp
  Groups Claim: groups
```

### Update configuration without toggling state

Use `configure` to change the resource URI or groups claim while leaving `enabled`/`disabled` as-is:

```bash theme={"dark"}
hoop admin mcp auth configure --groups-claim cognito:groups
```

You must pass at least one of `--resource-uri` or `--groups-claim`.

### Disable OAuth

```bash theme={"dark"}
hoop admin mcp auth disable
```

After this, `/api/mcp` accepts only Hoop bearer tokens. Any MCP client that was relying on the OAuth flow will need to switch to the `Authorization: Bearer <token>` header.

## First Calls

Once the client is connected, these are the recommended first tool calls:

<Steps>
  <Step title="Confirm identity">
    Ask the agent to call `me_get`. The response confirms which user the MCP session is acting as, the groups it belongs to, and whether it has admin or auditor privileges. This is the recommended first call in any session.
  </Step>

  <Step title="Discover what's available">
    Have the agent call `connections_list` (and optionally `serverinfo_get` for gateway version and license info). The agent now knows which databases, applications, and custom resources it can target.
  </Step>

  <Step title="Run a query">
    Use `exec` to run a command against a resource role. The response is one of the envelopes below.
  </Step>
</Steps>

The `exec` response is one of three envelopes the agent should handle explicitly:

| `status`           | Meaning                                             | What the agent does next                                            |
| ------------------ | --------------------------------------------------- | ------------------------------------------------------------------- |
| `completed`        | Output is in the response. May include AI analysis. | Use the output. Done.                                               |
| `failed`           | Command ran but exited non-zero.                    | Inspect `output` and `exit_code`.                                   |
| `pending_approval` | A review is required before the command can run.    | Call `reviews_wait`, then `reviews_execute` once `status=APPROVED`. |
| `running`          | Command is still running after a 50-second timeout. | Poll `sessions_get` with the returned `session_id`.                 |

For how the approval and long-running flows work, see [The Approval Flow](/learn/features/mcp-server#the-approval-flow) and [Long-Running Operations](/learn/features/mcp-server#long-running-operations) in the overview.

## Troubleshooting

### `unauthorized: missing auth context` or `missing access token`

**Check:**

1. If using OAuth, the MCP client completed the flow successfully and OAuth is enabled on the gateway
2. If using a Bearer token, the `Authorization: Bearer <token>` header is being sent and the token has not expired
3. The gateway URL points to `/api/mcp` exactly

### OAuth flow does not start / metadata endpoint returns 404

OAuth for the MCP endpoint is off by default. Ask an administrator to enable it on the gateway (`hoop admin mcp auth enable`), or fall back to the Bearer token method in the meantime.

### `Incompatible auth server: does not support dynamic client registration`

This message comes from the MCP client (Claude Code, Cursor, etc.), not from Hoop. The client discovered Hoop's protected-resource metadata, followed the `authorization_servers` URL to your IdP (Okta, Azure AD, Google, Auth0, etc.), and found that the IdP does not expose a `registration_endpoint` — so the client cannot create itself an OAuth client on the fly via [RFC 7591 Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591).

Hoop itself does not implement DCR; it only delegates authorization to your IdP. You have two ways to move forward:

* **Pre-register a static OAuth client in your IdP:**
  If you need full OAuth, ask your IdP admin to create an OAuth client for the MCP client manually and configure that client with the resulting `client_id` / `client_secret`. Each IdP exposes this differently — for example, Okta calls it an "OIDC application", Azure calls it an "App Registration". Most IdPs that support DCR have it disabled by default for security reasons.

* **Use the Bearer token method:**
  This skips OAuth entirely. Configure your MCP client with an `Authorization: Bearer <token>` header using a token from `hoop login`.

If your IdP **does** support DCR and you expected it to work, confirm that DCR is enabled in your tenant and that the IdP's discovery document (`/.well-known/openid-configuration` at the issuer URL) advertises a `registration_endpoint`.

### `admin access required`

The tool is gated to admin users. Ask an administrator to perform the action, or use a read-only equivalent.

### `connection not found or not accessible`

**Check:**

1. The connection name is correct (use `connections_list` to verify)
2. The user has a resource role granting access to this connection
3. If the connection is bound to `access_control`, the user is in one of the allowed groups

### `pending_approval` never resolves

**Check:**

1. A reviewer group exists and has at least one member who can approve
2. The reviewer was notified (Slack/Teams integration is configured, or they're checking the Web App)
3. The agent is calling `reviews_wait` repeatedly after each `timed_out=true`

### Agent disconnects on long queries

This is expected for executions over \~50 seconds. Ensure the agent handles `status=running` by polling `sessions_get` with the returned `session_id`, rather than treating it as an error.
