内容
# ARM MCP 服务器
一个实用的 [模型上下文协议](https://modelcontextprotocol.io) 服务器,暴露 Azure 资源管理器(ARM)API 给 MCP 客户端(Copilot, Claude Desktop, MCP Inspector, 自定义代理)。
此仓库组织为一个小型 Python 包:
- `server.py` 是薄入口点。
- `arm_mcp/core.py` 包含身份验证、HTTP、分页、LRO 轮询、API 版本推断和模式助手。
- `arm_mcp/tools.py` 注册 MCP 工具。
## 为什么选择这种设计
ARM 是一个统一的控制平面 API(`HTTP 动词 + ARM 路径 + api-version + 可选 JSON 正文` 对 `https://management.azure.com`)。
而不是手动编码服务特定的客户端,该服务器暴露:
- 通用执行工具,
- 发现工具以查找有效的资源类型/版本,
- 计划工具以塑造请求正文。
这给代理一个可靠的发现 -> 计划 -> 执行工作流程,同时保持服务器最小化。
## 暴露的工具
### 执行(直通)
| 工具 | 动词 | 目的 |
|------|------|---------|
| `arm_get` | GET | 读取任何 ARM 资源或集合(`all_pages=true` 遵循 `nextLink`) |
| `arm_put` | PUT | 创建或完全替换资源(默认情况下轮询异步 ARM 操作) |
| `arm_patch` | PATCH | 部分更新 |
| `arm_delete` | DELETE | 删除资源(`confirm=true` 保护) |
| `arm_action` | POST | 调用 ARM 操作(例如 `listKeys`,`restart`,`start`,`stop`) |
### 发现(存在)
| 工具 | 目的 |
|------|---------|
| `arm_list_subscriptions` | 列出可访问的订阅 |
| `arm_list_locations` | 列出订阅的 Azure 区域 |
| `arm_list_providers` | 列出提供程序命名空间,或提供程序资源类型 + API 版本 |
| `arm_search_resource_types` | 跨提供程序资源类型进行关键字搜索(`detail=names|versions|full`) |
### 规划(如何调用)
| 工具 | 目的 |
|------|---------|
| `arm_get_schema` | 返回资源类型 + API 版本所需的请求正文字段、汇总属性和示例正文 |
### 本地工作流程发现
| 工具 | 目的 |
|------|---------|
| `get_skill` | 使用语义文本匹配将用户意图与本地 `skills/` 文件夹中的 Markdown 工作流程文档匹配 |
所有工具都返回以下形式的构造有效载荷:
`{"ok": bool, "status": int, "data": ..., "error"?: {...}}`
工具还包括 MCP 注释(`readOnlyHint`,`destructiveHint`,`idempotentHint`)。
## API 版本行为
对于直通工具(`arm_get`,`arm_put`,`arm_patch`,`arm_delete`,`arm_action`),可以省略 `api_version`。
当省略时,服务器尝试从 ARM 路径推断资源类型,并解析提供程序 `defaultApiVersion`。
当默认成功时,响应包括:
- `api_version_used`
- `note`
如果推断失败,错误指向 `arm_search_resource_types` 或 `arm_list_providers`。
## 典型流程
```text
arm_search_resource_types(query="storage", detail="versions")
-> 选择 resourceType + apiVersion
arm_get_schema(resource_type="Microsoft.Storage/storageAccounts", api_version="2024-01-01")
-> 塑形正文
arm_put(path=".../storageAccounts/<name>", body={...})
```
## 先决条件
1. Python 3.10+
2. Azure CLI 通过 `az login` 进行身份验证
3. 已安装依赖项
```bash
python3 -m pip install -r requirements.txt
```
身份验证使用 `azure-identity` `DefaultAzureCredential`,它重用本地 Azure 身份验证上下文(包括 Azure CLI 登录)。此服务器不存储任何机密。
## 仓库布局
```text
arm-mcp-server/
├── README.md
├── requirements.txt
├── server.py
├── arm_mcp/
│ ├── __init__.py
│ ├── core.py
│ └── tools.py
├── docs/
│ └── ARM_MCP_TOOL_IMPLEMENTATION_GUIDE.md
├── eval/
│ ├── requirements.txt
│ ├── run_eval.py
│ ├── scenarios.json
│ └── results/
├── schema_cache/
│ └── <provider>_<api-version>.json
└── tests/
├── test_client.py
├── test_enhancements.py
└── test_all_tools.py
```
## 在本地运行和验证
安装依赖项:
```bash
python3 -m pip install -r requirements.txt
```
快速烟雾测试(读取导向的发现调用):
```bash
python3 tests/test_client.py
```
增强测试(模式/搜索/分页/注释/API 版本默认):
```bash
python3 tests/test_enhancements.py
```
综合演练脚本:
```bash
python3 tests/test_all_tools.py
```
使用 MCP Inspector 进行交互式探索:
```bash
npx @modelcontextprotocol/inspector python3 server.py
```
## MCP 客户端配置
示例 MCP 配置条目:
```json
{
"mcpServers": {
"arm": {
"command": "python3",
"args": ["/Users/stevenbucher/Testing/arm-mcp-server/server.py"]
}
}
}
```
## 示例工具调用
读取存储帐户:
```json
{
"tool": "arm_get",
"arguments": {
"path": "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<name>",
"api_version": "2023-01-01"
}
}
```
创建存储帐户:
```json
{
"tool": "arm_put",
"arguments": {
"path": "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<name>",
"api_version": "2023-01-01",
"body": {
"location": "eastus",
"sku": { "name": "Standard_LRS" },
"kind": "StorageV2",
"properties": {
"accessTier": "Hot",
"minimumTlsVersion": "TLS1_2"
}
}
}
}
```
调用操作(`listKeys`):
```json
{
"tool": "arm_action",
"arguments": {
"path": "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<name>/listKeys",
"api_version": "2023-01-01"
}
}
```
首先发现有效版本:
```json
{
"tool": "arm_list_providers",
"arguments": {
"subscription_id": "<sub>",
"namespace": "Microsoft.Storage"
}
}
```
将用户意图与本地工作流程技能匹配:
```json
{
"tool": "get_skill",
"arguments": {
"intent": "I need a repeatable workflow for creating an expense report from receipts",
"max_results": 3
}
}
```
## 评估框架
`eval/run_eval.py` 通过 GitHub Copilot SDK 运行场景提示,并仅附加此 ARM MCP 服务器。
捕获每个场景:
- 工具序列和参数,
- Token 使用和成本,
- 延迟,
- 工具失败,
- 阻止尝试调用非 ARM 工具,
- 最终模型答案。
设置:
```bash
python3 -m pip install -r eval/requirements.txt
python3 -m copilot download-runtime
az login
```
运行:
```bash
python3 eval/run_eval.py
python3 eval/run_eval.py --model gpt-5
python3 eval/run_eval.py --only S001,S002
python3 eval/run_eval.py --subscription-id <sub-id> --resource-group <rg-name>
```
注意:
- 默认模型是 `claude-sonnet-4.5`。
- 默认场景文件是 `eval/scenarios.json`。
- CSV 输入仍然通过 `--scenarios path.csv` 支持,带有 `id`、`prompt` 和 `expected_tools`(或旧版 `expect_tool`)。
输出:
- `eval/results/latest.json`
- `eval/results/report_<timestamp>.md`
## 操作说明
- 长时间运行的操作:`arm_put`、`arm_patch` 和 `arm_delete` 默认情况下会轮询 ARM 异步操作端点(最多约 5 分钟)。使用 `wait=false` 立即返回。
- 包含机密的操作:`arm_action` 可以返回敏感值(例如存储密钥)。相应地处理工具输出。
- 模式源和缓存:`arm_get_schema` 从 `https://schema.management.azure.com/schemas` 读取并在 `schema_cache/` 下缓存文件。
- 请求正文形状:`apiVersion`、`name` 和 `type` 是 URL/模板字段,旨在从 `arm_get_schema` 正文示例中排除。
## 实现文档
- `docs/ARM_MCP_TOOL_IMPLEMENTATION_GUIDE.md` 包含每个公开的 MCP 工具的深入实现演练,包括内部调用路径、行为细节和边缘情况。