ruby-mcp-client 0.6.2 → 0.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15f194d4e1504310a998aeeb819e5851dea4f1f8049bf494368ad5494e611d3c
4
- data.tar.gz: 93d8d00a95ab2436241b09253d7bb56d130122303c1e78c429cecc343d09fa82
3
+ metadata.gz: 94f8597a5cddfa1f86b6e09401b652d2c7aa3bd4eefc8771712b7c03d99772a8
4
+ data.tar.gz: b303e3056719fea1a62cf4eeff76156e6e3ed68d134d48aa3ce969e8095d85be
5
5
  SHA512:
6
- metadata.gz: f7edb3c0ae40b647c03d3a70af06e08b7d1290de0326fcf34b668b08f1fb156692799e1280f4a3a17c44b9afdb18b456d949a1cc39edec396877a25a00290c8f
7
- data.tar.gz: a169f6e4f24c9f1f4ed52e7853f00285565cfcd2aa2d8fe6049c10191dd2fcbf571c8468dea65bf6504175f1ca1ce402ad9d7353660888db2f96e57831056598
6
+ metadata.gz: da1d04e7aee8207ff32a2db24df14c2b832b8f5fd6acf36c6b8f22b86cf802d99de5514a608a6336f1973949a34a8829c8f71a5b2dadc68ebff50ed7d4d23bc7
7
+ data.tar.gz: e75630074326e81fddbc006f3bcd8b848c474792ac73c2e9f883722b49b0aeb2da31bb824263234599b279974c7c2445ce6d4d06766a0e447753e8060b248d8f
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:
@@ -38,6 +40,14 @@ with popular AI services with built-in conversions:
38
40
  - `to_anthropic_tools()` - Formats tools for Anthropic Claude API
39
41
  - `to_google_tools()` - Formats tools for Google Vertex AI API (automatically removes "$schema" keys not accepted by Vertex AI)
40
42
 
43
+ ## MCP 2025-03-26 Protocol Features
44
+
45
+ This Ruby MCP Client implements key features from the latest MCP specification (Protocol Revision: 2025-03-26):
46
+
47
+ ### Implemented Features
48
+ - **OAuth 2.1 Authorization Framework** - Complete authentication with PKCE, dynamic client registration, server discovery, and runtime configuration
49
+ - **Streamable HTTP Transport** - Enhanced transport with Server-Sent Event formatted responses and session management
50
+
41
51
  ## Usage
42
52
 
43
53
  ### Basic Client Usage
@@ -56,7 +66,7 @@ client = MCPClient.create_client(
56
66
  MCPClient.sse_config(
57
67
  base_url: 'https://api.example.com/sse',
58
68
  headers: { 'Authorization' => 'Bearer YOUR_TOKEN' },
59
- name: 'api', # Optional name for this server
69
+ name: 'sse_api', # Optional name for this server
60
70
  read_timeout: 30, # Optional timeout in seconds (default: 30)
61
71
  ping: 10, # Optional ping interval in seconds of inactivity (default: 10)
62
72
  # Connection closes automatically after inactivity (2.5x ping interval)
@@ -64,7 +74,19 @@ client = MCPClient.create_client(
64
74
  retry_backoff: 1, # Optional backoff delay in seconds (default: 1)
65
75
  # Native support for tool streaming via call_tool_streaming method
66
76
  logger: Logger.new($stdout, level: Logger::INFO) # Optional logger for this server
67
- ) ],
77
+ ),
78
+ # Remote HTTP server (request/response without streaming)
79
+ MCPClient.http_config(
80
+ base_url: 'https://api.example.com',
81
+ endpoint: '/rpc', # Optional JSON-RPC endpoint path (default: '/rpc')
82
+ headers: { 'Authorization' => 'Bearer YOUR_TOKEN' },
83
+ name: 'http_api', # Optional name for this server
84
+ read_timeout: 30, # Optional timeout in seconds (default: 30)
85
+ retries: 3, # Optional number of retry attempts (default: 3)
86
+ retry_backoff: 1, # Optional backoff delay in seconds (default: 1)
87
+ logger: Logger.new($stdout, level: Logger::INFO) # Optional logger for this server
88
+ )
89
+ ],
68
90
  # Optional logger for the client and all servers without explicit loggers
69
91
  logger: Logger.new($stdout, level: Logger::WARN)
70
92
  )
