datagrout-conduit 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8fcac4a1dc9cdb77ca7e0b1b75eb44fcacf867966312e05f21b93c0cba63a6cb
4
+ data.tar.gz: 7faa4fc8a6c23fb5eee90fb07b2cd02caee23245bc68899d297a32d693c1b464
5
+ SHA512:
6
+ metadata.gz: cca7ceddb65cb22cd3283659a6b44a792e683f4c57d93f9fe49226f00a71890fc59237f97c1cf13d56849febc453f7a0d84cd2ca4cfba5e967222a268c46f2b5
7
+ data.tar.gz: 95ab6ae19cf9a6a1b23b9444f7063fb0bcdd64d1a407af589bd00c543eb349aec98226dcfcba06598a879a6150578fbbf872fc358b84c4b9da38f55f45530228
data/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # DataGrout Conduit SDK for Ruby
2
+
3
+ Production-ready MCP client with mTLS, OAuth 2.1, and semantic discovery.
4
+
5
+ Connect to remote MCP and JSONRPC servers, invoke tools, discover capabilities with natural language, and track costs — all with enterprise-grade security.
6
+
7
+ ## Installation
8
+
9
+ Add to your Gemfile:
10
+
11
+ ```ruby
12
+ gem "datagrout-conduit", "~> 0.1"
13
+ ```
14
+
15
+ Or install directly:
16
+
17
+ ```sh
18
+ gem install datagrout-conduit
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```ruby
24
+ require "datagrout_conduit"
25
+
26
+ # Create a client
27
+ client = DatagroutConduit::Client.new(
28
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
29
+ auth: { bearer: "your-token" }
30
+ )
31
+
32
+ # Connect and initialize the MCP session
33
+ client.connect
34
+
35
+ # List available tools
36
+ tools = client.list_tools
37
+ puts "Found #{tools.size} tools"
38
+
39
+ # Call a tool
40
+ result = client.call_tool("salesforce@1/get_lead@1", { id: "123" })
41
+ puts result
42
+
43
+ # Disconnect
44
+ client.disconnect
45
+ ```
46
+
47
+ ## Authentication
48
+
49
+ ### Bearer Token
50
+
51
+ ```ruby
52
+ client = DatagroutConduit::Client.new(
53
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
54
+ auth: { bearer: "your-token" }
55
+ )
56
+ ```
57
+
58
+ ### API Key
59
+
60
+ ```ruby
61
+ client = DatagroutConduit::Client.new(
62
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
63
+ auth: { api_key: "your-api-key" }
64
+ )
65
+ ```
66
+
67
+ ### OAuth 2.1 (Client Credentials)
68
+
69
+ ```ruby
70
+ provider = DatagroutConduit::OAuth::TokenProvider.new(
71
+ client_id: "my_client_id",
72
+ client_secret: "my_client_secret",
73
+ token_endpoint: "https://app.datagrout.ai/servers/{uuid}/oauth/token"
74
+ )
75
+
76
+ client = DatagroutConduit::Client.new(
77
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
78
+ auth: { oauth: provider }
79
+ )
80
+ ```
81
+
82
+ The token endpoint is auto-derived from MCP URLs — `/mcp` becomes `/oauth/token`. Tokens are cached and refreshed 60 seconds before expiry.
83
+
84
+ ### mTLS (Mutual TLS)
85
+
86
+ ```ruby
87
+ # Auto-discover identity from standard locations
88
+ identity = DatagroutConduit::Identity.try_discover
89
+
90
+ # Or load explicitly
91
+ identity = DatagroutConduit::Identity.from_paths("cert.pem", "key.pem", ca_path: "ca.pem")
92
+
93
+ # Or from PEM strings
94
+ identity = DatagroutConduit::Identity.from_pem(cert_pem, key_pem, ca_pem: ca_pem)
95
+
96
+ # Or from environment variables
97
+ identity = DatagroutConduit::Identity.from_env
98
+
99
+ client = DatagroutConduit::Client.new(
100
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
101
+ identity: identity
102
+ )
103
+ ```
104
+
105
+ Identity auto-discovery order:
106
+
107
+ 1. `override_dir` (if provided)
108
+ 2. `CONDUIT_MTLS_CERT` + `CONDUIT_MTLS_KEY` env vars
109
+ 3. `CONDUIT_IDENTITY_DIR` env var
110
+ 4. `~/.conduit/identity.pem` + `identity_key.pem`
111
+ 5. `.conduit/` relative to cwd
112
+
113
+ For DataGrout URLs, identity discovery happens automatically.
114
+
115
+ ### Identity Registration & Bootstrap
116
+
117
+ Bootstrap a new mTLS identity with a one-time access token:
118
+
119
+ ```ruby
120
+ client = DatagroutConduit::Client.bootstrap_identity(
121
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
122
+ auth_token: "your-one-time-token",
123
+ name: "my-agent"
124
+ )
125
+ ```
126
+
127
+ Or with OAuth client credentials:
128
+
129
+ ```ruby
130
+ client = DatagroutConduit::Client.bootstrap_identity_oauth(
131
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
132
+ client_id: "id",
133
+ client_secret: "secret",
134
+ name: "my-agent"
135
+ )
136
+ ```
137
+
138
+ After bootstrap, subsequent runs auto-discover the saved identity — no tokens needed.
139
+
140
+ You can also use the registration class directly:
141
+
142
+ ```ruby
143
+ private_pem, public_pem = DatagroutConduit::Registration.generate_keypair
144
+ response = DatagroutConduit::Registration.register_identity(public_pem, auth_token: "token")
145
+ paths = DatagroutConduit::Registration.save_identity(response.cert_pem, private_pem, "~/.conduit", ca_pem: response.ca_cert_pem)
146
+ ca_pem = DatagroutConduit::Registration.fetch_ca_cert
147
+ ```
148
+
149
+ ## Transports
150
+
151
+ ### MCP (default)
152
+
153
+ ```ruby
154
+ client = DatagroutConduit::Client.new(
155
+ url: "https://gateway.datagrout.ai/servers/{uuid}/mcp",
156
+ auth: { bearer: "token" },
157
+ transport: :mcp
158
+ )
159
+ ```
160
+
161
+ ### JSONRPC
162
+
163
+ ```ruby
164
+ client = DatagroutConduit::Client.new(
165
+ url: "https://gateway.datagrout.ai/servers/{uuid}/jsonrpc",
166
+ auth: { bearer: "token" },
167
+ transport: :jsonrpc
168
+ )
169
+ ```
170
+
171
+ Both transports send JSON-RPC 2.0 requests via HTTP POST. MCP uses the MCP Streamable HTTP framing. Both configure Faraday SSL with mTLS client certificates when an identity is present.
172
+
173
+ ## Standard MCP Methods
174
+
175
+ ```ruby
176
+ client.connect
177
+
178
+ # Tools
179
+ tools = client.list_tools
180
+ result = client.call_tool("tool-name", { arg: "value" })
181
+
182
+ # Resources
183
+ resources = client.list_resources
184
+ content = client.read_resource("resource://uri")
185
+
186
+ # Prompts
187
+ prompts = client.list_prompts
188
+ messages = client.get_prompt("prompt-name", { key: "value" })
189
+
190
+ client.disconnect
191
+ ```
192
+
193
+ ## DataGrout Extensions
194
+
195
+ ### Semantic Discovery
196
+
197
+ Find tools by natural language — 10-100x more token-efficient than listing all tools.
198
+
199
+ ```ruby
200
+ results = client.discover(goal: "find unpaid invoices", limit: 10)
201
+ results.tools.each do |tool|
202
+ puts "#{tool.name} (score: #{tool.score})"
203
+ end
204
+ ```
205
+
206
+ ### Intelligent Tool Execution
207
+
208
+ ```ruby
209
+ result = client.perform("salesforce@1/get_lead@1", { email: "john@example.com" }, demux: false)
210
+ ```
211
+
212
+ ### Guided Workflows
213
+
214
+ ```ruby
215
+ session = client.guide(goal: "create invoice from lead")
216
+ puts session.status # => "in_progress"
217
+ puts session.options # => available choices
218
+
219
+ session = session.choose("option_a")
220
+ result = session.complete # => final result when status == "completed"
221
+ ```
222
+
223
+ ### Flow Orchestration
224
+
225
+ ```ruby
226
+ plan = [
227
+ { "tool" => "get_lead", "args" => { "email" => "john@example.com" } },
228
+ { "tool" => "create_invoice", "args" => { "lead_id" => "$prev.id" } }
229
+ ]
230
+ result = client.flow_into(plan)
231
+ ```
232
+
233
+ ### Prism Focus
234
+
235
+ ```ruby
236
+ result = client.prism_focus(data: raw_data, lens: "summary")
237
+ ```
238
+
239
+ ### Cost Estimation
240
+
241
+ ```ruby
242
+ estimate = client.estimate_cost("salesforce@1/get_lead@1", { id: "123" })
243
+ ```
244
+
245
+ ## Cost Tracking
246
+
247
+ Every tool-call result from DataGrout includes a cost receipt:
248
+
249
+ ```ruby
250
+ result = client.call_tool("salesforce@1/get_lead@1", { id: "123" })
251
+
252
+ meta = DatagroutConduit.extract_meta(result)
253
+ if meta
254
+ puts "Credits charged: #{meta.receipt.net_credits}"
255
+ puts "Receipt ID: #{meta.receipt.receipt_id}"
256
+ puts "Balance: #{meta.receipt.balance_after}"
257
+
258
+ if meta.receipt.byok.enabled
259
+ puts "BYOK discount: #{meta.receipt.byok.discount_applied}"
260
+ end
261
+ end
262
+ ```
263
+
264
+ ## Behaviors
265
+
266
+ - **DataGrout URL detection**: `DatagroutConduit.dg_url?(url)` returns `true` for `datagrout.ai` or `datagrout.dev` domains
267
+ - **Intelligent interface**: Automatically enabled for DG URLs — `list_tools` filters to non-`@` tools (DG semantic tools only). Disable with `use_intelligent_interface: false`
268
+ - **Auto mTLS**: DG URLs automatically attempt identity discovery
269
+ - **DG extension warnings**: Non-DG URLs log a one-time warning when DG-specific methods are called
270
+ - **Default transport**: `:mcp`
271
+
272
+ ## Error Handling
273
+
274
+ ```ruby
275
+ begin
276
+ client.list_tools
277
+ rescue DatagroutConduit::NotInitializedError
278
+ client.connect
279
+ retry
280
+ rescue DatagroutConduit::McpError => e
281
+ puts "MCP error #{e.code}: #{e.message}"
282
+ rescue DatagroutConduit::RateLimitedError => e
283
+ puts "Rate limited: #{e.used}/#{e.limit}"
284
+ rescue DatagroutConduit::AuthError => e
285
+ puts "Authentication failed: #{e.message}"
286
+ rescue DatagroutConduit::ConnectionError => e
287
+ puts "Connection error: #{e.message}"
288
+ rescue DatagroutConduit::ConfigError => e
289
+ puts "Configuration error: #{e.message}"
290
+ end
291
+ ```
292
+
293
+ ## Links
294
+
295
+ - [DataGrout Library](https://library.datagrout.ai) — Browse and discover integrations
296
+ - [Security](https://app.datagrout.ai/security) — Security documentation
297
+ - [MCP Inspector](https://app.datagrout.ai/inspector) — Interactive MCP testing
298
+ - [JSONRPC Inspector](https://app.datagrout.ai/jsonrpc-inspector) — Interactive JSONRPC testing
299
+ - [Labs Papers](https://datagrout.ai/labs) — Research and whitepapers
300
+
301
+ ## License
302
+
303
+ MIT License. Copyright (c) DataGrout.