robot_lab 0.0.1 → 0.0.4

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.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/deploy-github-pages.yml +9 -9
  3. data/.irbrc +6 -0
  4. data/CHANGELOG.md +90 -0
  5. data/README.md +203 -46
  6. data/Rakefile +70 -1
  7. data/docs/api/core/index.md +12 -0
  8. data/docs/api/core/robot.md +478 -130
  9. data/docs/api/core/tool.md +205 -209
  10. data/docs/api/history/active-record-adapter.md +174 -94
  11. data/docs/api/history/config.md +186 -93
  12. data/docs/api/history/index.md +57 -61
  13. data/docs/api/history/thread-manager.md +123 -73
  14. data/docs/api/mcp/client.md +119 -48
  15. data/docs/api/mcp/index.md +75 -60
  16. data/docs/api/mcp/server.md +120 -136
  17. data/docs/api/mcp/transports.md +172 -184
  18. data/docs/api/streaming/context.md +157 -74
  19. data/docs/api/streaming/events.md +114 -166
  20. data/docs/api/streaming/index.md +74 -72
  21. data/docs/architecture/core-concepts.md +361 -112
  22. data/docs/architecture/index.md +97 -59
  23. data/docs/architecture/message-flow.md +138 -129
  24. data/docs/architecture/network-orchestration.md +197 -50
  25. data/docs/architecture/robot-execution.md +199 -146
  26. data/docs/architecture/state-management.md +255 -187
  27. data/docs/concepts.md +312 -48
  28. data/docs/examples/basic-chat.md +89 -77
  29. data/docs/examples/index.md +222 -47
  30. data/docs/examples/mcp-server.md +207 -203
  31. data/docs/examples/multi-robot-network.md +129 -35
  32. data/docs/examples/rails-application.md +159 -160
  33. data/docs/examples/tool-usage.md +295 -204
  34. data/docs/getting-started/configuration.md +275 -162
  35. data/docs/getting-started/index.md +1 -1
  36. data/docs/getting-started/installation.md +22 -13
  37. data/docs/getting-started/quick-start.md +166 -121
  38. data/docs/guides/building-robots.md +417 -212
  39. data/docs/guides/creating-networks.md +94 -24
  40. data/docs/guides/mcp-integration.md +152 -113
  41. data/docs/guides/memory.md +220 -164
  42. data/docs/guides/streaming.md +80 -110
  43. data/docs/guides/using-tools.md +259 -212
  44. data/docs/index.md +50 -37
  45. data/examples/01_simple_robot.rb +6 -9
  46. data/examples/02_tools.rb +6 -9
  47. data/examples/03_network.rb +13 -14
  48. data/examples/04_mcp.rb +5 -8
  49. data/examples/05_streaming.rb +5 -8
  50. data/examples/06_prompt_templates.rb +42 -37
  51. data/examples/07_network_memory.rb +13 -14
  52. data/examples/08_llm_config.rb +140 -0
  53. data/examples/09_chaining.rb +223 -0
  54. data/examples/10_memory.rb +331 -0
  55. data/examples/11_network_introspection.rb +230 -0
  56. data/examples/12_message_bus.rb +74 -0
  57. data/examples/13_spawn.rb +90 -0
  58. data/examples/14_rusty_circuit/comic.rb +143 -0
  59. data/examples/14_rusty_circuit/display.rb +203 -0
  60. data/examples/14_rusty_circuit/heckler.rb +57 -0
  61. data/examples/14_rusty_circuit/open_mic.rb +121 -0
  62. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +20 -0
  63. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +23 -0
  64. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +20 -0
  65. data/examples/14_rusty_circuit/scout.rb +173 -0
  66. data/examples/14_rusty_circuit/scout_notes.md +89 -0
  67. data/examples/14_rusty_circuit/show.log +234 -0
  68. data/examples/15_memory_network_and_bus/editor_in_chief.rb +24 -0
  69. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +206 -0
  70. data/examples/15_memory_network_and_bus/linux_writer.rb +80 -0
  71. data/examples/15_memory_network_and_bus/os_editor.rb +46 -0
  72. data/examples/15_memory_network_and_bus/os_writer.rb +46 -0
  73. data/examples/15_memory_network_and_bus/output/combined_article.md +13 -0
  74. data/examples/15_memory_network_and_bus/output/final_article.md +15 -0
  75. data/examples/15_memory_network_and_bus/output/linux_draft.md +5 -0
  76. data/examples/15_memory_network_and_bus/output/mac_draft.md +7 -0
  77. data/examples/15_memory_network_and_bus/output/memory.json +13 -0
  78. data/examples/15_memory_network_and_bus/output/revision_1.md +19 -0
  79. data/examples/15_memory_network_and_bus/output/revision_2.md +15 -0
  80. data/examples/15_memory_network_and_bus/output/windows_draft.md +7 -0
  81. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +13 -0
  82. data/examples/15_memory_network_and_bus/prompts/os_chief.md +13 -0
  83. data/examples/15_memory_network_and_bus/prompts/os_editor.md +13 -0
  84. data/examples/README.md +197 -0
  85. data/examples/prompts/{assistant/system.txt.erb → assistant.md} +3 -0
  86. data/examples/prompts/{billing/system.txt.erb → billing.md} +3 -0
  87. data/examples/prompts/{classifier/system.txt.erb → classifier.md} +3 -0
  88. data/examples/prompts/comedian.md +6 -0
  89. data/examples/prompts/comedy_critic.md +10 -0
  90. data/examples/prompts/configurable.md +9 -0
  91. data/examples/prompts/dispatcher.md +12 -0
  92. data/examples/prompts/{entity_extractor/system.txt.erb → entity_extractor.md} +3 -0
  93. data/examples/prompts/{escalation/system.txt.erb → escalation.md} +7 -0
  94. data/examples/prompts/frontmatter_mcp_test.md +9 -0
  95. data/examples/prompts/frontmatter_named_test.md +5 -0
  96. data/examples/prompts/frontmatter_tools_test.md +6 -0
  97. data/examples/prompts/{general/system.txt.erb → general.md} +3 -0
  98. data/examples/prompts/{github_assistant/system.txt.erb → github_assistant.md} +8 -0
  99. data/examples/prompts/{helper/system.txt.erb → helper.md} +3 -0
  100. data/examples/prompts/{keyword_extractor/system.txt.erb → keyword_extractor.md} +3 -0
  101. data/examples/prompts/llm_config_demo.md +20 -0
  102. data/examples/prompts/{order_support/system.txt.erb → order_support.md} +8 -0
  103. data/examples/prompts/os_advocate.md +13 -0
  104. data/examples/prompts/os_chief.md +13 -0
  105. data/examples/prompts/os_editor.md +13 -0
  106. data/examples/prompts/{product_support/system.txt.erb → product_support.md} +7 -0
  107. data/examples/prompts/{sentiment_analyzer/system.txt.erb → sentiment_analyzer.md} +3 -0
  108. data/examples/prompts/{synthesizer/system.txt.erb → synthesizer.md} +3 -0
  109. data/examples/prompts/{technical/system.txt.erb → technical.md} +3 -0
  110. data/examples/prompts/{triage/system.txt.erb → triage.md} +6 -0
  111. data/lib/generators/robot_lab/templates/initializer.rb.tt +1 -1
  112. data/lib/robot_lab/adapters/openai.rb +2 -1
  113. data/lib/robot_lab/ask_user.rb +75 -0
  114. data/lib/robot_lab/config/defaults.yml +121 -0
  115. data/lib/robot_lab/config.rb +183 -0
  116. data/lib/robot_lab/error.rb +6 -0
  117. data/lib/robot_lab/mcp/client.rb +1 -1
  118. data/lib/robot_lab/memory.rb +2 -2
  119. data/lib/robot_lab/robot.rb +523 -249
  120. data/lib/robot_lab/robot_message.rb +44 -0
  121. data/lib/robot_lab/robot_result.rb +1 -0
  122. data/lib/robot_lab/robotic_model.rb +1 -1
  123. data/lib/robot_lab/streaming/context.rb +1 -1
  124. data/lib/robot_lab/tool.rb +108 -172
  125. data/lib/robot_lab/tool_config.rb +1 -1
  126. data/lib/robot_lab/tool_manifest.rb +2 -18
  127. data/lib/robot_lab/version.rb +1 -1
  128. data/lib/robot_lab.rb +66 -55
  129. metadata +107 -116
  130. data/examples/prompts/assistant/user.txt.erb +0 -1
  131. data/examples/prompts/billing/user.txt.erb +0 -1
  132. data/examples/prompts/classifier/user.txt.erb +0 -1
  133. data/examples/prompts/entity_extractor/user.txt.erb +0 -3
  134. data/examples/prompts/escalation/user.txt.erb +0 -34
  135. data/examples/prompts/general/user.txt.erb +0 -1
  136. data/examples/prompts/github_assistant/user.txt.erb +0 -1
  137. data/examples/prompts/helper/user.txt.erb +0 -1
  138. data/examples/prompts/keyword_extractor/user.txt.erb +0 -3
  139. data/examples/prompts/order_support/user.txt.erb +0 -22
  140. data/examples/prompts/product_support/user.txt.erb +0 -32
  141. data/examples/prompts/sentiment_analyzer/user.txt.erb +0 -3
  142. data/examples/prompts/synthesizer/user.txt.erb +0 -15
  143. data/examples/prompts/technical/user.txt.erb +0 -1
  144. data/examples/prompts/triage/user.txt.erb +0 -17
  145. data/lib/robot_lab/configuration.rb +0 -143
