当前位置: 首页 > wzjs >正文

响应式网页制作宁波百度seo点击软件

响应式网页制作,宁波百度seo点击软件,做网站建设赚钱吗,网站域名重要吗前言 首先介绍下MCP是什么? MCP是由开发了 Claude 模型的 Anthropic 公司2024年12月提出并开源的一项开放标准,全称:Model Context Protocol,它是一个开放协议,它使 LLM 应用与外部数据源和工具之间的无缝集成成为可能…

前言

首先介绍下MCP是什么?

MCP是由开发了 Claude 模型的 Anthropic 公司2024年12月提出并开源的一项开放标准,全称:Model Context Protocol,它是一个开放协议,它使 LLM 应用与外部数据源和工具之间的无缝集成成为可能。无论你是构建 AI 驱动的 IDE、改善chat 交互,还是构建自定义的 AI 工作流,MCP 提供了一种标准化的方式,将 LLM 与它们所需的上下文连接起来。

大白话

如果不使用 MCP 是什么样的?

就像自己(LLM大模型)学做菜,首先需要学会如何使用刀、锅、锅铲、炉灶,甚至需要自己生火,每一个步骤都需要从头摸索工具,无法专注烹饪本身。​

使用 MCP

MCP 协议相当于给大模型配了一个服务员(MCP Client),当食客(LLM大模型)需要吃什么菜时,可以直接根据菜单上的菜品告诉服务员(MCP Client),知道菜品后,服务员(MCP Client)根据菜品是哪个菜系找不同菜系的厨师(MCP Server),厨师(MCP Server)接到炒菜的任务就使用冰箱、食材、锅、锅铲等(工具)完成菜品制作任务,并将菜品(结果)精准端给服务员(MCP Client),让大模型无需直接操作工具就能完成复杂任务。

初衷

最近接触到 MCP 协议,我觉得它在未来AI实际应用中潜力巨大,很可能成为行业趋势。不过,我留意到mcp.so网站上,大部分 MCP Server 是用 Python 编写的,用 Java 开发的极为少见。就连 Spring AI,也是在 2025 年 2 月才开始支持并封装 MCP 协议的大部分逻辑。所以,我希望有更多从事 Java 开发的人员能够关注这项技术,将其广泛运用到实际项目里 。

正文

流程图

在这里插入图片描述

环境准备

  • Jenkins(需启用「远程访问API」权限)
  • JDK 17
  • SpringBoot 3.3.6
  • IDEA
  • Maven 3
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId><version>1.0.0-M6</version>
</dependency>
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.0</version>
</dependency>
<dependency><groupId>com.google.inject</groupId><artifactId>guice</artifactId><version>5.1.0</version>
</dependency>
<dependency><groupId>io.github.cdancy</groupId><artifactId>jenkins-rest</artifactId><version>1.0.2</version><exclusions><exclusion><artifactId>guice</artifactId><groupId>com.google.inject</groupId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.36</version><scope>provided</scope></dependency>

核心代码

  • JenkinsMcpServerConfig.java

MCP Server必须的配置类

package com.agua.ai.mcp.server.config;import com.agua.ai.mcp.server.service.JenkinsApiService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class JenkinsMcpServerConfig {@Beanpublic ToolCallbackProvider jenkinsTools(JenkinsApiService jenkinsApiService) {return MethodToolCallbackProvider.builder().toolObjects(jenkinsApiService).build();}
}
  • JenkinsProperties.java

定义Jenkins的配置

package com.agua.ai.mcp.server.properties;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties("jenkins")
public class JenkinsProperties {/*** 服务URI*/private String serverUri;/*** 用户名*/private String username;/*** 密码/token*/private String password;
}
  • JenkinsTemplate.java

对com.cdancy.jenkins(封装了Jenkins Rest API的工具类)已经集成的方法进行再次封装,方便调用

