内容
# MCP Azure 云壳
MCP(模型上下文协议)服务器,允许开发者在 Azure 云壳环境中执行 Azure CLI 命令和 bash 脚本。
## 快速链接
- [功能](#功能) - 可用的工具和功能
- [安装](#安装) - 3 步快速开始
- [用法](#用法) - 标准输入 vs HTTP 传输设置
- [下一步](#下一步) - 生产环境部署和开发建议
- [工作原理](#工作原理) - 技术深度解析,含代码引用
- [成本与计费](#成本与计费) - 定价明细和创建的资源
- [故障排除](#故障排除) - 常见问题和解决方案
## 功能
该 MCP 服务器通过以下工具提供对 Azure 云壳的编程访问:
### 工具
1. **azure_cli** - 执行 Azure CLI 命令
- 在 Azure 环境中运行任意 `az` 命令
- 示例:`az account show`、`az vm list`、`az group list`
2. **azure_shell** - 执行 bash shell 命令
- 运行常规 bash 命令、git 操作或脚本
- 示例:`ls -la`、`git status`、`pwd`、`cat file.txt`
3. **azure_shell_reconnect** - 强制重新连接云壳
- 如果连接似乎已超时或命令超时
## 工作原理
服务器使用官方 Azure REST API 连接到 Azure 云壳:
1. **身份验证** - 使用 `@azure/identity` 中的 `DefaultAzureCredential`
2. **控制台配置** - 通过 Azure 管理 API 配置云壳控制台
3. **终端创建** - 创建 bash 终端会话
4. **WebSocket 连接** - 建立双向通信以执行命令
## 先决条件
在使用此服务器之前,您需要:
1. **Azure 帐户**,具有有效的订阅
2. **Azure CLI** 已在本地安装(用于身份验证设置)
3. **Node.js** 18+ 已安装
4. **Azure 云壳** 资源提供程序已在您的订阅中注册
### 注册 Azure 云壳资源提供程序
如果这是您第一次使用云壳,请注册资源提供程序:
```bash
az provider register --namespace Microsoft.CloudShell
```
### 身份验证设置
服务器使用 `DefaultAzureCredential`,支持多种身份验证方法。请选择一种:
#### 选项 1:Azure CLI(推荐用于开发)
```bash
az login
```
这是本地开发最简单的方法。服务器将自动使用您的 Azure CLI 凭证。
#### 选项 2:环境变量(服务主体)
```bash
export AZURE_TENANT_ID="your-tenant-id"
export AZURE_CLIENT_ID="your-client-id"
export AZURE_CLIENT_SECRET="your-client-id"
```
#### 选项 3:托管标识(适用于 Azure 托管应用程序)
如果在 Azure VM、应用服务或函数上运行,则会自动使用托管标识。
## 安装
1. 导航到项目目录:
```bash
cd mcp-azure-cloudshell
```
2. 安装依赖项:
```bash
npm install
```
3. 构建服务器:
```bash
npm run build
```
## 用法
此服务器支持两种传输机制。请根据您的使用场景选择最合适的:
### 传输选项
| 传输方式 | 最适合 | 优点 | 缺点 |
|-----------|----------|------|------|
| **标准输入** | 本地开发,Claude Code 桌面版 | 低延迟,设置简单 | 单用户,仅限本地 |
| **HTTP** | 远程访问,Web 应用,多用户 | 网络可访问,可扩展 | 需要服务器管理 |
### 选项 1:标准输入传输(推荐用于 Claude Code)
**启动服务器:**
```bash
npm start
```
**使用 CLI 添加到 Claude Code:**
```bash
claude mcp add --transport stdio azure-cloudshell -- node /path/to/mcp-azure-cloudshell/dist/index.js
```
**或手动配置** `.mcp.json`(本地)或 `~/.config/claude/mcp.json`(全局):
```json
{
"mcpServers": {
"azure-cloudshell": {
"command": "node",
"args": ["/absolute/path/to/mcp-azure-cloudshell/dist/index.js"],
"transport": "stdio"
}
}
}
```
### 选项 2:HTTP 传输(适用于远程/ Web 访问)
**启动 HTTP 服务器:**
```bash
npm run start:http
```
服务器默认在 `http://localhost:3000/mcp` 启动。可以使用 `PORT=8080` 进行自定义。
**在 Claude Code 中配置**(`.mcp.json`):
```json
{
"mcpServers": {
"azure-cloudshell-http": {
"url": "http://localhost:3000/mcp",
"transport": "http"
}
}
}
```
**使用 curl 测试:**
```bash
# 初始化会话
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "curl-client", "version": "1.0.0"}}, "id": 1}'
# 列出工具(使用会话 ID)
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: YOUR-SESSION-ID" \
-d '{"jsonrpc": "2.0", "method": "tools/list", "params": {}, "id": 2}'
```
有关详细的 HTTP 设置、部署选项和故障排除,请参阅 [HTTP-TRANSPORT.md](./HTTP-TRANSPORT.md)。
### 示例查询
添加服务器后,您可以向 Claude Code 提出问题,例如:
- "我正在使用哪个 Azure 订阅?"
- "列出我所有的资源组"
- "显示我东区的所有 VM"
- "在 westus2 中创建一个名为 test-rg 的新资源组"
- "我当前的 Cloud Shell 目录是什么?"
- "将存储库 https://github.com/example/repo 克隆到 Cloud Shell"
## 下一步
既然您已经设置了服务器,这里有一些推荐的下一步:
### 生产环境部署(HTTP 传输)
1. **添加身份验证**:实施令牌或 API 密钥验证
```typescript
app.use((req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !validateToken(authHeader)) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
});
```
2. **启用 HTTPS**:使用有效的 TLS 证书进行安全通信
- 部署在反向代理后面(nginx,Caddy)
- 使用 Let's Encrypt 获取免费证书
- 配置 HTTPS 重定向
3. **部署到云**:
- **Azure 应用服务**:`az webapp up --name my-mcp-server --resource-group my-rg`
- **AWS Lambda**:与 HTTP 服务器一起使用 AWS Lambda Web 适配器
- **Docker**:构建和部署容器化版本(参见 [HTTP-TRANSPORT.md](./HTTP-TRANSPORT.md))
4. **添加监控**:跟踪使用情况、错误和性能
- 应用程序洞察(Azure)
- CloudWatch(AWS)
- 自定义日志和指标
5. **实施速率限制**:通过请求限制防止滥用
```bash
npm install express-rate-limit
```
### 开发
1. **使用 Azure 凭证测试**:确保 `az login` 已配置并测试实际命令执行
2. **添加自定义工具**:使用其他 Azure 特定工具扩展服务器
3. **改进输出解析**:增强 `cleanOutput` 方法以更好地格式化命令结果
4. **添加 PowerShell 支持**:修改终端创建以支持 PowerShell 而不仅仅是 bash
### 学习更多
- 阅读 [HTTP-TRANSPORT.md](./HTTP-TRANSPORT.md) 以获取详细的 HTTP 设置和部署指南
- 探索 [Azure 云壳 REST API](https://learn.microsoft.com/en-us/rest/api/cloudshell/) 文档
- 查看 [模型上下文协议规范](https://modelcontextprotocol.io)
## 项目结构
```
mcp-azure-cloudshell/
├── src/
│ ├── index.ts # 主 MCP 服务器(标准输入传输)
│ ├── http-server.ts # HTTP 服务器(HTTP 传输)
│ └── cloudshell.ts # Azure 云壳连接管理器
├── dist/ # 编译的 JavaScript(生成)
├── package.json # 依赖项和脚本
├── tsconfig.json # TypeScript 配置
├── README.md # 此文件
└── HTTP-TRANSPORT.md # HTTP 传输文档
```
## 开发
### 开发模式
在监视模式下运行 TypeScript 编译器:
```bash
npm run dev
```
### 构建
```bash
npm run build
```
### 启动服务器(用于测试)
```bash
npm start
```
## 架构详情
### 底层工作原理
MCP 服务器通过三步过程与 Azure 云壳建立连接:
#### 步骤 1:控制台配置(cloudshell.ts:60-93)
```typescript
PUT https://management.azure.com/providers/Microsoft.Portal/consoles/default
```
- 调用 **Microsoft.Portal** 资源提供程序(不是 Microsoft.CloudShell!)
- 创建或检索现有的云壳控制台元数据对象
- 这是一个 **免费** 管理资源,无计算/存储成本
- 返回指向云壳网关的 URI
#### 步骤 2:终端创建(cloudshell.ts:98-133)
```typescript
POST https://{gateway-url}/terminals?cols=160&rows=40&shell=bash
```
- 在云壳环境中创建 bash 终端会话
- 指定终端尺寸和 shell 类型
- 返回 WebSocket URI 和终端 ID 以进行双向通信
#### 步骤 3:WebSocket 连接(cloudshell.ts:138-177)
```typescript
wss://{gateway-url}/terminals/{terminal-id}
```
- 打开到终端的持久 WebSocket 连接
- 所有命令输入/输出都通过此连接
- 命令按队列顺序执行,输出在命令完成之前被缓冲
#### 命令执行流程(cloudshell.ts:212-244)
1. 命令通过 WebSocket 发送,带有换行符 (`command\n`)
2. 输出在消息到达时累积在缓冲区中
3. 通过观察 shell 提示符($,#,>)检测命令完成
4. 删除 ANSI 转义代码并清理输出
5. 从结果中删除回显命令行和最终提示符
#### 身份验证流程
```
┌─────────────────┐
│ 默认 Azure │
│ 凭证 │
└────────┬────────┘
│
v
┌─────────────────┐
│ Azure │
│ 管理 API │
└────────┬────────┘
│
v
┌─────────────────┐
│ 云壳 │
│ 控制台 │
└────────┬────────┘
│
v
┌─────────────────┐
│ 终端 │
│ 会话 │
└────────┬────────┘
│
v
┌─────────────────┐
│ WebSocket │
│ 连接 │
└─────────────────┘
```
### 使用的 API 端点
1. **控制台配置**
- `PUT https://management.azure.com/providers/Microsoft.Portal/consoles/default?api-version=2020-04-01-preview`
- 返回: `{ properties: { uri: "https://...", provisioningState: "Succeeded", osType: "linux" } }`
2. **终端创建**
- `POST https://{gateway-url}/terminals?cols=160&rows=40&shell=bash`
- 返回: `{ id: "terminal-id", socketUri: "wss://..." }`
3. **WebSocket 连接**
- `wss://{gateway-url}/terminals/{terminal-id}`
- 协议:具有终端 I/O 的双向文本消息
### 代码架构
#### index.ts(MCP 服务器)
```typescript
import { AzureCloudShell } from "./cloudshell.js";
// 服务器维护一个云壳实例的单例
let cloudShell: AzureCloudShell | null = null;
// 在第一个工具调用时初始化连接
if (!cloudShell) {
cloudShell = new AzureCloudShell(credential);
await cloudShell.connect(); // 运行 3 步连接过程
}
// 通过已建立的连接执行命令
const result = await cloudShell.executeCommand(command, timeout);
```
`.js` 扩展名在导入中是必需的,因为:
- TypeScript 编译为 ES 模块(`"type": "module"` 在 `package.json` 中)
- ES 模块导入必须包含文件扩展名
- 运行时,Node.js 加载 `dist/cloudshell.js`(编译后的输出)
#### cloudshell.ts(连接管理器)
```typescript
export class AzureCloudShell {
private ws: WebSocket | null = null; // WebSocket 连接
private commandQueue: Array<{...}> = []; // 命令队列
private outputBuffer: string = ""; // 累积命令输出
private isReady: boolean = false; // 连接状态
async connect() {
await this.provisionConsole(); // 步骤 1:获取控制台 URI
await this.createTerminal(); // 步骤 2:创建终端
await this.connectWebSocket(); // 步骤 3:打开 WebSocket
}
async executeCommand(command: string, timeout: number): Promise<string> {
// 通过 WebSocket 发送命令
this.ws.send(`${command}\n`);
// 等待完成(通过提示符检测)
return new Promise((resolve, reject) => {
this.commandQueue.push({ command, resolve, reject, timeout });
});
}
private handleMessage(data: WebSocket.Data) {
// 累积输出直到提示符检测到
this.outputBuffer += data.toString();
// 在提示符出现时解析待处理命令
if (message includes prompt characters) {
currentCommand.resolve(this.cleanOutput(this.outputBuffer));
}
}
}
```
关键设计模式:
- **单例连接**:每个服务器实例一个 WebSocket
- **命令队列**:顺序执行防止输出交错
- **基于承诺的 API**:调用者使用干净的 async/await 接口
- **自动清理**:SIGINT/SIGTERM 处理程序断开连接
## 命令执行
服务器使用以下功能处理命令执行:
- **超时支持** - 命令的超时参数(默认 30 秒)
- **输出清理** - 删除 ANSI 转义码和终端提示符
- **队列管理** - 顺序处理多个命令
- **错误处理** - 提供失败的明确错误消息
## 故障排除
### 身份验证错误
**错误:** "获取访问令牌失败"
**解决方案:**
- 确保已使用 Azure CLI 登录:`az login`
- 验证在使用环境变量时服务主体凭证是否正确
- 检查您在 Azure 订阅中是否有适当的权限
### 连接错误
**错误:** "控制台配置失败"
**解决方案:**
- 确保 Microsoft.CloudShell 资源提供程序已注册
- 验证您的订阅是否有效
- 检查到 Azure 的网络连接
### 命令超时
**错误:** "命令在 30000ms 后超时"
**解决方案:**
- 增加命令的超时参数
- 检查命令是否实际运行时间较长
- 使用 `azure_shell_reconnect` 刷新连接
### WebSocket 错误
**错误:** "WebSocket 连接关闭"
**解决方案:**
- 云壳会话在 20 分钟不活动后超时
- 使用 `azure_shell_reconnect` 建立新连接
- 服务器将在下一个命令上自动重新连接
## 成本与计费
### 创建了哪些资源?
此 MCP 服务器 **不** 创建 VM、沙盒或资源组。它使用 REST API 连接到 Azure 现有的云壳基础设施。
### 使用的资源提供程序
#### Microsoft.Portal 资源提供程序
- **资源类型**:`Microsoft.Portal/consoles`
- **成本**:**免费** - 仅跟踪云壳会话元数据
- **作用**:创建控制台对象,引用云壳网关
- **位置**:仅管理平面,无计算/存储资源
#### Microsoft.CloudShell 资源提供程序
- **资源类型**:仅注册(`operations`)
- **成本**:**免费** - 仅 API 操作定义
- **作用**:在您的订阅中启用云壳 API
### 云壳实际配置(仅首次使用)
当您第一次使用云壳时,Azure 会自动配置:
#### 1. 存储帐户(~0.05-0.10/月)
- **资源**:Azure 文件共享(5 GB)
- **目的**:您的 `$HOME` 目录的持久存储
- **命名**:通常 `cs<randomstring>`
- **成本**:~0.05-0.10/月 标准 LRS 存储
- **生命周期**:创建一次,持续跨会话
#### 2. 容器实例(大部分免费)
- **资源**:临时 Linux 容器
- **成本**:
- **前 20 小时/月**:**免费**
- 20 小时后:~0.0013 秒(~4.68 小时,如果连续运行)
- **生命周期**:
- 在第一个命令上启动
- 空闲 20 分钟后自动终止
- 没有运行时的费用
#### 3. 网络流出(免费范围内限)
- **资源**:WebSocket 流量和 Azure API 调用
- **成本**:通常由 Azure 免费层覆盖
- **数量**:最小(仅命令 I/O)
### 成本比较
| 场景 | 每月成本 |
|----------|--------------|
| **典型使用 Azure 免费层
| **高用量**(40 小时/月)| ~$0.10 + (20 小时 × $4.68)= ~93.70 美元 |
| **此 MCP 服务器 vs Azure 门户** | **相同成本** - 使用相同的基础设施 |
| **空闲(无命令运行)** | ~$0.05-0.10(仅存储) |
### 监控成本
要检查您的订阅中是否存在云壳存储帐户:
```bash
az storage account list --query "[?tags.ms-resource-usage=='azure-cloud-shell']"
```
要查看您的云壳使用情况:
- Azure 门户 → 成本管理 → 成本分析
- 按服务筛选:`Azure Container Instances` 和 `Storage`
## 限制
1. **会话超时** - 云壳会话在 20 分钟不活动后超时
2. **单个会话** - 每个服务器实例只能有一个活动会话
3. **输出解析** - 复杂的交互式命令可能无法完美运行
4. **速率限制** - Azure API 速率限制适用
5. **免费层限制** - 20 小时/月的免费计算;超出免费额度按标准费率计费
## 安全考虑
1. **凭证安全** - 使用Azure的官方凭证链
2. **无凭证存储** - 按需获取令牌
3. **API范围** - 限制在Azure管理API范围内
4. **命令执行** - 在您的Cloud Shell环境中以您的权限运行命令
## 高级用法
### 自定义超时
```typescript
// 在Claude Code中,为慢速命令指定更长的超时时间
"使用azure_cli列出所有资源,命令为'az resource list',超时时间为60秒"
```
### 链式命令
```bash
# 使用 && 链式多个命令
"在azure_shell中执行:cd /home && ls -la && pwd"
```
### 文件操作
```bash
# 在Cloud Shell中创建和读取文件
"在Cloud Shell中创建一个名为test.txt的文件,内容为'Hello World'"
"读取Cloud Shell中test.txt的内容"
```
## API参考
### azure_cli 工具
**参数:**
- `command`(字符串,必填)- 要执行的Azure CLI命令
- `timeout`(数字,可选)- 超时时间(秒,默认:30)
**返回:**
- 命令输出为文本
### azure_shell 工具
**参数:**
- `command`(字符串,必填)- 要执行的Bash命令
- `timeout`(数字,可选)- 超时时间(秒,默认:30)
**返回:**
- 命令输出为文本
### azure_shell_reconnect 工具
**参数:**
- 无
**返回:**
- 成功消息
## 贡献
要扩展此服务器:
1. **添加新工具** - 在 `src/index.ts` 中定义其他工具
2. **增强输出解析** - 改进 `src/cloudshell.ts` 中的 `cleanOutput` 方法
3. **添加PowerShell支持** - 修改终端创建以使用 `pwsh` 代替 `bash`
4. **实现资源** - 将Azure资源公开为MCP资源
## 资源
- [Azure Cloud Shell 文档](https://learn.microsoft.com/en-us/azure/cloud-shell/)
- [Azure Identity SDK](https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme)
- [模型上下文协议](https://modelcontextprotocol.io)
- [Claude Code MCP 指南](https://docs.claude.com/en/docs/claude-code/mcp)
## 许可证
MIT
## 致谢
本服务器的构建使用了:
- `@azure/identity` - Azure身份验证
- `@modelcontextprotocol/sdk` - MCP服务器框架
- `ws` - WebSocket客户端
- Azure Cloud Shell REST API
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器