@@ -4,108 +4,123 @@ Integration with MCP servers for extended tool capabilities.
4
4
 
5
5
  ## Overview
6
6
 
7
- MCP allows robots to connect to external tool servers, extending their capabilities without modifying robot code.
7
+ MCP allows robots to connect to external tool servers, extending their capabilities without modifying robot code. RobotLab provides an MCP client that communicates with MCP-compliant servers over multiple transport types.
8
8
 
9
9
  ```ruby
10
- robot = RobotLab.build do
11
- name "developer"
12
- template "You help with coding tasks."
13
-
14
- mcp [
10
+ robot = Robot.new(
11
+ name: "developer",
12
+ system_prompt: "You help with coding tasks.",
13
+ mcp: [
15
14
  {
16
15
  name: "filesystem",
17
16
  transport: { type: "stdio", command: "npx @modelcontextprotocol/server-filesystem" }
18
17
  }
19
18
  ]
20
- end
19
+ )
21
20
  ```
22
21
 
23
22
  ## Components
24
23
 
25
24
  | Component | Description |
26
25
  |-----------|-------------|
27
- | [Client](client.md) | Connects to MCP servers |
28
- | [Server](server.md) | Exposes tools via MCP |
29
- | [Transports](transports.md) | Communication methods |
26
+ | [Client](client.md) | Connects to MCP servers, lists tools, calls tools |
27
+ | [Server](server.md) | Server configuration data structure |
28
+ | [Transports](transports.md) | Communication methods (stdio, WebSocket, SSE, HTTP) |
30
29
 