package com.agua.ai.mcp.server.util;import com.cdancy.jenkins.rest.JenkinsClient;
import com.cdancy.jenkins.rest.domain.common.IntegerResponse;
import com.cdancy.jenkins.rest.domain.common.RequestStatus;
import com.cdancy.jenkins.rest.domain.job.BuildInfo;
import com.cdancy.jenkins.rest.domain.job.JobInfo;
import com.cdancy.jenkins.rest.domain.job.JobList;
import com.cdancy.jenkins.rest.domain.job.ProgressiveText;
import com.cdancy.jenkins.rest.features.JobsApi;
import com.agua.ai.mcp.server.properties.JenkinsProperties;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Map;/*** Jenkins 模板类,用于封装 Jenkins API 的调用*/
@Component
public class JenkinsTemplate {private final JenkinsClient jenkinsClient;private JobsApi jobsApi;@Autowiredpublic JenkinsTemplate(JenkinsProperties jenkinsProperties) {this.jenkinsClient = JenkinsClient.builder().endPoint(jenkinsProperties.getServerUri()).credentials(jenkinsProperties.getUsername() + ":" + jenkinsProperties.getPassword()).build();}@PostConstructpublic void init() {this.jobsApi = jenkinsClient.api().jobsApi();}/*** 获取任务列表** @param optionalFolderPath 可选的文件夹路径* @return 任务列表*/public JobList getJobList(String optionalFolderPath) {return jobsApi.jobList(optionalFolderPath);}/*** 获取任务信息** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 任务信息*/public JobInfo getJobInfo(String optionalFolderPath, String jobName) {return jobsApi.jobInfo(optionalFolderPath, jobName);}/*** 使用 XML 文件创建任务** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @param configXML 任务的配置 XML* @return 请求状态*/public RequestStatus createJob(String optionalFolderPath, String jobName, String configXML) {return jobsApi.create(optionalFolderPath, jobName, configXML);}/*** 删除任务** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 请求状态*/public RequestStatus deleteJob(String optionalFolderPath, String jobName) {return jobsApi.delete(optionalFolderPath, jobName);}/*** 启用任务** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 是否成功*/public boolean enableJob(String optionalFolderPath, String jobName) {return jobsApi.enable(optionalFolderPath, jobName);}/*** 禁用任务** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 是否成功*/public boolean disableJob(String optionalFolderPath, String jobName) {return jobsApi.disable(optionalFolderPath, jobName);}/*** 获取任务配置文件内容** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 配置文件内容*/public String getJobConfig(String optionalFolderPath, String jobName) {return jobsApi.config(optionalFolderPath, jobName);}/*** 更新任务配置文件内容** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @param configXML 新的配置 XML* @return 是否成功*/public boolean updateJobConfig(String optionalFolderPath, String jobName, String configXML) {return jobsApi.config(optionalFolderPath, jobName, configXML);}/*** 构建任务** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 构建响应*/public IntegerResponse buildJob(String optionalFolderPath, String jobName) {return jobsApi.build(optionalFolderPath, jobName);}/*** 构建带参数的任务** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @param properties 参数列表* @return 构建响应*/public IntegerResponse buildJobWithParams(String optionalFolderPath, String jobName, Map<String, List<String>> properties) {return jobsApi.buildWithParameters(optionalFolderPath, jobName, properties);}/*** 获取任务上次构建序号** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 构建序号*/public Integer getLastBuildNumber(String optionalFolderPath, String jobName) {return jobsApi.lastBuildNumber(optionalFolderPath, jobName);}/*** 获取任务上次构建时间戳** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @return 时间戳*/public String getLastBuildTimestamp(String optionalFolderPath, String jobName) {return jobsApi.lastBuildTimestamp(optionalFolderPath, jobName);}/*** 获取构建信息** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @param buildNumber 构建编号* @return 构建信息*/public BuildInfo getBuildInfo(String optionalFolderPath, String jobName, int buildNumber) {return jobsApi.buildInfo(optionalFolderPath, jobName, buildNumber);}/*** 获取构建控制台输出内容** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @param buildNumber 构建编号* @param start 开始位置* @return 控制台输出内容*/public ProgressiveText getBuildLog(String optionalFolderPath, String jobName, int buildNumber, int start) {return jobsApi.progressiveText(optionalFolderPath, jobName, buildNumber, start);}/*** 重命名任务** @param optionalFolderPath 可选的文件夹路径* @param currentJobName 当前任务名称* @param newJobName 新任务名称* @return 是否成功*/public boolean renameJob(String optionalFolderPath, String currentJobName, String newJobName) {return jobsApi.rename(optionalFolderPath, currentJobName, newJobName);}/*** 停止任务** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @param buildNumber 构建编号* @return 是否成功*/public RequestStatus killJob(String optionalFolderPath, String jobName, int buildNumber) {return jobsApi.kill(optionalFolderPath, jobName, buildNumber);}/*** 查看执行日志** @param optionalFolderPath 可选的文件夹路径* @param jobName 任务名称* @param start 开始位置* @return 是否成功*/public ProgressiveText progressiveTextJob(String optionalFolderPath, String jobName, int start) {return jobsApi.progressiveText(optionalFolderPath, jobName, start);}
}
  • JenkinsApiService.java

