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
@@ -1,238 +1,190 @@
1
1
  # MCP Server
2
2
 
3
- Creating and using Model Context Protocol servers.
3
+ Connecting robots to Model Context Protocol servers for external tool access.
4
4
 
5
5
  ## Overview
6
6
 
7
- This example demonstrates how to create MCP servers to expose tools and how to connect robots to external MCP servers.
7
+ This example demonstrates how to connect robots to external MCP servers. MCP servers expose tools that robots can discover and invoke automatically. RobotLab supports stdio, HTTP, WebSocket, and SSE transports.
8
8
 
9
- ## Creating an MCP Server
9
+ ## Using MCP with a Robot
10
+
11
+ The primary pattern is to pass MCP server configurations via `mcp:` or `mcp_servers:` when building a robot:
10
12
 
11
13
  ```ruby
12
14
  #!/usr/bin/env ruby
13
- # examples/mcp_server.rb
15
+ # examples/mcp_client.rb
14
16
 
15
17
  require "bundler/setup"
16
18
  require "robot_lab"
17
- require "json"
18
-
19
- # Create an MCP server with database tools
20
- server = RobotLab::MCP::Server.new(
21
- name: "database_tools",
22
- version: "1.0.0"
23
- )
24
-
25
- # Mock database
26
- USERS = {
27
- "1" => { id: "1", name: "Alice", email: "alice@example.com", plan: "pro" },
28
- "2" => { id: "2", name: "Bob", email: "bob@example.com", plan: "free" }
29
- }
30
19
 
31
- ORDERS = {
32
- "ORD001" => { id: "ORD001", user_id: "1", total: 99.99, status: "shipped" },
33
- "ORD002" => { id: "ORD002", user_id: "1", total: 49.99, status: "pending" },
34
- "ORD003" => { id: "ORD003", user_id: "2", total: 29.99, status: "delivered" }
20
+ # MCP server configuration (stdio transport)
21
+ github_server = {
22
+ name: "github",
23
+ transport: {
24
+ type: "stdio",
25
+ command: "github-mcp-server",
26
+ args: ["stdio"],
27
+ env: {
28
+ "GITHUB_PERSONAL_ACCESS_TOKEN" => ENV.fetch("GITHUB_PERSONAL_ACCESS_TOKEN", "")
29
+ }
30
+ }
35
31
  }
36
32
 
37
- # Add tools to the server
38
- server.add_tool(
39
- name: "get_user",
40
- description: "Get user by ID",
41
- parameters: {
42
- user_id: { type: "string", required: true, description: "User ID" }
43
- },
44
- handler: ->(user_id:) {
45
- user = USERS[user_id]
46
- user || { error: "User not found" }
47
- }
33
+ # Create a robot with MCP server integration
34
+ # Tools are automatically discovered when the robot connects
35
+ robot = RobotLab.build(
36
+ name: "github_assistant",
37
+ system_prompt: <<~PROMPT,
38
+ You are a GitHub assistant with access to repository tools.
39
+ Help users search repos, manage issues, and explore code.
40
+ PROMPT
41
+ mcp: [github_server],
42
+ model: "claude-sonnet-4"
48
43
  )
49
44
 
50
- server.add_tool(
51
- name: "list_users",
52
- description: "List all users",
53
- parameters: {
54
- plan: { type: "string", enum: ["free", "pro"], description: "Filter by plan" }
55
- },
56
- handler: ->(plan: nil) {
57
- users = USERS.values
58
- users = users.select { |u| u[:plan] == plan } if plan
59
- users
60
- }
61
- )
45
+ # The robot auto-discovers MCP tools on first run
46
+ puts "MCP Servers: #{robot.mcp_clients.keys.join(", ")}"
47
+ puts "MCP Tools: #{robot.mcp_tools.size} discovered"
62
48
 
63
- server.add_tool(
64
- name: "get_orders",
65
- description: "Get orders for a user",
66
- parameters: {
67
- user_id: { type: "string", required: true },
68
- status: { type: "string", enum: ["pending", "shipped", "delivered"] }
69
- },
70
- handler: ->(user_id:, status: nil) {
71
- orders = ORDERS.values.select { |o| o[:user_id] == user_id }
72
- orders = orders.select { |o| o[:status] == status } if status
73
- orders
74
- }
75
- )
49
+ # Run the robot -- it can use any discovered MCP tools
50
+ result = robot.run("What are the top 3 most starred Ruby web frameworks on GitHub?")
51
+ puts result.last_text_content
76
52
 
77
- server.add_tool(
78
- name: "update_order_status",
79
- description: "Update an order's status",
80
- parameters: {
81
- order_id: { type: "string", required: true },
82
- status: { type: "string", required: true, enum: ["pending", "shipped", "delivered"] }
83
- },
84
- handler: ->(order_id:, status:) {
85
- order = ORDERS[order_id]
86
- return { error: "Order not found" } unless order
87
- order[:status] = status
88
- { success: true, order: order }
89
- }
90
- )
53
+ # Show tool calls if any were made
54
+ if result.tool_calls.any?
55
+ puts "\nTool calls made:"
56
+ result.tool_calls.each do |tc|
57
+ tool_info = tc.respond_to?(:tool) ? tc.tool : tc
58
+ puts " #{tool_info[:name] || tool_info}"
59
+ end
60
+ end
91
61
 
92
- # Start the server (stdio for local use)
93
- puts "Starting MCP server..."
94
- server.start(transport: :stdio)
62
+ # Always disconnect MCP clients when done
63
+ robot.disconnect
95
64
  ```