31
30
  ## Quick Start
32
31
 
33
- ### Using MCP Tools
32
+ ### Using MCP with a Robot
34
33
 
35
- ```ruby
36
- network = RobotLab.create_network do
37
- name "with_mcp"
34
+ Pass MCP server configurations via the `mcp:` parameter when creating a robot:
38
35
 
39
- mcp [
36
+ ```ruby
37
+ robot = Robot.new(
38
+ name: "assistant",
39
+ template: :assistant,
40
+ mcp: [
40
41
  { name: "github", transport: { type: "stdio", command: "mcp-server-github" } }
41
42
  ]
43
+ )
42
44
 
43
- add_robot RobotLab.build {
44
- name "assistant"
45
- template "You help with GitHub tasks."
46
- mcp :inherit # Use network's MCP servers
47
- }
48
- end
45
+ result = robot.run("List my open pull requests")
46
+ result.last_text_content
49
47
  ```
50
48
 
51
- ### Creating an MCP Server
49
+ ### MCP in Networks
50
+
51
+ Robots in a network can inherit MCP servers from the network or define their own:
52
52
 
53
53
  ```ruby
54
- server = RobotLab::MCP::Server.new(name: "my_tools")
54
+ network_mcp = [
55
+ { name: "github", transport: { type: "stdio", command: "mcp-server-github" } }
56
+ ]
57
+
58
+ robot = Robot.new(
59
+ name: "assistant",
60
+ template: :assistant,
61
+ mcp: :inherit # Use network's MCP servers
62
+ )
63
+ ```
64
+
65
+ ### Direct Client Usage
55
66
 
56
- server.add_tool(
57
- name: "get_user",
58
- description: "Get user by ID",
59
- parameters: { id: { type: "string", required: true } },
60
- handler: ->(id:) { User.find(id).to_h }
67
+ ```ruby
68
+ client = RobotLab::MCP::Client.new(
69
+ name: "filesystem",
70
+ transport: { type: "stdio", command: "mcp-server-filesystem", args: ["--root", "/data"] }
61
71
  )
62
72
 
63
- server.start(transport: :stdio)
73
+ client.connect
74
+ tools = client.list_tools
75
+ result = client.call_tool("readFile", { path: "/data/config.yml" })
76
+ client.disconnect
64
77
  ```
65
78
 
66
79
  ## Transport Types
67
80
 
68
- | Type | Use Case |
69
- |------|----------|
70
- | `stdio` | Local command execution |
71
- | `websocket` | Real-time bidirectional |
72
- | `sse` | Server-sent events |
73
- | `http` | HTTP request/response |
81
+ | Type | Config Key | Use Case |
82
+ |------|------------|----------|
83
+ | `stdio` | `"stdio"` | Local command/subprocess execution |
84
+ | `websocket` | `"ws"` or `"websocket"` | Real-time bidirectional communication |
85
+ | `sse` | `"sse"` | Server-sent events streaming |
86
+ | `streamable-http` | `"streamable-http"` or `"http"` | HTTP request/response with session support |
74
87
 
75
- ## Configuration Levels
88
+ ## MCP Parameter Values
76
89
 
77
- ### Network Level
90
+ The `mcp:` parameter on a Robot accepts three types of values:
78
91
 
79
- ```ruby
80
- network = RobotLab.create_network do
81
- mcp [
82
- { name: "server1", transport: { type: "stdio", command: "..." } }
83
- ]
84
- end
85
- ```
92
+ | Value | Meaning |
93
+ |-------|---------|
94
+ | `:none` | No MCP servers (explicitly disabled) |
95
+ | `:inherit` | Use the network's MCP servers |
96
+ | `Array<Hash>` | Explicit list of server configurations |
86
97
 
87
- ### Robot Level
98
+ Each server configuration hash requires:
88
99
 
89
- ```ruby
90
- robot = RobotLab.build do
91
- mcp :inherit # Use network's servers
92
- # or
93
- mcp :none # No MCP servers
94
- # or
95
- mcp [...] # Specific servers
96
- end
97
- ```
100
+ | Key | Type | Description |
101
+ |-----|------|-------------|
102
+ | `name` | `String` | Unique server identifier |
103
+ | `transport` | `Hash` | Transport configuration (must include `type`) |
104
+
105
+ ## Error Handling
106
+
107
+ MCP operations raise `RobotLab::MCPError` when:
98
108
 
99
- ### Tool Filtering
109
+ - Connection to a server fails
110
+ - A request is made without an active connection
111
+ - An unsupported transport type is specified
100
112
 
101
113
  ```ruby
102
- robot = RobotLab.build do
103
- mcp :inherit
104
- tools %w[read_file write_file] # Only allow these tools
114
+ begin
115
+ client.connect
116
+ client.call_tool("unknown_tool", {})
117
+ rescue RobotLab::MCPError => e
118
+ puts "MCP error: #{e.message}"
105
119
  end
106
120
  ```
107
121
 
108
122
  ## See Also
109
123
 
110
- - [MCP Integration Guide](../../guides/mcp-integration.md)
111
- - [Tool](../core/tool.md)
124
+ - [MCP Client](client.md)
125
+ - [MCP Server](server.md)
126
+ - [Transports](transports.md)
@@ -1,221 +1,205 @@
1
- # MCP Server
1
+ # MCP Server Configuration
2
2
 
3
- Expose tools via Model Context Protocol.
3
+ Data structure for MCP server connection configuration.
4
4
 
5
5
  ## Class: `RobotLab::MCP::Server`
6
6
 
7
- ```ruby
8
- server = RobotLab::MCP::Server.new(name: "my_tools")
7
+ `Server` is a configuration object that defines how to connect to an MCP server. It holds the server name and transport settings, and validates the configuration on construction.
9
8
 
10
- server.add_tool(
11
- name: "get_time",
12
- description: "Get current time",
13
- handler: ->(**_) { Time.now.iso8601 }
14
- )
9
+ This is **not** an MCP server implementation -- it is the configuration used by `MCP::Client` to establish a connection to an external MCP server.
15
10
 
16
- server.start(transport: :stdio)
11
+ ```ruby
12
+ server = RobotLab::MCP::Server.new(
13
+ name: "filesystem",
14
+ transport: { type: "stdio", command: "mcp-server-filesystem", args: ["--root", "/data"] }
15
+ )
17
16
  ```
18
17
 
19
18
  ## Constructor
20
19
 
21
20
  ```ruby
22
- Server.new(name:, version: "1.0.0")
21
+ Server.new(name:, transport:)
23
22
  ```
24
23
 
25
24
  **Parameters:**
26
25
 
27
26
  | Name | Type | Description |
28
27
  |------|------|-------------|
29
- | `name` | `String` | Server name |
30
- | `version` | `String` | Server version |
28
+ | `name` | `String` | Unique server identifier |
29
+ | `transport` | `Hash` | Transport configuration (must include `type`) |
31
30
 
32
- ## Attributes
31
+ **Raises:** `ArgumentError` if:
32
+ - The transport type is not one of the valid types
33
+ - A stdio transport is missing the `:command` key
34
+ - A network transport (ws, websocket, sse, streamable-http, http) is missing the `:url` key
33
35
 
34
- ### name
36
+ ## Valid Transport Types
35
37
 
36
38
  ```ruby
37
- server.name # => String
39
+ RobotLab::MCP::Server::VALID_TRANSPORT_TYPES
40
+ # => ["stdio", "sse", "ws", "websocket", "streamable-http", "http"]
38
41
  ```
39
42
 
40
- Server identifier.
43
+ ## Attributes
41
44
 
42
- ### version
45
+ ### name
43
46
 
44
47
  ```ruby
45
- server.version # => String
48
+ server.name # => String
46
49
  ```
47
50
 
48
- Server version.
51
+ The server identifier string.
49
52
 
50
- ### tools
53
+ ### transport
51
54
 
52
55
  ```ruby
53
- server.tools # => Array<Tool>
56
+ server.transport # => Hash
54
57
  ```
55
58
 
56
- Registered tools.
59
+ The normalized transport configuration hash (keys are symbols, type is downcased).
57
60
 
58
61
  ## Methods
59
62
 
60
- ### add_tool
63
+ ### transport_type
61
64
 
62
65
  ```ruby
63
- server.add_tool(
64
- name:,
65
- description:,
66
- parameters: {},
67
- handler:
68
- )
66
+ server.transport_type # => String
69
67
  ```
70
68
 
71
- Register a tool with the server.
69
+ Returns the transport type string (e.g., `"stdio"`, `"ws"`, `"sse"`).
72
70
 