直接暴露给LLM大模型的可调用的工具的Service

package com.agua.ai.mcp.server.service;import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.agua.ai.mcp.server.util.JenkinsTemplate;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;@Service
@AllArgsConstructor
public class JenkinsApiService {private final JenkinsTemplate jenkinsTemplate;@Tool(description = "获取任务列表")public String getJobList(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.getJobList(optionalFolderPath));}@Tool(description = "获取任务信息")public String getJobInfo(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.getJobInfo(optionalFolderPath, jobName));}@Tool(description = "使用 XML 文件创建任务")public String createJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName,@ToolParam(description = "任务的配置 XML") String configXML) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.createJob(optionalFolderPath, jobName, configXML));}@Tool(description = "删除任务")public String deleteJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.deleteJob(optionalFolderPath, jobName));}@Tool(description = "启用任务")public String enableJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.enableJob(optionalFolderPath, jobName));}@Tool(description = "禁用任务")public String disableJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.disableJob(optionalFolderPath, jobName));}@Tool(description = "获取任务配置文件内容")public String getJobConfig(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.getJobConfig(optionalFolderPath, jobName));}@Tool(description = "更新任务配置文件内容")public String updateJobConfig(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName,@ToolParam(description = "新的配置 XML") String configXML) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.updateJobConfig(optionalFolderPath, jobName, configXML));}@Tool(description = "构建任务")public String buildJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.buildJob(optionalFolderPath, jobName));}@Tool(description = "构建带参数的任务")public String buildJobWithParams(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName,@Schema(description = "参数列表(格式:Map<String, List<String>>)") String properties) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.buildJobWithParams(optionalFolderPath, jobName, JSON.parseObject(properties, new TypeReference<>() {})));}@Tool(description = "获取任务上次构建序号")public String getLastBuildNumber(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.getLastBuildNumber(optionalFolderPath, jobName));}@Tool(description = "获取任务上次构建时间戳")public String getLastBuildTimestamp(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.getLastBuildTimestamp(optionalFolderPath, jobName));}@Tool(description = "获取构建信息")public String getBuildInfo(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName,@ToolParam(description = "构建编号(必须是整数)") String buildNumber,@ToolParam(description = "是否返回变更历史(boolean类型)") String changeSetFlag) {Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {@Overridepublic boolean shouldSkipField(FieldAttributes f) {return Boolean.parseBoolean(changeSetFlag) && "changeSet".equals(f.getName());}@Overridepublic boolean shouldSkipClass(Class<?> clazz) {return false;}}).create();return gson.toJson(jenkinsTemplate.getBuildInfo(optionalFolderPath, jobName, Integer.parseInt(buildNumber)));}@Tool(description = "获取构建控制台输出内容")public String getBuildLog(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName,@ToolParam(description = "构建编号(必须是整数)") String buildNumber,@ToolParam(description = "开始位置(必须是整数)") String start) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.getBuildLog(optionalFolderPath, jobName, Integer.parseInt(buildNumber), Integer.parseInt(start)));}@Tool(description = "重命名任务")public String renameJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "当前任务名称") String currentJobName,@ToolParam(description = "新任务名称") String newJobName) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.renameJob(optionalFolderPath, currentJobName, newJobName));}@Tool(description = "停止任务(必须二次确认)")public String killJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName,@ToolParam(description = "构建编号(必须是整数)") String buildNumber) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.killJob(optionalFolderPath, jobName, Integer.parseInt(buildNumber)));}@Tool(description = "查看执行日志")public String progressiveTextJob(@ToolParam(description = "可选的文件夹路径") String optionalFolderPath,@ToolParam(description = "任务名称") String jobName,@ToolParam(description = "开始位置(必须是整数)") String start) {Gson gson = new GsonBuilder().create();return gson.toJson(jenkinsTemplate.progressiveTextJob(optionalFolderPath, jobName, Integer.parseInt(start)));}
}
  • application.yml
