ruby-sdk/test/mcp/client/http_test.rb

212 lines
6.1 KiB
Ruby

# frozen_string_literal: true
require "test_helper"
require "faraday"
require "webmock/minitest"
require "mcp/client/http"
require "mcp/client/tool"
require "mcp/client"
module MCP
class Client
class HTTPTest < Minitest::Test
def test_raises_load_error_when_faraday_not_available
client = HTTP.new(url: url)
# simulate Faraday not being available
HTTP.any_instance.stubs(:require).with("faraday").raises(LoadError, "cannot load such file -- faraday")
error = assert_raises(LoadError) do
# This should immediately try to instantiate the client and fail
client.send_request(request: {})
end
assert_includes(error.message, "The 'faraday' gem is required to use the MCP client HTTP transport")
assert_includes(error.message, "Add it to your Gemfile: gem 'faraday', '>= 2.0'")
end
def test_headers_are_added_to_the_request
headers = { "Authorization" => "Bearer token" }
client = HTTP.new(url: url, headers: headers)
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(
headers: {
"Authorization" => "Bearer token",
"Content-Type" => "application/json",
},
body: request.to_json,
)
.to_return(
status: 200,
headers: { "Content-Type" => "application/json" },
body: { result: { tools: [] } }.to_json,
)
# The test passes if the request is made with the correct headers
# If headers are wrong, the stub_request won't match and will raise
client.send_request(request: request)
end
def test_send_request_returns_faraday_response
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(body: request.to_json)
.to_return(
status: 200,
headers: { "Content-Type" => "application/json" },
body: { result: { tools: [] } }.to_json,
)
response = client.send_request(request: request)
assert_instance_of(Hash, response)
assert_equal({ "result" => { "tools" => [] } }, response)
end
def test_send_request_raises_bad_request_error
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(body: request.to_json)
.to_return(status: 400)
error = assert_raises(RequestHandlerError) do
client.send_request(request: request)
end
assert_equal("The tools/list request is invalid", error.message)
assert_equal(:bad_request, error.error_type)
assert_equal({ method: "tools/list", params: nil }, error.request)
end
def test_send_request_raises_unauthorized_error
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(body: request.to_json)
.to_return(status: 401)
error = assert_raises(RequestHandlerError) do
client.send_request(request: request)
end
assert_equal("You are unauthorized to make tools/list requests", error.message)
assert_equal(:unauthorized, error.error_type)
assert_equal({ method: "tools/list", params: nil }, error.request)
end
def test_send_request_raises_forbidden_error
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(body: request.to_json)
.to_return(status: 403)
error = assert_raises(RequestHandlerError) do
client.send_request(request: request)
end
assert_equal("You are forbidden to make tools/list requests", error.message)
assert_equal(:forbidden, error.error_type)
assert_equal({ method: "tools/list", params: nil }, error.request)
end
def test_send_request_raises_not_found_error
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(body: request.to_json)
.to_return(status: 404)
error = assert_raises(RequestHandlerError) do
client.send_request(request: request)
end
assert_equal("The tools/list request is not found", error.message)
assert_equal(:not_found, error.error_type)
assert_equal({ method: "tools/list", params: nil }, error.request)
end
def test_send_request_raises_unprocessable_entity_error
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(body: request.to_json)
.to_return(status: 422)
error = assert_raises(RequestHandlerError) do
client.send_request(request: request)
end
assert_equal("The tools/list request is unprocessable", error.message)
assert_equal(:unprocessable_entity, error.error_type)
assert_equal({ method: "tools/list", params: nil }, error.request)
end
def test_send_request_raises_internal_error
request = {
jsonrpc: "2.0",
id: "test_id",
method: "tools/list",
}
stub_request(:post, url)
.with(body: request.to_json)
.to_return(status: 500)
error = assert_raises(RequestHandlerError) do
client.send_request(request: request)
end
assert_equal("Internal error handling tools/list request", error.message)
assert_equal(:internal_error, error.error_type)
assert_equal({ method: "tools/list", params: nil }, error.request)
end
private
def stub_request(method, url)
WebMock.stub_request(method, url)
end
def url
"http://example.com"
end
def client
@client ||= HTTP.new(url: url)
end
end
end
end