基于 MCP 协议构建私有研发智能体:将内部 API 与 CI/CD 全面 Agent 化


本文深入剖析基于 MCP(Model Context Protocol)协议构建私有研发智能体的实战方案。通过 Java/Spring Boot 将 GitLab、Jenkins、K8s 封装为标准 MCP Tool 与 Resource,配合 Human-in-the-loop 人机确认机制,实现安全可靠的 CI/CD 自动化与排错闭环。

基于 MCP 协议构建私有研发智能体:将内部 API 与 CI/CD 全面 Agent 化

在日常研发协同中,工程师经常在各种异构平台间疲于奔命:切到 GitLab 提 MR、登录 Jenkins 查看流水线构建失败原因、再开终端敲 kubectl logs 排查 CrashLoopBackOff。虽然大模型拥有强大的代码理解与推理能力,但传统以单一 Function Calling 为核心的二次开发方案存在协议不通用、上下文状态共享脆弱、缺乏统一鉴权与生命周期管理等严重缺陷。

随着 Anthropic 主导开源的 MCP(Model Context Protocol,模型上下文协议) 迅速成为事实标准,研发基础设施的 Agent 化迎来了架构统一的最佳契机。本文将以大厂生产落地的视角,带大家基于 Java / Spring Boot 生态,将 GitLab、Jenkins、K8s 封装为标准化 MCP 架构,并攻克高危发布场景下的 Human-in-the-loop(人机交互确认) 安全难题。


一、问题背景与业务痛点

在尝试让 LLM 接管日常研发与运维流程时,多数团队初期会采用“大模型 + 自建 OpenAPI Plugin”的简易方案,但在复杂企业环境中很快会遭遇以下痛点:

  1. 协议孤岛与上下文割裂:每个研发系统(GitLab、Jira、Jenkins、ArgoCD)的 API 返回结构迥异。LLM 单纯靠多次调用 Tool,不仅消耗大量 Token,还极易丢失上下文;同时,缺乏如“实时查看日志流”这种针对动态资源(Resource)的标准订阅通道。
  2. 缺乏统一协议,客户端难以复用:自建的 Function Calling 往往深度绑定特定的 Agent 框架。一旦开发者想在 Claude Desktop、Cursor、VS Code 或内部自研聊天机器人中接入这些运维能力,必须重写大量适配层。
  3. 高危写操作引发的“灾难性幻觉”:运维操作与代码分析不同,触发流水线、重启 Pod、打 Tag、合并主干均具有不可逆的外部副作用。如果缺乏框架级的安全拦截与二次确认机制,模型的任何一次意图漂移都可能导致生产事故。

MCP 的出现完美解耦了这一架构:它将外部能力抽象为 Resources(静态/动态上下文)、Tools(可执行函数) 以及 Prompts(提示词模版),基于 JSON-RPC 2.0 规范,让私有内部服务能够一处编写、处处挂载。


二、


▲ 权威参考图:Modern Agentic Architecture & RAG Retrieval Flow (已转存博客园图床)

核心设计与解决思路

为了实现高内聚、低耦合且安全可控的 DevOps Agent,我们基于 Spring Boot 构建统一的 Private DevOps MCP Server。

1. 核心架构设计与组件拓扑图

MCP 架构的核心是明确三层职责:Host(宿主) 负责大模型驱动与 UI 渲染,Client(客户端) 负责路由与连接,Server(服务端) 负责业务封装与资源隔离。

