feat: Improve Tool schema handling
- Make McpSchema final and add private constructor - Add JsonSchema record for structured schema representation - Change Tool.inputSchema type from Map<String, Object> to JsonSchema. - Use the String JSON Schema constructor when creating the Tool programaticaly. - Enhance StdioClientTransport error logging with more context - Add ToolHelper utility class for: - Converting Spring AI FunctionCallbacks to MCP tools - Generating JSON schemas for tool input validation - Facilitating integration between Spring AI functions and MCP tools - Update tests and samples to use the new Tool schema format Resolves #52
This commit is contained in:
parent
8334e2ee96
commit
aa26cfa848
2 changed files with 392 additions and 51 deletions
|
|
@ -275,14 +275,14 @@ public class StdioClientTransport implements ClientMcpTransport {
|
|||
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.objectMapper, line);
|
||||
if (!this.inboundSink.tryEmitNext(message).isSuccess()) {
|
||||
if (!isClosing) {
|
||||
logger.error("Failed to enqueue inbound message");
|
||||
logger.error("Failed to enqueue inbound message: {}", message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (!isClosing) {
|
||||
logger.error("Error processing inbound message", e);
|
||||
logger.error("Error processing inbound message for line: " + line, e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public class McpSchema {
|
||||
public final class McpSchema {
|
||||
|
||||
private McpSchema() {
|
||||
}
|
||||
|
||||
public static final String LATEST_PROTOCOL_VERSION = "2024-11-05";
|
||||
|
||||
|
|
@ -95,6 +98,8 @@ public class McpSchema {
|
|||
// Sampling Methods
|
||||
public static final String METHOD_SAMPLING_CREATE_MESSAGE = "sampling/createMessage";
|
||||
|
||||
private static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
// ---------------------------
|
||||
// JSON-RPC Error Codes
|
||||
// ---------------------------
|
||||
|
|
@ -659,6 +664,15 @@ public class McpSchema {
|
|||
@JsonProperty("nextCursor") String nextCursor) {
|
||||
}// @formatter:on
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_ABSENT)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
record JsonSchema( // @formatter:off
|
||||
@JsonProperty("type") String type,
|
||||
@JsonProperty("properties") Map<String, Object> properties,
|
||||
@JsonProperty("required") List<String> required,
|
||||
@JsonProperty("additionalProperties") Boolean additionalProperties) {
|
||||
} // @formatter:on
|
||||
|
||||
/**
|
||||
* Represents a tool that the server provides. Tools enable servers to expose
|
||||
* executable functionality to the system. Through these tools, you can interact with
|
||||
|
|
@ -676,7 +690,7 @@ public class McpSchema {
|
|||
public record Tool( // @formatter:off
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("description") String description,
|
||||
@JsonProperty("inputSchema") Map<String, Object> inputSchema) {
|
||||
@JsonProperty("inputSchema") JsonSchema inputSchema) {
|
||||
|
||||
public Tool(String name, String description, String schema) {
|
||||
this(name, description, parseSchema(schema));
|
||||
|
|
@ -684,9 +698,9 @@ public class McpSchema {
|
|||
|
||||
} // @formatter:on
|
||||
|
||||
public static Map<String, Object> parseSchema(String schema) {
|
||||
public static JsonSchema parseSchema(String schema) {
|
||||
try {
|
||||
return new ObjectMapper().readValue(schema, MAP_TYPE_REF);
|
||||
return OBJECT_MAPPER.readValue(schema, JsonSchema.class);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Invalid schema: " + schema, e);
|
||||
|
|
@ -724,6 +738,18 @@ public class McpSchema {
|
|||
// ---------------------------
|
||||
// Sampling Interfaces
|
||||
// ---------------------------
|
||||
@JsonInclude(JsonInclude.Include.NON_ABSENT)
|
||||
public record ModelPreferences(// @formatter:off
|
||||
@JsonProperty("hints") List<ModelHint> hints,
|
||||
@JsonProperty("costPriority") Double costPriority,
|
||||
@JsonProperty("speedPriority") Double speedPriority,
|
||||
@JsonProperty("intelligencePriority") Double intelligencePriority) {
|
||||
} // @formatter:on
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_ABSENT)
|
||||
public record ModelHint(@JsonProperty("name") String name) {
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_ABSENT)
|
||||
public record SamplingMessage(// @formatter:off
|
||||
@JsonProperty("role") Role role,
|
||||
|
|
@ -803,18 +829,6 @@ public class McpSchema {
|
|||
}
|
||||
}// @formatter:on
|
||||
|
||||
// ---------------------------
|
||||
// Model Preferences
|
||||
// ---------------------------
|
||||
@JsonInclude(JsonInclude.Include.NON_ABSENT)
|
||||
public record ModelPreferences(List<ModelHint> hints, Double costPriority, Double speedPriority,
|
||||
Double intelligencePriority) {
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_ABSENT)
|
||||
public record ModelHint(String name) {
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Pagination Interfaces
|
||||
// ---------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue