返回市场
苍鹰-mcp

苍鹰-mcp

作者:OFFSET32 星标更新:2025-11-15

项目介绍

技术文档摘要

Taiga MCP 服务器

项目概述

  • 实现了一个基于Starlette的模型上下文协议(MCP)服务器,该服务器暴露了用于ChatGPT和其他符合MCP标准客户端的Server-Sent Events(SSE)和可流式传输HTTP传输。
  • 担任ChatGPT与Taiga项目管理API之间的桥梁,当前包括一个用于传输验证的echo工具,并正在进行Taiga特定操作的集成。
  • 部署为容器工作负载到Azure容器应用,并通过GitHub容器注册表(GHCR)打包分发。

配置

  • .env.example复制为.env(或直接导出变量),并填写你的Taiga实例、凭据和部署设置的值。
  • 不要提交.env文件或秘密;项目.gitignore默认排除常见模式。
  • 本地脚本和辅助应用程序读取相同的变量(如TAIGA_BASE_URLTAIGA_USERNAMETAIGA_PASSWORDACTION_PROXY_API_KEYMCP_URLTAIGA_PROXY_BASE_URL等),因此更新环境可以保持整个工具链的一致性。

运行时架构

  • app.py实例化带有Taiga MCP身份的FastMCP,在/sse/挂载SSE,在/mcp/挂载可流式传输HTTP,并禁用尾随斜杠重定向以保留MCP会话头。
  • 自定义中间件将裸/mcp请求重写为/mcp/,并在子应用程序内部规范化空白路径,以避免先前导致MCP会话头丢失的307重定向。
  • FastMCP会话管理器通过Starlette的生命周期钩子启动,确保流式传输会话在长时间运行的ChatGPT对话中保持活跃。
  • 健康检查:
    • GET / → 简单文本“Taiga MCP up”,用于快速可用性探测。
    • GET /healthz → 最小健康端点,供容器编排器使用。

端点总结

  • / — 根状态页面。
  • /healthz — 由Azure容器应用使用的存活探测。
  • /sse/ — Server-Sent Events传输;需要Accept: text/event-stream,并在第一个事件有效载荷中返回消息发布端点。
  • /sse/sse/messages/ — SSE消息提交的目标(在SSE endpoint事件中返回)。
  • /mcp/ — 可流式传输HTTP传输;客户端必须发送Accept: application/json, text/event-stream以满足协议协商。

MCP工具

  • echo(message) — 诊断助手,返回提供的消息。
  • taiga.projects.list(search?) — 列出服务账户成员的项目(可选大小写不敏感的子字符串搜索,范围限定于认证用户ID)。
  • taiga.projects.get(project_id?, slug?) — 通过数字标识符或slug获取项目记录(两个输入中的一个必须提供)。
  • taiga.epics.list(project_id) — 列出项目的史诗,包括id/ref/subject/status元数据。
  • taiga.stories.list(project_id, search?, epic_id?, tags?, page?, page_size?) — 列出项目的用户故事,可选过滤器包括文本搜索、史诗成员资格、标签和分页。
  • taiga.stories.create(project_id, subject, description?, status?, tags?, assigned_to?) — 创建Taiga用户故事;status接受id或状态名称/别名。
  • taiga.stories.update(user_story_id, subject?, description?, status?, tags?, assigned_to?, epic_id?, milestone_id?, custom_attributes?, version?) — 使用乐观并发检查和服务器端状态解析更新现有故事。
  • taiga.epics.add_user_story(epic_id, user_story_id) — 将用户故事链接到史诗。
  • taiga.tasks.create(user_story_id, subject, description?, assigned_to?, status?, tags?, due_date?, idempotency_key?) — 在故事下创建Taiga任务,应用状态查找和幂等保护。
  • taiga.tasks.update(task_id, subject?, description?, assigned_to?, status?, tags?, due_date?, version?) — 使用与故事相同的乐观并发处理更新任务。
  • taiga.tasks.list(project_id?, user_story_id?, assigned_to?, search?, status?, page?, page_size?) — 列出任务,具有灵活的过滤器和分页元数据,当提供project_id时解析状态名称。
  • taiga.users.list(project_id?, search?) — 根据项目成员资格查找Taiga用户,可选子字符串匹配全名、用户名或电子邮件。
  • taiga.milestones.list(project_id, search?) — 返回项目的里程碑/冲刺,允许可选的名称/别名过滤。