96
65
 
97
- ## Using MCP Server in Robot
66
+ ## Direct MCP Client Usage
98
67
 
99
- ```ruby
100
- #!/usr/bin/env ruby
101
- # examples/mcp_client.rb
68
+ You can also use the MCP client directly without a robot:
102
69
 
103
- require "bundler/setup"
70
+ ```ruby
104
71
  require "robot_lab"
105
72
 
106
- RobotLab.configure do |config|
107
- config.default_model = "claude-sonnet-4"
108
- end
109
-
110
- # Robot that uses the MCP server
111
- admin_bot = RobotLab.build do
112
- name "admin_assistant"
113
- description "Helps with administrative tasks"
73
+ # Create and connect MCP client
74
+ github_server = {
75
+ name: "github",
76
+ transport: {
77
+ type: "stdio",
78
+ command: "github-mcp-server",
79
+ args: ["stdio"],
80
+ env: { "GITHUB_PERSONAL_ACCESS_TOKEN" => ENV["GITHUB_PERSONAL_ACCESS_TOKEN"] }
81
+ }
82
+ }
114
83
 
115
- template <<~PROMPT
116
- You are an administrative assistant with access to user and order data.
117
- Help users look up information and manage orders.
118
- PROMPT
84
+ client = RobotLab::MCP::Client.new(github_server)
85
+ client.connect
119
86
 
120
- mcp [
121
- {
122
- name: "database",
123
- transport: {
124
- type: "stdio",
125
- command: "ruby",
126
- args: ["examples/mcp_server.rb"]
127
- }
128
- }
129
- ]
130
- end
87
+ if client.connected?
88
+ # List available tools
89
+ tools = client.list_tools
90
+ tools.each do |tool|
91
+ puts "#{tool[:name]}: #{tool[:description]}"
92
+ end
131
93
 
132
- # Interactive session
133
- puts "Admin Assistant (uses MCP server)"
134
- puts "-" * 50
94
+ # Call a tool directly
95
+ result = client.call_tool("search_repositories", {
96
+ query: "language:ruby stars:>1000",
97
+ per_page: 5
98
+ })
135
99
 
136
- state = RobotLab.create_state(message: "List all pro users and their orders")
100
+ puts JSON.pretty_generate(result)
137
101
 
138
- admin_bot.run(state: state) do |event|
139
- case event.type
140
- when :text_delta
141
- print event.text
142
- when :tool_call
143
- puts "\n[MCP: #{event.name}]"
144
- end
102
+ client.disconnect
145
103
  end
146
-
147
- puts
148
- admin_bot.disconnect
149
104
  ```
150
105
 
151
- ## Network with MCP
106
+ ## Multiple MCP Servers
107
+
108
+ A robot can connect to multiple MCP servers simultaneously:
152
109
 
153
110
  ```ruby
154
- # examples/network_with_mcp.rb
111
+ filesystem_server = {
112
+ name: "filesystem",
113
+ transport: {
114
+ type: "stdio",
115
+ command: "npx",
116
+ args: ["@modelcontextprotocol/server-filesystem", "/data"]
117
+ }
118
+ }
155
119
 
156
- network = RobotLab.create_network do
157
- name "support_with_mcp"
120
+ github_server = {
121
+ name: "github",
122
+ transport: {
123
+ type: "stdio",
124
+ command: "github-mcp-server",
125
+ args: ["stdio"],
126
+ env: { "GITHUB_PERSONAL_ACCESS_TOKEN" => ENV["GITHUB_PERSONAL_ACCESS_TOKEN"] }
127
+ }
128
+ }
158
129
 
