Metadata-Version: 2.4
Name: mcp-apisix
Version: 0.3.1
Summary: MCP Server for Apache APISIX Admin API
Project-URL: Homepage, https://github.com/zhouweico/mcp-apisix
Project-URL: Repository, https://github.com/zhouweico/mcp-apisix
Author: zhouweico
License-Expression: MIT
License-File: LICENSE
Keywords: admin-api,apisix,gateway,mcp,model-context-protocol
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: httpx2>=1.0.0
Requires-Dist: mcp<3.0.0,>=2.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: starlette>=0.37.0
Requires-Dist: uvicorn>=0.27.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Description-Content-Type: text/markdown

# mcp-apisix

Apache APISIX Admin API MCP Server —— 让 AI 助手查询与管理 APISIX 网关配置。

兼容 APISIX 2.x/3.x，响应格式（v2/v3）自动探测（优先依据 `X-API-VERSION` 响应头，头缺失时按响应体结构推断）。

## 特性

- **多协议传输**：`stdio`（默认）、`sse`、`streamable-http`
- **HTTP 接口认证**：Bearer Token 保护，未授权请求返回 `401`
- **写前确认**：创建 / 更新 / 切换状态等写操作强制二次确认，客户端需支持 Elicitation 能力
- **MCP Resources**：`apisix://` URI 暴露服务器环境等只读元数据
- **Stateless HTTP**：无会话状态，适配 Serverless / 多副本部署
- **凭据脱敏**：强制启用（不可关闭），消费者凭据、插件密钥等响应时自动遮盖
- **默认只读**：写工具默认不注册，需显式 `APISIX_READ_ONLY=false` 开启
- **灵活部署**：`uvx` 免安装、Docker 公开镜像、或本地构建

## 快速开始

### MCP 客户端（stdio，本地）

Claude Code 示例，写入项目 `.mcp.json` 或全局 `~/.claude.json`：

```json
{
  "mcpServers": {
    "apisix": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-apisix"],
      "env": {
        "APISIX_BASE_URL": "http://localhost:9180",
        "APISIX_ADMIN_KEY": "your-admin-key",
        "APISIX_READ_ONLY": "false"
      }
    }
  }
}
```

Cursor / OpenCode / Claude Desktop 等客户端格式相同：`command: uvx` + `args: ["mcp-apisix"]` + `APISIX_*` 环境变量。

**`APISIX_BASE_URL` 格式**：`scheme://host[:port]`。Admin API 默认独立监听 `9180`，Data Plane 监听 `9080`，二者分离。典型取值：

| 部署形态 | `APISIX_BASE_URL` 示例 |
|---|---|
| 默认 | `http://<host>:9180` |
| 经反向代理转发 | 填代理对外完整地址 |
| 自签名 TLS | `https://<host>:9180` + `APISIX_INSECURE=true` |

### Docker（公开镜像，免构建）

公开镜像：`ghcr.io/zhouweico/mcp-apisix:latest`。

**方式一：stdio（客户端拉起容器）**

```json
{
  "mcpServers": {
    "apisix": {
      "type": "stdio",
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/zhouweico/mcp-apisix:latest"],
      "env": {
        "APISIX_BASE_URL": "http://your-apisix-host:9180",
        "APISIX_ADMIN_KEY": "your-admin-key",
        "APISIX_READ_ONLY": "false"
      }
    }
  }
}
```

> 必须带 `-i`（保持 stdin 管道）。

**方式二：HTTP + 认证（容器独立运行）**

> 容器启动时会校验 `APISIX_ADMIN_KEY`（缺失则 `${VAR:?...}` 报错退出），必须显式传入。

启动容器：

```bash
docker run -d -p 8000:8000 \
  -e MCP_TRANSPORT=streamable-http \
  -e MCP_AUTH_TOKEN=your-strong-token \
  -e APISIX_BASE_URL=http://your-apisix-host:9180 \
  -e APISIX_ADMIN_KEY=your-admin-key \
  -e APISIX_READ_ONLY=false \
  ghcr.io/zhouweico/mcp-apisix:latest
```

客户端 `.mcp.json`：

```json
{
  "mcpServers": {
    "apisix": {
      "type": "streamable-http",
      "url": "http://localhost:8000/mcp",
      "headers": {
        "Authorization": "Bearer your-strong-token"
      }
    }
  }
}
```

## 可用工具

共 22 个原子工具 + 1 个 MCP Resource。

### 资源读取（11 个，只读）