动作代理表面

  • 目的:为Taiga自动化提供轻量级HTTP桥接,同时MCP写入工具保持白名单。
  • 认证:每个请求提供X-Api-Key;值必须与ACTION_PROXY_API_KEY环境变量匹配(缺少/无效的键返回401,未配置的键返回503)。
  • 端点:
    • GET /actions/list_projects?search=foo{ "projects": [...] },可选大小写不敏感的名称过滤器(自动设置member=<service-account-id>,除非覆盖member查询参数)。
    • GET /actions/get_project?project_id=123{ "project": {...} },返回给定ID的完整Taiga项目负载。
    • GET /actions/get_project_by_slug?slug=acme-backlog{ "project": {...} },通过slug解析项目。
    • GET /actions/list_epics?project_id=111&project_id=222{ "epics": [...] },包含每个史诗的原始project_id
    • GET /actions/list_stories?project_id=123&epic_id=456&search=prior+art&tag=ip{ "stories": [...] },按项目、史诗、关键词、标签和可选分页(page/page_size)过滤。
    • GET /actions/statuses?project_id=123{ "statuses": [...] },驱动状态选择器。
    • POST /actions/create_story{ "story": {...} };接受与MCP工具相同的负载,并解析状态别名/名称。
    • POST /actions/update_story{ "story": {...} };接受story_id加上任何组合的project_idsubjectdescriptionstatustagsassigned_to(状态字符串自动解析为id)。
    • POST /actions/delete_story{ "deleted": {"story_id": ...} }
    • POST /actions/add_story_to_epic{ "link": {...} },在链接故事到史诗后。
    • POST /actions/create_epic / update_epic / delete_epic → 管理史诗(project_idsubject、可选descriptionstatusassigned_totagscolor)。
    • POST /actions/create_task / update_task / delete_task → 管理任务(project_idsubject、可选descriptionstatusassigned_totagsuser_story_id)。
    • POST /actions/create_issue / update_issue / delete_issue → 管理问题(project_idsubject、可选descriptionstatuspriorityseveritytypeassigned_totags)。
  • 错误模型:JSON { "error": "..." }负载,4xx用于验证/Taiga错误,500用于意外失败(也记录在服务器端)。
  • 辅助脚本(需要设置ACTION_PROXY_API_KEYTAIGA_PROXY_BASE_URL):
    • \.\.chat-venv\Scripts\python.exe scripts/actions_proxy_client.py --pretty list-projects
    • \.\.chat-venv\Scripts\python.exe scripts/actions_proxy_client.py get-project --project-id <ID>
    • \.\.chat-venv\Scripts\python.exe scripts/actions_proxy_client.py get-project-by-slug --slug <slug>
    • powershell.exe -File scripts/actions-proxy.ps1 list-projects
  • 原始curl示例:
    • curl.exe -H "X-Api-Key: $env:ACTION_PROXY_API_KEY" "$env:TAIGA_PROXY_BASE_URL/actions/list_projects?search=beta"
    • curl.exe -H "X-Api-Key: $env:ACTION_PROXY_API_KEY" -H "Content-Type: application/json" -d "{\"project_id\":123,\"subject\":\"Story\"}" "$env:TAIGA_PROXY_BASE_URL/actions/create_story"

