协作连接器示例

一个基于Spring Boot 4和Mocapi的Claude Cowork连接器,用于通过MCP协议暴露虚构的服务目录,帮助LLM回答企业工程组织常见问题。

  • by callibrity
  • Java
  • 本地部署
  • 更新于
在 GitHub 查看 callibrity/cowork-connector-example

使用说明

协作连接器示例

Claude Cowork连接器采用Spring Boot 4和 莫卡皮它通过MCP协议公开了一个虚构的服务目录,因此Cowork中的LLM可以回答每个企业工程组织都难以回答的问题:

  • 谁拥有这项服务? 如果它坏了怎么办?
  • 哪些服务涉及PII/PCI? 他们中有孤儿吗?
  • 我们的迁移积压是什么? 哪些已弃用的服务仍在被调用,由谁调用?
  • 如果我们缩减这个团队,我们会有什么麻烦?

演示船上有一个以中型虚构公司(“Meridian”)为蓝本的种子36服务/8团队目录。数据故意混乱——功能失调才是关键。

认识Meridian

Meridian是一个中型虚拟电子商务平台。八个工程团队;八个业务领域的三十六项服务;生产依赖性约为86倍。目录是围绕每个真正的服务目录所具有的模式而精心设计的——弃用的仍在使用的服务、合规范围的孤儿、命名漂移集群、仍承载流量的退役服务——因此工具编排的答案保持具体而非学术性。

八支队伍

  • 平台 --基础服务(身份验证、功能标志、Kafka网关、日志聚合器、秘密管理器)。
  • 身份 --帐户、SSO代理、会话存储、密码重置。
  • 结账 --购物车、付款、订单协调、税务计算、结账界面。
  • 目录 --产品、搜索索引器、库存、目录管理。
  • 履行 --发货、标签生成、退货、承运商集成。
  • 数据 --分析引擎、事件总线、报告(复数)、ETL编排器。
  • 通知 --电子邮件、推送、短信调度员、模板渲染器。
  • 集成 --合作伙伴网关、webhook中继。

故意造成功能障碍

种子数据是围绕每个企业工程组织都有的五种特定模式形成的——这些模式使演示答案产生共鸣:

  1. 已弃用的用例。 reporting-legacy 已标记 DEPRECATED 但仍被称为 payment-processor (对于税务汇总端点), analytics-ingester和孤儿 legacy-invoicing每个组织都有这个——没有人迁移的服务,因为它仍然有效。显示在 deprecated-in-use 结果和in payment-processor的直接依赖关系。

  2. 孤儿符合范围。 legacy-invoicing 有 无主 --根据种子描述,“所有者于2023年离开;团队从未被重新分配”,并被标记为 pci 和 soc2-scope。它仍然被图中的其他服务调用。这是每个人的合规噩梦 orphaned-services 查询应该浮出水面。

  3. 命名漂移集群。 数据团队拥有 reports-v2, reports-v2-new,以及 reporting-legacy“当前”一词含糊不清 reports-v2 (使用人 catalog-admin)虽然 reports-v2-new 是“替代品,但在第三季度暂停了推出”,以及 reporting-legacy 已弃用,但仍被调用。经典的每家店都有三个版本集群。

  4. 退役服务仍在图表中。 webhook-relay 是 RETIRING 但仍向 kafka-gateway说明退休计划和实际交通并不总是一致的。

  5. 基础爆炸半径。 auth-service 有 6个团队中17名受暂时影响的家属,加上 legacy-invoicing 孤儿。 kafka-gateway, feature-flags,以及 events-bus 同样具有承重能力。驱动器 blast-radius 查询和“哪些服务值得最强的SLO”对话。

为什么种子看起来像这样

工具界面是通用的——您可以将此连接器指向您的真实CMDB导出、Backstage目录或任何服务清单系统,每个查询仍然有效。Meridian数据之所以存在,是因为一个针对原始、拥有良好、记录完善的服务回答目录查询的演示并不是一个有用的演示。真正的服务目录有一个命名漂移集群、一个合规范围的孤儿、一个没有人迁移的弃用服务。将这些形状压缩成36个服务,可以让LLM进行实质性的推理——答案是具体的,功能障碍是你真正希望从自己的目录中出现的。