73
- **Parameters:**
74
-
75
- | Name | Type | Description |
76
- |------|------|-------------|
77
- | `name` | `String` | Tool name |
78
- | `description` | `String` | Tool description |
79
- | `parameters` | `Hash` | Parameter schema |
80
- | `handler` | `Proc` | Execution function |
81
-
82
- ### remove_tool
71
+ ### to_h
83
72
 
84
73
  ```ruby
85
- server.remove_tool(name)
74
+ server.to_h # => { name: "...", transport: { ... } }
86
75
  ```
87
76
 
88
- Unregister a tool.
77
+ Converts the server configuration to a hash representation.
78
+
79
+ ## Transport Configuration Options
89
80
 
90
- ### start
81
+ ### Stdio Transport
82
+
83
+ For local MCP servers running as subprocesses:
91
84
 
92
85
  ```ruby
93
- server.start(transport: :stdio, **options)
86
+ Server.new(
87
+ name: "filesystem",
88
+ transport: {
89
+ type: "stdio",
90
+ command: "mcp-server-filesystem", # Required
91
+ args: ["--root", "/data"], # Optional
92
+ env: { "DEBUG" => "true" } # Optional
93
+ }
94
+ )
94
95
  ```
95
96
 
96
- Start the server.
97
+ | Key | Type | Required | Description |
98
+ |-----|------|----------|-------------|
99
+ | `type` | `String` | Yes | Must be `"stdio"` |
100
+ | `command` | `String` | Yes | Executable command |
101
+ | `args` | `Array<String>` | No | Command arguments |
102
+ | `env` | `Hash` | No | Environment variables |
97
103
 
98
- **Transport Options:**
104
+ ### WebSocket Transport
99
105
 
100
- | Transport | Options |
101
- |-----------|---------|
102
- | `:stdio` | None |
103
- | `:websocket` | `port:`, `host:` |
104
- | `:sse` | `port:`, `host:`, `path:` |
105
- | `:http` | `port:`, `host:`, `path:` |
106
-
107
- ### stop
106
+ For bidirectional real-time communication:
108
107
 
109
108
  ```ruby
110
- server.stop
109
+ Server.new(
110
+ name: "neon",
111
+ transport: {
112
+ type: "ws",
113
+ url: "ws://localhost:8080" # Required
114
+ }
115
+ )
111
116
  ```
112
117
 
113
- Stop the server.
118
+ | Key | Type | Required | Description |
119
+ |-----|------|----------|-------------|
120
+ | `type` | `String` | Yes | `"ws"` or `"websocket"` |
121
+ | `url` | `String` | Yes | WebSocket endpoint URL |
114
122
 
115
- ## Examples
123
+ ### SSE Transport
116
124
 
117
- ### Basic Server
125
+ For server-sent events streaming:
118
126
 
119
127
  ```ruby
120
- server = RobotLab::MCP::Server.new(name: "utilities")
121
-
122
- server.add_tool(
123
- name: "echo",
124
- description: "Echo back the input",
125
- parameters: {
126
- message: { type: "string", required: true }
127
- },
128
- handler: ->(message:) { message }
128
+ Server.new(
129
+ name: "streaming",
130
+ transport: {
131
+ type: "sse",
132
+ url: "http://localhost:8080/sse" # Required
133
+ }
129
134
  )
130
-
131
- server.start(transport: :stdio)
132
135
  ```
133
136
 
134
- ### Database Tools Server
137
+ | Key | Type | Required | Description |
138
+ |-----|------|----------|-------------|
139
+ | `type` | `String` | Yes | Must be `"sse"` |
140
+ | `url` | `String` | Yes | SSE endpoint URL |
135
141
 
