ruby-mcp-client 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +0 -16
- data/lib/mcp_client/server_factory.rb +0 -9
- data/lib/mcp_client/version.rb +1 -1
- data/lib/mcp_client.rb +0 -1
- metadata +1 -2
- data/lib/mcp_client/server_http.rb +0 -121
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 233c83227145cb76167e75784b7eaecef56828743f65f6256c84062bb2290b1e
|
4
|
+
data.tar.gz: 4fb49b0cc82f5bd2b07d15ec200da4f9dced0fce52ddfacd4860a5a689152328
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdd2b7223f25e4e8516f9bad648854a8e935b823d269762d769a545571960041041082f861a85e559a637e00bb9357541548bd87155bbe9df490c501fb755ade
|
7
|
+
data.tar.gz: 3aef9c1fd10b846e46cc183c072443946a5aa39bfae43245949204e15e89a132df676af927cdabd4cae9c65e4052d220d4012bf0dadaffeb988cddf2a5ab7cfc
|
data/README.md
CHANGED
@@ -30,7 +30,6 @@ via different transport mechanisms:
|
|
30
30
|
|
31
31
|
- **Standard I/O**: Local processes implementing the MCP protocol
|
32
32
|
- **Server-Sent Events (SSE)**: Remote MCP servers over HTTP with streaming support
|
33
|
-
- **HTTP JSON-RPC**: Remote MCP servers over standard HTTP
|
34
33
|
|
35
34
|
The core client resides in `MCPClient::Client` and provides helper methods for integrating
|
36
35
|
with popular AI services with built-in conversions:
|
@@ -53,12 +52,6 @@ client = MCPClient.create_client(
|
|
53
52
|
MCPClient.sse_config(
|
54
53
|
base_url: 'https://api.example.com/sse',
|
55
54
|
headers: { 'Authorization' => 'Bearer YOUR_TOKEN' },
|
56
|
-
read_timeout: 30 # Optional timeout in seconds (default: 30)
|
57
|
-
),
|
58
|
-
# Remote HTTP JSON-RPC server
|
59
|
-
MCPClient.http_config(
|
60
|
-
base_url: 'https://api.example.com/jsonrpc',
|
61
|
-
headers: { 'Authorization' => 'Bearer YOUR_TOKEN' },
|
62
55
|
read_timeout: 30, # Optional timeout in seconds (default: 30)
|
63
56
|
retries: 3, # Optional number of retry attempts (default: 0)
|
64
57
|
retry_backoff: 1 # Optional backoff delay in seconds (default: 1)
|
@@ -205,15 +198,6 @@ The SSE client implementation provides these key features:
|
|
205
198
|
- **JSON-RPC over SSE**: Full implementation of JSON-RPC 2.0 over SSE transport
|
206
199
|
- **Streaming support**: Native streaming for real-time updates
|
207
200
|
|
208
|
-
### HTTP JSON-RPC Implementation
|
209
|
-
|
210
|
-
The HTTP client implementation provides these key features:
|
211
|
-
|
212
|
-
- **Resilient connection handling**: Manages HTTP/HTTPS connections with configurable timeouts
|
213
|
-
- **Retry mechanism**: Configurable retry attempts with exponential backoff for transient errors
|
214
|
-
- **Error handling**: Comprehensive error handling for network issues, timeouts, and malformed responses
|
215
|
-
- **JSON-RPC over HTTP**: Standard JSON-RPC 2.0 implementation
|
216
|
-
|
217
201
|
## Requirements
|
218
202
|
|
219
203
|
- Ruby >= 2.7.0
|
@@ -19,15 +19,6 @@ module MCPClient
|
|
19
19
|
retry_backoff: config[:retry_backoff] || 1,
|
20
20
|
logger: config[:logger]
|
21
21
|
)
|
22
|
-
when 'http'
|
23
|
-
MCPClient::ServerHTTP.new(
|
24
|
-
base_url: config[:base_url],
|
25
|
-
headers: config[:headers] || {},
|
26
|
-
read_timeout: config[:read_timeout] || 30,
|
27
|
-
retries: config[:retries] || 0,
|
28
|
-
retry_backoff: config[:retry_backoff] || 1,
|
29
|
-
logger: config[:logger]
|
30
|
-
)
|
31
22
|
else
|
32
23
|
raise ArgumentError, "Unknown server type: #{config[:type]}"
|
33
24
|
end
|
data/lib/mcp_client/version.rb
CHANGED
data/lib/mcp_client.rb
CHANGED
@@ -6,7 +6,6 @@ require_relative 'mcp_client/tool'
|
|
6
6
|
require_relative 'mcp_client/server_base'
|
7
7
|
require_relative 'mcp_client/server_stdio'
|
8
8
|
require_relative 'mcp_client/server_sse'
|
9
|
-
require_relative 'mcp_client/server_http'
|
10
9
|
require_relative 'mcp_client/server_factory'
|
11
10
|
require_relative 'mcp_client/client'
|
12
11
|
require_relative 'mcp_client/version'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-mcp-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Szymon Kurcab
|
@@ -81,7 +81,6 @@ files:
|
|
81
81
|
- lib/mcp_client/errors.rb
|
82
82
|
- lib/mcp_client/server_base.rb
|
83
83
|
- lib/mcp_client/server_factory.rb
|
84
|
-
- lib/mcp_client/server_http.rb
|
85
84
|
- lib/mcp_client/server_sse.rb
|
86
85
|
- lib/mcp_client/server_stdio.rb
|
87
86
|
- lib/mcp_client/tool.rb
|
@@ -1,121 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'uri'
|
4
|
-
require 'net/http'
|
5
|
-
require 'json'
|
6
|
-
require 'openssl'
|
7
|
-
require 'logger'
|
8
|
-
|
9
|
-
module MCPClient
|
10
|
-
# Implementation of MCP server over HTTP JSON-RPC
|
11
|
-
class ServerHTTP < ServerBase
|
12
|
-
attr_reader :base_url, :headers, :read_timeout, :max_retries, :retry_backoff, :logger
|
13
|
-
|
14
|
-
# @param base_url [String] The base URL of the MCP HTTP server
|
15
|
-
# @param headers [Hash] HTTP headers to include in requests
|
16
|
-
# @param read_timeout [Integer] Read timeout in seconds
|
17
|
-
# @param retries [Integer] number of retry attempts on transient errors
|
18
|
-
# @param retry_backoff [Numeric] base delay in seconds for exponential backoff
|
19
|
-
# @param logger [Logger, nil] optional logger
|
20
|
-
def initialize(base_url:, headers: {}, read_timeout: 30, retries: 0, retry_backoff: 1, logger: nil)
|
21
|
-
super()
|
22
|
-
@base_url = base_url
|
23
|
-
@headers = headers
|
24
|
-
@read_timeout = read_timeout
|
25
|
-
@max_retries = retries
|
26
|
-
@retry_backoff = retry_backoff
|
27
|
-
@logger = logger || Logger.new($stdout, level: Logger::WARN)
|
28
|
-
@request_id = 0
|
29
|
-
end
|
30
|
-
|
31
|
-
# List available tools
|
32
|
-
# @return [Array<MCPClient::Tool>]
|
33
|
-
def list_tools
|
34
|
-
request_json = jsonrpc_request('tools/list', {})
|
35
|
-
result = send_request(request_json)
|
36
|
-
(result['tools'] || []).map { |td| MCPClient::Tool.from_json(td) }
|
37
|
-
rescue MCPClient::Errors::MCPError
|
38
|
-
raise
|
39
|
-
rescue StandardError => e
|
40
|
-
raise MCPClient::Errors::ToolCallError, "Error listing tools: #{e.message}"
|
41
|
-
end
|
42
|
-
|
43
|
-
# Call a tool with given parameters
|
44
|
-
# @param tool_name [String]
|
45
|
-
# @param parameters [Hash]
|
46
|
-
# @return [Object] result of invocation
|
47
|
-
def call_tool(tool_name, parameters)
|
48
|
-
request_json = jsonrpc_request('tools/call', { 'name' => tool_name, 'arguments' => parameters })
|
49
|
-
send_request(request_json)
|
50
|
-
rescue MCPClient::Errors::MCPError
|
51
|
-
raise
|
52
|
-
rescue StandardError => e
|
53
|
-
raise MCPClient::Errors::ToolCallError, "Error calling tool '#{tool_name}': #{e.message}"
|
54
|
-
end
|
55
|
-
|
56
|
-
# Streaming is not supported over simple HTTP transport; fallback to single response
|
57
|
-
# @param tool_name [String]
|
58
|
-
# @param parameters [Hash]
|
59
|
-
# @return [Enumerator]
|
60
|
-
def call_tool_streaming(tool_name, parameters)
|
61
|
-
Enumerator.new do |yielder|
|
62
|
-
yielder << call_tool(tool_name, parameters)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def jsonrpc_request(method, params)
|
69
|
-
@request_id += 1
|
70
|
-
{
|
71
|
-
'jsonrpc' => '2.0',
|
72
|
-
'id' => @request_id,
|
73
|
-
'method' => method,
|
74
|
-
'params' => params
|
75
|
-
}
|
76
|
-
end
|
77
|
-
|
78
|
-
def send_request(request)
|
79
|
-
attempts = 0
|
80
|
-
begin
|
81
|
-
attempts += 1
|
82
|
-
uri = URI.parse(base_url)
|
83
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
84
|
-
if uri.scheme == 'https'
|
85
|
-
http.use_ssl = true
|
86
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
87
|
-
end
|
88
|
-
http.open_timeout = 10
|
89
|
-
http.read_timeout = read_timeout
|
90
|
-
|
91
|
-
@logger.debug("Sending HTTP JSONRPC request: #{request.to_json}")
|
92
|
-
response = http.post(uri.path, request.to_json, default_headers)
|
93
|
-
@logger.debug("Received HTTP response: #{response.code} #{response.body}")
|
94
|
-
|
95
|
-
unless response.is_a?(Net::HTTPSuccess)
|
96
|
-
raise MCPClient::Errors::ServerError, "Server returned error: #{response.code} #{response.message}"
|
97
|
-
end
|
98
|
-
|
99
|
-
data = JSON.parse(response.body)
|
100
|
-
raise MCPClient::Errors::ServerError, data['error']['message'] if data['error']
|
101
|
-
|
102
|
-
data['result']
|
103
|
-
rescue MCPClient::Errors::ServerError, MCPClient::Errors::TransportError, IOError, Timeout::Error => e
|
104
|
-
raise unless attempts <= max_retries
|
105
|
-
|
106
|
-
delay = retry_backoff * (2**(attempts - 1))
|
107
|
-
@logger.debug("Retry attempt #{attempts} after error: #{e.message}, sleeping #{delay}s")
|
108
|
-
sleep(delay)
|
109
|
-
retry
|
110
|
-
rescue JSON::ParserError => e
|
111
|
-
raise MCPClient::Errors::TransportError, "Invalid JSON response: #{e.message}"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def default_headers
|
116
|
-
h = headers.dup
|
117
|
-
h['Content-Type'] = 'application/json'
|
118
|
-
h
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|