Merge pull request #342 from koic/json_schema_2020_12

Advertise JSON Schema 2020-12 dialect on emitted tool schemas
This commit is contained in:
Koichi ITO 2026-05-13 10:38:26 +09:00 • committed by GitHub
commit 9d2fdd02ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 196 additions and 22 deletions

View file

@ -263,7 +263,9 @@ module MCP
assert_equal "test_tool", result[:tools][0][:name]
assert_equal "Test tool", result[:tools][0][:title]
assert_equal "A test tool", result[:tools][0][:description]
assert_equal({ type: "object" }, result[:tools][0][:inputSchema])
assert_equal(
{ "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object" }, result[:tools][0][:inputSchema]
)
assert_equal({ foo: "bar" }, result[:tools][0][:_meta])
assert_instrumentation_data({ method: "tools/list" })
end
@ -284,6 +286,24 @@ module MCP
assert_equal({ foo: "bar" }, result[:tools][0][:_meta])
end
test "#handle tools/list emits 2020-12 $schema on inputSchema and outputSchema" do
tool_with_output = Tool.define(
name: "tool_with_output",
description: "tool with output schema",
input_schema: { properties: { msg: { type: "string" } } },
output_schema: { properties: { result: { type: "string" } } },
) do
Tool::Response.new([{ type: "text", content: "OK" }])
end
server = Server.new(name: "test_server", tools: [tool_with_output])
response = server.handle({ jsonrpc: "2.0", method: "tools/list", id: 1 })
tool = response[:result][:tools][0]
assert_equal "https://json-schema.org/draft/2020-12/schema", tool[:inputSchema][:"$schema"]
assert_equal "https://json-schema.org/draft/2020-12/schema", tool[:outputSchema][:"$schema"]
end
test "#handle tools/call executes tool and returns result" do
tool_name = "test_tool"
tool_args = { arg: "value" }

View file

@ -13,7 +13,12 @@ module MCP
test "to_h returns a hash representation of the input schema" do
input_schema = InputSchema.new(properties: { message: { type: "string" } }, required: ["message"])
assert_equal(
{ type: "object", properties: { message: { type: "string" } }, required: ["message"] },
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { message: { type: "string" } },
required: ["message"],
},
input_schema.to_h,
)
end
@ -21,11 +26,52 @@ module MCP
test "to_h returns a hash representation of the input schema with additionalProperties set to false" do
input_schema = InputSchema.new(properties: { message: { type: "string" } }, required: ["message"], additionalProperties: false)
assert_equal(
{ type: "object", properties: { message: { type: "string" } }, required: ["message"], additionalProperties: false },
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { message: { type: "string" } },
required: ["message"],
additionalProperties: false,
},
input_schema.to_h,
)
end
test "to_h preserves user-supplied $schema dialect" do
input_schema = InputSchema.new(
"$schema": "https://json-schema.org/draft/2019-09/schema",
properties: { message: { type: "string" } },
)
assert_equal "https://json-schema.org/draft/2019-09/schema", input_schema.to_h[:"$schema"]
end
test "validate_arguments works when user supplies a 2020-12 $schema" do
input_schema = InputSchema.new(
"$schema": "https://json-schema.org/draft/2020-12/schema",
properties: { foo: { type: "string" } },
required: ["foo"],
)
assert_nil(input_schema.validate_arguments(foo: "bar"))
assert_raises(InputSchema::ValidationError) do
input_schema.validate_arguments({ foo: 123 })
end
end
test "to_h preserves user-supplied $schema given via string key" do
# The initializer normalizes input through `JSON.parse(...,
# symbolize_names: true)`, so a string-keyed `"$schema"` should
# arrive at `schema_for_validation` the same as a symbol-keyed one.
input_schema = InputSchema.new(
{
"$schema" => "https://json-schema.org/draft/2020-12/schema",
"properties" => { "foo" => { "type" => "string" } },
"required" => ["foo"],
},
)
assert_equal "https://json-schema.org/draft/2020-12/schema", input_schema.to_h[:"$schema"]
assert_nil(input_schema.validate_arguments(foo: "bar"))
end
test "missing_required_arguments returns an array of missing required arguments" do
input_schema = InputSchema.new(properties: { message: { type: "string" } }, required: ["message"])
assert_equal ["message"], input_schema.missing_required_arguments({})
@ -38,7 +84,15 @@ module MCP
test "valid schema initialization" do
schema = InputSchema.new(properties: { foo: { type: "string" } }, required: ["foo"])
assert_equal({ type: "object", properties: { foo: { type: "string" } }, required: ["foo"] }, schema.to_h)
assert_equal(
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { foo: { type: "string" } },
required: ["foo"],
},
schema.to_h,
)
end
test "invalid schema raises argument error" do

View file

@ -8,11 +8,38 @@ module MCP
test "to_h returns a hash representation of the output schema" do
output_schema = OutputSchema.new(properties: { result: { type: "string" } }, required: ["result"])
assert_equal(
{ type: "object", properties: { result: { type: "string" } }, required: ["result"] },
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { result: { type: "string" } },
required: ["result"],
},
output_schema.to_h,
)
end
test "to_h preserves user-supplied $schema dialect" do
output_schema = OutputSchema.new(
"$schema": "https://json-schema.org/draft/2019-09/schema",
properties: { result: { type: "string" } },
)
assert_equal "https://json-schema.org/draft/2019-09/schema", output_schema.to_h[:"$schema"]
end
test "validate_result works when user supplies a 2020-12 $schema" do
output_schema = OutputSchema.new(
"$schema": "https://json-schema.org/draft/2020-12/schema",
properties: { result: { type: "string" } },
required: ["result"],
)
assert_nothing_raised do
output_schema.validate_result({ result: "success" })
end
assert_raises(OutputSchema::ValidationError) do
output_schema.validate_result({ result: 123 })
end
end
test "validate_result validates result against the schema" do
output_schema = OutputSchema.new(properties: { result: { type: "string" } }, required: ["result"])
assert_nothing_raised do
@ -57,7 +84,15 @@ module MCP
test "valid schema initialization" do
schema = OutputSchema.new(properties: { foo: { type: "string" } }, required: ["foo"])
assert_equal({ type: "object", properties: { foo: { type: "string" } }, required: ["foo"] }, schema.to_h)
assert_equal(
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { foo: { type: "string" } },
required: ["foo"],
},
schema.to_h,
)
end
test "invalid schema raises argument error" do
@ -136,7 +171,10 @@ module MCP
test "empty schema is valid" do
schema = OutputSchema.new
assert_equal({ type: "object" }, schema.to_h)
assert_equal(
{ "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object" },
schema.to_h,
)
end
test "validates complex nested schemas" do
@ -187,6 +225,7 @@ module MCP
})
assert_equal(
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "array",
items: {
properties: { foo: { type: "string" } },

View file

@ -33,7 +33,7 @@ module MCP
title: "Mock Tool",
description: "a mock tool for testing",
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
inputSchema: { type: "object" },
inputSchema: { "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object" },
}
tool = Tool.define(
name: "mock_tool",
@ -109,7 +109,15 @@ module MCP
tool = MockTool
assert_equal "my_mock_tool", tool.name_value
assert_equal "a mock tool for testing", tool.description
assert_equal({ type: "object", properties: { message: { type: "string" } }, required: ["message"] }, tool.input_schema.to_h)
assert_equal(
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { message: { type: "string" } },
required: ["message"],
},
tool.input_schema.to_h,
)
end
test "defaults to class name as tool name" do
@ -126,7 +134,7 @@ module MCP
tool = NoInputSchemaTool
expected = { type: "object" }
expected = { "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object" }
assert_equal expected, tool.input_schema.to_h
end
@ -137,7 +145,12 @@ module MCP
tool = InputSchemaTool
expected = { type: "object", properties: { message: { type: "string" } }, required: ["message"] }
expected = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { message: { type: "string" } },
required: ["message"],
}
assert_equal expected, tool.input_schema.to_h
end
@ -342,8 +355,13 @@ module MCP
title: "Mock Tool",
description: "a mock tool for testing",
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
inputSchema: { type: "object" },
outputSchema: { type: "object", properties: { result: { type: "string" } }, required: ["result"] },
inputSchema: { "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object" },
outputSchema: {
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { result: { type: "string" } },
required: ["result"],
},
}
tool = Tool.define(
name: "mock_tool",
@ -376,7 +394,12 @@ module MCP
end
tool = HashOutputSchemaTool
expected = { type: "object", properties: { result: { type: "string" } }, required: ["result"] }
expected = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { result: { type: "string" } },
required: ["result"],
}
assert_equal expected, tool.output_schema.to_h
end
@ -386,7 +409,12 @@ module MCP
end
tool = OutputSchemaObjectTool
expected = { type: "object", properties: { result: { type: "string" } }, required: ["result"] }
expected = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { result: { type: "string" } },
required: ["result"],
}
assert_equal expected, tool.output_schema.to_h
end
@ -436,7 +464,12 @@ module MCP
assert_equal "mock_tool", tool.name_value
assert_equal "a mock tool for testing", tool.description
assert_instance_of Tool::OutputSchema, tool.output_schema
expected_output_schema = { type: "object", properties: { result: { type: "string" } }, required: ["result"] }
expected_output_schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { result: { type: "string" } },
required: ["result"],
}
assert_equal expected_output_schema, tool.output_schema.to_h
end
@ -458,10 +491,20 @@ module MCP
assert_equal "test_tool_with_output", tool.name_value
assert_equal "a test tool with output schema", tool.description
expected_input = { type: "object", properties: { message: { type: "string" } }, required: ["message"] }
expected_input = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { message: { type: "string" } },
required: ["message"],
}
assert_equal expected_input, tool.input_schema.to_h
expected_output = { type: "object", properties: { result: { type: "string" }, success: { type: "boolean" } }, required: ["result", "success"] }
expected_output = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { result: { type: "string" }, success: { type: "boolean" } },
required: ["result", "success"],
}
assert_equal expected_output, tool.output_schema.to_h
end