-
Notifications
You must be signed in to change notification settings - Fork 51
Add basic http client support #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jcat4
wants to merge
17
commits into
modelcontextprotocol:main
Choose a base branch
from
jcat4:add-basic-http-client-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,080
−184
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
4e4d1cb
refactor cdoe in prep for client support
jcat4 245d647
remove gem
jcat4 c258684
removed comments
jcat4 5bd5d25
fix namespacing
jcat4 f5a4292
drop unnecsessary change
jcat4 fad37eb
remove DS_Store
jcat4 cecd7e3
add original spec files code back
jcat4 c3a4b80
fix imports
jcat4 c780241
remove extra require statements
jcat4 477b007
move resource stuff
jcat4 29771c5
move and fix some tests
jcat4 9e30a0a
anotha fix
jcat4 c5b325e
Add basic HTTP client support
jcat4 43d4dd0
exit preview version
jcat4 d8e1caf
add some client docs
jcat4 d1e7a83
add more robust error handling
jcat4 e72bcfa
Add basic HTTP client support
jcat4 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,6 @@ | |
/spec/reports/ | ||
/tmp/ | ||
Gemfile.lock | ||
|
||
# Mac stuff | ||
.DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# frozen_string_literal: true | ||
|
||
# require "json_rpc_handler" | ||
# require_relative "shared/instrumentation" | ||
# require_relative "shared/methods" | ||
|
||
module ModelContextProtocol | ||
module Client | ||
# Can be made an abstract class if we need shared behavior | ||
|
||
class RequestHandlerError < StandardError | ||
attr_reader :error_type, :original_error, :request | ||
|
||
def initialize(message, request, error_type: :internal_error, original_error: nil) | ||
super(message) | ||
@request = request | ||
@error_type = error_type | ||
@original_error = original_error | ||
end | ||
end | ||
end | ||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# frozen_string_literal: true | ||
|
||
module ModelContextProtocol | ||
module Client | ||
class Http | ||
DEFAULT_VERSION = "0.1.0" | ||
|
||
attr_reader :url, :version | ||
|
||
def initialize(url:, version: DEFAULT_VERSION, headers: {}) | ||
@url = url | ||
@version = version | ||
@headers = headers | ||
end | ||
|
||
def tools | ||
response = make_request(method: "tools/list").body | ||
|
||
::ModelContextProtocol::Client::Tools.new(response) | ||
end | ||
|
||
def call_tool(tool:, input:) | ||
response = make_request( | ||
method: "tools/call", | ||
params: { name: tool.name, arguments: input }, | ||
).body | ||
|
||
response.dig("result", "content", 0, "text") | ||
end | ||
|
||
private | ||
|
||
attr_reader :headers | ||
|
||
def client | ||
@client ||= Faraday.new(url) do |faraday| | ||
faraday.request(:json) | ||
faraday.response(:json) | ||
faraday.response(:raise_error) | ||
|
||
headers.each do |key, value| | ||
faraday.headers[key] = value | ||
end | ||
end | ||
end | ||
|
||
def make_request(method:, params: nil) | ||
client.post( | ||
"", | ||
{ | ||
jsonrpc: "2.0", | ||
id: request_id, | ||
method:, | ||
params:, | ||
mcp: { jsonrpc: "2.0", id: request_id, method:, params: }.compact, | ||
}.compact, | ||
) | ||
rescue Faraday::BadRequestError => e | ||
raise RequestHandlerError.new( | ||
"The #{method} request is invalid", | ||
{ method:, params: }, | ||
error_type: :bad_request, | ||
original_error: e, | ||
) | ||
rescue Faraday::UnauthorizedError => e | ||
raise RequestHandlerError.new( | ||
"You are unauthorized to make #{method} requests", | ||
{ method:, params: }, | ||
error_type: :unauthorized, | ||
original_error: e, | ||
) | ||
rescue Faraday::ForbiddenError => e | ||
raise RequestHandlerError.new( | ||
"You are forbidden to make #{method} requests", | ||
{ method:, params: }, | ||
error_type: :forbidden, | ||
original_error: e, | ||
) | ||
rescue Faraday::ResourceNotFound => e | ||
raise RequestHandlerError.new( | ||
"The #{method} request is not found", | ||
{ method:, params: }, | ||
error_type: :not_found, | ||
original_error: e, | ||
) | ||
rescue Faraday::UnprocessableEntityError => e | ||
raise RequestHandlerError.new( | ||
"The #{method} request is unprocessable", | ||
{ method:, params: }, | ||
error_type: :unprocessable_entity, | ||
original_error: e, | ||
) | ||
rescue Faraday::Error => e # Catch-all | ||
raise RequestHandlerError.new( | ||
"Internal error handling #{method} request", | ||
{ method:, params: }, | ||
error_type: :internal_error, | ||
original_error: e, | ||
) | ||
end | ||
|
||
def request_id | ||
SecureRandom.uuid_v7 | ||
end | ||
end | ||
end | ||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# typed: false | ||
# frozen_string_literal: true | ||
|
||
module ModelContextProtocol | ||
module Client | ||
class Tool | ||
attr_reader :payload | ||
|
||
def initialize(payload) | ||
@payload = payload | ||
end | ||
|
||
def name | ||
payload["name"] | ||
end | ||
|
||
def description | ||
payload["description"] | ||
end | ||
|
||
def input_schema | ||
payload["inputSchema"] | ||
end | ||
end | ||
end | ||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# typed: false | ||
# frozen_string_literal: true | ||
|
||
module ModelContextProtocol | ||
module Client | ||
class Tools | ||
include Enumerable | ||
|
||
attr_reader :response | ||
|
||
def initialize(response) | ||
@response = response | ||
end | ||
|
||
def each(&block) | ||
tools.each(&block) | ||
end | ||
|
||
def all | ||
tools | ||
end | ||
|
||
private | ||
|
||
def tools | ||
@tools ||= @response.dig("result", "tools")&.map { |tool| Tool.new(tool) } || [] | ||
end | ||
end | ||
end | ||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if I'm missing something, but what about other types of tool responses? Should we assume that the text property needs to be used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true.
text
is not a mandatory content chunk to have.