> ## 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-001

> Every MCP server entry in a repo's MCP configuration must be pinned to an exact version or digest. Floating references — `@latest`, missing versions, dist-tags, semver ranges, and branch/commit-less git sources — are a supply-chain risk (OWASP MCP Top 10 beta, MCP04 Software Supply Chain Attacks & Dependency Tampering).

**Rule ID:** AE-MCP-001 · **Severity:** <Badge color="orange">High</Badge> · **Category:** MCP Safety · **Auto-fixable:** Yes (partial)

<Note>
  AE-MCP-001 is **partially** auto-fixable. Charter can bump unpinned or behind-stable packages to the catalog's stable version. Deprecated or archived packages require manual migration — Charter provides the successor package name in the finding evidence, but will not rewrite the entry automatically.
</Note>

## Why this rule

An MCP server at `@latest` can change behavior between runs without any change to the repo. A package can be deprecated, archived, or found to contain a known vulnerability after a repo first passed Charter. Pinning to an exact version ties the tool definition to a reviewable artifact — every tool-call behavior is deterministic across machines and runs. See the [MCP safety model](/docs/concepts/mcp-safety-model) for how Charter reasons about MCP supply chain.

## What triggers it

Charter scans MCP configuration files for server entries launched by package runners and checks whether each entry pins an exact version.

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

**Scanned runners:** `npx`, `bunx`, `uvx`, `pnpm dlx`

The finding ladder based on signal type:

| Signal                                                        | Severity      | Example                               |
| ------------------------------------------------------------- | ------------- | ------------------------------------- |
| Deprecated or archived package                                | High          | `@modelcontextprotocol/server-github` |
| Known CVE / GHSA advisory on pinned version                   | High          | `mcp-server-git@2025.8.0`             |
| Unpinned reference (`@latest`, semver range, missing version) | High          | `mcp-server-git@latest`               |
| Behind catalog stable, no advisory                            | Informational | Old exact pin, no known issues        |

**Unpinned forms that fire High:** `@latest`, a missing version suffix, semver ranges (`^1.0.0`, `~1.0.0`, `>=1.0.0`), floating git refs, or dynamic values like `pkg@${VERSION}`.

## Examples

<Tabs>
  <Tab title="Failing">
    ```json .mcp.json (floating tag) theme={null}
    {
      "mcpServers": {
        "git": {
          "command": "npx",
          "args": ["-y", "mcp-server-git@latest"]
        }
      }
    }
    ```

    ```json .mcp.json (archived package) theme={null}
    {
      "mcpServers": {
        "github": {
          "command": "npx",
          "args": ["-y", "@modelcontextprotocol/server-github@1.0.0"]
        }
      }
    }
    ```

    ```
    # @modelcontextprotocol/server-github is archived — fires High
    # even though the version is pinned exactly
    ```
  </Tab>

  <Tab title="Passing">
    ```json .mcp.json theme={null}
    {
      "mcpServers": {
        "filesystem": {
          "command": "npx",
          "args": ["-y", "@modelcontextprotocol/server-filesystem@2026.1.14"]
        }
      }
    }
    ```

    ```json .mcp.json (uvx runner) theme={null}
    {
      "mcpServers": {
        "git": {
          "command": "uvx",
          "args": ["mcp-server-git@2026.1.14"]
        }
      }
    }
    ```
  </Tab>
</Tabs>

## How to fix

<CodeGroup>
  ```bash Preview the fix theme={null}
  charter fix --rule AE-MCP-001 --dry-run
  ```

  ```bash Apply the fix theme={null}
  charter fix --rule AE-MCP-001
  ```
</CodeGroup>

For unpinned or behind-stable packages, [`charter fix`](/cli/fix) updates the package spec to the catalog's stable version as a diff-first preview before writing anything.

For **deprecated or archived packages**, migration is manual — the finding evidence includes the recommended successor package name. Update the entry to use the successor at its current stable version.

## Score impact

Deprecated, unpinned, or advisory-covered findings are `High` (−10 per finding). The behind-stable-only nudge is Informational (0). No hard cap — caps are reserved for raw-secret and Blocker findings. See [Scoring and caps](/docs/concepts/scoring-and-caps).

## Edge cases

Package specs are resolved only for direct runners (`npx`, `bunx`, `uvx`) and the `dlx` subcommand of `pnpm`/`yarn`. Local path arguments (`./`, `/`, `../`) and `exec`/`run` forms launch local binaries and are not treated as registry packages. Scoped packages (`@scope/name@1.2.3`) are pinned only when the trailing version is exact. A dynamic `pkg@${VERSION}` reference is treated as unpinned.

## Related rules

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

  <Card title="AE-MCP-003" icon="shield" href="/rules/AE-MCP-003">
    Remote MCP servers must declare auth.
  </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-001
```