所有 `list_*` 工具共享通用参数：`page` / `page_size`（有效区间 [10, 500]）/ `detail`（返回完整配置）/ `fields`（JSON 数组，覆盖默认投影；`detail=true` 时忽略）。所有资源响应统一经过脱敏层。

| 工具 | 对应端点 | 资源特有过滤参数 | 只读模式 |
|------|----------|------------------|----------|
| `apisix_list_routes` | `GET /routes` | `name` / `uri` / `label`（v3）/ `service_id` / `upstream_id`（引用过滤，≥3.13） | ✅ |
| `apisix_get_route` | `GET /routes/{id}` | — | ✅ |
| `apisix_list_services` | `GET /services` | 无 | ✅ |
| `apisix_get_service` | `GET /services/{id}` | — | ✅ |
| `apisix_list_upstreams` | `GET /upstreams` | 无 | ✅ |
| `apisix_get_upstream` | `GET /upstreams/{id}` | — | ✅ |
| `apisix_list_consumers` | `GET /consumers` | 无（凭据字段已脱敏） | ✅ |
| `apisix_get_consumer` | `GET /consumers/{username}` | —（凭据字段已脱敏） | ✅ |
| `apisix_list_global_rules` | `GET /global_rules` | 无 | ✅ |
| `apisix_list_stream_routes` | `GET /stream_routes` | 无 | ✅ |
| `apisix_list_plugin_configs` | `GET /plugin_configs` | 无 | ✅ |

> `global_rules` / `stream_routes` / `plugin_configs` 有意只提供 list，不提供 get：资源数量通常很少，一次 list 即可获取全部。需完整配置时传 `detail=true`。

### 语义支撑（3 个，只读）

| 工具 | 对应端点 | 说明 | 只读模式 |
|------|----------|------|----------|
| `apisix_list_plugins` | `GET /plugins/list` | 插件名数组（按 priority 降序，不含 schema）；`subsystem` 取 `http`（默认）或 `stream` | ✅ |
| `apisix_get_plugin_schema` | `GET /schema/plugins/{name}` | 单个插件字段定义、类型、必填项、默认值（含 `metadata_schema` 与 `consumer_schema`） | ✅ |
| `apisix_get_server_info` | 探测层数据 | 客户端探测层状态（响应格式 v2/v3、可用能力清单），非 APISIX 节点运行时信息 | ✅ |

### 资源配置校验（1 个，只读）

| 工具 | 对应端点 | 说明 | 只读模式 |
|------|----------|------|----------|
| `apisix_validate_resource_config` | `POST /schema/validate/{resource}`（≥3.5） | 校验配置是否符合 JSON schema；仅校验 schema，不校验引用存在性与插件合法性；通过不代表写入必定成功 | ✅ |

### 写操作（7 个，`APISIX_READ_ONLY=true` 时不注册）

| 工具 | 语义 | 只读模式 |
|------|------|----------|
| `apisix_create_route` | POST 创建（服务端生成 id） | ❌ |
| `apisix_update_route` | PATCH 增量（带乐观锁） | ❌ |
| `apisix_toggle_route` | PATCH `status` 0/1（仅 route 有此字段） | ❌ |
| `apisix_create_upstream` | POST 创建（服务端生成 id） | ❌ |
| `apisix_update_upstream` | PATCH 增量 | ❌ |
| `apisix_create_service` | POST 创建（服务端生成 id） | ❌ |
| `apisix_update_service` | PATCH 增量 | ❌ |

**写操作约定**：

- **create 严格用 POST**，服务端生成 id，不接受 `id` 参数；禁止 PUT（会静默全量覆盖且无乐观锁）
- **update 用 PATCH**，仅传需修改字段，未提及字段保持不变；自带乐观锁，配置在读取后被其他来源修改会返回冲突提示
- **toggle 仅限 route**：upstream 和 service 的 schema 无 `status` 字段，不提供 toggle
- **不提供 DELETE**：破坏性过大，需删除时通过 APISIX Dashboard 或 Admin API 手动处理
- **不提供 consumer 写操作**：consumer 涉及凭据写入，风险过高

**写前确认**：所有写工具执行前强制向用户确认，确认由 MCP SDK 在参数解析阶段发起（`Resolve` + `Elicit`），并按协议版本自动选择传输方式（2025-06-18 同步 Elicitation / 2026-07-28 MRTR）。

> ⚠️ **客户端能力要求**：客户端必须声明 `elicitation` 能力，否则 SDK 直接返回 `-32021` 拒绝，写工具不会执行。自 v0.3.0 起不再提供"放行并标注未经人工确认"的降级路径——确认机制失效时一律拒绝，而非视为无需确认。非交互环境（如自动化脚本）如需写入，请直接调用 APISIX Admin API。

