283 lines
No EOL
8.7 KiB
Java
283 lines
No EOL
8.7 KiB
Java
package ai.dynamixs.mcp;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import jakarta.json.Json;
|
|
import jakarta.json.JsonObject;
|
|
import jakarta.json.JsonObjectBuilder;
|
|
|
|
/**
|
|
* Represents an MCP Tool based on Imixs-Workflow BPMN models.
|
|
*
|
|
* MCP Tools represent functions that can be called by the MCP client. Each tool
|
|
* corresponds to a workflow task/event combination.
|
|
*/
|
|
public class MCPTool implements Serializable {
|
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
// MCP Standard Fields
|
|
private String name; // Tool name/identifier
|
|
private String description; // Tool description
|
|
private JsonObject inputSchema; // JSON Schema for input parameters
|
|
|
|
// Imixs-specific fields
|
|
private String modelVersion;
|
|
private int taskId;
|
|
private int eventId;
|
|
private List<String> tags;
|
|
private List<String> examples;
|
|
|
|
// Constructors
|
|
public MCPTool() {
|
|
this.tags = new ArrayList<>();
|
|
this.examples = new ArrayList<>();
|
|
}
|
|
|
|
public MCPTool(String modelVersion, int taskId, int eventId) {
|
|
this();
|
|
this.modelVersion = modelVersion;
|
|
this.taskId = taskId;
|
|
this.eventId = eventId;
|
|
this.name = createToolName(modelVersion, taskId, eventId);
|
|
}
|
|
|
|
/**
|
|
* Creates a tool name from Imixs workflow components
|
|
*/
|
|
public static String createToolName(String modelVersion, int taskId, int eventId) {
|
|
if (modelVersion == null || modelVersion.trim().isEmpty()) {
|
|
throw new IllegalArgumentException("Model version cannot be null or empty");
|
|
}
|
|
return String.format("%s_%d_%d", modelVersion.replace("-", "_"), taskId, eventId);
|
|
}
|
|
|
|
/**
|
|
* Parses model version from tool name
|
|
*/
|
|
public String getModelVersionFromName() {
|
|
if (name == null || !name.contains("_")) {
|
|
throw new IllegalStateException("Invalid tool name format: " + name);
|
|
}
|
|
return name.substring(0, name.lastIndexOf('_', name.lastIndexOf('_') - 1)).replace("_", "-");
|
|
}
|
|
|
|
/**
|
|
* Parses task ID from tool name
|
|
*/
|
|
public int getTaskIdFromName() {
|
|
if (name == null || !name.contains("_")) {
|
|
throw new IllegalStateException("Invalid tool name format: " + name);
|
|
}
|
|
String[] parts = name.split("_");
|
|
if (parts.length < 3) {
|
|
throw new IllegalStateException("Invalid tool name format: " + name);
|
|
}
|
|
try {
|
|
return Integer.parseInt(parts[parts.length - 2]);
|
|
} catch (NumberFormatException e) {
|
|
throw new IllegalStateException("Invalid task ID in tool name: " + name, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses event ID from tool name
|
|
*/
|
|
public int getEventIdFromName() {
|
|
if (name == null || !name.contains("_")) {
|
|
throw new IllegalStateException("Invalid tool name format: " + name);
|
|
}
|
|
String[] parts = name.split("_");
|
|
if (parts.length < 3) {
|
|
throw new IllegalStateException("Invalid tool name format: " + name);
|
|
}
|
|
try {
|
|
return Integer.parseInt(parts[parts.length - 1]);
|
|
} catch (NumberFormatException e) {
|
|
throw new IllegalStateException("Invalid event ID in tool name: " + name, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a default input schema for workflow tools
|
|
*/
|
|
public JsonObject createDefaultInputSchema() {
|
|
return Json.createObjectBuilder()
|
|
.add("type", "object")
|
|
.add("properties", Json.createObjectBuilder()
|
|
.add("workitem", Json.createObjectBuilder()
|
|
.add("type", "object")
|
|
.add("description", "Workflow item data")
|
|
.add("properties", Json.createObjectBuilder()
|
|
.add("$modelversion", Json.createObjectBuilder()
|
|
.add("type", "string")
|
|
.add("description", "Workflow model version")
|
|
.build())
|
|
.add("$taskid", Json.createObjectBuilder()
|
|
.add("type", "integer")
|
|
.add("description", "Task ID")
|
|
.build())
|
|
.add("$eventid", Json.createObjectBuilder()
|
|
.add("type", "integer")
|
|
.add("description", "Event ID")
|
|
.build())
|
|
.build())
|
|
.add("required", Json.createArrayBuilder()
|
|
.add("$modelversion")
|
|
.add("$taskid")
|
|
.add("$eventid")
|
|
.build())
|
|
.build())
|
|
.build())
|
|
.add("required", Json.createArrayBuilder()
|
|
.add("workitem")
|
|
.build())
|
|
.build();
|
|
}
|
|
|
|
/**
|
|
* Converts this tool to MCP JSON format
|
|
*/
|
|
public JsonObject toJsonObject() {
|
|
JsonObjectBuilder builder = Json.createObjectBuilder()
|
|
.add("name", name != null ? name : "")
|
|
.add("description", description != null ? description : "");
|
|
|
|
// Input schema
|
|
if (inputSchema != null) {
|
|
builder.add("inputSchema", inputSchema);
|
|
} else {
|
|
builder.add("inputSchema", createDefaultInputSchema());
|
|
}
|
|
|
|
return builder.build();
|
|
}
|
|
|
|
/**
|
|
* Creates an MCPTool from a JsonObject
|
|
*/
|
|
public static MCPTool fromJsonObject(JsonObject jsonObject) {
|
|
MCPTool tool = new MCPTool();
|
|
|
|
tool.setName(jsonObject.getString("name", ""));
|
|
tool.setDescription(jsonObject.getString("description", ""));
|
|
|
|
if (jsonObject.containsKey("inputSchema")) {
|
|
tool.setInputSchema(jsonObject.getJsonObject("inputSchema"));
|
|
}
|
|
|
|
return tool;
|
|
}
|
|
|
|
/**
|
|
* Validates this tool for MCP compliance
|
|
*/
|
|
public boolean isValid() {
|
|
if (name == null || name.trim().isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
if (description == null || description.trim().isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Validate tool name format
|
|
try {
|
|
getModelVersionFromName();
|
|
getTaskIdFromName();
|
|
getEventIdFromName();
|
|
} catch (Exception e) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Getters and Setters
|
|
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 JsonObject getInputSchema() {
|
|
return inputSchema;
|
|
}
|
|
|
|
public void setInputSchema(JsonObject inputSchema) {
|
|
this.inputSchema = inputSchema;
|
|
}
|
|
|
|
public String getModelVersion() {
|
|
return modelVersion;
|
|
}
|
|
|
|
public void setModelVersion(String modelVersion) {
|
|
this.modelVersion = modelVersion;
|
|
}
|
|
|
|
public int getTaskId() {
|
|
return taskId;
|
|
}
|
|
|
|
public void setTaskId(int taskId) {
|
|
this.taskId = taskId;
|
|
}
|
|
|
|
public int getEventId() {
|
|
return eventId;
|
|
}
|
|
|
|
public void setEventId(int eventId) {
|
|
this.eventId = eventId;
|
|
}
|
|
|
|
public List<String> getTags() {
|
|
return tags;
|
|
}
|
|
|
|
public void setTags(List<String> tags) {
|
|
this.tags = tags != null ? tags : new ArrayList<>();
|
|
}
|
|
|
|
public List<String> getExamples() {
|
|
return examples;
|
|
}
|
|
|
|
public void setExamples(List<String> examples) {
|
|
this.examples = examples != null ? examples : new ArrayList<>();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return String.format("MCPTool{name='%s', description='%s', modelVersion='%s', taskId=%d, eventId=%d}",
|
|
name, description, modelVersion, taskId, eventId);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null || getClass() != obj.getClass())
|
|
return false;
|
|
MCPTool that = (MCPTool) obj;
|
|
return name != null ? name.equals(that.name) : that.name == null;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return name != null ? name.hashCode() : 0;
|
|
}
|
|
} |