136
- ```ruby
137
- server = RobotLab::MCP::Server.new(name: "database")
138
-
139
- server.add_tool(
140
- name: "query_users",
141
- description: "Query users by criteria",
142
- parameters: {
143
- status: { type: "string", enum: ["active", "inactive"] },
144
- limit: { type: "integer", default: 10 }
145
- },
146
- handler: ->(status: nil, limit: 10) {
147
- scope = User.all
148
- scope = scope.where(status: status) if status
149
- scope.limit(limit).map(&:to_h)
150
- }
151
- )
142
+ ### Streamable HTTP Transport
152
143
 
153
- server.add_tool(
154
- name: "get_user",
155
- description: "Get user by ID",
156
- parameters: {
157
- id: { type: "string", required: true }
158
- },
159
- handler: ->(id:) {
160
- user = User.find_by(id: id)
161
- user ? user.to_h : { error: "Not found" }
144
+ For HTTP-based communication with session management:
145
+
146
+ ```ruby
147
+ Server.new(
148
+ name: "api",
149
+ transport: {
150
+ type: "streamable-http",
151
+ url: "https://server.smithery.ai/neon/mcp", # Required
152
+ session_id: "abc123", # Optional
153
+ auth_provider: -> { "Bearer #{token}" } # Optional
162
154
  }
163
155
  )
164
-
165
- server.start(transport: :websocket, port: 8080)
166
156
  ```
167
157
 
168
- ### From Robot Tools
158
+ | Key | Type | Required | Description |
159
+ |-----|------|----------|-------------|
160
+ | `type` | `String` | Yes | `"streamable-http"` or `"http"` |
161
+ | `url` | `String` | Yes | HTTP endpoint URL |
162
+ | `session_id` | `String` | No | Session identifier |
163
+ | `auth_provider` | `Proc` | No | Authentication callback returning auth header value |
169
164
 
170
- ```ruby
171
- # Convert existing robot tools to MCP server
172
- robot = RobotLab.build do
173
- name "assistant"
174
-
175
- tool :calculate do
176
- description "Perform calculation"
177
- parameter :expression, type: :string, required: true
178
- handler { |expression:, **_| eval(expression) }
179
- end
180
- end
181
-
182
- server = RobotLab::MCP::Server.from_robot(robot)
183
- server.start(transport: :stdio)
184
- ```
165
+ ## Examples
185
166
 
186
- ### HTTP Server
167
+ ### Multiple Server Configurations
187
168
 
188
169
  ```ruby
189
- server = RobotLab::MCP::Server.new(name: "api_tools")
190
-
191
- server.add_tool(
192
- name: "fetch_data",
193
- description: "Fetch data from API",
194
- parameters: {
195
- endpoint: { type: "string", required: true }
170
+ servers = [
171
+ {
172
+ name: "filesystem",
173
+ transport: { type: "stdio", command: "mcp-server-filesystem", args: ["/data"] }
174
+ },
175
+ {
176
+ name: "github",
177
+ transport: { type: "stdio", command: "mcp-server-github" }
196
178
  },
197
- handler: ->(endpoint:) {
198
- response = HTTP.get("https://api.example.com/#{endpoint}")
199
- JSON.parse(response.body)
179
+ {
180
+ name: "database",
181
+ transport: { type: "ws", url: "ws://localhost:9090" }
200
182
  }
201
- )
183
+ ]
202
184
 
203
- server.start(transport: :http, port: 3001, path: "/mcp")
185
+ # Pass directly to a robot
186
+ robot = Robot.new(
187
+ name: "dev_assistant",
188
+ system_prompt: "You help with development tasks.",
189
+ mcp: servers
190
+ )
204
191
  ```
205
192
 
206
- ### With Resources
193
+ ### Creating a Client from a Server
207
194
 
208
195
  ```ruby
209
- server = RobotLab::MCP::Server.new(name: "files")
210
-
211
- server.add_resource(
212
- uri: "file://config",
213
- name: "Configuration",
214
- description: "Application configuration",
215
- handler: -> { File.read("config.yml") }
196
+ server = RobotLab::MCP::Server.new(
197
+ name: "tools",
198
+ transport: { type: "ws", url: "ws://localhost:8080" }
216
199
  )
217
200
 
218
- server.start(transport: :stdio)
201
+ client = RobotLab::MCP::Client.new(server)
202
+ client.connect
219
203
  ```
220
204
 
221
205
  ## See Also