159
- # MCP servers available to all robots
160
- mcp [
161
- {
162
- name: "database",
163
- transport: { type: "stdio", command: "ruby examples/mcp_server.rb" }
164
- },
165
- {
166
- name: "filesystem",
167
- transport: {
168
- type: "stdio",
169
- command: "npx",
170
- args: ["@modelcontextprotocol/server-filesystem", "/data"]
171
- }
172
- }
173
- ]
130
+ robot = RobotLab.build(
131
+ name: "developer",
132
+ system_prompt: "You help with coding tasks using GitHub and the filesystem.",
133
+ mcp: [filesystem_server, github_server],
134
+ model: "claude-sonnet-4"
135
+ )
174
136
 
175
- add_robot RobotLab.build {
176
- name "data_analyst"
177
- template "You analyze user data."
178
- mcp :inherit # Uses network's MCP servers
179
- }
137
+ result = robot.run("Search for Ruby repos with CI configs and list their workflow files")
138
+ puts result.last_text_content
180
139
 
181
- add_robot RobotLab.build {
182
- name "file_manager"
183
- template "You manage files."
184
- mcp :inherit
185
- tools %w[read_file list_directory] # Only these MCP tools
186
- }
187
- end
140
+ robot.disconnect
188
141
  ```
189
142
 
190
- ## HTTP MCP Server
191
-
192
- ```ruby
193
- #!/usr/bin/env ruby
194
- # examples/http_mcp_server.rb
143
+ ## MCP in Networks
195
144
 
196
- require "robot_lab"
197
- require "sinatra"
145
+ Networks pass MCP configuration through the hierarchical resolution system. Use `mcp: :inherit` on robots to use the network-level MCP config, or specify per-task MCP servers:
198
146
 
199
- server = RobotLab::MCP::Server.new(name: "api_tools")
147
+ ```ruby
148
+ # Create robots
149
+ data_analyst = RobotLab.build(
150
+ name: "data_analyst",
151
+ system_prompt: "You analyze data.",
152
+ mcp: :inherit # Will use whatever MCP config is resolved at runtime
153
+ )
200
154
 
201
- server.add_tool(
202
- name: "get_stats",
203
- description: "Get system statistics",
204
- parameters: {},
205
- handler: -> {
206
- {
207
- uptime: `uptime`.strip,
208
- memory: `free -m 2>/dev/null || vm_stat`.strip,
209
- time: Time.now.iso8601
210
- }
211
- }
155
+ file_manager = RobotLab.build(
156
+ name: "file_manager",
157
+ system_prompt: "You manage files.",
158
+ mcp: :inherit,
159
+ tools: :none # Only use inherited MCP tools, no local tools
212
160
  )
213
161
 
214
- # Sinatra endpoint for MCP
215
- post "/mcp" do
216
- content_type :json
217
- request_body = JSON.parse(request.body.read)
218
- response = server.handle_request(request_body)
219
- response.to_json
162
+ # Create network with per-task MCP configuration
163
+ network = RobotLab.create_network(name: "support_with_mcp") do
164
+ task :analyst, data_analyst,
165
+ mcp: [github_server],
166
+ depends_on: :none
167
+
168
+ task :files, file_manager,
169
+ mcp: [filesystem_server],
170
+ tools: %w[read_file list_directory], # Whitelist only these MCP tools
171
+ depends_on: :optional
220
172
  end
221
173
 
222
- # Run: ruby examples/http_mcp_server.rb
223
- # Connect with HTTP transport
174
+ result = network.run(message: "Analyze the project structure")
224
175
  ```
225
176
 
226
- ## Connecting to HTTP Server
177
+ ## HTTP Transport
227
178
 
228
- ```ruby
229
- robot = RobotLab.build do
230
- name "remote_assistant"
231
- template "You have access to remote tools."
179
+ Connect to remote MCP servers over HTTP:
232
180
 
233
- mcp [
181
+ ```ruby
182
+ robot = RobotLab.build(
183
+ name: "remote_assistant",
184
+ system_prompt: "You have access to remote tools.",
185
+ mcp: [
234
186
  {
235
- name: "remote",
187
+ name: "remote_api",
236
188
  transport: {
237
189
  type: "http",
238
190
  url: "https://mcp.example.com/mcp",
@@ -240,48 +192,100 @@ robot = RobotLab.build do
240
192
  }
241
193
  }
242
194
  ]
243
- end
195
+ )
196
+
197
+ result = robot.run("Use the remote tools to check system status")
198
+ robot.disconnect
244
199
  ```
245
200
 
246
- ## WebSocket Server
201
+ ## WebSocket Transport
202
+
203
+ For real-time bidirectional communication:
247
204
 
248
205
  ```ruby