**多来源共管风险**：APISIX 配置可能同时被 Dashboard、Ingress Controller（源自 ApisixRoute 等 CRD）等多方管理。若目标资源由声明式控制器管理，此处修改可能在数秒后被控制器按 CRD 覆盖回原状。写工具的返回结果中会显式提示此风险。

### APISIX 概念

- **route**：核心路由配置，匹配请求并指向 upstream 或 service
- **service**：可复用的服务配置（upstream + plugins），被 route 引用
- **upstream**：后端节点集合（含负载均衡策略、健康检查等）
- **consumer**：消费者身份，承载认证凭据（如 key-auth 的 key）与限流配额
- **global_rules**：全局生效的插件配置，作用于所有路由
- **plugin_configs**：可复用的插件配置组，被 route 引用
- **stream_routes**：四层（TCP/UDP）流路由

> **响应格式 v2/v3**：APISIX 3.x 可通过 `deployment.admin.admin_api_version` 配置返回 v2 格式，APISIX 2.x 原生返回 v2 格式。本 Server 自动探测响应格式（优先依据 `X-API-VERSION` 响应头，头缺失时按响应体结构推断），无需手动配置。v2 格式下分页与过滤参数被服务端静默忽略，返回结果中会显式告知。

## 配置

### 环境变量

**MCP 传输与认证**

| 变量 | 说明 | 默认值 |
|------|------|--------|
| `MCP_TRANSPORT` | 传输协议：`stdio` / `sse` / `streamable-http` | `stdio` |
| `MCP_HOST` | HTTP 监听地址（stdio 忽略） | `0.0.0.0` |
| `MCP_PORT` | HTTP 监听端口（stdio 忽略） | `8000` |
| `MCP_AUTH_TOKEN` | 非空时启用 Bearer Token 认证 | -（不鉴权） |
| `MCP_STATELESS_HTTP` | 启用无状态 HTTP（适配 Serverless） | `false` |
| `MCP_LOG_LEVEL` | 日志级别：`debug` / `info` / `warning` / `error` | `info` |

**APISIX 连接**

| 变量 | 说明 | 默认值 |
|------|------|--------|
| `APISIX_BASE_URL` | Admin API 地址，格式 `scheme://host[:port]` | `http://localhost:9180` |
| `APISIX_ADMIN_KEY` | **必填**。映射到 `X-API-KEY` 请求头 | - |
| `APISIX_API_VERSION` | 响应格式：`auto`（自动探测）/ `v2` / `v3` | `auto` |
| `APISIX_READ_ONLY` | 只读模式（禁用写工具） | `true` |
| `APISIX_TIMEOUT` | 请求超时秒数 | `30` |
| `APISIX_INSECURE` | 跳过 TLS 证书验证（自签名 / 内部 CA 场景） | `false` |

### 只读模式

默认开启，写工具（create / update / toggle）不注册，Agent 看不到也调不到。开启写操作：

```json
{ "env": { "APISIX_READ_ONLY": "false" } }
```

### 响应格式探测

`APISIX_API_VERSION=auto`（默认）时，从成功响应（2xx）中自动探测：优先读取 `X-API-VERSION` 响应头，头缺失时按响应体结构推断（`node`+`action` → v2，`list`+`total` → v3）。探测未完成前按 v3 处理。可强制指定 `v2` 或 `v3` 跳过探测。

> 探测结果在进程生命周期内缓存，不主动失效。若 APISIX 实例重启并切换了配置，需重启 MCP 进程。

### TLS 证书验证

默认验证 TLS 证书（行为与 httpx 一致）。自签名或内部 CA 环境：

```json
{ "env": { "APISIX_INSECURE": "true" } }
```

> 禁用证书验证不安全，生产环境应使用受信任 CA 签发的有效证书。

## 多协议传输

| 协议 | 端点 | 适用 |
|---|---|---|
| `stdio`（默认） | - | 本地客户端集成（Claude Code、Cursor 等） |
| `sse` | `http://<host>:<port>/sse` | SSE 传输（已废弃） |
| `streamable-http` | `http://<host>:<port>/mcp` | 远程部署 / 多客户端共享 |

启动示例：

```bash
MCP_TRANSPORT=streamable-http \
MCP_HOST=0.0.0.0 MCP_PORT=8000 \
MCP_AUTH_TOKEN=your-strong-token \
APISIX_BASE_URL=http://localhost:9180 \
APISIX_ADMIN_KEY=your-admin-key \
mcp-apisix
```