@@ -78,11 +100,12 @@ client = MCPClient.create_client(
78
100
  # MCP server configuration JSON format can be:
79
101
  # 1. A single server object:
80
102
  # { "type": "sse", "url": "http://example.com/sse" }
103
+ # { "type": "http", "url": "http://example.com", "endpoint": "/rpc" }
81
104
  # 2. An array of server objects:
82
- # [{ "type": "stdio", "command": "npx server" }, { "type": "sse", "url": "http://..." }]
105
+ # [{ "type": "stdio", "command": "npx server" }, { "type": "sse", "url": "http://..." }, { "type": "http", "url": "http://..." }]
83
106
  # 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
107
+ # { "mcpServers": { "server1": { "type": "sse", "url": "http://..." }, "server2": { "type": "http", "url": "http://..." } } }
108
+ # Note: When using this format, server1/server2 will be accessible by name
86
109
 
87
110
  # List available tools
88
111
  tools = client.list_tools
@@ -143,6 +166,114 @@ client.clear_cache
143
166
  client.cleanup
144
167
  ```
145
168
 
169
+ ### HTTP Transport Example
170
+
171
+ The HTTP transport provides simple request/response communication with MCP servers:
172
+
173
+ ```ruby
174
+ require 'mcp_client'
175
+ require 'logger'
176
+
177
+ # Optional logger for debugging
178
+ logger = Logger.new($stdout)
179
+ logger.level = Logger::INFO
180
+
181
+ # Create an MCP client that connects to an HTTP MCP server
182
+ http_client = MCPClient.create_client(
183
+ mcp_server_configs: [
184
+ MCPClient.http_config(
185
+ base_url: 'https://api.example.com',
186
+ endpoint: '/mcp', # JSON-RPC endpoint path
187
+ headers: {
188
+ 'Authorization' => 'Bearer YOUR_API_TOKEN',
189
+ 'X-Custom-Header' => 'custom-value'
190
+ },
191
+ read_timeout: 30, # Timeout in seconds for HTTP requests
192
+ retries: 3, # Number of retry attempts on transient errors
193
+ retry_backoff: 1, # Base delay in seconds for exponential backoff
194
+ logger: logger # Optional logger for debugging HTTP requests
195
+ )
196
+ ]
197
+ )
198
+
199
+ # List available tools
200
+ tools = http_client.list_tools
201
+
202
+ # Call a tool
203
+ result = http_client.call_tool('analyze_data', {
204
+ dataset: 'sales_2024',
205
+ metrics: ['revenue', 'conversion_rate']
206
+ })
207
+
208
+ # HTTP transport also supports streaming (though implemented as single response)
209
+ # This provides API compatibility with SSE transport
210
+ http_client.call_tool_streaming('process_batch', { batch_id: 123 }).each do |result|
211
+ puts "Processing result: #{result}"
212
+ end
213
+
214
+ # Send custom JSON-RPC requests
215
+ custom_result = http_client.send_rpc('custom_method', params: { key: 'value' })
216
+
217
+ # Send notifications (fire-and-forget)
218
+ http_client.send_notification('status_update', params: { status: 'processing' })
219
+
220
+ # Test connectivity
221
+ ping_result = http_client.ping
222
+ puts "Server is responsive: #{ping_result.inspect}"
223
+
224
+ # Clean up
225
+ http_client.cleanup
226
+ ```
227
+
228
+ ### Streamable HTTP Transport Example
229
+
230
+ 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:
231
+
232
+ ```ruby
233
+ require 'mcp_client'
234
+ require 'logger'
235
+
236
+ # Optional logger for debugging
237
+ logger = Logger.new($stdout)
238
+ logger.level = Logger::INFO
239
+
240
+ # Create an MCP client that connects to a Streamable HTTP MCP server
241
+ streamable_client = MCPClient.create_client(
242
+ mcp_server_configs: [
243
+ MCPClient.streamable_http_config(
244
+ base_url: 'https://mcp.zapier.com/api/mcp/s/YOUR_SESSION_ID/mcp',
245
+ headers: {
246
+ 'Authorization' => 'Bearer YOUR_ZAPIER_TOKEN'
247
+ },
248
+ read_timeout: 60, # Timeout in seconds for HTTP requests
249
+ retries: 3, # Number of retry attempts on transient errors
250
+ retry_backoff: 2, # Base delay in seconds for exponential backoff
251
+ logger: logger # Optional logger for debugging requests
252
+ )
253
+ ]
254
+ )
255
+
256
+ # List available tools (server responds with SSE-formatted JSON)
257
+ tools = streamable_client.list_tools
258
+ puts "Found #{tools.size} tools:"
259
+ tools.each { |tool| puts "- #{tool.name}: #{tool.description}" }
260
+
261
+ # Call a tool (response will be in SSE format)
262
+ result = streamable_client.call_tool('google_calendar_find_event', {
263
+ instructions: 'Find today\'s meetings',
264
+ calendarid: 'primary'
265
+ })
266
+
267
+ # The client automatically parses SSE responses like:
268
+ # event: message
269
+ # data: {"jsonrpc":"2.0","id":1,"result":{"content":[...]}}
270
+
271
+ puts "Tool result: #{result.inspect}"
272
+
273
+ # Clean up
274
+ streamable_client.cleanup
275
+ ```
276
+
146
277
  ### Server-Sent Events (SSE) Example
147
278
 
148
279
  The SSE transport provides robust connection handling for remote MCP servers:
@@ -313,6 +444,15 @@ You can define MCP server configurations in JSON files for easier management:
313
444
  "Authorization": "Bearer TOKEN"
314
445
  }
315
446
  },
447
+ "api_server": {
448
+ "type": "http",
449
+ "url": "https://api.example.com",
450
+ "endpoint": "/mcp",
451
+ "headers": {
452
+ "Authorization": "Bearer API_TOKEN",
453
+ "X-Custom-Header": "value"
454
+ }
455
+ },
316
456
  "filesystem": {
317
457
  "type": "stdio",
318
458
  "command": "npx",
@@ -346,20 +486,145 @@ client = MCPClient.create_client(server_definition_file: 'path/to/definition.jso
346
486
  ```
347
487
 
348
488
  The JSON format supports:
349
- 1. A single server object: `{ "type": "sse", "url": "..." }`
350
- 2. An array of server objects: `[{ "type": "stdio", ... }, { "type": "sse", ... }]`
489
+ 1. A single server object: `{ "type": "sse", "url": "..." }` or `{ "type": "http", "url": "..." }`
490
+ 2. An array of server objects: `[{ "type": "stdio", ... }, { "type": "sse", ... }, { "type": "http", ... }]`
351
491
  3. An object with named servers under `mcpServers` key (as shown above)
352
492
 
353
493
  Special configuration options:
354
494
  - `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)
495
+ - Server type can be inferred from the presence of either `command` (for stdio) or `url` (for SSE/HTTP)
496
+ - For HTTP servers, `endpoint` specifies the JSON-RPC endpoint path (defaults to '/rpc' if not specified)
356
497
  - All string values in arrays (like `args`) are automatically converted to strings
357
498
 
499
+ ## Session-Based MCP Protocol Support
500
+
501
+ Both HTTP and Streamable HTTP transports now support session-based MCP servers that require session continuity:
502
+
503
+ ### Session Management Features
504
+
505
+ - **Automatic Session Management**: Captures session IDs from `initialize` response headers
506
+ - **Session Header Injection**: Automatically includes `Mcp-Session-Id` header in subsequent requests
507
+ - **Session Termination**: Sends HTTP DELETE requests to properly terminate sessions during cleanup
508
+ - **Session Validation**: Validates session ID format for security (8-128 alphanumeric characters with hyphens/underscores)
509
+ - **Backward Compatibility**: Works with both session-based and stateless MCP servers
510
+ - **Session Cleanup**: Properly cleans up session state during connection teardown
511
+
512
+ ### Resumability and Redelivery (Streamable HTTP)
513
+
514
+ The Streamable HTTP transport provides additional resumability features for reliable message delivery:
515
+
516
+ - **Event ID Tracking**: Automatically tracks event IDs from SSE responses
517
+ - **Last-Event-ID Header**: Includes `Last-Event-ID` header in requests for resuming from disconnection points
518
+ - **Message Replay**: Enables servers to replay missed messages from the last received event
519
+ - **Connection Recovery**: Maintains message continuity even with unstable network connections
520
+
521
+ ### Security Features
522
+
523
+ Both transports implement security best practices:
524
+
525
+ - **URL Validation**: Validates server URLs to ensure only HTTP/HTTPS protocols are used
526
+ - **Session ID Validation**: Enforces secure session ID formats to prevent malicious injection
527
+ - **Security Warnings**: Logs warnings for potentially insecure configurations (e.g., 0.0.0.0 binding)
528
+ - **Header Sanitization**: Properly handles and validates all session-related headers
529
+
530
+ ### Usage
531
+
532
+ The session support is transparent to the user - no additional configuration is required. The client will automatically detect and handle session-based servers by:
533
+
534
+ 1. **Session Initialization**: Capturing the `Mcp-Session-Id` header from the `initialize` response
535
+ 2. **Session Persistence**: Including this header in all subsequent requests (except `initialize`)
536
+ 3. **Session Termination**: Sending HTTP DELETE request with session ID during cleanup
537
+ 4. **Resumability** (Streamable HTTP): Tracking event IDs and including `Last-Event-ID` for message replay
538
+ 5. **Security Validation**: Validating session IDs and server URLs for security
539
+ 6. **Logging**: Comprehensive logging of session activity for debugging purposes
540
+
541
+ Example of automatic session termination:
542
+
543
+ ```ruby
544
+ # Session is automatically terminated when client is cleaned up
545
+ client = MCPClient.create_client(
546
+ mcp_server_configs: [
547
+ MCPClient.http_config(base_url: 'https://api.example.com/mcp')
548
+ ]
549
+ )
550
+
551
+ # Use the client...
552
+ tools = client.list_tools
553
+
554
+ # Session automatically terminated with HTTP DELETE request
555
+ client.cleanup
556
+ ```
557
+
558
+ This enables compatibility with MCP servers that maintain state between requests and require session identification.
559
+
560
+ ## OAuth 2.1 Authentication
561
+
562
+ The Ruby MCP Client includes comprehensive OAuth 2.1 support for secure authentication with MCP servers:
563
+
564
+ ```ruby
565
+ require 'mcp_client'
566
+
567
+ # Create an OAuth-enabled HTTP server
568
+ server = MCPClient::OAuthClient.create_http_server(
569
+ server_url: 'https://api.example.com/mcp',
570
+ redirect_uri: 'http://localhost:8080/callback',
571
+ scope: 'mcp:read mcp:write'
572
+ )
573
+
574
+ # Check if authorization is needed
575
+ unless MCPClient::OAuthClient.valid_token?(server)
576
+ # Start OAuth flow
577
+ auth_url = MCPClient::OAuthClient.start_oauth_flow(server)
578
+ puts "Please visit: #{auth_url}"
579
+
580
+ # After user authorization, complete the flow
581
+ # token = MCPClient::OAuthClient.complete_oauth_flow(server, code, state)
582
+ end
583
+
584
+ # Use the server normally
585
+ server.connect
586
+ tools = server.list_tools
587
+ ```
588
+
589
+ ### Manual OAuth Provider
590
+
591
+ For more control over the OAuth flow:
592
+
593
+ ```ruby
594
+ # Create OAuth provider directly
595
+ oauth_provider = MCPClient::Auth::OAuthProvider.new(
596
+ server_url: 'https://api.example.com/mcp',
597
+ redirect_uri: 'http://localhost:8080/callback',
598
+ scope: 'mcp:read mcp:write'
599
+ )
600
+
601
+ # Update configuration at runtime
602
+ oauth_provider.scope = 'mcp:read mcp:write admin'
603
+ oauth_provider.redirect_uri = 'http://localhost:9000/callback'
604
+
605
+ # Start authorization flow
606
+ auth_url = oauth_provider.start_authorization_flow
607
+
608
+ # Complete flow after user authorization
609
+ token = oauth_provider.complete_authorization_flow(code, state)
610
+ ```
611
+
612
+ ### OAuth Features
613
+
614
+ - **OAuth 2.1 compliance** with PKCE for security
615
+ - **Automatic server discovery** via `.well-known` endpoints
616
+ - **Dynamic client registration** when supported by servers
617
+ - **Token refresh** and automatic token management
618
+ - **Pluggable storage** for tokens and client credentials
619
+ - **Runtime configuration** via getter/setter methods
620
+
621
+ For complete OAuth documentation, see [OAUTH.md](OAUTH.md).
622
+
358
623
  ## Key Features
359
624
 
360
625
  ### Client Features
361
626
 
362
- - **Multiple transports** - Support for both stdio and SSE transports
627
+ - **Multiple transports** - Support for stdio, SSE, HTTP, and Streamable HTTP transports
363
628
  - **Multiple servers** - Connect to multiple MCP servers simultaneously
364
629
  - **Named servers** - Associate names with servers and find/reference them by name
365
630
  - **Server lookup** - Find servers by name using `find_server`
@@ -404,6 +669,47 @@ The SSE client implementation provides these key features:
404
669
  - **URL normalization**: Consistent URL handling that respects user-provided formats
405
670
  - **Server connectivity check**: Built-in `ping` method to test server connectivity and health
406
671
 
672
+ ### HTTP Transport Implementation
673
+
674
+ The HTTP transport provides a simpler, stateless communication mechanism for MCP servers:
675
+
676
+ - **Request/Response Model**: Standard HTTP request/response cycle for each JSON-RPC call
677
+ - **JSON-Only Responses**: Accepts only `application/json` responses (no SSE support)
678
+ - **Session Support**: Automatic session header (`Mcp-Session-Id`) capture and injection for session-based MCP servers
679
+ - **Session Termination**: Proper session cleanup with HTTP DELETE requests during connection teardown
680
+ - **Session Validation**: Security validation of session IDs to prevent malicious injection
681
+ - **Stateless & Stateful**: Supports both stateless servers and session-based servers that require state continuity
682
+ - **HTTP Headers Support**: Full support for custom headers including authorization, API keys, and other metadata
683
+ - **Reliable Error Handling**: Comprehensive HTTP status code handling with appropriate error mapping
684
+ - **Configurable Retries**: Exponential backoff retry logic for transient network failures
685
+ - **Connection Pooling**: Uses Faraday's connection pooling for efficient HTTP connections
686
+ - **Timeout Management**: Configurable timeouts for both connection establishment and request completion
687
+ - **JSON-RPC over HTTP**: Full JSON-RPC 2.0 implementation over HTTP POST requests
688
+ - **MCP Protocol Compliance**: Supports all standard MCP methods (initialize, tools/list, tools/call)
689
+ - **Custom RPC Methods**: Send any custom JSON-RPC method or notification
690
+ - **Thread Safety**: All operations are thread-safe for concurrent usage
691
+ - **Streaming API Compatibility**: Provides `call_tool_streaming` method for API compatibility (returns single response)
692
+ - **Graceful Degradation**: Simple fallback behavior when complex features aren't needed
693
+
694
+ ### Streamable HTTP Transport Implementation
695
+
696
+ The Streamable HTTP transport bridges HTTP and Server-Sent Events, designed for servers that use HTTP POST but return SSE-formatted responses:
697
+
698
+ - **Hybrid Communication**: HTTP POST requests with Server-Sent Event formatted responses
699
+ - **SSE Response Parsing**: Automatically parses `event:` and `data:` lines from SSE responses
700
+ - **Session Support**: Automatic session header (`Mcp-Session-Id`) capture and injection for session-based MCP servers
701
+ - **Session Termination**: Proper session cleanup with HTTP DELETE requests during connection teardown
702
+ - **Resumability**: Event ID tracking and `Last-Event-ID` header support for message replay after disconnections
703
+ - **Session Validation**: Security validation of session IDs to prevent malicious injection
704
+ - **HTTP Semantics**: Maintains standard HTTP request/response model for client compatibility
705
+ - **Streaming Format Support**: Handles complex SSE responses with multiple fields (event, id, retry, etc.)
706
+ - **Error Handling**: Comprehensive error handling for both HTTP and SSE parsing failures
707
+ - **Headers Optimization**: Includes SSE-compatible headers (`Accept: text/event-stream, application/json`, `Cache-Control: no-cache`)
708
+ - **JSON-RPC Compliance**: Full JSON-RPC 2.0 support over the hybrid HTTP/SSE transport
709
+ - **Retry Logic**: Exponential backoff for both connection and parsing failures
710
+ - **Thread Safety**: All operations are thread-safe for concurrent usage
711
+ - **Malformed Response Handling**: Graceful handling of invalid SSE format or missing data lines
712
+
407
713
  ## Requirements
408
714
 
409
715
  - Ruby >= 3.2.0
@@ -413,7 +719,7 @@ The SSE client implementation provides these key features:
413
719
 
414
720
  To implement a compatible MCP server you must:
415
721
 
416
- - Listen on your chosen transport (JSON-RPC stdio, or HTTP SSE)
722
+ - Listen on your chosen transport (JSON-RPC stdio, HTTP SSE, HTTP, or Streamable HTTP)
417
723
  - Respond to `list_tools` requests with a JSON list of tools
418
724
  - Respond to `call_tool` requests by executing the specified tool
419
725
  - Return results (or errors) in JSON format