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

# AE-MCP-003

> Remote MCP servers must declare authentication metadata. A non-local remote server with no auth declaration is flagged (OWASP MCP Top 10 beta, MCP07 Insufficient Authentication & Authorization), aligned with MCP specification revision `2025-11-25`.

**Rule ID:** AE-MCP-003 · **Severity:** <Badge color="orange">High</Badge> · **Category:** MCP Safety · **Auto-fixable:** No

## Why this rule

A public remote MCP server with no declared auth boundary accepts tool calls from any agent that can reach it. Charter checks whether the config declares that auth is required — the minimum signal that the server was configured with access control in mind. Without this declaration, there is no evidence that tool calls to the server are gated at all. See the [MCP safety model](/docs/concepts/mcp-safety-model) for how the auth check fits the broader trust boundary.

## What triggers it

Charter inspects every remote HTTP or SSE server entry in tracked MCP configuration files. For each non-local remote server, it checks whether an auth header is declared in the server's config block.

**Accepted auth header names** (checked case-insensitively):

* `Authorization`
* `X-Api-Key`
* `Api-Key`
* `X-Auth-Token`

An environment variable reference such as `"Bearer ${TOKEN}"` counts as a valid declaration — Charter checks for the *presence* of an auth header, not the validity of the credential.

**Scanned files:** `.mcp.json`, `mcp.json`, `.cursor/mcp.json`, `.vscode/mcp.json`, `.gemini/settings.json`

**Always exempt:**

| Exemption                  | Reason                                                                                                  |
| -------------------------- | ------------------------------------------------------------------------------------------------------- |
| Local / internal origins   | Loopback, RFC 1918 private addresses, `*.localhost`, `*.local`, `*.internal`                            |
| Catalog OAuth vendor hosts | Sentry, Atlassian, Context7, and similar — they authenticate via OAuth flow, not a static config header |
| Dynamic `${VAR}` URL       | No parseable host — skipped                                                                             |

## Examples

<Tabs>
  <Tab title="Failing">
    ```json .mcp.json theme={null}
    {
      "mcpServers": {
        "self-hosted": {
          "type": "http",
          "url": "https://self-hosted.example.com/mcp"
        }
      }
    }
    ```

    ```
    # Remote server, no headers block — Charter cannot confirm auth is configured
    # Fires High
    ```
  </Tab>

  <Tab title="Passing">
    ```json .mcp.json (env-var auth header) theme={null}
    {
      "mcpServers": {
        "self-hosted": {
          "type": "http",
          "url": "https://self-hosted.example.com/mcp",
          "headers": {
            "Authorization": "Bearer ${MCP_SERVER_TOKEN}"
          }
        }
      }
    }
    ```

    ```json .mcp.json (catalog OAuth vendor — no header needed) theme={null}
    {
      "mcpServers": {
        "sentry": {
          "type": "http",
          "url": "https://mcp.sentry.dev/mcp"
        }
      }
    }
    ```
  </Tab>
</Tabs>

## How to fix

Add a `headers` block to the remote MCP server entry with an auth header that references an environment variable:

```json theme={null}
{
  "mcpServers": {
    "your-server": {
      "type": "http",
      "url": "https://your-mcp-server.example.com",
      "headers": {
        "Authorization": "Bearer ${MCP_SERVER_TOKEN}"
      }
    }
  }
}
```

If the server uses a different auth mechanism, use the appropriate header name (`X-Api-Key`, `Api-Key`, or `X-Auth-Token`) with the same env-reference pattern.

<Warning>
  Use env var references for header values — never literal credentials. A literal credential in an auth header triggers AE-SEC-002 (Blocker, raw-secret cap ≤49).
</Warning>

## Score impact

`High` (−10 per finding). No hard cap — caps are reserved for raw-secret and Blocker findings. See [Scoring and caps](/docs/concepts/scoring-and-caps).

## Edge cases

Local and internal origins never fire. Catalog OAuth vendor hosts never fire. An env-reference header value (`${TOKEN}`) satisfies the presence check — Charter does not validate the credential itself, only its declaration. A bare `${VAR}` URL with no parseable host is skipped entirely.

## Related rules

<CardGroup cols={2}>
  <Card title="AE-MCP-001" icon="shield" href="/rules/AE-MCP-001">
    MCP servers must be pinned to exact versions.
  </Card>

  <Card title="AE-MCP-002" icon="shield" href="/rules/AE-MCP-002">
    Remote MCP server origins must be trusted.
  </Card>

  <Card title="AE-SEC-002" icon="lock" href="/rules/AE-SEC-002">
    No raw secrets in MCP config files.
  </Card>
</CardGroup>

## CLI

```bash theme={null}
charter explain AE-MCP-003
```