本地开发工作流程

  • 前提条件
    • Python 3.11(项目默认使用.chat-venv虚拟环境)。
    • Docker Desktop用于容器构建。
    • Azure CLI用于部署自动化。
    • GHCR认证(docker login ghcr.io)。
  • 安装依赖项
    • python -m venv .chat-venv
    • .\.chat-venv\Scripts\python.exe -m pip install -r requirements.txt
  • 配置环境
    • copy .env.example .env(PowerShell: Copy-Item .env.example .env),并更新值指向你的Taiga实例。
  • 本地运行服务器
    • .\.chat-venv\Scripts\uvicorn.exe app:app --host 127.0.0.1 --port 8010
    • 流式传输探测:.\.chat-venv\Scripts\python.exe streamable_client.py http://127.0.0.1:8010/mcp --message "hello local"
  • 手动测试SSE
    • curl.exe -sN -H "Accept: text/event-stream" http://127.0.0.1:8010/sse/

容器构建与发布

  • 选择镜像名称(默认部署使用ghcr.io/johnwblack/taiga-mcp),并设置:
    • PowerShell: $env:CONTAINER_IMAGE = 'ghcr.io/johnwblack/taiga-mcp'$env:IMAGE_TAG = 'v0.0.29'
    • Bash: export CONTAINER_IMAGE=ghcr.io/johnwblack/taiga-mcpexport IMAGE_TAG=v0.0.29
  • 构建标记的镜像(交叉构建时设置--platform):
    • docker build -t "$CONTAINER_IMAGE:$IMAGE_TAG" -t "$CONTAINER_IMAGE:latest" .
  • 推送到你的注册表:
    • docker push "$CONTAINER_IMAGE:$IMAGE_TAG"
    • docker push "$CONTAINER_IMAGE:latest"

Azure容器应用部署

  • 导出以下环境变量(更新名称以匹配你的订阅):
    • $env:AZURE_RESOURCE_GROUP = 'your-resource-group'
    • $env:AZURE_CONTAINER_APP = 'taiga-mcp'
  • 部署新版本(推送镜像后):
    • az containerapp update -g $env:AZURE_RESOURCE_GROUP -n $env:AZURE_CONTAINER_APP --image "$CONTAINER_IMAGE:$IMAGE_TAG"
  • 或运行辅助脚本(构建、推送和部署一步完成;尊重相同的环境变量并接受覆盖):
    • python scripts/deploy_to_azure.py --image "$env:CONTAINER_IMAGE" --tag "$env:IMAGE_TAG" --resource-group "$env:AZURE_RESOURCE_GROUP" --container-app "$env:AZURE_CONTAINER_APP"
    • 可选标志:--skip-build--skip-push--latest-tag帮助热修复重新部署
  • 有用的Windows设置(避免WinError 5权限问题):
    • $env:AZURE_EXTENSION_DIR = Join-Path $HOME '.az-extensions'
    • $env:AZURE_CONFIG_DIR = Join-Path $HOME '.az-cli'