flowchart TD
 subgraph Agent Host & Client Layer [智能体宿主与交互层]
 Host[研发交互终端 IDE / ChatBot / Cursor]
 LLM[大语言模型 (DeepSeek / Claude / Qwen)]
 MCPClient[MCP Client (路由、协议解析、连接池)]
 Host <--> LLM
 Host <--> MCPClient
 end

 subgraph Security Layer [安全与审批层]
 HITL[Human-in-the-loop 拦截网关]
 Approver[企业微信 / 钉钉审批端]
 HITL -.->|高危操作推审| Approver
 end

 subgraph Private DevOps MCP Server [私有 DevOps MCP 服务端 (Spring Boot 3.x)]
 Dispatcher[JSON-RPC 2.0 调度器 (Stdio / SSE)]
 subgraph MCP Primitives
 Tools[MCP Tools<br/>- trigger_jenkins_build<br/>- restart_k8s_deployment]
 Resources[MCP Resources<br/>- k8s://logs/{podName}<br/>- gitlab://diff/{mrId}]
 Prompts[MCP Prompts<br/>- triage-ci-failure<br/>- review-k8s-event]
 end
 Dispatcher --> Tools
 Dispatcher --> Resources
 Dispatcher --> Prompts
 end

 subgraph Internal Infra [企业基础设施]
 GitLab[(GitLab API)]
 Jenkins[(Jenkins Master)]
 K8s[(Kubernetes Cluster)]
 end

 MCPClient <==>|JSON-RPC via SSE/HTTP| Dispatcher
 Tools --> HITL
 HITL --> Jenkins
 HITL --> K8s
 Resources --> GitLab
 Resources --> K8s

2. 端到端请求执行时序图(含 Human-in-the-loop 审批)

当研发人员发出“排查构建失败并重新发布到预发环境”的意向时,系统通过 MCP 资源拉取日志,分析后若涉及写操作,自动触发中断挂起与人工确认:


▲ 时序图 2:端到端请求处理与调用时序链路

3. 技术方案选型对比

评估维度 传统自建 OpenAPI + Function Calling LangChain / Agent Framework 专用 Tool 基于 MCP 标准协议 (本文方案)
生态通用性 极低,仅私有系统可用 中等,强绑定 Python / TS 运行时环境 极高,天然支持 Cursor、Claude、各类 IDE 与 CLI
模型上下文管理 纯靠字符串拼接,无标准协议约束 依赖 Framework 内置 Memory,多系统难共享 协议级支持 Resources 与 Prompts,结构化下发
传输协议支持 仅标准 HTTP Restful 框架进程内部调用,跨语言成本高 双模支持:本地 Stdio 管道 / 远程 SSE (Server-Sent Events)
运维控制粒度 依赖业务代码写死安全控制 难以跨进程解耦中断审核流 标准拦截点:在 RPC 协议层原生实现鉴权与 HITL

三、完整实战代码与配置

环境说明:JDK 21、Spring Boot 3.3.4、Spring AI 1.0.0-M3(包含 MCP 官方规范适配体系)或使用标准 JSON-RPC 2.0 规范接入。此处给出基于真实企业环境的 MCP DevOps Server 核心实现代码。

1. 核心依赖配置与引导配置

<!-- pom.xml 片段 -->
<dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-webflux</artifactId>
 </dependency>
 <!-- 引入标准 JSON-RPC 支持与 Kubernetes Client -->
 <dependency>
 <groupId>io.fabric8</groupId>
 <artifactId>kubernetes-client</artifactId>
 <version>6.13.1</version>
 </dependency>
 <dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <scope>provided</scope>
 </dependency>
</dependencies>
# bootstrap.yml
server:
 port: 8088

mcp:
 server:
 name: "corp-devops-agent-server"
 version: "1.0.0"
 security:
 hitl:
 webhook-url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-token"
 require-approval-tools:
 - "restart_k8s_deployment"
 - "trigger_jenkins_build"

gitlab:
 api-url: "https://gitlab.internal.corp/api/v4"
 token: "${GITLAB_PRIVATE_TOKEN}"

2. MCP 协议基础模型与注解声明

// McpSchema.java - 抽象核心 MCP 交互协议规范
package com.corp.mcp.protocol;

import java.lang.annotation.*;
import java.util.Map;

public class McpSchema {

 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface McpTool {
 String name();
 String description();
 boolean requiresApproval() default false;
 }

 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface McpResource {
 String uriTemplate();
 String mimeType() default "text/plain";
 String description();
 }

 public record ToolCallRequest(String name, Map<String, Object> arguments) {}
 public record ToolCallResult(String content, boolean isPendingApproval, String taskId) {}
 public record ResourceResponse(String uri, String mimeType, String text) {}
}

3. DevOps MCP Server 资源与工具实现

// DevOpsMcpTools.java - 将 Jenkins、K8s 注册为标准 MCP 能力
package com.corp.mcp.server;

import com.corp.mcp.protocol.McpSchema.*;
import com.corp.mcp.security.HitlApprovalService;
import io.fabric8.kubernetes.client.KubernetesClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;

@Slf4j
@Component
@RequiredArgsConstructor
public class DevOpsMcpTools {

 private final KubernetesClient k8sClient;
 private final HitlApprovalService hitlService;

 /**
 * 声明 MCP Resource:通过 URI 读取实时 Pod 日志
 * 客户端可直接读取:k8s://logs/{namespace}/{podName}
 */
 @McpResource(
 uriTemplate = "k8s://logs/{namespace}/{podName}",
 mimeType = "text/plain",
 description = "实时获取 Kubernetes 指定集群命名空间内 Pod 的最后 100 行日志"
 )
 public ResourceResponse getPodLogs(String namespace, String podName) {
 log.info("MCP Resource 读取日志: {}/{}", namespace, podName);
 String logData = k8sClient.pods()
 .inNamespace(namespace)
 .withName(podName)
 .tailingLines(100)
 .getLog();
 return new ResourceResponse("k8s://logs/" + namespace + "/" + podName, "text/plain", logData);
 }

 /**
 * 声明 MCP Tool:重启 K8s 服务(定义为敏感写操作,接入审批流程)
 */
 @McpTool(
 name = "restart_k8s_deployment",
 description = "对指定的 Kubernetes Deployment 触发滚动重启",
 requiresApproval = true
 )
 public ToolCallResult restartDeployment(Map<String, Object> params) {
 String namespace = (String) params.get("namespace");
 String deploymentName = (String) params.get("deploymentName");
 String operator = (String) params.getOrDefault("operator", "agent-system");

 // 触发 HITL 审批挂起机制
 String taskId = hitlService.submitApprovalTask("K8S_ROLLOUT_RESTART", 
 "请求重启 Deployment: " + namespace + "/" + deploymentName, operator, () -> {
 k8sClient.apps().deployments()
 .inNamespace(namespace)
 .withName(deploymentName)
 .rolling()
 .restart();
 log.info("Approval Passed: Restart executed for {}/{}", namespace, deploymentName);
 });

 return new ToolCallResult("操作属于高危指令,已进入人机审核队列。任务ID: " + taskId, true, taskId);
 }

 /**
 * 声明 MCP Tool:触发 Jenkins 构建
 */
 @McpTool(
 name = "trigger_jenkins_build",
 description = "触发特定工程的分支流水线构建",
 requiresApproval = false
 )
 public ToolCallResult triggerBuild(Map<String, Object> params) {
 String jobName = (String) params.get("jobName");
 String branch = (String) params.get("branch");
 log.info("执行 Jenkins 构建: job={}, branch={}", jobName, branch);

 // 此处省略 Jenkins Rest API 客户端调用
 return new ToolCallResult("Build triggered successfully on branch: " + branch, false, null);
 }
}

4. Human-in-the-loop (HITL) 审批协调器

// HitlApprovalService.java - 处理安全挂起与异步回调通知
package com.corp.mcp.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class HitlApprovalService {

 private final Map<String, PendingTask> taskRegistry = new ConcurrentHashMap<>();

 public record PendingTask(String taskId, String actionType, String detail, String operator, Runnable callback) {}

 public String submitApprovalTask(String actionType, String detail, String operator, Runnable callback) {
 String taskId = UUID.randomUUID().toString().substring(0, 8);
 taskRegistry.put(taskId, new PendingTask(taskId, actionType, detail, operator, callback));

 // 模拟企业微信 Webhook 通知
 pushNotificationToApprover(taskId, actionType, detail, operator);
 return taskId;
 }

 public boolean approveAndExecute(String taskId) {
 PendingTask task = taskRegistry.remove(taskId);
 if (task == null) {
 log.warn("审批任务不存在或已失效: {}", taskId);
 return false;
 }
 try {
 task.callback().run();
 log.info("任务 [{}] 审批通过,已回调成功执行!", taskId);
 return true;
 } catch (Exception e) {
 log.error("执行批准任务失败: {}", e.getMessage(), e);
 return false;
 }
 }

 private void pushNotificationToApprover(String taskId, String actionType, String detail, String operator) {
 log.warn(">>>> [HITL 预警] 操作需人工确认: TaskID=[{}], Action=[{}], 详情=[{}], 发起人=[{}]", 
 taskId, actionType, detail, operator);
 // 生产对接企业微信 API 发送带「批准」「拒绝」按钮的卡片
 }
}

四、避坑指南与总结验证

在生产落地与大模型压测过程中,将运维系统 Agent 化会暴露多个极具隐蔽性的工程挑战,以下是核心避坑经验:

1. 核心踩坑与解决方案

  • 避坑 1:日志资源拉取导致“上下文膨胀”与 Token 瞬时打爆
    • 问题场景:运维排查让 Agent 读取日志,K8s 默认返回上千行堆栈,直接耗尽上下文窗口甚至引发模型拒绝响应。
    • 解法:在 MCP Resource 内部做智能分块(Chunking)与特征修剪(Pruning)。在服务端预过滤掉健康检查(如 /actuator/health 200 OK 日志),并仅截取异常抛错点(Exception/Error/Fatal)向上 30 行、向下 50 行的上下文返回,严禁原样抛出原始流。
  • 避坑 2:SSE(Server-Sent Events)长连接被内网网关强行超时重置
    • 问题场景:远程 MCP 客户端使用 SSE 协议连接内部 MCP Server,Nginx 或 ALB 默认配置了 60 秒无数据自动断开,导致 Agent 长对话中途出现断连。
    • 解法:服务端必须实现规范的心跳 ping 机制(每 15 秒推送一次空注释包 :keepalive\n\n);同时配置 Nginx 禁用代理缓冲(proxy_buffering off;)与读写超时时间(proxy_read_timeout 3600s;)。
  • 避坑 3:Tool 参数注入漏洞与越权操作(Prompt Injection)
    • 问题场景:恶意 PR 或攻击者通过 Issue 标题注入恶意 Prompt,诱导 LLM 构造出如 deploymentName: "order-service; rm -rf /" 等异常参数。
    • 解法:MCP Server 层坚决不直接通过 Shell/Bash 执行拼接字符串。全面采用强类型的 SDK(如 Fabric8 Kubernetes Client、GitLab4J),参数严格走正则白名单校验(如 ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$)。

2. 成果与验证步骤

  1. 协议发现验证:启动 MCP 服务,通过客户端发送 JSON-RPC 探活请求:
    bash curl -X POST http://localhost:8088/mcp/v1/rpc \ -H "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'
    检查是否成功输出 trigger_jenkins_build、restart_k8s_deployment 及其 JSON Schema。
  2. 端到端发布阻断测试:
    在 Chat 终端输入:“帮我重启订单服务”。
  3. 观察控制台,MCP Server 立即截获该操作,返回状态 Pending Approval,并打印出审批 Task ID;
  4. 模拟运维人员调用审批接口后,K8s 集群才真正触发滚动重启。

总结

通过引入 MCP 协议,我们成功抹平了研发运维体系中由于异构 API 导致的割裂现状。LLM 不再是一个空洞的代码生成器,而是升级为具备私有上下文洞察力、拥有标准化执行抓手、且始终处于安全护栏限制下的高可靠研发副驾(Copilot)。这种标准化的 Agentic DevOps 架构,将是企业研发平台演进的确定性方向。

文章摘自:https://www.cnblogs.com/995i996/p/23219145