249
- #!/usr/bin/env ruby
250
- # examples/websocket_mcp_server.rb
206
+ robot = RobotLab.build(
207
+ name: "realtime_assistant",
208
+ system_prompt: "You monitor real-time events.",
209
+ mcp: [
210
+ {
211
+ name: "realtime",
212
+ transport: {
213
+ type: "websocket",
214
+ url: "ws://localhost:8765"
215
+ }
216
+ }
217
+ ]
218
+ )
251
219
 
252
- require "robot_lab"
220
+ result = robot.run("Subscribe to the events channel")
221
+ robot.disconnect
222
+ ```
223
+
224
+ ## SSE Transport
225
+
226
+ Server-Sent Events transport for streaming responses:
227
+
228
+ ```ruby
229
+ robot = RobotLab.build(
230
+ name: "sse_assistant",
231
+ system_prompt: "You have access to streaming tools.",
232
+ mcp: [
233
+ {
234
+ name: "streaming_api",
235
+ transport: {
236
+ type: "sse",
237
+ url: "https://api.example.com/sse"
238
+ }
239
+ }
240
+ ]
241
+ )
242
+
243
+ result = robot.run("Stream the latest metrics")
244
+ robot.disconnect
245
+ ```
246
+
247
+ ## Runtime MCP Overrides
253
248
 
254
- server = RobotLab::MCP::Server.new(name: "realtime_tools")
249
+ Override MCP configuration at runtime via `robot.run`:
255
250
 
256
- server.add_tool(
257
- name: "subscribe_events",
258
- description: "Subscribe to real-time events",
259
- parameters: { channel: { type: "string", required: true } },
260
- handler: ->(channel:) { { subscribed: channel } }
251
+ ```ruby
252
+ robot = RobotLab.build(
253
+ name: "flexible_bot",
254
+ system_prompt: "You use available tools.",
255
+ mcp: [github_server]
261
256
  )
262
257
 
263
- # Start WebSocket server
264
- server.start(transport: :websocket, port: 8765)
258
+ # Use default MCP config
259
+ result = robot.run("Search for Ruby repos")
260
+
261
+ # Override MCP at runtime -- disable all MCP
262
+ result = robot.run("Just answer from your knowledge", mcp: :none)
263
+
264
+ robot.disconnect
265
265
  ```
266
266
 
267
267
  ## Running
268
268
 
269
269
  ```bash
270
- # Start MCP server in one terminal
271
- ruby examples/mcp_server.rb
272
-
273
- # Run client in another terminal
270
+ # Set API keys
274
271
  export ANTHROPIC_API_KEY="your-key"
272
+ export GITHUB_PERSONAL_ACCESS_TOKEN="your-token"
273
+
274
+ # Install MCP server (example: GitHub)
275
+ brew install github-mcp-server
276
+
277
+ # Run client
275
278
  ruby examples/mcp_client.rb
276
279
  ```
277
280
 
278
281
  ## Key Concepts
279
282
 
280
- 1. **Server Creation**: Use `RobotLab::MCP::Server.new`
281
- 2. **Tool Registration**: Add tools with `server.add_tool`
282
- 3. **Transport**: Choose stdio, http, websocket, or sse
283
- 4. **Client Connection**: Configure in robot's `mcp` block
284
- 5. **Tool Filtering**: Use `tools` whitelist for security
283
+ 1. **MCP Configuration**: Pass server configs via `mcp:` parameter on `RobotLab.build` or `Robot.new`
284
+ 2. **Auto-Discovery**: Tools are automatically discovered when the robot connects to an MCP server
285
+ 3. **Transport Types**: stdio, http, websocket, sse
286
+ 4. **Hierarchical Config**: `runtime > robot > network > global`, using `:none`, `:inherit`, or explicit arrays
287
+ 5. **Tool Filtering**: Use `tools:` whitelist to limit which MCP tools are available
288
+ 6. **Cleanup**: Always call `robot.disconnect` when done to release MCP connections
285
289
 
286
290
  ## See Also
287
291