混合MCP沸腾板
建筑样板 混合MCP(模型上下文协议)服务器 -一个单一的可部署应用程序,在同一进程上通过SSE公开标准REST API(FastAPI)和MCP服务器。AI客户端连接到MCP端点;人工和集成使用REST API。两者都有相同的商业逻辑。
这是什么
main.py # entry point — mounts MCP SSE onto FastAPI
src/
settings.py # typed env-var config with pydantic-settings
api/
app.py # FastAPI instance + CORS + router registration
routers/
words.py # example: CRUD REST endpoints
mcp/
app.py # FastMCP instance
tools/
words.py # example: same CRUD exposed as MCP tools
services/
words.py # business logic — shared by REST and MCP
iac/
terraform/ # Azure infrastructure (App Service + PostgreSQL)
scripts/bootstrap.sh # one-time state storage setup
.github/workflows/
iac-plan.yml # terraform plan on PR
iac-deploy.yml # terraform apply on merge堆栈: Python 3.12、FastAPI、FastMCP、Pydantic v2、uv、Alembic、PostgreSQL\ 部署: Azure应用服务(基本B1,始终开启)+PostgreSQL灵活服务器\ IaC: 具有按订阅环境和GitHub Actions CI/CD的Terraform
______________________________________________________________________
设置
先决条件
- Python 3.12+
- 紫外线 —
curl -LsSf https://astral.sh/uv/install.sh | sh - Git
1.克隆并安装
git clone
cd hybrid-mcp
uv sync2.配置环境
复制示例env并填写您的值:
cp .env.example .env.env 值:
# App
APP_NAME=hybrid-mcp
# CORS
CORS_ALLOWED_ORIGINS=["http://localhost:3000"]
CORS_ALLOWED_METHODS=["GET","POST","PUT","DELETE","OPTIONS"]
CORS_ALLOWED_HEADERS=["*"]
# Database
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=hybrid_mcp
DATABASE_USER=postgres
DATABASE_PASSWORD=secret
# Sharepoint (optional integration)
SHAREPOINT_CLIENT_ID=
SHAREPOINT_CLIENT_SECRET=
SHAREPOINT_TENANT_ID=
SHAREPOINT_SITE_URL=
SHAREPOINT_FILE_PATH=3.在本地运行
uv run uvicorn main:app --host 0.0.0.0 --port 8000 --reload3a。使用Docker运行(推荐给开发人员)
需要 使用Compose v2.22+。
docker compose watch这将启动API和本地PostgreSQL数据库。文件更改会自动处理:
| 你改变了什么 | 会发生什么 |
|---|---|
任何东西 src/ 或 main.py | Compose将文件同步到容器中,uvicorn重新加载 |
pyproject.toml 或 uv.lock | 图像已重建(uv sync 重新运行),容器重新启动 |
Dockerfile.dev | 图像已重建 |
当地的Postgres运行 localhost:5432 与:
- 用户:
postgres,密码:secret,db:hybrid_mcp
确保你的 .env 有 DATABASE_HOST=db (Docker服务名称)在通过Compose运行时。
| 端点 | 描述 |
|---|---|
http://localhost:8000/docs | REST API文档(Swagger UI) |
http://localhost:8000/api/words/ | 示例单词CRUD |
http://localhost:8000/mcp/sse | MCP SSE流 |
4.测试MCP连接
使用官方MCP检查员:
npx @modelcontextprotocol/inspector http://localhost:8000/mcp/sse它打开一个浏览器UI,您可以在其中浏览和调用所有注册的MCP工具。
______________________________________________________________________
进行更改
添加新功能(REST+MCP)
每个功能都遵循相同的三文件模式:
1.创建服务-- src/services/.py
纯业务逻辑,无HTTP或MCP问题:
def list_items() -> list[str]:
...
def add_item(item: str) -> list[str]:
...2.创建REST路由器-- src/api/routers/.py
from fastapi import APIRouter
from src.services. import list_items, add_item
router = APIRouter(prefix="/", tags=[""])
@router.get("/", response_model=list[str])
def get_items():
return list_items()
@router.post("/", response_model=list[str], status_code=201)
def create_item(body: ItemBody):
return add_item(body.item)在中注册 src/api/app.py:
from src.api.routers. import router as feature_router
api_router.include_router(feature_router)3.创建MCP工具-- src/mcp/tools/.py
from mcp.server.fastmcp import FastMCP
from src.services. import list_items, add_item
def register_feature_tools(server: FastMCP) -> None:
@server.tool()
def feature_list() -> list[str]:
"""List all items."""
return list_items()
@server.tool()
def feature_add(item: str) -> list[str]:
"""Add an item."""
return add_item(item)在中注册 src/mcp/app.py:
from src.mcp.tools. import register_feature_tools
register_feature_tools(mcp)添加环境变量
向添加新设置 src/settings.py。每个嵌套类都是独立的 BaseSettings 它独立读取自己的前缀env变量:
class _MyIntegration(BaseSettings):
model_config = _config("MY_INTEGRATION_")
api_key: str
base_url: str = "https://api.example.com"然后将其添加到 _Settings:
class _Settings(BaseSettings):
...
my_integration: _MyIntegration = _MyIntegration()通过以下方式随时随地访问 from src.settings import settings → settings.my_integration.api_key.
数据库迁移
迁移使用 蒸馏器.从项目根开始:
# Create a new migration
uv run alembic revision --autogenerate -m "add my table"
# Apply migrations
uv run alembic upgrade head
# Rollback one step
uv run alembic downgrade -1______________________________________________________________________
部署
步骤0--选择您的提供商
选择一个提供者并将其设置在一个地方。 打开 .github/workflows/iac-deploy.yml 并在此行设置默认值:
# .github/workflows/iac-deploy.yml
TF_PROVIDER: ${{ inputs.provider || 'azure' }} # ← change to: azure | aws | gcp这控制了每个自动分支触发部署(PR合并到 dev 或 main).对于一次性手动部署到其他提供商,您始终可以通过以下方式覆盖它 workflow_dispatch 而不改变这条线。
所有基础设施均位于 iac/terraform/ / --只需填写所选提供商的文件。
| 提供者 | 计算 | 数据库 | ~成本/环境/月 |
|---|---|---|---|
| 蔚蓝 | 应用服务基本B1(始终打开) | PostgreSQL灵活服务器B1ms | 28美元 |
| 亚马逊网络服务 | Elastic Beanstalk t3.micro | RDS PostgreSQL t4g.micro | 20美元 |
| 谷歌云平台 | 云运行(最小实例数=1) | 云SQL db-f1-micro | 22美元 |
仅适用于GCP: Cloud Run需要容器映像。在部署之前构建并推送到工件注册表(见下文)。 仅限AWS: 弹性豆茎需要Procfile在repo根目录:web: uvicorn main:app --host 0.0.0.0 --port 5000
先决条件
- 地形1.6+
- 所选提供商的Cloud CLI:
- Azure: Azure命令行界面 — az login - AWS: AWS-CLI — aws configure - GCP: gcloud命令行界面 — gcloud auth application-default login
首次设置
1.填写您的值
编辑所选提供商和环境的后端配置和环境文件:
iac/terraform/
/backends/dev.conf # state storage config
iac/terraform/
/envs/dev.tfvars # subscription/project ID + app values2.Bootstrap状态存储
每个提供者+环境运行一次以创建远程状态存储桶/存储帐户:
./iac/scripts/bootstrap.sh azure dev
./iac/scripts/bootstrap.sh aws dev
./iac/scripts/bootstrap.sh gcp dev3.部署
# Azure
terraform -chdir=iac/terraform/azure init -backend-config=backends/dev.conf
terraform -chdir=iac/terraform/azure apply -var-file=envs/dev.tfvars -var="db_password=
"
# AWS
terraform -chdir=iac/terraform/aws init -backend-config=backends/dev.conf
terraform -chdir=iac/terraform/aws apply -var-file=envs/dev.tfvars -var="db_password=
"
# GCP (build and push image first — see below)
terraform -chdir=iac/terraform/gcp init -backend-config=backends/dev.conf
terraform -chdir=iac/terraform/gcp apply -var-file=envs/dev.tfvars -var="db_password=
"GCP——构建和推送容器映像
跑 terraform apply 首先创建工件注册表存储库,然后:
# Build
docker build -t -docker.pkg.dev/
/-dev/app:latest .
# Push
gcloud auth configure-docker -docker.pkg.dev
docker push -docker.pkg.dev/
/-dev/app:latest然后更新 container_image 在 iac/terraform/gcp/envs/dev.tfvars 并重新申请。
你还需要一个 Dockerfile 在repo根目录下。例子:
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install uv && uv sync --no-dev
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]GitHub操作CI/CD
工作流文件位于 iac/github-actions/ 并且是 默认情况下处于非活动状态 因此,它们不会在样板回购本身上运行。要在项目中激活它们,请执行以下操作:
mkdir -p .github/workflows
cp iac/github-actions/iac-plan.yml .github/workflows/
cp iac/github-actions/iac-deploy.yml .github/workflows/一旦 .github/workflows/,GitHub将自动接收它们。
| 事件 | 行动 |
|---|---|
公关定位 dev | terraform plan 反对dev,结果作为公关评论发布 |
PR合并为 dev | terraform apply 到dev |
公关定位 main | terraform plan 反对prod |
PR合并为 main | terraform apply 刺激 |
手册 workflow_dispatch | 选择提供商+环境 |
提供程序默认为 azure 由树枝引发的跑步。要部署到其他提供程序,请使用 workflow_dispatch 并选择提供者。
所需的GitHub机密(根据GitHub环境设置 dev / prod)
| 机密 | 由使用 |
|---|---|
DB_PASSWORD | 所有供应商 |
AZURE_CLIENT_ID | 蔚蓝 |
AZURE_TENANT_ID | 蔚蓝 |
AZURE_SUBSCRIPTION_ID | 蔚蓝 |
AWS_ROLE_ARN | aws |
AWS_REGION | aws |
GCP_WORKLOAD_IDENTITY_PROVIDER | GCP |
GCP_SERVICE_ACCOUNT | GCP |
仅为您使用的提供商设置机密。所有供应商使用 OIDC/工作负载标识 --GitHub中没有存储长期有效的凭据。