## 接口认证

`MCP_AUTH_TOKEN` 非空时，HTTP 请求需携带：

```
Authorization: Bearer <MCP_AUTH_TOKEN>
```

兼容 `X-Auth-Token` / `X-MCP-Token` 请求头。`GET /health` 免鉴权（容器探活）。

> `stdio` 不经过网络，不做 Token 认证。未设 `MCP_AUTH_TOKEN` 时 HTTP 接口不鉴权，生产环境务必配置。

## MCP Resources

| URI | 说明 |
|---|---|
| `apisix://server-info` | 客户端探测层状态（响应格式 v2/v3、可用能力清单），非 APISIX 节点运行时信息 |

会话建立时探测层尚无数据，Resource 返回配置值 + 探测状态"未知"；首次调用 Admin API 后探测完成，后续读取返回准确格式。每次读取动态返回，非静态快照。

## Stateless HTTP 模式

`MCP_STATELESS_HTTP=true`：每次请求独立处理，不保留会话状态。适配 Serverless（AWS Lambda、阿里云函数计算）或多副本部署。

```bash
MCP_TRANSPORT=streamable-http \
MCP_STATELESS_HTTP=true \
MCP_HOST=0.0.0.0 MCP_PORT=8000 \
mcp-apisix
```

> Stateless 模式不支持 SSE 流式响应，每个 HTTP 请求独立完成后返回。

## 容器化部署

### 本地构建（Docker）

```bash
docker build -t mcp-apisix:latest .

docker run -d --name mcp-apisix -p 8000:8000 \
  -e MCP_TRANSPORT=streamable-http \
  -e MCP_AUTH_TOKEN=your-strong-token \
  -e APISIX_BASE_URL=http://your-apisix-host:9180 \
  -e APISIX_ADMIN_KEY=your-admin-key \
  -e APISIX_READ_ONLY=false \
  mcp-apisix:latest
```

### Docker Compose

```bash
cp .env.example .env   # 按需修改
docker compose up -d
```

`docker-compose.yml` 已内置：基于 Dockerfile 构建（标记为 `mcp-apisix:latest`）、`/health` 健康检查、非 root 用户运行。

> 跳过本地构建、直接拉取公开镜像：删除 `build:` 段，只保留 `image: ghcr.io/zhouweico/mcp-apisix:latest`。

## 使用示例

下面示例均为自然语言提示，AI 助手会自动映射到对应 MCP 工具。

### 资源查询

```
列出 APISIX 里所有的路由（只看 id、name、uri）
```

```
查看路由 r1 的完整配置
```

```
列出所有上游，按名称过滤包含 "user-service" 的
```

```
查看消费者 alice 的配置
```

```
列出所有全局规则，返回完整配置
```

### 语义查询

```
APISIX 支持哪些插件？按优先级列出来
```

```
查看 key-auth 插件的 schema，需要哪些字段
```

```
当前 APISIX 实例返回的是 v2 还是 v3 格式？支持引用过滤吗？
```

### 配置校验

```
帮我校验这份路由配置是否符合 schema：
{"uri": "/api/v1/*", "upstream": {"type": "roundrobin", "nodes": {"127.0.0.1:8080": 1}}}
```

### 写操作（需 `APISIX_READ_ONLY=false`）

```
创建一个路由，uri 是 /api/v1/users，转发到 upstream u1
```

```
更新路由 r1，把 priority 改成 100
```

```
禁用路由 r1
```

```
创建一个上游，类型 roundrobin，节点 127.0.0.1:8080 权重 1
```

```
更新上游 u1，把超时改成 10 秒
```

```
创建一个服务，绑定 upstream u1，开启 key-auth 插件
```

> 写操作属破坏性操作，执行前会弹出二次确认。客户端未声明 `elicitation` 能力时，请求被 SDK 以 `-32021` 拒绝，工具不会执行。

### 字段投影

```
列出所有路由，只返回 id、name、uri、upstream_id 这几个字段
```

```
列出路由的完整配置（不要裁剪字段）
```

> `labels` 为强制保留字段，任何投影都会包含（用于识别资源归属）。

### 只读模式（`APISIX_READ_ONLY=true`）

写工具在只读模式下不注册，AI 只能执行查询类操作：

```
只读模式下：帮我禁用路由 r1
```

AI 会回复该操作不可用，引导用户关闭只读模式或手动处理。

## License

MIT
