groq_ruby 0.1.0 → 0.2.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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +49 -0
- data/CLAUDE.md +24 -1
- data/README.md +57 -25
- data/examples/README.md +2 -0
- data/examples/mcp_http_remote.rb +47 -0
- data/lib/groq_ruby/mcp/client.rb +38 -12
- data/lib/groq_ruby/mcp/http_server_config.rb +25 -0
- data/lib/groq_ruby/mcp/protocol/v2024_11_05.rb +29 -0
- data/lib/groq_ruby/mcp/protocol/v2025_11_25.rb +33 -0
- data/lib/groq_ruby/mcp/protocol.rb +37 -0
- data/lib/groq_ruby/mcp/transports/http_streamable.rb +221 -0
- data/lib/groq_ruby/version.rb +1 -1
- data/lib/groq_ruby.rb +3 -1
- data/sig/groq_ruby.rbs +33 -2
- data.tar.gz.sig +0 -0
- metadata +7 -1
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f61d7fe590a9389b584b1d6f6a30551809aa980204401ec03189c7fb468c4d9
|
|
4
|
+
data.tar.gz: d08fa9af8238213284d457d3b234aa706f1aba45ca99c22edd5b21d61fbeef13
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c7cfbecd253877f1a17b0e688d2b48b4e9a96e04eda485843e4403d254b685643222d29405bae9e9b5d938a887ee301de958ffd4454557d9d766411c27c721fe
|
|
7
|
+
data.tar.gz: 71c6dad9a48dbc928f31feb545038e4df06cb8e44f7f734a62b3d791ae8a5edf1c9ce0c828af9b9c03ade06848137587c7b40e51d9938f69b961ad67ced1ff5e
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.0]
|
|
10
|
+
|
|
11
|
+
Adds HTTP-based MCP transport support and per-protocol-version selection,
|
|
12
|
+
so Groq agents can talk to remote MCP servers (HTTP/HTTPS) in addition
|
|
13
|
+
to local stdio-launched ones.
|
|
14
|
+
|
|
15
|
+
### Added — MCP
|
|
16
|
+
|
|
17
|
+
- `GroqRuby::MCP::HttpServerConfig` — describes a remote MCP server
|
|
18
|
+
(URL + extra headers, e.g. for bearer auth). Sibling of `ServerConfig`.
|
|
19
|
+
- `GroqRuby::MCP::Transports::HttpStreamable` — implements the MCP
|
|
20
|
+
HTTP Streamable transport (single endpoint POST with JSON or SSE
|
|
21
|
+
response, `Mcp-Session-Id` header captured and echoed,
|
|
22
|
+
`MCP-Protocol-Version` header on every request, best-effort `DELETE`
|
|
23
|
+
on `stop`). Each request runs on a background thread; `stop` joins
|
|
24
|
+
all in-flight threads before terminating the session.
|
|
25
|
+
- `GroqRuby::MCP::Protocol` — registry of versioned protocol objects
|
|
26
|
+
with `Protocol.for(version)`, `Protocol.default`. Each protocol
|
|
27
|
+
object owns its `initialize` payload shape and version string.
|
|
28
|
+
- `GroqRuby::MCP::Protocol::V2024_11_05` — original public release
|
|
29
|
+
protocol (the pre-existing default for stdio servers).
|
|
30
|
+
- `GroqRuby::MCP::Protocol::V2025_11_25` — capability stub for the
|
|
31
|
+
newest spec; future PRs will add the tasks API surface.
|
|
32
|
+
- `Client.new` and `Client.connect` accept a `protocol:` kwarg.
|
|
33
|
+
`Client#protocol` exposes the active protocol object.
|
|
34
|
+
- `Client.connect` now dispatches the transport by config type:
|
|
35
|
+
`ServerConfig` → stdio + 2024-11-05, `HttpServerConfig` → HTTP
|
|
36
|
+
Streamable + 2025-11-25. Both transport choice and protocol are
|
|
37
|
+
overridable.
|
|
38
|
+
- `Bridge` accepts mixed `ServerConfig` and `HttpServerConfig` arrays
|
|
39
|
+
transparently — no API change required.
|
|
40
|
+
- New example: `examples/mcp_http_remote.rb`.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- `Client.connect` signature: gained `protocol:` kwarg (default `nil`,
|
|
45
|
+
resolved from config type). Existing callers passing only a stdio
|
|
46
|
+
`ServerConfig` are unaffected.
|
|
47
|
+
|
|
48
|
+
### Notes
|
|
49
|
+
|
|
50
|
+
- HTTP transport currently lacks the long-lived `GET` SSE channel for
|
|
51
|
+
server-initiated notifications without an in-flight request; that
|
|
52
|
+
arrives with the tasks-API follow-up. Server-initiated frames
|
|
53
|
+
interleaved on a `POST` SSE response are dispatched normally.
|
|
54
|
+
- Sticking with `MCP::PROTOCOL_VERSION = "2024-11-05"` as the
|
|
55
|
+
top-level constant for backward compatibility; per-instance protocol
|
|
56
|
+
selection is the forward-compatible API.
|
|
57
|
+
|
|
9
58
|
## [0.1.0]
|
|
10
59
|
|
|
11
60
|
Initial release. Idiomatic Ruby client for the Groq API, mirroring the
|
data/CLAUDE.md
CHANGED
|
@@ -52,6 +52,16 @@ explicit discussion:
|
|
|
52
52
|
feature. The bridge speaks JSON-RPC 2.0 to MCP servers and converts
|
|
53
53
|
their tools to OpenAI-shaped function tools. Don't suggest adding a
|
|
54
54
|
request-side `mcp_servers:` parameter — Groq's API doesn't accept one.
|
|
55
|
+
- **MCP transports are pluggable; protocol versions are pluggable.**
|
|
56
|
+
`Transports::Stdio` (child process) and `Transports::HttpStreamable`
|
|
57
|
+
(single HTTPS endpoint) are siblings. `Protocol::V2024_11_05` and
|
|
58
|
+
`Protocol::V2025_11_25` are sibling protocol objects, each owning the
|
|
59
|
+
`initialize` payload shape and the version string. `Client.connect`
|
|
60
|
+
dispatches both transport and default protocol off the config class
|
|
61
|
+
(`ServerConfig` → stdio + V2024_11_05, `HttpServerConfig` → HTTP +
|
|
62
|
+
V2025_11_25); both are overridable via the `protocol:` kwarg. Don't
|
|
63
|
+
consolidate transports into the Client or push protocol-version
|
|
64
|
+
choice up to a global constant — per-instance is the design.
|
|
55
65
|
|
|
56
66
|
## Layout
|
|
57
67
|
|
|
@@ -62,7 +72,9 @@ explicit discussion:
|
|
|
62
72
|
- `lib/groq_ruby/resources/{chat,audio}/*.rb` and `lib/groq_ruby/resources/*.rb` — one class per API surface.
|
|
63
73
|
- `lib/groq_ruby/models/{chat,audio,embeddings,files,batches}/*.rb` — collapsed → `GroqRuby::Models::*`.
|
|
64
74
|
- `lib/groq_ruby/streaming/*.rb` — SSE adapter (`event_stream_parser`) + `ChunkStream` enumerable.
|
|
65
|
-
- `lib/groq_ruby/mcp/*.rb` — MCP client, bridge, transports, error families (collapsed). `MCP::PROTOCOL_VERSION` lives in `mcp.rb
|
|
75
|
+
- `lib/groq_ruby/mcp/*.rb` — MCP client, bridge, transports, protocol objects, error families (collapsed). `MCP::PROTOCOL_VERSION` lives in `mcp.rb` (kept for backward compat — points at the V2024_11_05 wire string).
|
|
76
|
+
- `lib/groq_ruby/mcp/transports/{stdio,http_streamable}.rb` — one transport per file.
|
|
77
|
+
- `lib/groq_ruby/mcp/protocol/{v2024_11_05,v2025_11_25}.rb` — versioned protocol objects under `MCP::Protocol::*`. Class names contain underscores deliberately (mirroring the wire format) and carry an inline `rubocop:disable` for `Naming/ClassAndModuleCamelCase`.
|
|
66
78
|
- `sig/groq_ruby.rbs` — public-API RBS sigs. Keep in sync when adding public API.
|
|
67
79
|
- `test/**/test_*.rb` — Minitest. Real network calls are forbidden — every HTTP test stubs via WebMock; every MCP test uses `test/support/fake_mcp_transport.rb`.
|
|
68
80
|
- `examples/*.rb` — runnable scripts. Each starts with `require "bundler/setup"; require "groq_ruby"`.
|
|
@@ -99,5 +111,16 @@ explicit discussion:
|
|
|
99
111
|
`Bridge` if the LLM should be able to use it through chat
|
|
100
112
|
completions. Probe optional capabilities gracefully (catch
|
|
101
113
|
`JsonRpcError` / `-32601`).
|
|
114
|
+
- New MCP transport → add a class under
|
|
115
|
+
`lib/groq_ruby/mcp/transports/` that `include Transport` (so
|
|
116
|
+
`send_message`/`on_message`/`stop` are mandatory) + a sibling config
|
|
117
|
+
class (`<Name>ServerConfig`) at `lib/groq_ruby/mcp/`. Wire the
|
|
118
|
+
dispatch in `Client.build_transport` / `Client.default_protocol_for`.
|
|
119
|
+
- New MCP protocol version → add a class under
|
|
120
|
+
`lib/groq_ruby/mcp/protocol/` (filename uses the wire format, e.g.
|
|
121
|
+
`v2025_11_25.rb` → `Protocol::V2025_11_25`) and register it in
|
|
122
|
+
`Protocol.registry`. Add a Zeitwerk inflection in `lib/groq_ruby.rb`.
|
|
123
|
+
Carry the `rubocop:disable Naming/ClassAndModuleCamelCase` inline on
|
|
124
|
+
the class.
|
|
102
125
|
- New public method → add a YARD `@param`/`@return`/`@raise` and
|
|
103
126
|
update `sig/groq_ruby.rbs`.
|
data/README.md
CHANGED
|
@@ -8,7 +8,8 @@ shape: typed response objects, single-purpose resource classes, internal
|
|
|
8
8
|
`dry-monads` `Result` pipelines, and request validation via
|
|
9
9
|
`dry-schema`. Streaming chat completions are supported via Server-Sent
|
|
10
10
|
Events. A built-in [MCP](https://modelcontextprotocol.io) client lets you
|
|
11
|
-
wire one or more MCP servers
|
|
11
|
+
wire one or more MCP servers — local stdio processes or remote HTTP
|
|
12
|
+
endpoints — into a Groq chat completion as tools.
|
|
12
13
|
|
|
13
14
|
This gem is **not** an official Groq product. The wire protocol it
|
|
14
15
|
implements and the API surface it mirrors come from the publicly
|
|
@@ -240,8 +241,9 @@ client.batches.cancel(batch.id)
|
|
|
240
241
|
|
|
241
242
|
## MCP — Model Context Protocol
|
|
242
243
|
|
|
243
|
-
`groq_ruby` ships with
|
|
244
|
-
exposed by any MCP-compatible server
|
|
244
|
+
`groq_ruby` ships with stdio and HTTP Streamable MCP clients, so a Groq
|
|
245
|
+
agent can use tools exposed by any MCP-compatible server — local
|
|
246
|
+
processes (filesystem, custom tooling) or remote HTTPS endpoints.
|
|
245
247
|
Coverage matches what host applications like Claude Desktop surface:
|
|
246
248
|
|
|
247
249
|
| MCP capability | Coverage |
|
|
@@ -257,40 +259,67 @@ empty for that server.
|
|
|
257
259
|
|
|
258
260
|
### Configuring servers
|
|
259
261
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
Two transports are available — pick by config class:
|
|
263
|
+
|
|
264
|
+
- `ServerConfig` → **stdio**, child process launched locally.
|
|
265
|
+
- `HttpServerConfig` → **HTTP Streamable**, single HTTPS endpoint
|
|
266
|
+
(the transport defined for MCP 2025-03-26+ and required by 2025-11-25).
|
|
264
267
|
|
|
265
268
|
```ruby
|
|
266
|
-
# (a)
|
|
267
|
-
|
|
269
|
+
# (a) stdio — local process
|
|
270
|
+
fs = GroqRuby::MCP::ServerConfig.new(
|
|
268
271
|
name: "fs",
|
|
269
272
|
command: "npx",
|
|
270
273
|
args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/docs"]
|
|
271
274
|
)
|
|
272
275
|
|
|
273
|
-
# (b)
|
|
276
|
+
# (b) HTTP — remote endpoint, headers carry auth
|
|
277
|
+
remote = GroqRuby::MCP::HttpServerConfig.new(
|
|
278
|
+
name: "spectrum-ferret",
|
|
279
|
+
url: "https://mcp-staging.spectrumferret.com/mcp",
|
|
280
|
+
headers: {"Authorization" => "Bearer #{ENV.fetch("SF_TOKEN")}"}
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
bridge = GroqRuby::MCP::Bridge.new([fs, remote]) # mix freely
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Or load the same JSON shape Claude Desktop uses (`mcpServers` block) for
|
|
287
|
+
stdio servers — the adapter expands `${VAR}` references against each
|
|
288
|
+
server's `env` block first, then the process's `ENV`, and raises on
|
|
289
|
+
unresolved references.
|
|
290
|
+
|
|
291
|
+
```ruby
|
|
274
292
|
configs = GroqRuby::MCP::ClaudeDesktopConfig.load(
|
|
275
293
|
"~/Library/Application Support/Claude/claude_desktop_config.json"
|
|
276
294
|
)
|
|
277
295
|
bridge = GroqRuby::MCP::Bridge.new(configs)
|
|
296
|
+
```
|
|
278
297
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
298
|
+
#### Picking a protocol version
|
|
299
|
+
|
|
300
|
+
Each `Client` carries a `Protocol` object that selects an MCP spec year.
|
|
301
|
+
Defaults are sensible for each transport:
|
|
302
|
+
|
|
303
|
+
| Transport | Default protocol |
|
|
304
|
+
|--------------------|-------------------|
|
|
305
|
+
| `ServerConfig` | `Protocol::V2024_11_05` |
|
|
306
|
+
| `HttpServerConfig` | `Protocol::V2025_11_25` |
|
|
307
|
+
|
|
308
|
+
Override per-client when you need to:
|
|
309
|
+
|
|
310
|
+
```ruby
|
|
311
|
+
mcp = GroqRuby::MCP::Client.connect(
|
|
312
|
+
config,
|
|
313
|
+
protocol: GroqRuby::MCP::Protocol::V2024_11_05.new
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
mcp.protocol.version # => "2024-11-05"
|
|
292
317
|
```
|
|
293
318
|
|
|
319
|
+
`GroqRuby::MCP::Protocol.for("2025-11-25")` returns the matching class
|
|
320
|
+
(or `nil` for unknown versions); `Protocol.default` returns the
|
|
321
|
+
conservative default (`V2024_11_05`).
|
|
322
|
+
|
|
294
323
|
### Direct usage
|
|
295
324
|
|
|
296
325
|
```ruby
|
|
@@ -321,7 +350,7 @@ mcp.stop
|
|
|
321
350
|
|
|
322
351
|
`Bridge` does three things at construction:
|
|
323
352
|
|
|
324
|
-
1.
|
|
353
|
+
1. opens a transport for each config (stdio child process for `ServerConfig`, HTTPS connection for `HttpServerConfig`),
|
|
325
354
|
2. runs the MCP `initialize` handshake and asks each server for its tool list,
|
|
326
355
|
3. indexes those tools by namespaced name `<server>__<tool>` so collisions across servers are impossible.
|
|
327
356
|
|
|
@@ -443,7 +472,7 @@ Hierarchy:
|
|
|
443
472
|
| `GroqRuby::InternalServerError` | 5xx |
|
|
444
473
|
| `GroqRuby::APIResponseError` | API returned an unexpected payload |
|
|
445
474
|
| `GroqRuby::MCP::Error` | Base for any MCP-layer failure |
|
|
446
|
-
| `GroqRuby::MCP::TransportError` | Stdio pipe broke
|
|
475
|
+
| `GroqRuby::MCP::TransportError` | Stdio pipe broke / HTTP request failed / non-2xx |
|
|
447
476
|
| `GroqRuby::MCP::TimeoutError` | MCP request timed out |
|
|
448
477
|
| `GroqRuby::MCP::ProtocolError` | Server sent malformed JSON-RPC |
|
|
449
478
|
| `GroqRuby::MCP::JsonRpcError` | Server returned a JSON-RPC `error` |
|
|
@@ -469,6 +498,9 @@ The python SDK has a few features that aren't in `groq_ruby` v1:
|
|
|
469
498
|
- `with_raw_response` / `with_streaming_response` accessors (responses are always parsed into typed models).
|
|
470
499
|
- Built-in retries / backoff (handle in your own caller).
|
|
471
500
|
- MCP sampling and `notifications/list_changed` (resource and prompt inventories are snapshotted at `Bridge` construction).
|
|
501
|
+
- MCP tasks API (`tasks/get`, `tasks/result`, `tasks/list`, `tasks/cancel`) and `notifications/tasks/status` from the 2025-11-25 spec — the transport is in place; the methods land in a follow-up.
|
|
502
|
+
- Long-lived `GET` SSE channel for server-initiated notifications without an in-flight request — request-correlated SSE responses on `POST` are supported.
|
|
503
|
+
- MCP version negotiation downgrade: the `Protocol` object selected at construction is the version sent on every request; the server's response `protocolVersion` is recorded in `server_capabilities` but isn't auto-applied.
|
|
472
504
|
|
|
473
505
|
## Development
|
|
474
506
|
|
data/examples/README.md
CHANGED
|
@@ -19,6 +19,7 @@ bundle exec examples/error_handling.rb
|
|
|
19
19
|
bundle exec examples/mcp_agent.rb /path/to/sandbox # needs npx
|
|
20
20
|
bundle exec examples/mcp_chat_with_tools.rb /path/to/sandbox # needs npx
|
|
21
21
|
bundle exec examples/mcp_resources_and_prompts.rb /path/to/sandbox # needs npx
|
|
22
|
+
SF_TOKEN=... bundle exec examples/mcp_http_remote.rb # remote HTTP MCP server
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
| Script | Endpoint | What it shows |
|
|
@@ -37,3 +38,4 @@ bundle exec examples/mcp_resources_and_prompts.rb /path/to/sandbox # needs npx
|
|
|
37
38
|
| `mcp_agent.rb` | chat.completions + MCP | Minimal agent loop — bridge tools, dispatch tool_calls back |
|
|
38
39
|
| `mcp_chat_with_tools.rb` | chat.completions + MCP | Heavily annotated walkthrough of the same loop, step by step |
|
|
39
40
|
| `mcp_resources_and_prompts.rb` | chat.completions + MCP | Full coverage: tools + resources (synthetic read_resource) + prompts |
|
|
41
|
+
| `mcp_http_remote.rb` | MCP over HTTP Streamable transport | Connect to a remote MCP server (no child process), list its tools |
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# Talk to a remote MCP server over HTTP Streamable transport (no stdio,
|
|
3
|
+
# no child process, no `npx`). The server is reached at a single HTTPS
|
|
4
|
+
# endpoint and may speak the 2025-11-25 MCP protocol.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# GROQ_API_KEY=gsk_... \
|
|
8
|
+
# SF_TOKEN=... \
|
|
9
|
+
# bundle exec examples/mcp_http_remote.rb
|
|
10
|
+
#
|
|
11
|
+
# By default this connects to the Spectrum Ferret staging MCP server.
|
|
12
|
+
# Override with MCP_URL=https://your-server/mcp.
|
|
13
|
+
|
|
14
|
+
require "bundler/setup"
|
|
15
|
+
require "groq_ruby"
|
|
16
|
+
require "json"
|
|
17
|
+
|
|
18
|
+
url = ENV.fetch("MCP_URL", "https://mcp-staging.spectrumferret.com/mcp")
|
|
19
|
+
token = ENV["SF_TOKEN"]
|
|
20
|
+
|
|
21
|
+
headers = {}
|
|
22
|
+
headers["Authorization"] = "Bearer #{token}" if token
|
|
23
|
+
|
|
24
|
+
config = GroqRuby::MCP::HttpServerConfig.new(
|
|
25
|
+
name: "remote",
|
|
26
|
+
url: url,
|
|
27
|
+
headers: headers
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# By default Client.connect picks Protocol::V2025_11_25 for HTTP configs.
|
|
31
|
+
# Pass protocol: explicitly if you want to pin a specific version, e.g.
|
|
32
|
+
# GroqRuby::MCP::Client.connect(config, protocol: GroqRuby::MCP::Protocol::V2024_11_05.new)
|
|
33
|
+
mcp = GroqRuby::MCP::Client.connect(config)
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
puts "Connected to: #{mcp.server_name} #{mcp.server_version}"
|
|
37
|
+
puts "Protocol: #{mcp.protocol.version}"
|
|
38
|
+
puts "Capabilities: #{mcp.server_capabilities.keys.join(", ")}"
|
|
39
|
+
puts
|
|
40
|
+
|
|
41
|
+
tools = mcp.tools_list
|
|
42
|
+
puts "Tools (#{tools.size}):"
|
|
43
|
+
tools.first(10).each { |t| puts " - #{t.name}: #{t.description}" }
|
|
44
|
+
puts " ..." if tools.size > 10
|
|
45
|
+
ensure
|
|
46
|
+
mcp.stop
|
|
47
|
+
end
|
data/lib/groq_ruby/mcp/client.rb
CHANGED
|
@@ -18,15 +18,39 @@ module GroqRuby
|
|
|
18
18
|
class Client
|
|
19
19
|
DEFAULT_REQUEST_TIMEOUT = 30.0
|
|
20
20
|
|
|
21
|
-
# Connect to a server
|
|
22
|
-
#
|
|
21
|
+
# Connect to a server and complete the initialize handshake. The
|
|
22
|
+
# transport is chosen by config type — {ServerConfig} → stdio,
|
|
23
|
+
# {HttpServerConfig} → HTTP Streamable. Caller must call {#stop}
|
|
24
|
+
# when done.
|
|
23
25
|
#
|
|
24
|
-
# @param config [ServerConfig]
|
|
26
|
+
# @param config [ServerConfig, HttpServerConfig]
|
|
25
27
|
# @param request_timeout [Numeric] seconds to wait for any single response
|
|
28
|
+
# @param protocol [Object, nil] protocol object selecting an MCP spec
|
|
29
|
+
# year. If `nil`, a sensible default is picked from the config type
|
|
30
|
+
# (stdio → 2024-11-05, HTTP → 2025-11-25).
|
|
26
31
|
# @return [Client]
|
|
27
|
-
def self.connect(config, request_timeout: DEFAULT_REQUEST_TIMEOUT)
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
def self.connect(config, request_timeout: DEFAULT_REQUEST_TIMEOUT, protocol: nil)
|
|
33
|
+
protocol ||= default_protocol_for(config)
|
|
34
|
+
transport = build_transport(config, protocol)
|
|
35
|
+
new(transport, request_timeout: request_timeout, protocol: protocol).tap(&:initialize_session)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @api private
|
|
39
|
+
def self.build_transport(config, protocol)
|
|
40
|
+
case config
|
|
41
|
+
when HttpServerConfig
|
|
42
|
+
Transports::HttpStreamable.start(config, protocol_version: protocol.version)
|
|
43
|
+
else
|
|
44
|
+
Transports::Stdio.spawn(config)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @api private
|
|
49
|
+
def self.default_protocol_for(config)
|
|
50
|
+
case config
|
|
51
|
+
when HttpServerConfig then Protocol::V2025_11_25.new
|
|
52
|
+
else Protocol::V2024_11_05.new
|
|
53
|
+
end
|
|
30
54
|
end
|
|
31
55
|
|
|
32
56
|
# @return [String, nil] the server-reported name, populated after handshake
|
|
@@ -35,12 +59,16 @@ module GroqRuby
|
|
|
35
59
|
attr_reader :server_version
|
|
36
60
|
# @return [Hash] the server's advertised capabilities
|
|
37
61
|
attr_reader :server_capabilities
|
|
62
|
+
# @return [Object] the protocol object in use
|
|
63
|
+
attr_reader :protocol
|
|
38
64
|
|
|
39
65
|
# @param transport [Transport]
|
|
40
66
|
# @param request_timeout [Numeric]
|
|
41
|
-
|
|
67
|
+
# @param protocol [Object] protocol object selecting an MCP spec year
|
|
68
|
+
def initialize(transport, request_timeout: DEFAULT_REQUEST_TIMEOUT, protocol: Protocol.default)
|
|
42
69
|
@transport = transport
|
|
43
70
|
@request_timeout = request_timeout
|
|
71
|
+
@protocol = protocol
|
|
44
72
|
@next_id = 0
|
|
45
73
|
@id_mutex = Mutex.new
|
|
46
74
|
@pending = {}
|
|
@@ -52,11 +80,9 @@ module GroqRuby
|
|
|
52
80
|
# {.connect}; safe to call again to re-handshake.
|
|
53
81
|
# @return [Hash] the server's response payload
|
|
54
82
|
def initialize_session
|
|
55
|
-
result = request("initialize",
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
clientInfo: {name: "groq_ruby", version: GroqRuby::VERSION}
|
|
59
|
-
})
|
|
83
|
+
result = request("initialize", @protocol.initialize_params(
|
|
84
|
+
client_info: {name: "groq_ruby", version: GroqRuby::VERSION}
|
|
85
|
+
))
|
|
60
86
|
info = result["serverInfo"] || {}
|
|
61
87
|
@server_name = info["name"]
|
|
62
88
|
@server_version = info["version"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module GroqRuby
|
|
2
|
+
module MCP
|
|
3
|
+
# Description of an MCP server reachable over HTTP Streamable transport.
|
|
4
|
+
# Sibling of {ServerConfig} (which describes a stdio-launched server).
|
|
5
|
+
# Immutable — build one per server, then pass to {Client.connect} or
|
|
6
|
+
# {Bridge.new}.
|
|
7
|
+
#
|
|
8
|
+
# @example A remote MCP server with bearer auth
|
|
9
|
+
# HttpServerConfig.new(
|
|
10
|
+
# name: "spectrumferret",
|
|
11
|
+
# url: "https://mcp-staging.spectrumferret.com/mcp",
|
|
12
|
+
# headers: {"Authorization" => "Bearer #{ENV['SF_TOKEN']}"}
|
|
13
|
+
# )
|
|
14
|
+
class HttpServerConfig < Data.define(:name, :url, :headers)
|
|
15
|
+
# @param name [String] short identifier used to namespace tools in {Bridge}
|
|
16
|
+
# @param url [String] full URL of the MCP endpoint (single endpoint —
|
|
17
|
+
# the transport POSTs JSON-RPC and may receive SSE responses)
|
|
18
|
+
# @param headers [Hash{String => String}] extra HTTP headers added to
|
|
19
|
+
# every request (e.g. authorization)
|
|
20
|
+
def initialize(name:, url:, headers: {})
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module GroqRuby
|
|
2
|
+
module MCP
|
|
3
|
+
module Protocol
|
|
4
|
+
# MCP protocol version 2024-11-05 — the original public release.
|
|
5
|
+
# Stdio transport only; no tasks, no elicitation, no _meta fields.
|
|
6
|
+
#
|
|
7
|
+
# Class name underscores deliberately mirror the wire format.
|
|
8
|
+
class V2024_11_05 # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
9
|
+
VERSION = "2024-11-05".freeze
|
|
10
|
+
|
|
11
|
+
# @return [String] the protocol version this object speaks
|
|
12
|
+
def version
|
|
13
|
+
VERSION
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Build the `params` payload for the JSON-RPC `initialize` request.
|
|
17
|
+
# @param client_info [Hash] `{name:, version:}` describing the client
|
|
18
|
+
# @return [Hash]
|
|
19
|
+
def initialize_params(client_info:)
|
|
20
|
+
{
|
|
21
|
+
protocolVersion: VERSION,
|
|
22
|
+
capabilities: {},
|
|
23
|
+
clientInfo: client_info
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module GroqRuby
|
|
2
|
+
module MCP
|
|
3
|
+
module Protocol
|
|
4
|
+
# MCP protocol version 2025-11-25 — "The Task Master".
|
|
5
|
+
# HTTP/HTTPS transport only (no stdio). Adds tasks API, structured
|
|
6
|
+
# output, _meta fields, elicitation, OAuth 2.1 — the tasks methods
|
|
7
|
+
# land in a follow-up; this stub exposes only what the HTTP transport
|
|
8
|
+
# needs (the version string for the `MCP-Protocol-Version` header
|
|
9
|
+
# and the `protocolVersion` field in `initialize`).
|
|
10
|
+
#
|
|
11
|
+
# Class name underscores deliberately mirror the wire format.
|
|
12
|
+
class V2025_11_25 # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
13
|
+
VERSION = "2025-11-25".freeze
|
|
14
|
+
|
|
15
|
+
# @return [String] the protocol version this object speaks
|
|
16
|
+
def version
|
|
17
|
+
VERSION
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Build the `params` payload for the JSON-RPC `initialize` request.
|
|
21
|
+
# @param client_info [Hash] `{name:, version:}` describing the client
|
|
22
|
+
# @return [Hash]
|
|
23
|
+
def initialize_params(client_info:)
|
|
24
|
+
{
|
|
25
|
+
protocolVersion: VERSION,
|
|
26
|
+
capabilities: {},
|
|
27
|
+
clientInfo: client_info
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module GroqRuby
|
|
2
|
+
module MCP
|
|
3
|
+
# Per-version MCP protocol objects. A {Client} delegates version-specific
|
|
4
|
+
# decisions (initialize payload shape, supported capabilities) to one of
|
|
5
|
+
# these so callers can target different MCP spec years against the same
|
|
6
|
+
# transport.
|
|
7
|
+
#
|
|
8
|
+
# client = GroqRuby::MCP::Client.connect(
|
|
9
|
+
# config,
|
|
10
|
+
# protocol: GroqRuby::MCP::Protocol::V2024_11_05.new
|
|
11
|
+
# )
|
|
12
|
+
#
|
|
13
|
+
# Without an explicit `protocol:`, {Client} uses {.default}.
|
|
14
|
+
module Protocol
|
|
15
|
+
# Look up a protocol class by its wire version string. Returns `nil`
|
|
16
|
+
# if the version is unknown to this client.
|
|
17
|
+
# @param version [String] e.g. `"2024-11-05"`
|
|
18
|
+
# @return [Class, nil]
|
|
19
|
+
def self.for(version)
|
|
20
|
+
registry[version]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Object] a fresh instance of the default protocol
|
|
24
|
+
def self.default
|
|
25
|
+
V2024_11_05.new
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Hash{String => Class}]
|
|
29
|
+
def self.registry
|
|
30
|
+
{
|
|
31
|
+
V2024_11_05::VERSION => V2024_11_05,
|
|
32
|
+
V2025_11_25::VERSION => V2025_11_25
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
require "uri"
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module GroqRuby
|
|
6
|
+
module MCP
|
|
7
|
+
module Transports
|
|
8
|
+
# HTTP Streamable transport (the post-stdio transport defined by the
|
|
9
|
+
# MCP spec from 2025-03-26 onward and required by 2025-11-25).
|
|
10
|
+
#
|
|
11
|
+
# Single endpoint URL. Each outbound JSON-RPC frame is a `POST` whose
|
|
12
|
+
# response is either `application/json` (one frame) or
|
|
13
|
+
# `text/event-stream` (one or more frames followed by stream close).
|
|
14
|
+
# Notifications/responses get back a 202 with no body.
|
|
15
|
+
#
|
|
16
|
+
# `Mcp-Session-Id` is captured from the response to `initialize` and
|
|
17
|
+
# echoed on every subsequent request. `MCP-Protocol-Version` goes on
|
|
18
|
+
# every request.
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# config = HttpServerConfig.new(name: "x", url: "https://example/mcp")
|
|
22
|
+
# transport = Transports::HttpStreamable.start(config, protocol_version: "2025-11-25")
|
|
23
|
+
# transport.on_message { |msg| ... }
|
|
24
|
+
# transport.send_message({jsonrpc: "2.0", id: 1, method: "tools/list"})
|
|
25
|
+
#
|
|
26
|
+
# PR 2 limitation: there is no long-lived `GET` SSE channel for
|
|
27
|
+
# server-initiated notifications. Server-initiated traffic that
|
|
28
|
+
# arrives interleaved on a `POST` SSE response is dispatched, but
|
|
29
|
+
# standalone notifications (e.g. `notifications/tools/list_changed`
|
|
30
|
+
# with no in-flight request) are not yet received. Adding the GET
|
|
31
|
+
# stream is part of the tasks-API follow-up.
|
|
32
|
+
class HttpStreamable
|
|
33
|
+
include Transport
|
|
34
|
+
|
|
35
|
+
DEFAULT_OPEN_TIMEOUT = 10
|
|
36
|
+
DEFAULT_READ_TIMEOUT = 60
|
|
37
|
+
|
|
38
|
+
# Construct and return a transport ready to {#send_message}. The
|
|
39
|
+
# underlying HTTP connection is not opened until the first send;
|
|
40
|
+
# this is a pure constructor by another name.
|
|
41
|
+
# @param config [HttpServerConfig]
|
|
42
|
+
# @param protocol_version [String] e.g. `"2025-11-25"`
|
|
43
|
+
# @return [HttpStreamable]
|
|
44
|
+
def self.start(config, protocol_version:)
|
|
45
|
+
new(config, protocol_version: protocol_version)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [String] protocol version sent in the `MCP-Protocol-Version`
|
|
49
|
+
# header. Mutable so {Client} can update it after negotiation.
|
|
50
|
+
attr_accessor :protocol_version
|
|
51
|
+
|
|
52
|
+
# @return [String, nil] session id captured from the initialize
|
|
53
|
+
# response, or `nil` if the server is stateless
|
|
54
|
+
attr_reader :session_id
|
|
55
|
+
|
|
56
|
+
# @param config [HttpServerConfig]
|
|
57
|
+
# @param protocol_version [String]
|
|
58
|
+
# @param open_timeout [Numeric]
|
|
59
|
+
# @param read_timeout [Numeric]
|
|
60
|
+
def initialize(config, protocol_version:, open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT)
|
|
61
|
+
@config = config
|
|
62
|
+
@protocol_version = protocol_version
|
|
63
|
+
@open_timeout = open_timeout
|
|
64
|
+
@read_timeout = read_timeout
|
|
65
|
+
@uri = URI.parse(config.url)
|
|
66
|
+
@on_message = nil
|
|
67
|
+
@session_id = nil
|
|
68
|
+
@session_mutex = Mutex.new
|
|
69
|
+
@threads = []
|
|
70
|
+
@threads_mutex = Mutex.new
|
|
71
|
+
@stopped = false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def send_message(message)
|
|
75
|
+
return if @stopped
|
|
76
|
+
thread = Thread.new { post(message) }
|
|
77
|
+
@threads_mutex.synchronize { @threads << thread }
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def on_message(&block)
|
|
82
|
+
@on_message = block
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def stop
|
|
86
|
+
return if @stopped
|
|
87
|
+
@stopped = true
|
|
88
|
+
drain_threads
|
|
89
|
+
delete_session if @session_id
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
# Wait for in-flight POSTs to finish so we don't leave straggler
|
|
95
|
+
# threads making HTTP requests after the caller thinks we've shut
|
|
96
|
+
# down (especially important in tests, where stale threads pollute
|
|
97
|
+
# the next test's expectations).
|
|
98
|
+
def drain_threads
|
|
99
|
+
threads = @threads_mutex.synchronize { @threads.dup }
|
|
100
|
+
threads.each { |t| t.join(@read_timeout) }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def post(message)
|
|
104
|
+
req = build_request(Net::HTTP::Post, body: JSON.generate(message))
|
|
105
|
+
with_http do |http|
|
|
106
|
+
http.request(req) do |resp|
|
|
107
|
+
capture_session_id(resp)
|
|
108
|
+
handle_response(resp, message)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
rescue => e
|
|
112
|
+
surface_request_failure(message, e)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def delete_session
|
|
116
|
+
req = build_request(Net::HTTP::Delete)
|
|
117
|
+
with_http { |http| http.request(req) }
|
|
118
|
+
rescue
|
|
119
|
+
# Session termination is best-effort; the server will GC stale
|
|
120
|
+
# sessions on its own.
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def with_http(&block)
|
|
124
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
|
125
|
+
http.use_ssl = (@uri.scheme == "https")
|
|
126
|
+
http.open_timeout = @open_timeout
|
|
127
|
+
http.read_timeout = @read_timeout
|
|
128
|
+
http.start(&block)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def build_request(klass, body: nil)
|
|
132
|
+
req = klass.new(@uri.request_uri)
|
|
133
|
+
apply_headers(req)
|
|
134
|
+
if body
|
|
135
|
+
req.body = body
|
|
136
|
+
req["Content-Type"] = "application/json"
|
|
137
|
+
end
|
|
138
|
+
req
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def apply_headers(req)
|
|
142
|
+
req["Accept"] = "application/json, text/event-stream"
|
|
143
|
+
req["MCP-Protocol-Version"] = @protocol_version
|
|
144
|
+
if (sid = current_session_id)
|
|
145
|
+
req["Mcp-Session-Id"] = sid
|
|
146
|
+
end
|
|
147
|
+
@config.headers.each { |k, v| req[k] = v }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def current_session_id
|
|
151
|
+
@session_mutex.synchronize { @session_id }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def capture_session_id(resp)
|
|
155
|
+
value = resp["Mcp-Session-Id"] || resp["mcp-session-id"]
|
|
156
|
+
return if value.nil? || value.empty?
|
|
157
|
+
@session_mutex.synchronize { @session_id = value }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def handle_response(resp, request_message)
|
|
161
|
+
status = resp.code.to_i
|
|
162
|
+
case status
|
|
163
|
+
when 200 then dispatch_body(resp)
|
|
164
|
+
when 202 then nil
|
|
165
|
+
else surface_request_failure(request_message, TransportError.new("HTTP #{status} from MCP server #{@config.name.inspect}"))
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def dispatch_body(resp)
|
|
170
|
+
ctype = resp["Content-Type"].to_s
|
|
171
|
+
if ctype.include?("text/event-stream")
|
|
172
|
+
dispatch_sse(resp)
|
|
173
|
+
else
|
|
174
|
+
dispatch_json_body(resp)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def dispatch_json_body(resp)
|
|
179
|
+
body = read_body(resp)
|
|
180
|
+
return if body.nil? || body.empty?
|
|
181
|
+
message = JSON.parse(body)
|
|
182
|
+
@on_message&.call(message)
|
|
183
|
+
rescue JSON::ParserError
|
|
184
|
+
# Malformed; nothing actionable. Drop.
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def dispatch_sse(resp)
|
|
188
|
+
parser = Streaming::EventParser.new
|
|
189
|
+
buffer = +""
|
|
190
|
+
resp.read_body { |chunk| buffer << chunk }
|
|
191
|
+
parser.feed(buffer) do |_event, data, _id, _retry|
|
|
192
|
+
next if data.nil? || data.empty?
|
|
193
|
+
begin
|
|
194
|
+
@on_message&.call(JSON.parse(data))
|
|
195
|
+
rescue JSON::ParserError
|
|
196
|
+
# Skip malformed event payloads.
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def read_body(resp)
|
|
202
|
+
# Net::HTTP block form requires read_body; outside the block the
|
|
203
|
+
# body would be auto-loaded.
|
|
204
|
+
chunks = +""
|
|
205
|
+
resp.read_body { |c| chunks << c }
|
|
206
|
+
chunks
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def surface_request_failure(request_message, error)
|
|
210
|
+
id = request_message[:id] || request_message["id"]
|
|
211
|
+
return unless id && @on_message
|
|
212
|
+
@on_message.call({
|
|
213
|
+
"jsonrpc" => "2.0",
|
|
214
|
+
"id" => id,
|
|
215
|
+
"error" => {"code" => -32000, "message" => error.message}
|
|
216
|
+
})
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
data/lib/groq_ruby/version.rb
CHANGED
data/lib/groq_ruby.rb
CHANGED
|
@@ -9,7 +9,9 @@ loader.inflector.inflect(
|
|
|
9
9
|
"api_connection_error" => "APIConnectionError",
|
|
10
10
|
"api_timeout_error" => "APITimeoutError",
|
|
11
11
|
"api_status_error" => "APIStatusError",
|
|
12
|
-
"api_response_error" => "APIResponseError"
|
|
12
|
+
"api_response_error" => "APIResponseError",
|
|
13
|
+
"v2024_11_05" => "V2024_11_05",
|
|
14
|
+
"v2025_11_25" => "V2025_11_25"
|
|
13
15
|
)
|
|
14
16
|
# Collapse organizational sub-directories so files inside them define
|
|
15
17
|
# constants in the parent namespace. Public API stays flat — callers
|
data/sig/groq_ruby.rbs
CHANGED
|
@@ -124,6 +124,18 @@ module GroqRuby
|
|
|
124
124
|
) -> void
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
+
class HttpServerConfig
|
|
128
|
+
attr_reader name: String
|
|
129
|
+
attr_reader url: String
|
|
130
|
+
attr_reader headers: Hash[String, String]
|
|
131
|
+
|
|
132
|
+
def initialize: (
|
|
133
|
+
name: String,
|
|
134
|
+
url: String,
|
|
135
|
+
?headers: Hash[String, String]
|
|
136
|
+
) -> void
|
|
137
|
+
end
|
|
138
|
+
|
|
127
139
|
module ClaudeDesktopConfig
|
|
128
140
|
VAR_PATTERN: Regexp
|
|
129
141
|
|
|
@@ -131,6 +143,24 @@ module GroqRuby
|
|
|
131
143
|
def self.parse: ((Hash[untyped, untyped] | String) input) -> Array[ServerConfig]
|
|
132
144
|
end
|
|
133
145
|
|
|
146
|
+
module Protocol
|
|
147
|
+
def self.for: (String version) -> untyped
|
|
148
|
+
def self.default: () -> untyped
|
|
149
|
+
def self.registry: () -> Hash[String, untyped]
|
|
150
|
+
|
|
151
|
+
class V2024_11_05
|
|
152
|
+
VERSION: String
|
|
153
|
+
def version: () -> String
|
|
154
|
+
def initialize_params: (client_info: Hash[Symbol, String]) -> Hash[Symbol, untyped]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
class V2025_11_25
|
|
158
|
+
VERSION: String
|
|
159
|
+
def version: () -> String
|
|
160
|
+
def initialize_params: (client_info: Hash[Symbol, String]) -> Hash[Symbol, untyped]
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
134
164
|
class Tool
|
|
135
165
|
attr_reader name: String
|
|
136
166
|
attr_reader description: String?
|
|
@@ -159,9 +189,10 @@ module GroqRuby
|
|
|
159
189
|
attr_reader server_name: String?
|
|
160
190
|
attr_reader server_version: String?
|
|
161
191
|
attr_reader server_capabilities: Hash[String, untyped]
|
|
192
|
+
attr_reader protocol: untyped
|
|
162
193
|
|
|
163
|
-
def self.connect: (ServerConfig, ?request_timeout: Numeric) -> Client
|
|
164
|
-
def initialize: (untyped transport, ?request_timeout: Numeric) -> void
|
|
194
|
+
def self.connect: ((ServerConfig | HttpServerConfig) config, ?request_timeout: Numeric, ?protocol: untyped) -> Client
|
|
195
|
+
def initialize: (untyped transport, ?request_timeout: Numeric, ?protocol: untyped) -> void
|
|
165
196
|
def initialize_session: () -> Hash[String, untyped]
|
|
166
197
|
def tools_list: () -> Array[Tool]
|
|
167
198
|
def tools_call: (name: String, ?arguments: Hash[untyped, untyped]) -> Hash[String, untyped]
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: groq_ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pawel Osiczko
|
|
@@ -118,6 +118,7 @@ files:
|
|
|
118
118
|
- examples/file_upload.rb
|
|
119
119
|
- examples/mcp_agent.rb
|
|
120
120
|
- examples/mcp_chat_with_tools.rb
|
|
121
|
+
- examples/mcp_http_remote.rb
|
|
121
122
|
- examples/mcp_resources_and_prompts.rb
|
|
122
123
|
- examples/models_list.rb
|
|
123
124
|
- examples/speech.rb
|
|
@@ -153,12 +154,17 @@ files:
|
|
|
153
154
|
- lib/groq_ruby/mcp/errors/timeout_error.rb
|
|
154
155
|
- lib/groq_ruby/mcp/errors/transport_error.rb
|
|
155
156
|
- lib/groq_ruby/mcp/errors/unknown_tool_error.rb
|
|
157
|
+
- lib/groq_ruby/mcp/http_server_config.rb
|
|
156
158
|
- lib/groq_ruby/mcp/json_rpc.rb
|
|
157
159
|
- lib/groq_ruby/mcp/prompt.rb
|
|
160
|
+
- lib/groq_ruby/mcp/protocol.rb
|
|
161
|
+
- lib/groq_ruby/mcp/protocol/v2024_11_05.rb
|
|
162
|
+
- lib/groq_ruby/mcp/protocol/v2025_11_25.rb
|
|
158
163
|
- lib/groq_ruby/mcp/resource.rb
|
|
159
164
|
- lib/groq_ruby/mcp/server_config.rb
|
|
160
165
|
- lib/groq_ruby/mcp/tool.rb
|
|
161
166
|
- lib/groq_ruby/mcp/transport.rb
|
|
167
|
+
- lib/groq_ruby/mcp/transports/http_streamable.rb
|
|
162
168
|
- lib/groq_ruby/mcp/transports/stdio.rb
|
|
163
169
|
- lib/groq_ruby/models/audio/transcription.rb
|
|
164
170
|
- lib/groq_ruby/models/audio/translation.rb
|
metadata.gz.sig
CHANGED
|
Binary file
|