使用说明
GKE上具有工作负载身份联合(WIF)的MCP服务器
概述
概念证明,证明:
- Kubernetes上的MCP -在GKE上运行模型上下文协议服务器
- 工作负载身份联合 -从GitHub Actions到GCP的无密钥身份验证(无服务帐户密钥)
- MCP-UI -丰富的交互式界面,而不是原始的JSON响应
为什么选择MCP-UI?
文本非常适合简单的确认。这对天气预报、数据表或任何需要视觉结构的东西来说都是可怕的。MCP-UI允许服务器返回直接在聊天窗口中呈现的HTML接口——在正确的时间以正确的输出格式呈现。
看 docs/MCP_UI.md 了解实施细节。
堆栈
Python 3.12•Starlette•FastMCP•MCP-UI•GKE•GitHub Actions OIDC
项目结构
├── .github/workflows/
│ └── deploy.yml # CI/CD Pipeline definition
├── k8s/
│ └── deployment.yml # Kubernetes Deployment & Service manifests
├── src/
│ └── main.py # Application entrypoint & logic
├── Dockerfile # Multi-stage build instruction
├── pyproject.toml # Dependencies managed by uv
└── uv.lock # Exact versions for reproducibility
## Prerequisites
uv: Our chosen Python package manager. It replaces pip, poetry, and venv.
```bash
# macOS / Linux
curl -LsSf [https://astral.sh/uv/install.sh](https://astral.sh/uv/install.sh) | sh
Google Cloud CLI:用于与GCP资源交互。
Docker:用于本地容器构建和测试
基础架构设置(Bootstrap) 要配置所需的基础设施(GKE集群、工件注册表和工作负载标识),请在Google Cloud Shell中运行以下脚本。
先决条件:确保您已创建GCP项目并启用了计费。
提供资源
将此块复制并粘贴到您的Cloud Shell终端中。它将自动检测项目ID,并等效地提供所有必要的资源。
# --- CONFIGURATION ---
export PROJECT_ID=$(gcloud config get-value project)
export REGION="europe-west2"
export CLUSTER_NAME="mcp-cluster"
export REPO_NAME="mcp-repo"
export SA_NAME="github-actions-sa"
export POOL_NAME="github-pool-v2"
export PROVIDER_NAME="github-provider-v2"
export USER_GITHUB="ettysekhon" # <--- VERIFY THIS MATCHES YOUR GITHUB USER/ORG
echo "Provisioning Infrastructure for: $PROJECT_ID"
# 1. Enable APIs
gcloud services enable container.googleapis.com artifactregistry.googleapis.com iamcredentials.googleapis.com
# 2. Create Artifact Registry
if ! gcloud artifacts repositories describe $REPO_NAME --location=$REGION > /dev/null 2>&1; then
gcloud artifacts repositories create $REPO_NAME --repository-format=docker --location=$REGION --description="Docker repository for MCP Server"
fi
# 3. Create GKE Cluster
if ! gcloud container clusters describe $CLUSTER_NAME --location=$REGION > /dev/null 2>&1; then
echo "Creating GKE Cluster (approx 5-8 mins)..."
gcloud container clusters create-auto $CLUSTER_NAME --location=$REGION
fi
# 4. Configure Identity & Security
if ! gcloud iam service-accounts describe "$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" > /dev/null 2>&1; then
gcloud iam service-accounts create $SA_NAME --display-name="GitHub Actions Deployer"
fi
# Grant Roles
gcloud artifacts repositories add-iam-policy-binding $REPO_NAME --location=$REGION --member="serviceAccount:$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --role="roles/artifactregistry.writer"
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --role="roles/container.developer"
# Setup Workload Identity Federation
if ! gcloud iam workload-identity-pools describe $POOL_NAME --location="global" > /dev/null 2>&1; then
gcloud iam workload-identity-pools create $POOL_NAME --location="global" --display-name="GitHub Actions Pool V2"
fi
if ! gcloud iam workload-identity-pools providers describe $PROVIDER_NAME --location="global" --workload-identity-pool=$POOL_NAME > /dev/null 2>&1; then
gcloud iam workload-identity-pools providers create-oidc $PROVIDER_NAME --location="global" --workload-identity-pool=$POOL_NAME --display-name="GitHub Provider" --issuer-uri="[https://token.actions.githubusercontent.com](https://token.actions.githubusercontent.com)" --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" --attribute-condition="assertion.repository_owner == '${USER_GITHUB}'"
fi
# Link GitHub Repo to Service Account
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
gcloud iam service-accounts add-iam-policy-binding "$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --role="roles/iam.workloadIdentityUser" --member="principalSet://[iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_NAME/attribute.repository_owner/$](https://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_NAME/attribute.repository_owner/$){USER_GITHUB}"
echo ""
echo "SETUP COMPLETE. Add these to GitHub Secrets:"
echo "---------------------------------------------------"
echo "GCP_WIF_PROVIDER: projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_NAME/providers/$PROVIDER_NAME"
echo "GCP_WIF_SA: $SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"
echo "---------------------------------------------------"
配置GitHub机密
导航到GitHub存储库>设置>机密和变量>操作,并添加上面脚本输出的两个机密:
- GCP_WIF-PROVIDER
- GCP与SA
MCP工具
服务器通过MCP协议在以下位置公开天气工具 /mcp.工具归还 丰富的HTML界面 通过 MCP-UI 在兼容的客户端中显示美丽的天气。
get_weather
通过交互式UI显示按坐标获取天气。
| 参数 | 类型 | 说明 |
|---|---|---|
latitude |
float | 纬度(例如,伦敦为51.5074) |
longitude |
float | 经度(例如,伦敦为-0.1278) |
get_weather_by_city
通过交互式UI显示按城市名称获取天气(使用地理编码)。
| 参数 | 类型 | 说明 |
|---|---|---|
city |
string | 城市名称(例如,“伦敦”、“纽约”) |
get_weather_json
获取原始JSON天气数据(用于编程访问)。
| 参数 | 类型 | 说明 |
|---|---|---|
latitude |
float | 纬度(例如,伦敦为51.5074) |
longitude |
float | 经度(例如,伦敦为-0.1278) |
UI响应包括:
- 带有天气表情符号图标的当前温度
- 基于WMO代码的天气描述
- 湿度和风速
- 7天预报卡,包括每日高温/低温和降水量
支持的MCP-UI主机: ChatGPT Apps SDK、Goose、LibreChat、MCP-UI聊天、邮递员、UI检查器
开发流程
git clone https://github.com/ettysekhon/mcp-server-gke.git
cd mcp-server-gke
uv sync
uv run uvicorn src.main:app --reload --port 8000
端点
| 端点 | 描述 |
|---|---|
/ |
服务状态和版本 |
/health |
k8s探头的健康检查 |
/mcp |
MCP服务器(流式HTTP传输) |
安全模型
我严格避免使用长期存在的JSON服务帐户密钥。
- GitHub OIDC:GitHub在Action运行期间签署一个临时令牌。
- GCP交换:谷歌根据工作负载身份池验证令牌。
- 模拟:谷歌为github操作授予一个短期访问令牌,即服务帐户。
sequenceDiagram
participant GH as GitHub Action
participant GCP as Google Cloud (WIF)
participant SA as Service Account
GH->>GH: 1. Sign OIDC Token
GH->>GCP: 2. Exchange Token
GCP->>GCP: 3. Verify Repo & Owner
GCP->>SA: 4. Grant Access
SA->>GH: 5. Return Short-lived Key
Note over GH, SA: No static keys stored!
过程
- 将更改提交到main。
- 管道通过WIF进行身份验证。
- Docker镜像被构建并推送到工件注册表(europe-west2)。
- Kubernetes在k8s/中的清单通过新的image标签进行了水合。
- 更改将应用于GKE集群。
- 集群名称:mcp集群
- 地区:欧洲西部2(伦敦)
- 服务类型:LoadBalancer(公开公共IP)
故障排除
待定外部IP部署新服务时,LoadBalancer可能需要1-3分钟来配置静态IP。通过以下方式监控流程:
kubectl get service mcp-server-service --watch
测试已部署的服务
一旦你有了外部IP:
# Health check
curl http://<EXTERNAL-IP>/health
# Service status
curl http://<EXTERNAL-IP>/
测试MCP工具
MCP检查器(JSON调试)
使用 MCP检查员 对于原始协议测试:
npx @modelcontextprotocol/inspector
- 集 传输类型 到
Streamable HTTP - 输入URL:
http://<EXTERNAL-IP>/mcp - 点击 连接
- 首选 工具 要测试的选项卡
get_weather和get_weather_by_city
UI检查器(MCP-UI预览版)
使用 ui检查员 查看渲染的HTML天气卡:
git clone https://github.com/idosal/ui-inspector
cd ui-inspector
npm install
npm run dev
然后连接到 http://localhost:8000/mcp (本地)或 http://<EXTERNAL-IP>/mcp (已部署)。
路线图
- [x] MCP协议:集成FastMCP和Open-Meteo天气API
- [x] MCP-UI:通过MCP-UI服务器显示丰富的HTML天气
- []身份验证:实现用于客户端安全的API密钥中间件
- []数据库:配置到Cloud SQL的私有IP连接