Taiga凭证的秘密管理

  • 将Taiga凭证和代理密钥存储在你选择的秘密存储中(例如Azure容器应用秘密、Kubernetes秘密等),并在容器内作为环境变量呈现。
  • 示例(Azure容器应用):
    • az containerapp secret set --resource-group $env:AZURE_RESOURCE_GROUP --name $env:AZURE_CONTAINER_APP --secrets taiga-username="<USERNAME>" taiga-password="<PASSWORD>"
    • az containerapp update --resource-group $env:AZURE_RESOURCE_GROUP --name $env:AZURE_CONTAINER_APP --set-env-vars TAIGA_USERNAME=secretref:taiga-username TAIGA_PASSWORD=secretref:taiga-password
  • 以相同方式更新或轮换动作代理密钥:
    • az containerapp secret set --resource-group $env:AZURE_RESOURCE_GROUP --name $env:AZURE_CONTAINER_APP --secrets action-proxy-api-key="<RANDOM_TOKEN>"
    • az containerapp update --resource-group $env:AZURE_RESOURCE_GROUP --name $env:AZURE_CONTAINER_APP --set-env-vars ACTION_PROXY_API_KEY=secretref:action-proxy-api-key
  • 容器期望以下环境变量存在:
    • TAIGA_BASE_URL — Taiga API的基本URL(通常由秘密引用支持)。
    • TAIGA_USERNAME — 服务账户用户名。
    • TAIGA_PASSWORD — 服务账户密码。
    • ACTION_PROXY_API_KEY/actions/*端点使用的共享秘密。
  • 定期轮换凭证并重新部署,以便新版本能够获取更改。

连接MCP客户端

  • 你应部署并托管自己的MCP服务器实例(例如在Azure容器应用、Docker Desktop或其他Python托管目标上)。此仓库不公开共享公共端点。
  • ChatGPT自定义GPT设置:
    • 打开GPT Builder UI,选择创建,然后在模型上下文协议工具部分下选择配置添加
    • 输入已部署的可流式传输HTTP URL(例如https://your-domain.example/mcp)作为端点,并在没有代理的情况下留空头部/正文。
    • 保存GPT并测试echo工具以确认连接。会话将在每次调用时重复使用你的部署服务器。
  • 开源MCP客户端(如mcp Python CLI或Claude Desktop)可以针对相同的/mcp端点;在运行辅助脚本如streamable_client.py之前,将MCP_URL设置为你的部署URL。
  • 如果重新生成容器镜像,现有的环境变量和秘密引用仍附加到容器应用。只有在引入新的键/变量或凭证轮换时才需再次设置它们。

验证检查清单

  • 可流式传输HTTP烟雾测试:
    • \.\.chat-venv\Scripts\python.exe streamable_client.py $env:MCP_URL --message "ping"
  • SSE可用性测试:
    • curl.exe -sN -H "Accept: text/event-stream" "$env:TAIGA_PROXY_BASE_URL/sse/" --max-time 5
  • Azure日志审查(如果部署到ACA):
    • az containerapp logs show -g $env:AZURE_RESOURCE_GROUP -n $env:AZURE_CONTAINER_APP --tail 50
  • ChatGPT连接器验证:
    • 使用你的部署MCP端点配置ChatGPT或其他MCP客户端,并确认echo工具响应。
    • 端到端地练习项目、史诗和故事的工作流程,以确保Taiga凭证和权限正确。

故障排除说明

  • Not Acceptable: Client must accept text/event-stream — 确保客户端在调用/mcp/时发送Accept: application/json, text/event-stream
  • Session terminated错误通常表示重定向;验证请求命中/mcp/(带尾随斜杠),并且代理没有重写头部。
  • 解决Azure CLI WinError 5权限问题的方法是将AZURE_EXTENSION_DIRAZURE_CONFIG_DIR设置为用户可写的目录。
  • 更新秘密后,Azure容器应用会重启修订版;在重新测试端点前,请等待1-2分钟。

测试

  • 安装开发依赖项:python -m pip install -r requirements.txt pytest(从.chat-venv环境)。
  • 运行Python单元套件:pytest(涵盖/actions/*认证、验证和通过假数据的Taiga错误处理)。
  • 对本地辅助CLI进行烟雾测试:.\.chat-venv\Scripts\python.exe scripts/actions_proxy_client.py --help
  • PowerShell验证:powershell.exe -File scripts/actions-proxy.ps1 list-projects -BaseUrl http://127.0.0.1:8010 -ApiKey local-test,当服务器使用临时密钥运行时。

请求有效负载参考

用户故事

  • 创建(POST /actions/create_story):{ "project_id": int, "subject": str, "description"?: str, "status"?: int|str, "tags"?: [str], "assigned_to"?: int }
  • 更新(POST /actions/update_story):{ "story_id": int, "project_id"?: int, "subject"?: str, "description"?: str, "status"?: int|str, "tags"?: [str], "assigned_to"?: int }
  • 删除(POST /actions/delete_story):{ "story_id": int }

史诗

  • 创建(POST /actions/create_epic):{ "project_id": int, "subject": str, "description"?: str, "status"?: int, "assigned_to"?: int, "tags"?: [str], "color"?: str }
  • 更新(POST /actions/update_epic):`{ "epic_id": int, "subject"?: str, "description"?: str,