ruby-mcp-client 0.6.1 → 0.7.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 +245 -10
- data/lib/mcp_client/client.rb +1 -1
- data/lib/mcp_client/config_parser.rb +73 -1
- data/lib/mcp_client/http_transport_base.rb +246 -0
- data/lib/mcp_client/json_rpc_common.rb +8 -10
- data/lib/mcp_client/server_factory.rb +42 -0
- data/lib/mcp_client/server_http/json_rpc_transport.rb +27 -0
- data/lib/mcp_client/server_http.rb +329 -0
- data/lib/mcp_client/server_sse/json_rpc_transport.rb +5 -5
- data/lib/mcp_client/server_sse/reconnect_monitor.rb +2 -1
- data/lib/mcp_client/server_sse.rb +16 -8
- data/lib/mcp_client/server_stdio/json_rpc_transport.rb +1 -1
- data/lib/mcp_client/server_stdio.rb +5 -7
- data/lib/mcp_client/server_streamable_http/json_rpc_transport.rb +76 -0
- data/lib/mcp_client/server_streamable_http.rb +338 -0
- data/lib/mcp_client/tool.rb +4 -3
- data/lib/mcp_client/version.rb +4 -1
- data/lib/mcp_client.rb +59 -2
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f797750d8f5a6f1b742411418f77c8352cc89e8879e77ba51bcb7257f9de6db
|
4
|
+
data.tar.gz: 104e26ec1506bebae21b5b4e70508db0159d3ef8b9b69148720fed202633d7e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20aa894d62ed87e70d50f92b7ce4b60839855f7ce9697f476c7822dcf99167f62030bfbd90f1d5c50d535cc78a075e35f25086e0b3f09d57c3d0bd9f4c8ff35e
|
7
|
+
data.tar.gz: dd252c97f599834a3f1e4f9a3acf0c7e98489c247c4601a3d038f8af646c431ef0245ed00b33cb61ea387c296ee5c63c99a8487bf8b9b3ed68be5bfd4e5a5f55
|
data/README.md
CHANGED
@@ -30,6 +30,8 @@ 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**: Remote MCP servers over HTTP request/response (non-streaming Streamable HTTP)
|
34
|
+
- **Streamable HTTP**: Remote MCP servers that use HTTP POST with Server-Sent Event formatted responses
|
33
35
|
|
34
36
|
The core client resides in `MCPClient::Client` and provides helper methods for integrating
|
35
37
|
with popular AI services with built-in conversions:
|
@@ -56,7 +58,7 @@ client = MCPClient.create_client(
|
|
56
58
|
MCPClient.sse_config(
|
57
59
|
base_url: 'https://api.example.com/sse',
|
58
60
|
headers: { 'Authorization' => 'Bearer YOUR_TOKEN' },
|
59
|
-
name: '
|
61
|
+
name: 'sse_api', # Optional name for this server
|
60
62
|
read_timeout: 30, # Optional timeout in seconds (default: 30)
|
61
63
|
ping: 10, # Optional ping interval in seconds of inactivity (default: 10)
|
62
64
|
# Connection closes automatically after inactivity (2.5x ping interval)
|
@@ -64,7 +66,19 @@ client = MCPClient.create_client(
|
|
64
66
|
retry_backoff: 1, # Optional backoff delay in seconds (default: 1)
|
65
67
|
# Native support for tool streaming via call_tool_streaming method
|
66
68
|
logger: Logger.new($stdout, level: Logger::INFO) # Optional logger for this server
|
67
|
-
)
|
69
|
+
),
|
70
|
+
# Remote HTTP server (request/response without streaming)
|
71
|
+
MCPClient.http_config(
|
72
|
+
base_url: 'https://api.example.com',
|
73
|
+
endpoint: '/rpc', # Optional JSON-RPC endpoint path (default: '/rpc')
|
74
|
+
headers: { 'Authorization' => 'Bearer YOUR_TOKEN' },
|
75
|
+
name: 'http_api', # Optional name for this server
|
76
|
+
read_timeout: 30, # Optional timeout in seconds (default: 30)
|
77
|
+
retries: 3, # Optional number of retry attempts (default: 3)
|
78
|
+
retry_backoff: 1, # Optional backoff delay in seconds (default: 1)
|
79
|
+
logger: Logger.new($stdout, level: Logger::INFO) # Optional logger for this server
|
80
|
+
)
|
81
|
+
],
|
68
82
|
# Optional logger for the client and all servers without explicit loggers
|
69
83
|
logger: Logger.new($stdout, level: Logger::WARN)
|
70
84
|
)
|
@@ -78,11 +92,12 @@ client = MCPClient.create_client(
|
|
78
92
|
# MCP server configuration JSON format can be:
|
79
93
|
# 1. A single server object:
|
80
94
|
# { "type": "sse", "url": "http://example.com/sse" }
|
95
|
+
# { "type": "http", "url": "http://example.com", "endpoint": "/rpc" }
|
81
96
|
# 2. An array of server objects:
|
82
|
-
# [{ "type": "stdio", "command": "npx server" }, { "type": "sse", "url": "http://..." }]
|
97
|
+
# [{ "type": "stdio", "command": "npx server" }, { "type": "sse", "url": "http://..." }, { "type": "http", "url": "http://..." }]
|
83
98
|
# 3. An object with "mcpServers" key containing named servers:
|
84
|
-
# { "mcpServers": { "server1": { "type": "sse", "url": "http://..." } } }
|
85
|
-
# Note: When using this format, server1 will be accessible by name
|
99
|
+
# { "mcpServers": { "server1": { "type": "sse", "url": "http://..." }, "server2": { "type": "http", "url": "http://..." } } }
|
100
|
+
# Note: When using this format, server1/server2 will be accessible by name
|
86
101
|
|
87
102
|
# List available tools
|
88
103
|
tools = client.list_tools
|
@@ -143,6 +158,114 @@ client.clear_cache
|
|
143
158
|
client.cleanup
|
144
159
|
```
|
145
160
|
|
161
|
+
### HTTP Transport Example
|
162
|
+
|
163
|
+
The HTTP transport provides simple request/response communication with MCP servers:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
require 'mcp_client'
|
167
|
+
require 'logger'
|
168
|
+
|
169
|
+
# Optional logger for debugging
|
170
|
+
logger = Logger.new($stdout)
|
171
|
+
logger.level = Logger::INFO
|
172
|
+
|
173
|
+
# Create an MCP client that connects to an HTTP MCP server
|
174
|
+
http_client = MCPClient.create_client(
|
175
|
+
mcp_server_configs: [
|
176
|
+
MCPClient.http_config(
|
177
|
+
base_url: 'https://api.example.com',
|
178
|
+
endpoint: '/mcp', # JSON-RPC endpoint path
|
179
|
+
headers: {
|
180
|
+
'Authorization' => 'Bearer YOUR_API_TOKEN',
|
181
|
+
'X-Custom-Header' => 'custom-value'
|
182
|
+
},
|
183
|
+
read_timeout: 30, # Timeout in seconds for HTTP requests
|
184
|
+
retries: 3, # Number of retry attempts on transient errors
|
185
|
+
retry_backoff: 1, # Base delay in seconds for exponential backoff
|
186
|
+
logger: logger # Optional logger for debugging HTTP requests
|
187
|
+
)
|
188
|
+
]
|
189
|
+
)
|
190
|
+
|
191
|
+
# List available tools
|
192
|
+
tools = http_client.list_tools
|
193
|
+
|
194
|
+
# Call a tool
|
195
|
+
result = http_client.call_tool('analyze_data', {
|
196
|
+
dataset: 'sales_2024',
|
197
|
+
metrics: ['revenue', 'conversion_rate']
|
198
|
+
})
|
199
|
+
|
200
|
+
# HTTP transport also supports streaming (though implemented as single response)
|
201
|
+
# This provides API compatibility with SSE transport
|
202
|
+
http_client.call_tool_streaming('process_batch', { batch_id: 123 }).each do |result|
|
203
|
+
puts "Processing result: #{result}"
|
204
|
+
end
|
205
|
+
|
206
|
+
# Send custom JSON-RPC requests
|
207
|
+
custom_result = http_client.send_rpc('custom_method', params: { key: 'value' })
|
208
|
+
|
209
|
+
# Send notifications (fire-and-forget)
|
210
|
+
http_client.send_notification('status_update', params: { status: 'processing' })
|
211
|
+
|
212
|
+
# Test connectivity
|
213
|
+
ping_result = http_client.ping
|
214
|
+
puts "Server is responsive: #{ping_result.inspect}"
|
215
|
+
|
216
|
+
# Clean up
|
217
|
+
http_client.cleanup
|
218
|
+
```
|
219
|
+
|
220
|
+
### Streamable HTTP Transport Example
|
221
|
+
|
222
|
+
The Streamable HTTP transport is designed for servers that use HTTP POST requests but return Server-Sent Event formatted responses. This is commonly used by services like Zapier's MCP implementation:
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
require 'mcp_client'
|
226
|
+
require 'logger'
|
227
|
+
|
228
|
+
# Optional logger for debugging
|
229
|
+
logger = Logger.new($stdout)
|
230
|
+
logger.level = Logger::INFO
|
231
|
+
|
232
|
+
# Create an MCP client that connects to a Streamable HTTP MCP server
|
233
|
+
streamable_client = MCPClient.create_client(
|
234
|
+
mcp_server_configs: [
|
235
|
+
MCPClient.streamable_http_config(
|
236
|
+
base_url: 'https://mcp.zapier.com/api/mcp/s/YOUR_SESSION_ID/mcp',
|
237
|
+
headers: {
|
238
|
+
'Authorization' => 'Bearer YOUR_ZAPIER_TOKEN'
|
239
|
+
},
|
240
|
+
read_timeout: 60, # Timeout in seconds for HTTP requests
|
241
|
+
retries: 3, # Number of retry attempts on transient errors
|
242
|
+
retry_backoff: 2, # Base delay in seconds for exponential backoff
|
243
|
+
logger: logger # Optional logger for debugging requests
|
244
|
+
)
|
245
|
+
]
|
246
|
+
)
|
247
|
+
|
248
|
+
# List available tools (server responds with SSE-formatted JSON)
|
249
|
+
tools = streamable_client.list_tools
|
250
|
+
puts "Found #{tools.size} tools:"
|
251
|
+
tools.each { |tool| puts "- #{tool.name}: #{tool.description}" }
|
252
|
+
|
253
|
+
# Call a tool (response will be in SSE format)
|
254
|
+
result = streamable_client.call_tool('google_calendar_find_event', {
|
255
|
+
instructions: 'Find today\'s meetings',
|
256
|
+
calendarid: 'primary'
|
257
|
+
})
|
258
|
+
|
259
|
+
# The client automatically parses SSE responses like:
|
260
|
+
# event: message
|
261
|
+
# data: {"jsonrpc":"2.0","id":1,"result":{"content":[...]}}
|
262
|
+
|
263
|
+
puts "Tool result: #{result.inspect}"
|
264
|
+
|
265
|
+
# Clean up
|
266
|
+
streamable_client.cleanup
|
267
|
+
```
|
268
|
+
|
146
269
|
### Server-Sent Events (SSE) Example
|
147
270
|
|
148
271
|
The SSE transport provides robust connection handling for remote MCP servers:
|
@@ -313,6 +436,15 @@ You can define MCP server configurations in JSON files for easier management:
|
|
313
436
|
"Authorization": "Bearer TOKEN"
|
314
437
|
}
|
315
438
|
},
|
439
|
+
"api_server": {
|
440
|
+
"type": "http",
|
441
|
+
"url": "https://api.example.com",
|
442
|
+
"endpoint": "/mcp",
|
443
|
+
"headers": {
|
444
|
+
"Authorization": "Bearer API_TOKEN",
|
445
|
+
"X-Custom-Header": "value"
|
446
|
+
}
|
447
|
+
},
|
316
448
|
"filesystem": {
|
317
449
|
"type": "stdio",
|
318
450
|
"command": "npx",
|
@@ -346,20 +478,82 @@ client = MCPClient.create_client(server_definition_file: 'path/to/definition.jso
|
|
346
478
|
```
|
347
479
|
|
348
480
|
The JSON format supports:
|
349
|
-
1. A single server object: `{ "type": "sse", "url": "..." }`
|
350
|
-
2. An array of server objects: `[{ "type": "stdio", ... }, { "type": "sse", ... }]`
|
481
|
+
1. A single server object: `{ "type": "sse", "url": "..." }` or `{ "type": "http", "url": "..." }`
|
482
|
+
2. An array of server objects: `[{ "type": "stdio", ... }, { "type": "sse", ... }, { "type": "http", ... }]`
|
351
483
|
3. An object with named servers under `mcpServers` key (as shown above)
|
352
484
|
|
353
485
|
Special configuration options:
|
354
486
|
- `comment` and `description` are reserved keys that are ignored during parsing and can be used for documentation
|
355
|
-
- Server type can be inferred from the presence of either `command` (for stdio) or `url` (for SSE)
|
487
|
+
- Server type can be inferred from the presence of either `command` (for stdio) or `url` (for SSE/HTTP)
|
488
|
+
- For HTTP servers, `endpoint` specifies the JSON-RPC endpoint path (defaults to '/rpc' if not specified)
|
356
489
|
- All string values in arrays (like `args`) are automatically converted to strings
|
357
490
|
|
491
|
+
## Session-Based MCP Protocol Support
|
492
|
+
|
493
|
+
Both HTTP and Streamable HTTP transports now support session-based MCP servers that require session continuity:
|
494
|
+
|
495
|
+
### Session Management Features
|
496
|
+
|
497
|
+
- **Automatic Session Management**: Captures session IDs from `initialize` response headers
|
498
|
+
- **Session Header Injection**: Automatically includes `Mcp-Session-Id` header in subsequent requests
|
499
|
+
- **Session Termination**: Sends HTTP DELETE requests to properly terminate sessions during cleanup
|
500
|
+
- **Session Validation**: Validates session ID format for security (8-128 alphanumeric characters with hyphens/underscores)
|
501
|
+
- **Backward Compatibility**: Works with both session-based and stateless MCP servers
|
502
|
+
- **Session Cleanup**: Properly cleans up session state during connection teardown
|
503
|
+
|
504
|
+
### Resumability and Redelivery (Streamable HTTP)
|
505
|
+
|
506
|
+
The Streamable HTTP transport provides additional resumability features for reliable message delivery:
|
507
|
+
|
508
|
+
- **Event ID Tracking**: Automatically tracks event IDs from SSE responses
|
509
|
+
- **Last-Event-ID Header**: Includes `Last-Event-ID` header in requests for resuming from disconnection points
|
510
|
+
- **Message Replay**: Enables servers to replay missed messages from the last received event
|
511
|
+
- **Connection Recovery**: Maintains message continuity even with unstable network connections
|
512
|
+
|
513
|
+
### Security Features
|
514
|
+
|
515
|
+
Both transports implement security best practices:
|
516
|
+
|
517
|
+
- **URL Validation**: Validates server URLs to ensure only HTTP/HTTPS protocols are used
|
518
|
+
- **Session ID Validation**: Enforces secure session ID formats to prevent malicious injection
|
519
|
+
- **Security Warnings**: Logs warnings for potentially insecure configurations (e.g., 0.0.0.0 binding)
|
520
|
+
- **Header Sanitization**: Properly handles and validates all session-related headers
|
521
|
+
|
522
|
+
### Usage
|
523
|
+
|
524
|
+
The session support is transparent to the user - no additional configuration is required. The client will automatically detect and handle session-based servers by:
|
525
|
+
|
526
|
+
1. **Session Initialization**: Capturing the `Mcp-Session-Id` header from the `initialize` response
|
527
|
+
2. **Session Persistence**: Including this header in all subsequent requests (except `initialize`)
|
528
|
+
3. **Session Termination**: Sending HTTP DELETE request with session ID during cleanup
|
529
|
+
4. **Resumability** (Streamable HTTP): Tracking event IDs and including `Last-Event-ID` for message replay
|
530
|
+
5. **Security Validation**: Validating session IDs and server URLs for security
|
531
|
+
6. **Logging**: Comprehensive logging of session activity for debugging purposes
|
532
|
+
|
533
|
+
Example of automatic session termination:
|
534
|
+
|
535
|
+
```ruby
|
536
|
+
# Session is automatically terminated when client is cleaned up
|
537
|
+
client = MCPClient.create_client(
|
538
|
+
mcp_server_configs: [
|
539
|
+
MCPClient.http_config(base_url: 'https://api.example.com/mcp')
|
540
|
+
]
|
541
|
+
)
|
542
|
+
|
543
|
+
# Use the client...
|
544
|
+
tools = client.list_tools
|
545
|
+
|
546
|
+
# Session automatically terminated with HTTP DELETE request
|
547
|
+
client.cleanup
|
548
|
+
```
|
549
|
+
|
550
|
+
This enables compatibility with MCP servers that maintain state between requests and require session identification.
|
551
|
+
|
358
552
|
## Key Features
|
359
553
|
|
360
554
|
### Client Features
|
361
555
|
|
362
|
-
- **Multiple transports** - Support for
|
556
|
+
- **Multiple transports** - Support for stdio, SSE, HTTP, and Streamable HTTP transports
|
363
557
|
- **Multiple servers** - Connect to multiple MCP servers simultaneously
|
364
558
|
- **Named servers** - Associate names with servers and find/reference them by name
|
365
559
|
- **Server lookup** - Find servers by name using `find_server`
|
@@ -404,6 +598,47 @@ The SSE client implementation provides these key features:
|
|
404
598
|
- **URL normalization**: Consistent URL handling that respects user-provided formats
|
405
599
|
- **Server connectivity check**: Built-in `ping` method to test server connectivity and health
|
406
600
|
|
601
|
+
### HTTP Transport Implementation
|
602
|
+
|
603
|
+
The HTTP transport provides a simpler, stateless communication mechanism for MCP servers:
|
604
|
+
|
605
|
+
- **Request/Response Model**: Standard HTTP request/response cycle for each JSON-RPC call
|
606
|
+
- **JSON-Only Responses**: Accepts only `application/json` responses (no SSE support)
|
607
|
+
- **Session Support**: Automatic session header (`Mcp-Session-Id`) capture and injection for session-based MCP servers
|
608
|
+
- **Session Termination**: Proper session cleanup with HTTP DELETE requests during connection teardown
|
609
|
+
- **Session Validation**: Security validation of session IDs to prevent malicious injection
|
610
|
+
- **Stateless & Stateful**: Supports both stateless servers and session-based servers that require state continuity
|
611
|
+
- **HTTP Headers Support**: Full support for custom headers including authorization, API keys, and other metadata
|
612
|
+
- **Reliable Error Handling**: Comprehensive HTTP status code handling with appropriate error mapping
|
613
|
+
- **Configurable Retries**: Exponential backoff retry logic for transient network failures
|
614
|
+
- **Connection Pooling**: Uses Faraday's connection pooling for efficient HTTP connections
|
615
|
+
- **Timeout Management**: Configurable timeouts for both connection establishment and request completion
|
616
|
+
- **JSON-RPC over HTTP**: Full JSON-RPC 2.0 implementation over HTTP POST requests
|
617
|
+
- **MCP Protocol Compliance**: Supports all standard MCP methods (initialize, tools/list, tools/call)
|
618
|
+
- **Custom RPC Methods**: Send any custom JSON-RPC method or notification
|
619
|
+
- **Thread Safety**: All operations are thread-safe for concurrent usage
|
620
|
+
- **Streaming API Compatibility**: Provides `call_tool_streaming` method for API compatibility (returns single response)
|
621
|
+
- **Graceful Degradation**: Simple fallback behavior when complex features aren't needed
|
622
|
+
|
623
|
+
### Streamable HTTP Transport Implementation
|
624
|
+
|
625
|
+
The Streamable HTTP transport bridges HTTP and Server-Sent Events, designed for servers that use HTTP POST but return SSE-formatted responses:
|
626
|
+
|
627
|
+
- **Hybrid Communication**: HTTP POST requests with Server-Sent Event formatted responses
|
628
|
+
- **SSE Response Parsing**: Automatically parses `event:` and `data:` lines from SSE responses
|
629
|
+
- **Session Support**: Automatic session header (`Mcp-Session-Id`) capture and injection for session-based MCP servers
|
630
|
+
- **Session Termination**: Proper session cleanup with HTTP DELETE requests during connection teardown
|
631
|
+
- **Resumability**: Event ID tracking and `Last-Event-ID` header support for message replay after disconnections
|
632
|
+
- **Session Validation**: Security validation of session IDs to prevent malicious injection
|
633
|
+
- **HTTP Semantics**: Maintains standard HTTP request/response model for client compatibility
|
634
|
+
- **Streaming Format Support**: Handles complex SSE responses with multiple fields (event, id, retry, etc.)
|
635
|
+
- **Error Handling**: Comprehensive error handling for both HTTP and SSE parsing failures
|
636
|
+
- **Headers Optimization**: Includes SSE-compatible headers (`Accept: text/event-stream, application/json`, `Cache-Control: no-cache`)
|
637
|
+
- **JSON-RPC Compliance**: Full JSON-RPC 2.0 support over the hybrid HTTP/SSE transport
|
638
|
+
- **Retry Logic**: Exponential backoff for both connection and parsing failures
|
639
|
+
- **Thread Safety**: All operations are thread-safe for concurrent usage
|
640
|
+
- **Malformed Response Handling**: Graceful handling of invalid SSE format or missing data lines
|
641
|
+
|
407
642
|
## Requirements
|
408
643
|
|
409
644
|
- Ruby >= 3.2.0
|
@@ -413,7 +648,7 @@ The SSE client implementation provides these key features:
|
|
413
648
|
|
414
649
|
To implement a compatible MCP server you must:
|
415
650
|
|
416
|
-
- Listen on your chosen transport (JSON-RPC stdio, or HTTP
|
651
|
+
- Listen on your chosen transport (JSON-RPC stdio, HTTP SSE, HTTP, or Streamable HTTP)
|
417
652
|
- Respond to `list_tools` requests with a JSON list of tools
|
418
653
|
- Respond to `call_tool` requests by executing the specified tool
|
419
654
|
- Return results (or errors) in JSON format
|
data/lib/mcp_client/client.rb
CHANGED
@@ -70,7 +70,7 @@ module MCPClient
|
|
70
70
|
if tools.empty? && !servers.empty?
|
71
71
|
raise connection_errors.first if connection_errors.any?
|
72
72
|
|
73
|
-
|
73
|
+
@logger.warn('No tools found from any server.')
|
74
74
|
end
|
75
75
|
|
76
76
|
tools
|
@@ -87,6 +87,10 @@ module MCPClient
|
|
87
87
|
parse_stdio_config(clean, config, server_name)
|
88
88
|
when 'sse'
|
89
89
|
return nil unless parse_sse_config(clean, config, server_name)
|
90
|
+
when 'streamable_http'
|
91
|
+
return nil unless parse_streamable_http_config(clean, config, server_name)
|
92
|
+
when 'http'
|
93
|
+
return nil unless parse_http_config(clean, config, server_name)
|
90
94
|
else
|
91
95
|
@logger.warn("Unrecognized type '#{type}' for server '#{server_name}'; skipping.")
|
92
96
|
return nil
|
@@ -106,7 +110,9 @@ module MCPClient
|
|
106
110
|
inferred_type = if config.key?('command') || config.key?('args') || config.key?('env')
|
107
111
|
'stdio'
|
108
112
|
elsif config.key?('url')
|
109
|
-
|
113
|
+
# Default to streamable_http unless URL contains "sse"
|
114
|
+
url = config['url'].to_s.downcase
|
115
|
+
url.include?('sse') ? 'sse' : 'streamable_http'
|
110
116
|
end
|
111
117
|
|
112
118
|
if inferred_type
|
@@ -181,6 +187,72 @@ module MCPClient
|
|
181
187
|
true
|
182
188
|
end
|
183
189
|
|
190
|
+
# Parse Streamable HTTP-specific configuration
|
191
|
+
# @param clean [Hash] clean configuration hash to update
|
192
|
+
# @param config [Hash] raw configuration from JSON
|
193
|
+
# @param server_name [String] name of the server for error reporting
|
194
|
+
# @return [Boolean] true if parsing succeeded, false if required elements are missing
|
195
|
+
def parse_streamable_http_config(clean, config, server_name)
|
196
|
+
# URL is required
|
197
|
+
source = config['url']
|
198
|
+
unless source
|
199
|
+
@logger.warn("Streamable HTTP server '#{server_name}' is missing required 'url' property; skipping.")
|
200
|
+
return false
|
201
|
+
end
|
202
|
+
|
203
|
+
unless source.is_a?(String)
|
204
|
+
@logger.warn("'url' for server '#{server_name}' is not a string; converting to string.")
|
205
|
+
source = source.to_s
|
206
|
+
end
|
207
|
+
|
208
|
+
# Headers are optional
|
209
|
+
headers = config['headers']
|
210
|
+
headers = headers.is_a?(Hash) ? headers.transform_keys(&:to_s) : {}
|
211
|
+
|
212
|
+
# Endpoint is optional (defaults to '/rpc' in the transport)
|
213
|
+
endpoint = config['endpoint']
|
214
|
+
endpoint = endpoint.to_s if endpoint && !endpoint.is_a?(String)
|
215
|
+
|
216
|
+
# Update clean config
|
217
|
+
clean[:url] = source
|
218
|
+
clean[:headers] = headers
|
219
|
+
clean[:endpoint] = endpoint if endpoint
|
220
|
+
true
|
221
|
+
end
|
222
|
+
|
223
|
+
# Parse HTTP-specific configuration
|
224
|
+
# @param clean [Hash] clean configuration hash to update
|
225
|
+
# @param config [Hash] raw configuration from JSON
|
226
|
+
# @param server_name [String] name of the server for error reporting
|
227
|
+
# @return [Boolean] true if parsing succeeded, false if required elements are missing
|
228
|
+
def parse_http_config(clean, config, server_name)
|
229
|
+
# URL is required
|
230
|
+
source = config['url']
|
231
|
+
unless source
|
232
|
+
@logger.warn("HTTP server '#{server_name}' is missing required 'url' property; skipping.")
|
233
|
+
return false
|
234
|
+
end
|
235
|
+
|
236
|
+
unless source.is_a?(String)
|
237
|
+
@logger.warn("'url' for server '#{server_name}' is not a string; converting to string.")
|
238
|
+
source = source.to_s
|
239
|
+
end
|
240
|
+
|
241
|
+
# Headers are optional
|
242
|
+
headers = config['headers']
|
243
|
+
headers = headers.is_a?(Hash) ? headers.transform_keys(&:to_s) : {}
|
244
|
+
|
245
|
+
# Endpoint is optional (defaults to '/rpc' in the transport)
|
246
|
+
endpoint = config['endpoint']
|
247
|
+
endpoint = endpoint.to_s if endpoint && !endpoint.is_a?(String)
|
248
|
+
|
249
|
+
# Update clean config
|
250
|
+
clean[:url] = source
|
251
|
+
clean[:headers] = headers
|
252
|
+
clean[:endpoint] = endpoint if endpoint
|
253
|
+
true
|
254
|
+
end
|
255
|
+
|
184
256
|
# Filter out reserved keys from configuration objects
|
185
257
|
# @param data [Hash] configuration data
|
186
258
|
# @return [Hash] filtered configuration data
|