你可以问克劳德什么

当问题听起来像是一个真正的员工工程师、工程经理或合规负责人会大声问出来的问题时,演示就处于最佳状态。LLM通过在种子目录上编排多个工具调用来编写答案;因为种子包括真实形状的功能障碍,所以答案保持具体和可操作性,而不是学术性的。

合规性/风险

  • “我们是否有任何没有人拥有的合规范围的服务?” → 表面 legacy-invoicing (PCI+SOC2,已弃用,未指定团队)。
  • “绘制我们的个人身份信息足迹。哪些团队的足迹最多?” → 返回13项服务,主要集中在身份和结账方面。
  • “如果审计员问哪些服务涉及PCI数据,答案是什么?” → 一个包含两个服务的列表,其中一个是无主的已弃用服务,这是有趣的部分。

迁移积压

  • “我们的迁移积压是什么?哪些已弃用的服务仍在使用中,谁需要停止调用它们?” → reporting-legacy 被称为 payment-processor, analytics-ingester,以及 legacy-invoicing; cart-v1 被称为 partner-gateway 和 legacy-invoicing.
  • “我们有 reports-v2, reports-v2-new,以及 reporting-legacy.新服务应该使用哪一个?" → LLM可以推断生命周期状态、调用者计数和命名信号。

事故准备/爆炸半径

  • “如果 auth-service 故障,什么故障,谁被呼叫?" → 17 6个团队的服务受到影响,还有一个没有随叫随到轮换的孤儿。
  • “我们计划30分钟 payment-processor 维护窗口。起草客户通信和内部公告副本。" → 爆炸半径加上受影响的面向客户的特征。
  • “我们最承重的服务是什么——那些失败会让最多团队感到困扰的服务?” → 迭代的 service-dependents 电话; auth-service, kafka-gateway,以及 events-bus 泡沫到顶部。

入职/升级

  • “我刚加入结账团队。我们拥有什么,我们依赖什么,什么依赖我们?” → 一个提示中的全貌——自有服务、出站deps、入站呼叫者、runbook链接。
  • “平台团队的表面积是多少?还有多少其他团队依赖他们?” → 其他七个团队都依赖于至少一个平台服务。

架构/变更影响

  • “映射从购物车到发货通知的端到端流程。” → 传递依赖从 order-coordinator 通过付款、库存、运输和电子邮件调度员。
  • “如果我们想将身份提取到自己的平台中,我们需要什么样的依赖契约?” → 每个身份拥有服务的每个调用者,以及这些身份服务本身所依赖的东西。
  • “为我们找到任何在有人离开时看起来像孤儿的服务。” → 到底是什么 legacy-invoicing的种子描述说发生了。

可生产的

这是一个参考示例,旨在说明如何将MCP连接器组合在一起,而不是可以按原样部署的模板。特别是: 没有身份验证 --the /mcp 端点对任何调用者开放。Claude Cowork的生产MCP服务器应该位于以下服务器之一的后面:

  • OAuth2资源服务器通过以下方式验证您的IdP(Auth0、Microsoft Entra、Okta等)中的JWT spring-boot-starter-oauth2-resource-server.
  • 处理身份验证+TLS终止的反向代理或API网关。
  • 在Cowork和连接器之间实施mTLS的服务网格。

此示例的早期修订版具有工作 spring-boot-starter-oauth2-resource-server 配置;为了保持目录演示焦点清晰,它被删除了。如果您正在为生产环境评估此内容,Mocapi文档和任何最近的Spring Boot 4 OAuth2资源服务器教程都将引导您完成重新连接。

工具

九个只读目录工具加上两个自我改进工具,所有这些工具都返回Mocapi通过自动生成的JSON模式发布的结构化DTO:

工具 退货 目的
service-lookup ServiceDto 完整的服务记录——所有者团队、标签、生命周期、runbook链接
team-lookup TeamDto 团队记录,包括随叫随到轮换、Slack频道、服务计数
services-list PageDto<ServiceSummaryDto> 带域、标签和生命周期阶段过滤器的分页列表
teams-list PageDto<TeamSummaryDto> 带有服务计数的分页团队列表
service-dependencies List<ServiceSummaryDto> 出境deps(直接或传递)
service-dependents List<ServiceSummaryDto> 呼入呼叫者(直接或传递)
blast-radius BlastRadiusDto 按所属团队分组的受暂时影响的服务——“如果发生这种情况,谁会被呼叫”
orphaned-services PageDto<ServiceSummaryDto> 无所有者的服务
deprecated-in-use PageDto<DeprecatedUsageDto> 弃用的服务仍被某些东西调用
submit-feedback FeedbackAckDto 让调用LLM报告与现有工具的摩擦——发出 MCP_FEEDBACK: 测井线
suggest-tool FeedbackAckDto 让调用LLM建议服务器应该添加一个全新的工具——发出 MCP_TOOL_PROPOSAL: 测井线

分页返回 PaginationDto 元数据(totalElementCount, hasNext等),因此LLM知道何时在没有被告知的情况下进一步翻页。

自我完善循环

submit-feedback 和 suggest-tool 是MCP服务器设计闭环的一个实验:LLM是实际用户,使工具表面尴尬的大部分内容只会在对话中出现。这两个工具故意分割信号:

  • submit-feedback 是指与现有工具的摩擦——一个缺失的字段、一个额外的往返、一个模糊的名称、一个尴尬的响应形状。该描述列举了具体的触发因素,并要求 suggestedChange 持有头寸的字段(迫使LLM通过模糊对冲)。
  • suggest-tool 是针对真正的新工具想法——你需要回答本次会议中现有工具没有涵盖的问题。架构要求 existingToolGap 描述你首先尝试了哪些工具的字段(过滤掉“这会不会很好”的猜测)和 frequency 估计数(ONCE_THIS_SESSION / RECURRING_PATTERN / FOUNDATIONAL),因此维护人员可以过滤出真正的承重建议。

这两个工具都明确地告诉LLM:如果你没有达到触发条件,就不要调用工具——沉默是最有用的信号。每个调用都会在INFO级别发出一个结构化的JSON有效负载,并带有一个不同的标记(MCP_FEEDBACK: vs。 MCP_TOOL_PROPOSAL:)因此,下游聚合器可以拆分流并将其路由到不同的决策流:摩擦报告集群为“我们应该更改现有工具吗?”,提案集群为“是否应该添加此工具?”。人类审查由此产生的PR;法学硕士的个人提交是嘈杂的信号,而不是承诺。

建筑

  • 弹簧靴4.0.5 --web服务器、DI、AOT处理
  • Mocapi0.4.1 — @ToolService / @ToolMethod bean发现、流式HTTP MCP传输、从方法签名生成JSON模式。为其拥有的每种类型以及 json-sKema 它用于工具输入验证的元模式。
  • 基材0.7.0 --用于MCP会话持久性的内存原子存储(交换输入 substrate-redis 用于集群部署)
  • 春季数据JPA+H2 --目录持久性。每次启动时,H2表都会在内存中播种;在Postgres中通过更改一个dep进行交换
  • jpa-utils 0.0.12 — BaseEntity (UUID+ @Version),框架无关 PageDto<T> 用于分页工具返回
  • GraalVM本机映像 --该链端到端地运送干净的可达性元数据:Mocapi、Substrate、Odyssey和Ripcurl各自运送自己的元数据 RuntimeHintsRegistrar。此回购包含 零 本地图像特定代码;掉落 spring-boot-starter-data-jpa 或者添加另一个MCP工具不需要触摸提示文件。

数据模型

三个实体,通过UUID主键 jpa-utils' BaseEntity:

  • Service --名称、显示名称、描述、业务域、所有者 Team (可以为null——演示中有一个故意孤立的服务), LifecycleStage (ACTIVE / DEPRECATED / RETIRING)、仓库URL、runbook URL和自由格式的标记集(pii, pci, soc2-scope, customer-facing, foundation, gdpr).
  • Team --名称、显示名称、随叫随到旋转手柄、主Slack频道。
  • Dependency --从一个方向边缘 Service 另一个,加上a DependencyType (CALLS, READS_FROM, PUBLISHES_TO, CONSUMES_FROM).

目录从启动时加载到H2中 CatalogSeeder 并在进程退出时丢弃。DTO在 catalog/dto/ 是线形的——实体永远不会泄露到工具或服务响应中。

演出

在苹果硅上测量;通过Paketo构建包构建的容器。

度量 本机映像 JVM映像 Fat jar
启动(据春季报道) 0.14秒 1.34秒 1.11秒
空闲RSS 约140兆字节 306 MiB 303 MiB
图像内容大小 68 MB 336 MB --

Native的启动速度快约10倍,内存效率高约2倍。在零规模平台(Azure容器应用程序、云运行、Fargate)上,这就是“冷启动难以察觉”和“用户刷新标签”之间的区别

跑步

先决条件

  • JDK 25(Temurin适用于JVM模式;Oracle GraalVM适用于本地本地构建)
  • Docker桌面(用于构建/运行本机容器映像)

JVM模式——最快迭代循环

mvn spring-boot:run

继续运行 http://localhost:8080.健康 /actuator/health,build+git信息位于 /actuator/info,MCP端点位于 /mcp.

本机容器映像——部署什么

mvn -Pnative spring-boot:build-image -DskipTests \
  -Dspring-boot.build-image.imageName=cowork-connector-example:native \
  -Dspring-boot.build-image.env.BP_NATIVE_IMAGE=true \
  -Dspring-boot.build-image.env.BP_JVM_VERSION=25

docker run --rm -p 8080:8080 \
  -e MOCAPI_SESSION_ENCRYPTION_MASTER_KEY=$(openssl rand -base64 32) \
  cowork-connector-example:native

第一个构建需要几分钟的时间(Paketo下载了本地映像构建器);缓存的重建时间约为60-90秒。

通过ngrok将本地服务器暴露给Cowork

协作连接器需要一个公共HTTPS URL-- localhost:8080 无法从克劳德的服务器访问。对于本地演示, 吸烟 将笔记本电脑隧道连接到公共端点:

ngrok http 8080

ngrok打印一个 https://<random>.ngrok-free.app URL。点合作 https://<random>.ngrok-free.app/mcp.

ngrok的免费层检查交通 http://localhost:4040,这对于在演示运行时实时查看MCP握手和工具调用非常有用。每次重新启动ngrok时,都会发出一个新的免费层URL;如果你想在Cowork中保存连接器配置,付费计划会给你一个稳定的子域。

从Cowork连接

在Cowork中配置一个指向您的ngrok URL(或您实际部署的URL)的自定义连接器。此演示中的服务器未经身份验证——请参阅 可生产的 在将任何非演示的Cowork工作区指向它之前。

CI/发布

  • .github/workflows/ci.yml --跑步 mvn -Pci verify sonar:sonar 每一次推送和公关 mainThe ci 配置文件激活JaCoCo,使SonarCloud获得覆盖报告; mvn verify 还通过mycila插件强制执行Spotless格式化(Google Java Format)和Apache 2.0许可证头。跑 mvn spotless:apply license:format 在推动之前,在本地修复违规行为。
  • .github/workflows/release.yml --触发于 GitHub发布创建 (不是简单的标签推送)。通过创建发布 gh release create X.Y.Z --title "X.Y.Z" --notes-file notes.md 通过Paketo buildpack构建本地映像,并将其作为两者发布到GHCR ghcr.io/<owner>/<repo>:X.Y.Z 和 :latest.继续运行 ubuntu-latest (amd64)-适用于Azure容器应用程序和其他amd64主机。在苹果硅上, docker run 将回到Rosetta仿真,它可以工作,但不能反映生产启动数字。
  • .github/dependabot.yml --每周分组的Maven和GitHub操作更新(每个分组的Spring、测试、构建插件)每周一上午。

延伸

目录模型有意紧凑——三个实体(Service, Team, Dependency),四个枚举,九个工具。真正的CMDB有几十个字段(SLO、成本中心、数据分类、合规范围)。添加它们是可添加的:扩展实体,重新公开DTO中的字段,扩展现有工具或添加新工具。原生映像元数据的故事没有改变——Mocapi的每bean AOT处理器涵盖了新的 @ToolMethod 自动签名。