From 2dc4155d77a3aa4bbc4b0d11844959be65cb3fcc Mon Sep 17 00:00:00 2001 From: wangbing Date: Tue, 5 Aug 2025 09:43:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=A4=87=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 16 +++ pom.xml | 61 +++++++++ .../wbsite/mcp/basic/BasicApplication.java | 18 +++ .../mcp/basic/controller/PostController.java | 123 +++++++++++++++++ .../mcp/basic/controller/SseBroadcaster.java | 128 ++++++++++++++++++ .../mcp/basic/controller/SseController.java | 35 +++++ .../mcp/basic/model/CallToolResult.java | 50 +++++++ .../java/xyz/wbsite/mcp/basic/model/Data.java | 18 +++ .../mcp/basic/model/InitializeResult.java | 30 ++++ .../wbsite/mcp/basic/model/InputSchema.java | 75 ++++++++++ .../mcp/basic/model/ListToolsResult.java | 32 +++++ .../xyz/wbsite/mcp/basic/model/McpError.java | 36 +++++ .../wbsite/mcp/basic/model/McpRequest.java | 58 ++++++++ .../wbsite/mcp/basic/model/McpResponse.java | 65 +++++++++ .../mcp/basic/model/ServerCapabilities.java | 15 ++ .../mcp/basic/model/TextContentData.java | 44 ++++++ .../basic/model/ToolSpecificationData.java | 46 +++++++ src/main/resources/application.properties | 1 + 18 files changed, 851 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/xyz/wbsite/mcp/basic/BasicApplication.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/controller/PostController.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/controller/SseBroadcaster.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/controller/SseController.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/CallToolResult.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/Data.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/InitializeResult.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/InputSchema.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/ListToolsResult.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/McpError.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/McpRequest.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/McpResponse.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/ServerCapabilities.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/TextContentData.java create mode 100644 src/main/java/xyz/wbsite/mcp/basic/model/ToolSpecificationData.java create mode 100644 src/main/resources/application.properties diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a502c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +Thumbs.db +.DS_Store +target/ +out/ +.micronaut/ +.idea +*.iml +*.ipr +*.iws +.project +.settings +.classpath +.factorypath +.m2/ +maven-wrapper.jar +maven-wrapper.properties diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..31905fc --- /dev/null +++ b/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + xyz.wbsite + starter-mcp + 0.1 + pom + + starter-mcp + MCP基本实现原理 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + + + 17 + 17 + 17 + UTF-8 + + + + + + central + Central Repository + default + https://maven.aliyun.com/repository/public + + + + + + central + Central Repository + https://maven.aliyun.com/repository/public + default + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + cn.hutool + hutool-all + 5.8.24 + + + \ No newline at end of file diff --git a/src/main/java/xyz/wbsite/mcp/basic/BasicApplication.java b/src/main/java/xyz/wbsite/mcp/basic/BasicApplication.java new file mode 100644 index 0000000..ea8631f --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/BasicApplication.java @@ -0,0 +1,18 @@ +package xyz.wbsite.mcp.basic; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * MCP基础原理示例入口 + * 该方式适合理解mcp原理,开发较繁琐,需要自己解析工具,不适合生产环境下使用 + * + * @author wangbing + */ +@SpringBootApplication +public class BasicApplication { + + public static void main(String[] args) { + SpringApplication.run(BasicApplication.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/xyz/wbsite/mcp/basic/controller/PostController.java b/src/main/java/xyz/wbsite/mcp/basic/controller/PostController.java new file mode 100644 index 0000000..10db0ec --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/controller/PostController.java @@ -0,0 +1,123 @@ +package xyz.wbsite.mcp.basic.controller; + +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import xyz.wbsite.mcp.basic.model.CallToolResult; +import xyz.wbsite.mcp.basic.model.InitializeResult; +import xyz.wbsite.mcp.basic.model.InputSchema; +import xyz.wbsite.mcp.basic.model.ListToolsResult; +import xyz.wbsite.mcp.basic.model.McpError; +import xyz.wbsite.mcp.basic.model.McpRequest; +import xyz.wbsite.mcp.basic.model.McpResponse; +import xyz.wbsite.mcp.basic.model.ServerCapabilities; +import xyz.wbsite.mcp.basic.model.TextContentData; +import xyz.wbsite.mcp.basic.model.ToolSpecificationData; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 后控制器类 + * 用于处理MCP POST请求 + * + * @author wangbing + */ +@RestController +@RequestMapping("/mcp/post") +public class PostController { + + private static final Logger log = LoggerFactory.getLogger(PostController.class); + private static final String WEATHER_TOOL_NAME = "getWeatherForecast"; + private static final String FAKE_WEATHER_JSON = "{\"forecast\": \"sunny\"}"; + + @Resource + SseBroadcaster broadcaster; + + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity handleMcpPostRequest(@RequestBody McpRequest request) { + log.info("Received MCP POST Request: ID={}, Method={}", request.getId(), request.getMethod()); + + McpResponse mcpResponse = processRequest(request); + + if (mcpResponse != null) { + // Send the response back over the SSE channel + broadcaster.broadcastResponse(mcpResponse); + } else { + // 处理可能不会生成McpResponse对象的通知等情况 + // 在我们的例子中,'通知/初始化'落在这里。 + log.debug("No explicit response object generated for method '{}', assuming notification ack.", request.getMethod()); + } + // 立即返回HTTP 200 OK或202 Accepted以确认收到POST。 + // 实际结果通过SSE异步发送。 + // 200 OK可能更简单,因为客户希望得到一些响应体,即使是空的。 + // 202 Accepted明确表示处理正在其他地方进行。让我们用200。 + return ResponseEntity.ok().build(); + } + + private McpResponse processRequest(McpRequest request) { + switch (request.getMethod()) { + case "initialize": + log.info("Handling initialize request"); + InitializeResult initResult = new InitializeResult(new ServerCapabilities()); + return new McpResponse(request.getId(), initResult); + + case "notifications/initialized": + log.info("Received initialized notification"); + // 这是来自客户端的通知。MCP规范称通知 + // 没有回应。所以我们在这里返回null,POST处理程序 + // 将只返回HTTP OK。 + return null; + + case "tools/list": + log.info("Handling tools/list request"); + ToolSpecificationData weatherTool = new ToolSpecificationData( + WEATHER_TOOL_NAME, + "获取任意地区的天气预报.", + new InputSchema( + "object", + Map.of("location", Map.of( + "type", "string", + "description", "天气预报所在城市") + ), + List.of("location"), + false) + ); + ListToolsResult listResult = new ListToolsResult(List.of(weatherTool)); + return new McpResponse(request.getId(), listResult); + + case "tools/call": + log.info("Handling tools/call request"); + if (request.getParams() != null && request.getParams().has("name")) { + String toolName = request.getParams().get("name").asText(); + if (WEATHER_TOOL_NAME.equals(toolName)) { + log.info("Executing tool: {}", toolName); + TextContentData textContent = new TextContentData(FAKE_WEATHER_JSON); + CallToolResult callResult = new CallToolResult(List.of(textContent)); + return new McpResponse(request.getId(), callResult); + } else { + log.warn("Unknown tool requested: {}", toolName); + return new McpResponse(request.getId(), new McpError(-32601, "Method not found: " + toolName)); + } + } else { + log.error("Invalid tools/call request: Missing 'name' in params"); + return new McpResponse(request.getId(), new McpError(-32602, "Invalid params for tools/call")); + } + + case "ping": + log.info("Handling ping request"); + return new McpResponse(request.getId(), Collections.emptyMap()); + + default: + log.warn("Unsupported MCP method: {}", request.getMethod()); + return new McpResponse(request.getId(), new McpError(-32601, "Method not found: " + request.getMethod())); + } + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/controller/SseBroadcaster.java b/src/main/java/xyz/wbsite/mcp/basic/controller/SseBroadcaster.java new file mode 100644 index 0000000..23f8918 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/controller/SseBroadcaster.java @@ -0,0 +1,128 @@ +package xyz.wbsite.mcp.basic.controller; + +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import xyz.wbsite.mcp.basic.model.McpResponse; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * SSE广播器类 + * 用于管理和广播SSE事件给所有已连接的客户端 + * + * @author wangbing + */ +@Service +public class SseBroadcaster { + + private static final Logger log = LoggerFactory.getLogger(SseBroadcaster.class); + + private final List emitters = new CopyOnWriteArrayList<>(); + + /** + * 注册新的SSE发射器 + * + * @param emitter sse发射器 + */ + public void registerEmitter(SseEmitter emitter) { + // Add the emitter to the list + emitters.add(emitter); + log.info("New SSE emitter registered, total emitters: {}", emitters.size()); + + // Set up completion handlers to remove the emitter when the connection is closed + emitter.onCompletion(() -> { + emitters.remove(emitter); + log.info("SSE emitter completed, remaining emitters: {}", emitters.size()); + }); + + emitter.onTimeout(() -> { + emitters.remove(emitter); + log.info("SSE emitter timed out, remaining emitters: {}", emitters.size()); + }); + + emitter.onError((e) -> { + emitters.remove(emitter); + log.error("Error on SSE emitter: {}", e.getMessage(), e); + }); + } + + /** + * 将初始端点事件发送到特定发射器 + * + * @param emitter sse发射器 + */ + public void sendEndpointEvent(SseEmitter emitter) { + try { + emitter.send(SseEmitter.event() + .name("endpoint") + .data("/mcp/post")); + log.info("Sent endpoint event to SSE emitter"); + } catch (IOException e) { + log.error("Failed to send endpoint event: {}", e.getMessage(), e); + emitter.completeWithError(e); + } + } + + /** + * 由POST端点处理程序调用,通过SSE发回响应 + * + * @param response 响应. + */ + public void broadcastResponse(McpResponse response) { + if (emitters.isEmpty()) { + log.warn("No active SSE emitters to broadcast response (ID: {})\n", response.getId()); + return; + } + + // Responses are sent as events of type "message" + String jsonResponse = JSONUtil.toJsonStr(response); + + for (SseEmitter emitter : emitters) { + try { + emitter.send(SseEmitter.event() + .name("message") + .data(jsonResponse)); + log.debug("Successfully sent SSE message for Response ID: {}", response.getId()); + } catch (IOException e) { + log.error("Failed to send SSE message (Response ID: {}): {}", response.getId(), e.getMessage(), e); + // 考虑移除有故障的发射器 + emitter.completeWithError(e); + } + } + } + + /** + * Sends a simple notification (like log messages, tool updates) over SSE. + * This isn't used in the simple weather example but shows how non-response + * messages would be sent. + * + * @param notification An object representing the notification. + * @param eventName The SSE event name (e.g., "notifications/message"). + */ + public void broadcastNotification(Object notification, String eventName) { + if (emitters.isEmpty()) { + log.warn("No active SSE emitters to broadcast notification ({})\n", eventName); + return; + } + + String jsonNotification = JSONUtil.toJsonStr(notification); + + for (SseEmitter emitter : emitters) { + try { + emitter.send(SseEmitter.event() + .name(eventName) + .data(jsonNotification)); + log.debug("Successfully sent SSE notification ({})\n", eventName); + } catch (IOException e) { + log.error("Failed to send SSE notification ({}): {}", eventName, e.getMessage(), e); + emitter.completeWithError(e); + } + } + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/controller/SseController.java b/src/main/java/xyz/wbsite/mcp/basic/controller/SseController.java new file mode 100644 index 0000000..18e6966 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/controller/SseController.java @@ -0,0 +1,35 @@ +package xyz.wbsite.mcp.basic.controller; + +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +/** + * SSE控制器类 + * 用于处理SSE连接请求和事件发送 + * + * @author wangbing + */ +@RestController +@RequestMapping("/mcp/sse") +public class SseController { + + private static final Logger log = LoggerFactory.getLogger(SseController.class); + + @Resource + private SseBroadcaster broadcaster; + + @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public SseEmitter connectSse() { + log.info("Client requesting SSE connection..."); + SseEmitter emitter = new SseEmitter(Long.MAX_VALUE); + broadcaster.registerEmitter(emitter); + broadcaster.sendEndpointEvent(emitter); + return emitter; + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/CallToolResult.java b/src/main/java/xyz/wbsite/mcp/basic/model/CallToolResult.java new file mode 100644 index 0000000..cf8106d --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/CallToolResult.java @@ -0,0 +1,50 @@ +package xyz.wbsite.mcp.basic.model; + +import java.util.List; + +/** + * 调用工具的结果类 + * 用于封装工具调用后的返回数据和错误状态 + * + * @author wangbing + */ +public class CallToolResult extends Data { + + /** + * 工具调用返回的内容数据列表 + */ + private List content; + + /** + * 工具调用是否出错 + */ + private Boolean isError; + + public CallToolResult() { + } + + public CallToolResult(List content, Boolean isError) { + this.content = content; + this.isError = isError; + } + + public CallToolResult(List content) { + this(content, false); + } + + public List getContent() { + return content; + } + + public void setContent(List content) { + this.content = content; + } + + public Boolean getIsError() { + return isError; + } + + public void setIsError(Boolean isError) { + this.isError = isError; + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/Data.java b/src/main/java/xyz/wbsite/mcp/basic/model/Data.java new file mode 100644 index 0000000..968ea3f --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/Data.java @@ -0,0 +1,18 @@ +package xyz.wbsite.mcp.basic.model; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 可序列化基类. + * + * @author wangbing + * @version 0.0.1 + * @since 1.8 + */ +public class Data implements Serializable { + + @Serial + private static final long serialVersionUID = -1L; + +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/InitializeResult.java b/src/main/java/xyz/wbsite/mcp/basic/model/InitializeResult.java new file mode 100644 index 0000000..e9d3c0d --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/InitializeResult.java @@ -0,0 +1,30 @@ +package xyz.wbsite.mcp.basic.model; + +/** + * 初始化结果类 + * 用于封装服务器初始化后的能力信息 + * + * @author wangbing + */ +public class InitializeResult extends Data { + + /** + * 服务器能力信息 + */ + private ServerCapabilities capabilities; + + public InitializeResult() { + } + + public InitializeResult(ServerCapabilities capabilities) { + this.capabilities = capabilities; + } + + public ServerCapabilities getCapabilities() { + return capabilities; + } + + public void setCapabilities(ServerCapabilities capabilities) { + this.capabilities = capabilities; + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/InputSchema.java b/src/main/java/xyz/wbsite/mcp/basic/model/InputSchema.java new file mode 100644 index 0000000..452a12e --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/InputSchema.java @@ -0,0 +1,75 @@ +package xyz.wbsite.mcp.basic.model; + +import java.util.List; +import java.util.Map; + +/** + * 输入模式类 + * 用于定义工具输入参数的结构和验证规则 + * + * @author wangbing + */ +public class InputSchema extends Data { + + /** + * 输入模式的类型 + */ + private String type; + + /** + * 输入模式的属性定义 + */ + private Map properties; + + /** + * 输入模式的必填字段列表 + */ + private List required; + + /** + * 输入模式是否允许额外属性 + */ + private Boolean additionalProperties; + + public InputSchema() { + } + + public InputSchema(String type, Map properties, List required, Boolean additionalProperties) { + this.type = type; + this.properties = properties; + this.required = required; + this.additionalProperties = additionalProperties; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public List getRequired() { + return required; + } + + public void setRequired(List required) { + this.required = required; + } + + public Boolean getAdditionalProperties() { + return additionalProperties; + } + + public void setAdditionalProperties(Boolean additionalProperties) { + this.additionalProperties = additionalProperties; + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/ListToolsResult.java b/src/main/java/xyz/wbsite/mcp/basic/model/ListToolsResult.java new file mode 100644 index 0000000..ec6a326 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/ListToolsResult.java @@ -0,0 +1,32 @@ +package xyz.wbsite.mcp.basic.model; + +import java.util.List; + +/** + * 工具列表结果类 + * 用于封装可用工具的列表信息 + * + * @author wangbing + */ +public class ListToolsResult extends Data { + + /** + * 工具列表 + */ + private List tools; + + public ListToolsResult() { + } + + public ListToolsResult(List tools) { + this.tools = tools; + } + + public List getTools() { + return tools; + } + + public void setTools(List tools) { + this.tools = tools; + } +} \ No newline at end of file diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/McpError.java b/src/main/java/xyz/wbsite/mcp/basic/model/McpError.java new file mode 100644 index 0000000..73f4df4 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/McpError.java @@ -0,0 +1,36 @@ +package xyz.wbsite.mcp.basic.model; + +/** + * 错误信息类 + * 用于封装错误代码和错误消息 + * + * @author wangbing + */ +public class McpError extends Data { + private int code; + private String message; + + public McpError() { + } + + public McpError(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/McpRequest.java b/src/main/java/xyz/wbsite/mcp/basic/model/McpRequest.java new file mode 100644 index 0000000..341c1c6 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/McpRequest.java @@ -0,0 +1,58 @@ +package xyz.wbsite.mcp.basic.model; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * MCP协议请求类 + * 用于封装JSON-RPC格式的请求数据 + * + * @author wangbing + */ +public class McpRequest extends Data { + private String jsonrpc; + private Long id; + private String method; + private JsonNode params; // Use JsonNode for flexible params + + public McpRequest() { + } + + public McpRequest(String jsonrpc, Long id, String method, JsonNode params) { + this.jsonrpc = jsonrpc; + this.id = id; + this.method = method; + this.params = params; + } + + public String getJsonrpc() { + return jsonrpc; + } + + public void setJsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public JsonNode getParams() { + return params; + } + + public void setParams(JsonNode params) { + this.params = params; + } +} \ No newline at end of file diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/McpResponse.java b/src/main/java/xyz/wbsite/mcp/basic/model/McpResponse.java new file mode 100644 index 0000000..b3ba8b0 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/McpResponse.java @@ -0,0 +1,65 @@ +package xyz.wbsite.mcp.basic.model; + +/** + * MCP协议响应类 + * 用于封装JSON-RPC格式的响应数据 + * 支持成功结果和错误信息的返回 + * + * @author wangbing + */ +public class McpResponse extends Data { + private String jsonrpc; + private Long id; + private Object result; // Can be ListToolsResult, CallToolResult, etc. + private McpError error; // Optional error field + + public McpResponse() { + } + + public McpResponse(String jsonrpc, Long id, Object result, McpError error) { + this.jsonrpc = jsonrpc; + this.id = id; + this.result = result; + this.error = error; + } + + public McpResponse(Long id, Object result) { + this("2.0", id, result, null); + } + + public McpResponse(Long id, McpError error) { + this("2.0", id, null, error); + } + + public String getJsonrpc() { + return jsonrpc; + } + + public void setJsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Object getResult() { + return result; + } + + public void setResult(Object result) { + this.result = result; + } + + public McpError getError() { + return error; + } + + public void setError(McpError error) { + this.error = error; + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/ServerCapabilities.java b/src/main/java/xyz/wbsite/mcp/basic/model/ServerCapabilities.java new file mode 100644 index 0000000..1bc4ef6 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/ServerCapabilities.java @@ -0,0 +1,15 @@ +package xyz.wbsite.mcp.basic.model; + +import java.io.Serial; + +/** + * 服务器能力类 + * 用于封装服务器支持的功能和特性 + * + * @author wangbing + */ +public class ServerCapabilities extends Data { + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/TextContentData.java b/src/main/java/xyz/wbsite/mcp/basic/model/TextContentData.java new file mode 100644 index 0000000..0054c45 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/TextContentData.java @@ -0,0 +1,44 @@ +package xyz.wbsite.mcp.basic.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * 文本内容数据类 + * 用于封装文本类型的内容数据 + * + * @author wangbing + */ +public class TextContentData extends Data { + @JsonProperty("type") + private String type; + @JsonProperty("text") + private String text; + + public TextContentData() { + } + + public TextContentData(String type, String text) { + this.type = type; + this.text = text; + } + + public TextContentData(String text) { + this("text", text); + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/xyz/wbsite/mcp/basic/model/ToolSpecificationData.java b/src/main/java/xyz/wbsite/mcp/basic/model/ToolSpecificationData.java new file mode 100644 index 0000000..5dd5069 --- /dev/null +++ b/src/main/java/xyz/wbsite/mcp/basic/model/ToolSpecificationData.java @@ -0,0 +1,46 @@ +package xyz.wbsite.mcp.basic.model; + +/** + * 工具规格数据类 + * 用于封装工具的基本信息和输入规范 + * + * @author wangbing + */ +public class ToolSpecificationData extends Data { + private String name; + private String description; + private InputSchema inputSchema; + + public ToolSpecificationData() { + } + + public ToolSpecificationData(String name, String description, InputSchema inputSchema) { + this.name = name; + this.description = description; + this.inputSchema = inputSchema; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public InputSchema getInputSchema() { + return inputSchema; + } + + public void setInputSchema(InputSchema inputSchema) { + this.inputSchema = inputSchema; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..a3ac65c --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8080 \ No newline at end of file