协作连接器示例
 ](https://github.com/callibrity/cowork-connector-example/pkgs/container/cowork-connector-example)
      
Claude Cowork连接器采用Spring Boot 4和 莫卡皮它通过MCP协议公开了一个虚构的服务目录,因此Cowork中的LLM可以回答每个企业工程组织都难以回答的问题:
- 谁拥有这项服务? 如果它坏了怎么办?
- 哪些服务涉及PII/PCI? 他们中有孤儿吗?
- 我们的迁移积压是什么? 哪些已弃用的服务仍在被调用,由谁调用?
- 如果我们缩减这个团队,我们会有什么麻烦?
演示船上有一个以中型虚构公司(“Meridian”)为蓝本的种子36服务/8团队目录。数据故意混乱——功能失调才是关键。
认识Meridian
Meridian是一个中型虚拟电子商务平台。八个工程团队;八个业务领域的三十六项服务;生产依赖性约为86倍。目录是围绕每个真正的服务目录所具有的模式而精心设计的——弃用的仍在使用的服务、合规范围的孤儿、命名漂移集群、仍承载流量的退役服务——因此工具编排的答案保持具体而非学术性。
八支队伍
- 平台 --基础服务(身份验证、功能标志、Kafka网关、日志聚合器、秘密管理器)。
- 身份 --帐户、SSO代理、会话存储、密码重置。
- 结账 --购物车、付款、订单协调、税务计算、结账界面。
- 目录 --产品、搜索索引器、库存、目录管理。
- 履行 --发货、标签生成、退货、承运商集成。
- 数据 --分析引擎、事件总线、报告(复数)、ETL编排器。
- 通知 --电子邮件、推送、短信调度员、模板渲染器。
- 集成 --合作伙伴网关、webhook中继。
故意造成功能障碍
种子数据是围绕每个企业工程组织都有的五种特定模式形成的——这些模式使演示答案产生共鸣:
- 已弃用的用例。
reporting-legacy已标记DEPRECATED但仍被称为payment-processor(对于税务汇总端点),analytics-ingester和孤儿legacy-invoicing每个组织都有这个——没有人迁移的服务,因为它仍然有效。显示在deprecated-in-use结果和inpayment-processor的直接依赖关系。
- 孤儿符合范围。
legacy-invoicing有 无主 --根据种子描述,“所有者于2023年离开;团队从未被重新分配”,并被标记为pci和soc2-scope。它仍然被图中的其他服务调用。这是每个人的合规噩梦orphaned-services查询应该浮出水面。
- 命名漂移集群。 数据团队拥有
reports-v2,reports-v2-new,以及reporting-legacy“当前”一词含糊不清reports-v2(使用人catalog-admin)虽然reports-v2-new是“替代品,但在第三季度暂停了推出”,以及reporting-legacy已弃用,但仍被调用。经典的每家店都有三个版本集群。
- 退役服务仍在图表中。
webhook-relay是RETIRING但仍向kafka-gateway说明退休计划和实际交通并不总是一致的。
- 基础爆炸半径。
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 | 带域、标签和生命周期阶段过滤器的分页列表 |
teams-list | PageDto | 带有服务计数的分页团队列表 |
service-dependencies | List | 出境deps(直接或传递) |
service-dependents | List | 呼入呼叫者(直接或传递) |
blast-radius | BlastRadiusDto | 按所属团队分组的受暂时影响的服务——“如果发生这种情况,谁会被呼叫” |
orphaned-services | PageDto | 无所有者的服务 |
deprecated-in-use | PageDto | 弃用的服务仍被某些东西调用 |
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/@ToolMethodbean发现、流式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用于分页工具返回 - 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另一个,加上aDependencyType(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 8080ngrok打印一个 https://.ngrok-free.app URL。点合作 https://.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每一次推送和公关mainTheci配置文件激活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构建本地映像,并将其作为两者发布到GHCRghcr.io//: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 自动签名。
