Add Tool output_schema support with comprehensive validation
This commit implements optional JSON Schema validation for tool outputs according to the MCP specification: - Add MCP::Tool::OutputSchema class mirroring InputSchema functionality - Support output_schema in class definitions, Tool.define, and OutputSchema objects - Include validate_result method for runtime validation - Update MCP::Client::Tool to track output schemas - Add comprehensive test coverage with 249 passing tests - Update README with dedicated Tool Output Schemas section - Follow MCP spec requirements for server/client validation
This commit is contained in:
parent
3f2a4b3b21
commit
aad8e94530
1 changed files with 495 additions and 7 deletions
106
README.md
106
README.md
|
|
@ -385,6 +385,14 @@ class MyTool < MCP::Tool
|
|||
},
|
||||
required: ["message"]
|
||||
)
|
||||
output_schema(
|
||||
properties: {
|
||||
result: { type: "string" },
|
||||
success: { type: "boolean" },
|
||||
timestamp: { type: "string", format: "date-time" }
|
||||
},
|
||||
required: ["result", "success", "timestamp"]
|
||||
)
|
||||
annotations(
|
||||
read_only_hint: true,
|
||||
destructive_hint: false,
|
||||
|
|
@ -448,6 +456,102 @@ Tools can include annotations that provide additional metadata about their behav
|
|||
|
||||
Annotations can be set either through the class definition using the `annotations` class method or when defining a tool using the `define` method.
|
||||
|
||||
### Tool Output Schemas
|
||||
|
||||
Tools can optionally define an `output_schema` to specify the expected structure of their results. This works similarly to how `input_schema` is defined and can be used in three ways:
|
||||
|
||||
1. **Class definition with output_schema:**
|
||||
|
||||
```ruby
|
||||
class WeatherTool < MCP::Tool
|
||||
tool_name "get_weather"
|
||||
description "Get current weather for a location"
|
||||
|
||||
input_schema(
|
||||
properties: {
|
||||
location: { type: "string" },
|
||||
units: { type: "string", enum: ["celsius", "fahrenheit"] }
|
||||
},
|
||||
required: ["location"]
|
||||
)
|
||||
|
||||
output_schema(
|
||||
properties: {
|
||||
temperature: { type: "number" },
|
||||
condition: { type: "string" },
|
||||
humidity: { type: "integer" }
|
||||
},
|
||||
required: ["temperature", "condition", "humidity"]
|
||||
)
|
||||
|
||||
def self.call(location:, units: "celsius", server_context:)
|
||||
# Call weather API and structure the response
|
||||
api_response = WeatherAPI.fetch(location, units)
|
||||
weather_data = {
|
||||
temperature: api_response.temp,
|
||||
condition: api_response.description,
|
||||
humidity: api_response.humidity_percent
|
||||
}
|
||||
|
||||
output_schema.validate_result(weather_data)
|
||||
|
||||
MCP::Tool::Response.new([{
|
||||
type: "text",
|
||||
text: weather_data.to_json
|
||||
}])
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
2. **Using Tool.define with output_schema:**
|
||||
|
||||
```ruby
|
||||
tool = MCP::Tool.define(
|
||||
name: "calculate_stats",
|
||||
description: "Calculate statistics for a dataset",
|
||||
input_schema: {
|
||||
properties: {
|
||||
numbers: { type: "array", items: { type: "number" } }
|
||||
},
|
||||
required: ["numbers"]
|
||||
},
|
||||
output_schema: {
|
||||
properties: {
|
||||
mean: { type: "number" },
|
||||
median: { type: "number" },
|
||||
count: { type: "integer" }
|
||||
},
|
||||
required: ["mean", "median", "count"]
|
||||
}
|
||||
) do |args, server_context|
|
||||
# Calculate statistics and validate against schema
|
||||
MCP::Tool::Response.new([{ type: "text", text: "Statistics calculated" }])
|
||||
end
|
||||
```
|
||||
|
||||
3. **Using OutputSchema objects:**
|
||||
|
||||
```ruby
|
||||
class DataTool < MCP::Tool
|
||||
output_schema MCP::Tool::OutputSchema.new(
|
||||
properties: {
|
||||
success: { type: "boolean" },
|
||||
data: { type: "object" }
|
||||
},
|
||||
required: ["success"]
|
||||
)
|
||||
end
|
||||
```
|
||||
|
||||
MCP spec for the [Output Schema](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema) specifies that:
|
||||
|
||||
- **Server Validation**: Servers MUST provide structured results that conform to the output schema
|
||||
- **Client Validation**: Clients SHOULD validate structured results against the output schema
|
||||
- **Better Integration**: Enables strict schema validation, type information, and improved developer experience
|
||||
- **Backward Compatibility**: Tools returning structured content SHOULD also include serialized JSON in a TextContent block
|
||||
|
||||
The output schema follows standard JSON Schema format and helps ensure consistent data exchange between MCP servers and clients.
|
||||
|
||||
### Prompts
|
||||
|
||||
MCP spec includes [Prompts](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts), which enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs.
|
||||
|
|
@ -755,7 +859,7 @@ The client provides a wrapper class for tools returned by the server:
|
|||
|
||||
- `MCP::Client::Tool` - Represents a single tool with its metadata
|
||||
|
||||
This class provide easy access to tool properties like name, description, and input schema.
|
||||
This class provides easy access to tool properties like name, description, input schema, and output schema.
|
||||
|
||||
## Releases
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue