MCP服务器部署工具

一个在GKE上部署MCP服务器的工具,支持无密钥身份验证和丰富的UI交互界面。

  • by ettysekhon
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 ettysekhon/mcp-server-gke

使用说明

GKE上具有工作负载身份联合(WIF)的MCP服务器

概述

概念证明,证明:

  1. Kubernetes上的MCP -在GKE上运行模型上下文协议服务器
  2. 工作负载身份联合 -从GitHub Actions到GCP的无密钥身份验证(无服务帐户密钥)
  3. 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服务帐户密钥。

  1. GitHub OIDC:GitHub在Action运行期间签署一个临时令牌。
  2. GCP交换:谷歌根据工作负载身份池验证令牌。
  3. 模拟:谷歌为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!

过程

  1. 将更改提交到main。
  2. 管道通过WIF进行身份验证。
  3. Docker镜像被构建并推送到工件注册表(europe-west2)。
  4. Kubernetes在k8s/中的清单通过新的image标签进行了水合。
  5. 更改将应用于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
  1. 集 传输类型 到 Streamable HTTP
  2. 输入URL: http://<EXTERNAL-IP>/mcp
  3. 点击 连接
  4. 首选 工具 要测试的选项卡 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连接