spring:ai:mcp:server:stdio: truename: jenkins-apiversion: 0.0.1type: SYNCmain:web-application-type: nonebanner-mode: off
jenkins:# jenkins的访问urlserver-uri: ${JENKINS_API_SERVER_URI}username: ${JENKINS_API_USERNAME}password: ${JENKINS_API_TOKEN}
logging:level:root: INFO

使用配置

如果是用 Cursor 作为客户端,那么可以通过一下方式启动 MCP Server ,本地 MCP Server 服务请将{你的路径}替换成实际的 jar 包存放路径

  • command方式
java -Dspring.ai.mcp.server.transport=STDIO -Dspring.main.web-application-type=none -jar {你的路径}\mcp-jenkins-server-0.0.1-SNAPSHOT.jar
  • mcp.json配置
{"mcpServers": {"jenkins-mcp": {"command": "java","args": ["-jar","{你的路径}\\mcp-jenkins-server-0.0.1-SNAPSHOT.jar"],"env": {"jenkins.server-uri": "jenkins-uri","jenkins.username": "username","jenkins.password": "password/token" }}}
}

最终演示效果

用户提问:请部署v1.2.3版本到测试环境

MCP Client解析后调用:

{"tool": "buildJobWithParams","params": {"optionalFolderPath": "","jobName": "qa-system","properties": {"version": ["v1.2.3"], "env": ["test"]}}
}

Jenkins MCP Server执行结果:

{"value": "12345","errors": []
}

总结

目前大模型的优势就是它能够一定程度地理解用户所说的内容,并转换成调用工具所需的请求参数,减少人工解析的工作量并且降低人工适配的成本。现在 MCP 还处于初期发展阶段,因此需要广大开发者的支持,才能支撑起庞大 AI 应用生态构建。

相关链接
MCP 介绍
Spring AI MCP
Jenkins 官网
jenkins-rest(Github 地址)

http://www.dtcms.com/wzjs/233086.html

相关文章:

  • 计算机网络技术毕业论文广州seo网站
  • webapp 做视频网站百度热搜关键词
  • 大连html5网站建设报价哪有网页设计公司
  • 杭州工作招聘网石家庄seo优化公司
  • 网站建设郑州宁波seo外包公司
  • 网站建设公司net2006保定网站推广公司
  • 兰州做网站一咨询兰州做网站公司新站整站优化
  • 中国能源建设股份有限公司新网站百度竞价培训
  • 哪网站建设好最新国际新闻
  • 慕课网电子商务网站开发百度竞价专员
  • 做月亮的网站背景图片最新小组排名
  • 江西赣州疫情最新情况系统优化工具
  • 做的网站太大怎么办快速seo优化
  • 龙江做网站最好的搜索引擎
  • 政府网站建设报告百度浏览器官网
  • 做网站.net和php哪个简单湖南最新消息今天
  • 博达网站建设竞价推广培训课程
  • 买完域名以后怎么做网站在线推广企业网站的方法
  • java做的网站2024年重启核酸
  • 教你怎么做垃圾网站软文广告投放平台
  • 海淀网站制作服务公司河北网站seo策划
  • 合肥做网站是什么百度问答优化
  • 镇江市精神文明建设网站微帮推广平台怎么加入
  • 网络 网站建设办公南昌百度推广联系方式
  • 网站的对比搜索引擎营销案例分析题
  • 福田莲花网站建设seo推广专员工作好做吗
  • 用idea做html网站百度seo是什么意思
  • 蓬莱网站建设哪家好深圳全网信息流推广公司
  • 总算把网站设计好了英文网站seo
  • 自字网站建设教程视频浏览器下载大全