language-operator 0.0.1 → 0.1.31

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +125 -0
  3. data/CHANGELOG.md +88 -0
  4. data/Gemfile +8 -0
  5. data/Gemfile.lock +284 -0
  6. data/LICENSE +229 -21
  7. data/Makefile +82 -0
  8. data/README.md +3 -11
  9. data/Rakefile +63 -0
  10. data/bin/aictl +7 -0
  11. data/completions/_aictl +232 -0
  12. data/completions/aictl.bash +121 -0
  13. data/completions/aictl.fish +114 -0
  14. data/docs/architecture/agent-runtime.md +585 -0
  15. data/docs/dsl/SCHEMA_VERSION.md +250 -0
  16. data/docs/dsl/agent-reference.md +604 -0
  17. data/docs/dsl/best-practices.md +1078 -0
  18. data/docs/dsl/chat-endpoints.md +895 -0
  19. data/docs/dsl/constraints.md +671 -0
  20. data/docs/dsl/mcp-integration.md +1177 -0
  21. data/docs/dsl/webhooks.md +932 -0
  22. data/docs/dsl/workflows.md +744 -0
  23. data/lib/language_operator/agent/base.rb +110 -0
  24. data/lib/language_operator/agent/executor.rb +440 -0
  25. data/lib/language_operator/agent/instrumentation.rb +54 -0
  26. data/lib/language_operator/agent/metrics_tracker.rb +183 -0
  27. data/lib/language_operator/agent/safety/ast_validator.rb +272 -0
  28. data/lib/language_operator/agent/safety/audit_logger.rb +104 -0
  29. data/lib/language_operator/agent/safety/budget_tracker.rb +175 -0
  30. data/lib/language_operator/agent/safety/content_filter.rb +93 -0
  31. data/lib/language_operator/agent/safety/manager.rb +207 -0
  32. data/lib/language_operator/agent/safety/rate_limiter.rb +150 -0
  33. data/lib/language_operator/agent/safety/safe_executor.rb +127 -0
  34. data/lib/language_operator/agent/scheduler.rb +183 -0
  35. data/lib/language_operator/agent/telemetry.rb +116 -0
  36. data/lib/language_operator/agent/web_server.rb +610 -0
  37. data/lib/language_operator/agent/webhook_authenticator.rb +226 -0
  38. data/lib/language_operator/agent.rb +149 -0
  39. data/lib/language_operator/cli/commands/agent.rb +1205 -0
  40. data/lib/language_operator/cli/commands/cluster.rb +371 -0
  41. data/lib/language_operator/cli/commands/install.rb +404 -0
  42. data/lib/language_operator/cli/commands/model.rb +266 -0
  43. data/lib/language_operator/cli/commands/persona.rb +393 -0
  44. data/lib/language_operator/cli/commands/quickstart.rb +22 -0
  45. data/lib/language_operator/cli/commands/status.rb +143 -0
  46. data/lib/language_operator/cli/commands/system.rb +772 -0
  47. data/lib/language_operator/cli/commands/tool.rb +537 -0
  48. data/lib/language_operator/cli/commands/use.rb +47 -0
  49. data/lib/language_operator/cli/errors/handler.rb +180 -0
  50. data/lib/language_operator/cli/errors/suggestions.rb +176 -0
  51. data/lib/language_operator/cli/formatters/code_formatter.rb +77 -0
  52. data/lib/language_operator/cli/formatters/log_formatter.rb +288 -0
  53. data/lib/language_operator/cli/formatters/progress_formatter.rb +49 -0
  54. data/lib/language_operator/cli/formatters/status_formatter.rb +37 -0
  55. data/lib/language_operator/cli/formatters/table_formatter.rb +163 -0
  56. data/lib/language_operator/cli/formatters/value_formatter.rb +113 -0
  57. data/lib/language_operator/cli/helpers/cluster_context.rb +62 -0
  58. data/lib/language_operator/cli/helpers/cluster_validator.rb +101 -0
  59. data/lib/language_operator/cli/helpers/editor_helper.rb +58 -0
  60. data/lib/language_operator/cli/helpers/kubeconfig_validator.rb +167 -0
  61. data/lib/language_operator/cli/helpers/pastel_helper.rb +24 -0
  62. data/lib/language_operator/cli/helpers/resource_dependency_checker.rb +74 -0
  63. data/lib/language_operator/cli/helpers/schedule_builder.rb +108 -0
  64. data/lib/language_operator/cli/helpers/user_prompts.rb +69 -0
  65. data/lib/language_operator/cli/main.rb +236 -0
  66. data/lib/language_operator/cli/templates/tools/generic.yaml +66 -0
  67. data/lib/language_operator/cli/wizards/agent_wizard.rb +246 -0
  68. data/lib/language_operator/cli/wizards/quickstart_wizard.rb +588 -0
  69. data/lib/language_operator/client/base.rb +214 -0
  70. data/lib/language_operator/client/config.rb +136 -0
  71. data/lib/language_operator/client/cost_calculator.rb +37 -0
  72. data/lib/language_operator/client/mcp_connector.rb +123 -0
  73. data/lib/language_operator/client.rb +19 -0
  74. data/lib/language_operator/config/cluster_config.rb +101 -0
  75. data/lib/language_operator/config/tool_patterns.yaml +57 -0
  76. data/lib/language_operator/config/tool_registry.rb +96 -0
  77. data/lib/language_operator/config.rb +138 -0
  78. data/lib/language_operator/dsl/adapter.rb +124 -0
  79. data/lib/language_operator/dsl/agent_context.rb +90 -0
  80. data/lib/language_operator/dsl/agent_definition.rb +427 -0
  81. data/lib/language_operator/dsl/chat_endpoint_definition.rb +115 -0
  82. data/lib/language_operator/dsl/config.rb +119 -0
  83. data/lib/language_operator/dsl/context.rb +50 -0
  84. data/lib/language_operator/dsl/execution_context.rb +47 -0
  85. data/lib/language_operator/dsl/helpers.rb +109 -0
  86. data/lib/language_operator/dsl/http.rb +184 -0
  87. data/lib/language_operator/dsl/mcp_server_definition.rb +73 -0
  88. data/lib/language_operator/dsl/parameter_definition.rb +124 -0
  89. data/lib/language_operator/dsl/registry.rb +36 -0
  90. data/lib/language_operator/dsl/schema.rb +1102 -0
  91. data/lib/language_operator/dsl/shell.rb +125 -0
  92. data/lib/language_operator/dsl/tool_definition.rb +112 -0
  93. data/lib/language_operator/dsl/webhook_authentication.rb +114 -0
  94. data/lib/language_operator/dsl/webhook_definition.rb +106 -0
  95. data/lib/language_operator/dsl/workflow_definition.rb +259 -0
  96. data/lib/language_operator/dsl.rb +161 -0
  97. data/lib/language_operator/errors.rb +60 -0
  98. data/lib/language_operator/kubernetes/client.rb +279 -0
  99. data/lib/language_operator/kubernetes/resource_builder.rb +194 -0
  100. data/lib/language_operator/loggable.rb +47 -0
  101. data/lib/language_operator/logger.rb +141 -0
  102. data/lib/language_operator/retry.rb +123 -0
  103. data/lib/language_operator/retryable.rb +132 -0
  104. data/lib/language_operator/templates/README.md +23 -0
  105. data/lib/language_operator/templates/examples/agent_synthesis.tmpl +115 -0
  106. data/lib/language_operator/templates/examples/persona_distillation.tmpl +19 -0
  107. data/lib/language_operator/templates/schema/.gitkeep +0 -0
  108. data/lib/language_operator/templates/schema/CHANGELOG.md +93 -0
  109. data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +306 -0
  110. data/lib/language_operator/templates/schema/agent_dsl_schema.json +452 -0
  111. data/lib/language_operator/tool_loader.rb +242 -0
  112. data/lib/language_operator/validators.rb +170 -0
  113. data/lib/language_operator/version.rb +1 -1
  114. data/lib/language_operator.rb +65 -3
  115. data/requirements/tasks/challenge.md +9 -0
  116. data/requirements/tasks/iterate.md +36 -0
  117. data/requirements/tasks/optimize.md +21 -0
  118. data/requirements/tasks/tag.md +5 -0
  119. data/test_agent_dsl.rb +108 -0
  120. metadata +507 -20
@@ -0,0 +1,1177 @@
1
+ # MCP Integration Guide
2
+
3
+ Complete guide to using the Model Context Protocol (MCP) with Language Operator agents.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [MCP Server: Exposing Tools](#mcp-server-exposing-tools)
9
+ - [Tool Definition](#tool-definition)
10
+ - [Parameter Definition](#parameter-definition)
11
+ - [Tool Execution](#tool-execution)
12
+ - [MCP Protocol Endpoints](#mcp-protocol-endpoints)
13
+ - [Complete Examples](#complete-examples)
14
+ - [Testing MCP Tools](#testing-mcp-tools)
15
+ - [Best Practices](#best-practices)
16
+
17
+ ## Overview
18
+
19
+ The Model Context Protocol (MCP) enables agents to expose and consume tools in a standardized way. Language Operator provides two key MCP capabilities:
20
+
21
+ 1. **MCP Server**: Agents can expose their own tools that other agents or MCP clients can call
22
+ 2. **MCP Client**: Agents can connect to external MCP servers and use their tools (via configuration)
23
+
24
+ ### What is MCP?
25
+
26
+ MCP is a standardized protocol for tool discovery and execution in LLM applications. It enables:
27
+ - Tool discovery via JSON-RPC protocol
28
+ - Type-safe parameter definitions with validation
29
+ - Remote tool execution
30
+ - Tool composition across different agents
31
+
32
+ ### Key Concepts
33
+
34
+ - **MCP Server**: An agent that exposes tools via the MCP protocol
35
+ - **Tool**: A function that can be called with parameters and returns results
36
+ - **Parameter**: A typed input to a tool with validation rules
37
+ - **JSON-RPC**: The protocol used for MCP communication
38
+
39
+ ## MCP Server: Exposing Tools
40
+
41
+ Any agent can act as an MCP server by defining tools in an `as_mcp_server` block.
42
+
43
+ ### Basic MCP Server
44
+
45
+ ```ruby
46
+ agent "data-processor" do
47
+ description "Data processing agent"
48
+ mode :reactive
49
+
50
+ as_mcp_server do
51
+ tool "process_csv" do
52
+ description "Process CSV data and return statistics"
53
+
54
+ parameter :csv_data do
55
+ type :string
56
+ required true
57
+ description "CSV data as string"
58
+ end
59
+
60
+ execute do |params|
61
+ # Tool implementation
62
+ lines = params['csv_data'].split("\n")
63
+ { total_rows: lines.length }.to_json
64
+ end
65
+ end
66
+ end
67
+ end
68
+ ```
69
+
70
+ **Key points:**
71
+ - Use `as_mcp_server` block to define MCP capabilities
72
+ - Agent automatically runs in `:reactive` mode when MCP server is defined
73
+ - MCP endpoint is automatically created at `/mcp`
74
+ - Tools are automatically registered and discoverable
75
+
76
+ ### Custom Server Name
77
+
78
+ By default, the server name is `{agent-name}-mcp`. You can customize it:
79
+
80
+ ```ruby
81
+ as_mcp_server do
82
+ name "custom-processor-server"
83
+
84
+ tool "my_tool" do
85
+ # Tool definition...
86
+ end
87
+ end
88
+ ```
89
+
90
+ ### Multiple Tools
91
+
92
+ Define multiple tools in one server:
93
+
94
+ ```ruby
95
+ as_mcp_server do
96
+ tool "process_csv" do
97
+ description "Process CSV data"
98
+ # ...
99
+ end
100
+
101
+ tool "calculate_stats" do
102
+ description "Calculate statistics"
103
+ # ...
104
+ end
105
+
106
+ tool "format_json" do
107
+ description "Format and validate JSON"
108
+ # ...
109
+ end
110
+ end
111
+ ```
112
+
113
+ ## Tool Definition
114
+
115
+ Tools are the core of MCP integration. Each tool has a name, description, parameters, and execution logic.
116
+
117
+ ### Basic Tool Structure
118
+
119
+ ```ruby
120
+ tool "tool_name" do
121
+ description "What this tool does"
122
+
123
+ parameter :param_name do
124
+ type :string
125
+ required true
126
+ description "What this parameter is for"
127
+ end
128
+
129
+ execute do |params|
130
+ # Tool logic here
131
+ # Return value (string, hash, array, etc.)
132
+ end
133
+ end
134
+ ```
135
+
136
+ ### Tool Components
137
+
138
+ **Name** (String)
139
+ - Unique identifier for the tool
140
+ - Used in MCP protocol and API calls
141
+ - Convention: lowercase with underscores
142
+
143
+ **Description** (String)
144
+ - Human-readable description of tool functionality
145
+ - Should explain what the tool does and when to use it
146
+ - Helps LLMs decide when to call the tool
147
+
148
+ **Parameters** (Block)
149
+ - Define inputs the tool accepts
150
+ - Each parameter has type, validation, and metadata
151
+ - See [Parameter Definition](#parameter-definition) below
152
+
153
+ **Execute Block** (Proc)
154
+ - Contains the tool's implementation logic
155
+ - Receives `params` hash with validated parameters
156
+ - Should return a value (string, hash, array, etc.)
157
+
158
+ ### Tool Examples
159
+
160
+ **Simple calculation tool:**
161
+ ```ruby
162
+ tool "add" do
163
+ description "Add two numbers together"
164
+
165
+ parameter :a do
166
+ type :number
167
+ required true
168
+ description "First number"
169
+ end
170
+
171
+ parameter :b do
172
+ type :number
173
+ required true
174
+ description "Second number"
175
+ end
176
+
177
+ execute do |params|
178
+ (params['a'] + params['b']).to_s
179
+ end
180
+ end
181
+ ```
182
+
183
+ **Data transformation tool:**
184
+ ```ruby
185
+ tool "transform_json" do
186
+ description "Transform JSON data according to mapping rules"
187
+
188
+ parameter :data do
189
+ type :object
190
+ required true
191
+ description "Input JSON data"
192
+ end
193
+
194
+ parameter :mapping do
195
+ type :object
196
+ required true
197
+ description "Transformation mapping rules"
198
+ end
199
+
200
+ execute do |params|
201
+ data = params['data']
202
+ mapping = params['mapping']
203
+
204
+ result = {}
205
+ mapping.each do |source_key, target_key|
206
+ result[target_key] = data[source_key] if data.key?(source_key)
207
+ end
208
+
209
+ result.to_json
210
+ end
211
+ end
212
+ ```
213
+
214
+ **HTTP API tool:**
215
+ ```ruby
216
+ tool "fetch_user" do
217
+ description "Fetch user data from API by ID"
218
+
219
+ parameter :user_id do
220
+ type :string
221
+ required true
222
+ description "User ID to fetch"
223
+ end
224
+
225
+ parameter :include_profile do
226
+ type :boolean
227
+ required false
228
+ description "Include full profile data"
229
+ end
230
+
231
+ execute do |params|
232
+ require 'net/http'
233
+ require 'json'
234
+
235
+ url = "https://api.example.com/users/#{params['user_id']}"
236
+ url += "?include_profile=true" if params['include_profile']
237
+
238
+ response = Net::HTTP.get(URI(url))
239
+ JSON.parse(response).to_json
240
+ rescue StandardError => e
241
+ { error: e.message }.to_json
242
+ end
243
+ end
244
+ ```
245
+
246
+ ## Parameter Definition
247
+
248
+ Parameters define the inputs a tool accepts, with type safety and validation.
249
+
250
+ ### Parameter Types
251
+
252
+ Language Operator supports the following parameter types:
253
+
254
+ ```ruby
255
+ parameter :string_param do
256
+ type :string # Text values
257
+ end
258
+
259
+ parameter :number_param do
260
+ type :number # Numeric values (integers or floats)
261
+ end
262
+
263
+ parameter :integer_param do
264
+ type :integer # Integer values only
265
+ end
266
+
267
+ parameter :boolean_param do
268
+ type :boolean # true/false values
269
+ end
270
+
271
+ parameter :array_param do
272
+ type :array # Array/list values
273
+ end
274
+
275
+ parameter :object_param do
276
+ type :object # Hash/object values
277
+ end
278
+ ```
279
+
280
+ ### Required vs Optional
281
+
282
+ ```ruby
283
+ parameter :required_param do
284
+ type :string
285
+ required true # Must be provided
286
+ end
287
+
288
+ parameter :optional_param do
289
+ type :string
290
+ required false # Can be omitted
291
+ end
292
+ ```
293
+
294
+ **Behavior:**
295
+ - Required parameters: Tool execution fails if not provided
296
+ - Optional parameters: Can be omitted, defaults to `nil` unless default set
297
+
298
+ ### Default Values
299
+
300
+ ```ruby
301
+ parameter :timeout do
302
+ type :number
303
+ required false
304
+ default 30 # Used if parameter not provided
305
+ description "Timeout in seconds (default: 30)"
306
+ end
307
+
308
+ parameter :format do
309
+ type :string
310
+ required false
311
+ default "json"
312
+ description "Output format: json, xml, or csv"
313
+ end
314
+ ```
315
+
316
+ ### Enum Values
317
+
318
+ Restrict parameter to specific allowed values:
319
+
320
+ ```ruby
321
+ parameter :status do
322
+ type :string
323
+ required true
324
+ enum ["active", "inactive", "pending"]
325
+ description "User status"
326
+ end
327
+
328
+ parameter :log_level do
329
+ type :string
330
+ required false
331
+ default "info"
332
+ enum ["debug", "info", "warn", "error"]
333
+ description "Log level for output"
334
+ end
335
+ ```
336
+
337
+ **Behavior:**
338
+ - Parameter value must match one of the enum values
339
+ - Validation error raised if value not in enum
340
+
341
+ ### Parameter Validation
342
+
343
+ **Built-in validators:**
344
+
345
+ ```ruby
346
+ # URL format validation
347
+ parameter :website do
348
+ type :string
349
+ required true
350
+ url_format # Validates http:// or https:// URLs
351
+ end
352
+
353
+ # Email format validation
354
+ parameter :email do
355
+ type :string
356
+ required true
357
+ email_format # Validates email address format
358
+ end
359
+
360
+ # Phone format validation
361
+ parameter :phone do
362
+ type :string
363
+ required true
364
+ phone_format # Validates +1234567890 format
365
+ end
366
+ ```
367
+
368
+ **Regex validators:**
369
+
370
+ ```ruby
371
+ parameter :zip_code do
372
+ type :string
373
+ required true
374
+ validate /^\d{5}(-\d{4})?$/ # US ZIP code format
375
+ description "US ZIP code (5 or 9 digits)"
376
+ end
377
+
378
+ parameter :product_code do
379
+ type :string
380
+ required true
381
+ validate /^[A-Z]{3}-\d{4}$/ # Custom format
382
+ description "Product code (e.g., ABC-1234)"
383
+ end
384
+ ```
385
+
386
+ **Custom validators (Proc):**
387
+
388
+ ```ruby
389
+ parameter :age do
390
+ type :number
391
+ required true
392
+ validate ->(value) {
393
+ if value < 0 || value > 150
394
+ "Age must be between 0 and 150"
395
+ else
396
+ true
397
+ end
398
+ }
399
+ description "Person's age"
400
+ end
401
+
402
+ parameter :username do
403
+ type :string
404
+ required true
405
+ validate ->(value) {
406
+ return "Username too short" if value.length < 3
407
+ return "Username too long" if value.length > 20
408
+ return "Username must be alphanumeric" unless value.match?(/^[a-zA-Z0-9_]+$/)
409
+ true
410
+ }
411
+ description "Username (3-20 alphanumeric characters)"
412
+ end
413
+ ```
414
+
415
+ **Validation behavior:**
416
+ - Validators run before tool execution
417
+ - If validation fails, tool execution is prevented
418
+ - Error message is returned to caller
419
+ - Custom validators can return `String` (error message) or `Boolean`
420
+
421
+ ### Complete Parameter Examples
422
+
423
+ **Simple required parameter:**
424
+ ```ruby
425
+ parameter :message do
426
+ type :string
427
+ required true
428
+ description "Message to send"
429
+ end
430
+ ```
431
+
432
+ **Optional parameter with default:**
433
+ ```ruby
434
+ parameter :retries do
435
+ type :number
436
+ required false
437
+ default 3
438
+ description "Number of retry attempts (default: 3)"
439
+ end
440
+ ```
441
+
442
+ **Enum with default:**
443
+ ```ruby
444
+ parameter :environment do
445
+ type :string
446
+ required false
447
+ default "production"
448
+ enum ["development", "staging", "production"]
449
+ description "Deployment environment"
450
+ end
451
+ ```
452
+
453
+ **Validated parameter:**
454
+ ```ruby
455
+ parameter :api_key do
456
+ type :string
457
+ required true
458
+ validate /^[A-Za-z0-9_-]{32,}$/ # At least 32 alphanumeric chars
459
+ description "API authentication key"
460
+ end
461
+ ```
462
+
463
+ ## Tool Execution
464
+
465
+ The `execute` block contains the tool's implementation logic.
466
+
467
+ ### Execute Block Basics
468
+
469
+ ```ruby
470
+ execute do |params|
471
+ # Access parameters
472
+ input = params['input_param']
473
+
474
+ # Perform logic
475
+ result = process(input)
476
+
477
+ # Return result (any JSON-serializable value)
478
+ result
479
+ end
480
+ ```
481
+
482
+ **Key points:**
483
+ - Receives `params` hash with validated parameter values
484
+ - Parameter names are strings (not symbols)
485
+ - Should return a value (string, number, hash, array, etc.)
486
+ - Exceptions are caught and returned as errors
487
+
488
+ ### Accessing Parameters
489
+
490
+ Parameters are passed as a hash with string keys:
491
+
492
+ ```ruby
493
+ tool "greet" do
494
+ parameter :name do
495
+ type :string
496
+ required true
497
+ end
498
+
499
+ parameter :greeting do
500
+ type :string
501
+ required false
502
+ default "Hello"
503
+ end
504
+
505
+ execute do |params|
506
+ name = params['name']
507
+ greeting = params['greeting']
508
+ "#{greeting}, #{name}!"
509
+ end
510
+ end
511
+ ```
512
+
513
+ ### Return Values
514
+
515
+ Tools can return various types:
516
+
517
+ **String:**
518
+ ```ruby
519
+ execute do |params|
520
+ "Result: #{params['value']}"
521
+ end
522
+ ```
523
+
524
+ **Number:**
525
+ ```ruby
526
+ execute do |params|
527
+ params['a'] + params['b']
528
+ end
529
+ ```
530
+
531
+ **Hash (returned as JSON):**
532
+ ```ruby
533
+ execute do |params|
534
+ {
535
+ success: true,
536
+ result: "processed",
537
+ timestamp: Time.now.iso8601
538
+ }.to_json
539
+ end
540
+ ```
541
+
542
+ **Array:**
543
+ ```ruby
544
+ execute do |params|
545
+ [1, 2, 3, 4, 5].to_json
546
+ end
547
+ ```
548
+
549
+ ### Error Handling
550
+
551
+ Handle errors gracefully in execute blocks:
552
+
553
+ ```ruby
554
+ execute do |params|
555
+ begin
556
+ # Risky operation
557
+ result = external_api_call(params['data'])
558
+ { success: true, result: result }.to_json
559
+ rescue StandardError => e
560
+ {
561
+ success: false,
562
+ error: e.message,
563
+ error_type: e.class.name
564
+ }.to_json
565
+ end
566
+ end
567
+ ```
568
+
569
+ **Best practices:**
570
+ - Always rescue exceptions in execute blocks
571
+ - Return error information in a consistent format
572
+ - Include error type and message for debugging
573
+ - Log errors for monitoring
574
+
575
+ ### External Dependencies
576
+
577
+ Tools can use external libraries and services:
578
+
579
+ ```ruby
580
+ tool "send_email" do
581
+ parameter :to do
582
+ type :string
583
+ required true
584
+ email_format
585
+ end
586
+
587
+ parameter :subject do
588
+ type :string
589
+ required true
590
+ end
591
+
592
+ parameter :body do
593
+ type :string
594
+ required true
595
+ end
596
+
597
+ execute do |params|
598
+ require 'mail'
599
+
600
+ Mail.deliver do
601
+ to params['to']
602
+ from ENV['SMTP_FROM']
603
+ subject params['subject']
604
+ body params['body']
605
+ end
606
+
607
+ { success: true, sent_at: Time.now.iso8601 }.to_json
608
+ rescue StandardError => e
609
+ { success: false, error: e.message }.to_json
610
+ end
611
+ end
612
+ ```
613
+
614
+ ## MCP Protocol Endpoints
615
+
616
+ When an agent acts as an MCP server, it automatically exposes MCP protocol endpoints.
617
+
618
+ ### Automatic Endpoints
619
+
620
+ **MCP Protocol** - `POST /mcp`
621
+ - JSON-RPC 2.0 endpoint for tool discovery and execution
622
+ - Supports standard MCP methods: `tools/list`, `tools/call`
623
+
624
+ **Webhook** - `POST /webhook`
625
+ - Standard webhook endpoint (if defined)
626
+ - Can coexist with MCP server functionality
627
+
628
+ **Health Check** - `GET /health`
629
+ - Returns server health status
630
+ - Always available
631
+
632
+ **Readiness Check** - `GET /ready`
633
+ - Returns readiness status
634
+ - Always available
635
+
636
+ ### MCP Protocol Methods
637
+
638
+ **List Tools** - `tools/list`
639
+
640
+ Request:
641
+ ```json
642
+ {
643
+ "jsonrpc": "2.0",
644
+ "method": "tools/list",
645
+ "id": 1
646
+ }
647
+ ```
648
+
649
+ Response:
650
+ ```json
651
+ {
652
+ "jsonrpc": "2.0",
653
+ "id": 1,
654
+ "result": {
655
+ "tools": [
656
+ {
657
+ "name": "process_csv",
658
+ "description": "Process CSV data and return statistics",
659
+ "inputSchema": {
660
+ "type": "object",
661
+ "properties": {
662
+ "csv_data": {
663
+ "type": "string",
664
+ "description": "CSV data as string"
665
+ }
666
+ },
667
+ "required": ["csv_data"]
668
+ }
669
+ }
670
+ ]
671
+ }
672
+ }
673
+ ```
674
+
675
+ **Call Tool** - `tools/call`
676
+
677
+ Request:
678
+ ```json
679
+ {
680
+ "jsonrpc": "2.0",
681
+ "method": "tools/call",
682
+ "params": {
683
+ "name": "process_csv",
684
+ "arguments": {
685
+ "csv_data": "name,age\nAlice,30\nBob,25"
686
+ }
687
+ },
688
+ "id": 2
689
+ }
690
+ ```
691
+
692
+ Response:
693
+ ```json
694
+ {
695
+ "jsonrpc": "2.0",
696
+ "id": 2,
697
+ "result": {
698
+ "content": [
699
+ {
700
+ "type": "text",
701
+ "text": "{\"total_rows\":2}"
702
+ }
703
+ ]
704
+ }
705
+ }
706
+ ```
707
+
708
+ ## Complete Examples
709
+
710
+ ### Data Processing MCP Server
711
+
712
+ ```ruby
713
+ agent "data-processor-mcp" do
714
+ description "Data processing agent with MCP tools"
715
+ mode :reactive
716
+
717
+ as_mcp_server do
718
+ # Tool 1: Process CSV
719
+ tool "process_csv" do
720
+ description "Process CSV data and return summary statistics"
721
+
722
+ parameter :csv_data do
723
+ type :string
724
+ required true
725
+ description "CSV data as string"
726
+ end
727
+
728
+ execute do |params|
729
+ lines = params['csv_data'].split("\n")
730
+ headers = lines.first&.split(',') || []
731
+ data_rows = lines[1..]
732
+
733
+ {
734
+ total_rows: data_rows&.length || 0,
735
+ total_columns: headers.length,
736
+ headers: headers,
737
+ sample: data_rows&.first || ''
738
+ }.to_json
739
+ end
740
+ end
741
+
742
+ # Tool 2: Calculate statistics
743
+ tool "calculate_stats" do
744
+ description "Calculate basic statistics for a list of numbers"
745
+
746
+ parameter :numbers do
747
+ type :array
748
+ required true
749
+ description "Array of numbers"
750
+ end
751
+
752
+ execute do |params|
753
+ nums = params['numbers']
754
+ return { error: 'Empty array' }.to_json if nums.empty?
755
+
756
+ sum = nums.sum
757
+ mean = sum.to_f / nums.length
758
+ sorted = nums.sort
759
+ median = if nums.length.odd?
760
+ sorted[nums.length / 2]
761
+ else
762
+ (sorted[(nums.length / 2) - 1] + sorted[nums.length / 2]) / 2.0
763
+ end
764
+
765
+ {
766
+ count: nums.length,
767
+ sum: sum,
768
+ mean: mean,
769
+ median: median,
770
+ min: nums.min,
771
+ max: nums.max
772
+ }.to_json
773
+ end
774
+ end
775
+
776
+ # Tool 3: Format JSON
777
+ tool "format_json" do
778
+ description "Format and validate JSON data"
779
+
780
+ parameter :json_string do
781
+ type :string
782
+ required true
783
+ description "JSON string to format"
784
+ end
785
+
786
+ parameter :indent do
787
+ type :number
788
+ required false
789
+ default 2
790
+ description "Indentation spaces (default: 2)"
791
+ end
792
+
793
+ execute do |params|
794
+ indent = params['indent'] || 2
795
+ parsed = JSON.parse(params['json_string'])
796
+ JSON.pretty_generate(parsed, indent: ' ' * indent.to_i)
797
+ rescue JSON::ParserError => e
798
+ { error: "Invalid JSON: #{e.message}" }.to_json
799
+ end
800
+ end
801
+ end
802
+
803
+ # Optional: Also expose webhook endpoint
804
+ webhook "/process" do
805
+ method :post
806
+ on_request do |_context|
807
+ {
808
+ status: 'processed',
809
+ tools_available: 3,
810
+ mcp_endpoint: '/mcp'
811
+ }
812
+ end
813
+ end
814
+ end
815
+ ```
816
+
817
+ ### Text Processing MCP Server
818
+
819
+ ```ruby
820
+ agent "text-processor" do
821
+ description "Text processing and transformation tools"
822
+ mode :reactive
823
+
824
+ as_mcp_server do
825
+ name "text-tools-server"
826
+
827
+ tool "word_count" do
828
+ description "Count words, characters, and lines in text"
829
+
830
+ parameter :text do
831
+ type :string
832
+ required true
833
+ description "Text to analyze"
834
+ end
835
+
836
+ execute do |params|
837
+ text = params['text']
838
+ {
839
+ characters: text.length,
840
+ words: text.split.length,
841
+ lines: text.lines.count,
842
+ paragraphs: text.split("\n\n").length
843
+ }.to_json
844
+ end
845
+ end
846
+
847
+ tool "case_transform" do
848
+ description "Transform text case"
849
+
850
+ parameter :text do
851
+ type :string
852
+ required true
853
+ description "Text to transform"
854
+ end
855
+
856
+ parameter :format do
857
+ type :string
858
+ required true
859
+ enum ["uppercase", "lowercase", "titlecase", "capitalize"]
860
+ description "Target format"
861
+ end
862
+
863
+ execute do |params|
864
+ text = params['text']
865
+ case params['format']
866
+ when "uppercase"
867
+ text.upcase
868
+ when "lowercase"
869
+ text.downcase
870
+ when "titlecase"
871
+ text.split.map(&:capitalize).join(' ')
872
+ when "capitalize"
873
+ text.capitalize
874
+ else
875
+ text
876
+ end
877
+ end
878
+ end
879
+
880
+ tool "extract_emails" do
881
+ description "Extract email addresses from text"
882
+
883
+ parameter :text do
884
+ type :string
885
+ required true
886
+ description "Text to scan for emails"
887
+ end
888
+
889
+ execute do |params|
890
+ email_regex = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i
891
+ emails = params['text'].scan(email_regex).uniq
892
+ { emails: emails, count: emails.length }.to_json
893
+ end
894
+ end
895
+ end
896
+
897
+ constraints do
898
+ timeout '30s'
899
+ requests_per_minute 60
900
+ end
901
+ end
902
+ ```
903
+
904
+ ### API Integration MCP Server
905
+
906
+ ```ruby
907
+ agent "weather-api-server" do
908
+ description "Weather data API integration"
909
+ mode :reactive
910
+
911
+ as_mcp_server do
912
+ tool "get_current_weather" do
913
+ description "Get current weather for a location"
914
+
915
+ parameter :location do
916
+ type :string
917
+ required true
918
+ description "City name or ZIP code"
919
+ end
920
+
921
+ parameter :units do
922
+ type :string
923
+ required false
924
+ default "metric"
925
+ enum ["metric", "imperial"]
926
+ description "Temperature units"
927
+ end
928
+
929
+ execute do |params|
930
+ require 'net/http'
931
+ require 'json'
932
+
933
+ api_key = ENV['WEATHER_API_KEY']
934
+ location = params['location']
935
+ units = params['units'] || 'metric'
936
+
937
+ url = "https://api.openweathermap.org/data/2.5/weather?q=#{location}&units=#{units}&appid=#{api_key}"
938
+ response = Net::HTTP.get(URI(url))
939
+ data = JSON.parse(response)
940
+
941
+ {
942
+ location: data['name'],
943
+ temperature: data['main']['temp'],
944
+ feels_like: data['main']['feels_like'],
945
+ humidity: data['main']['humidity'],
946
+ description: data['weather'].first['description'],
947
+ units: units
948
+ }.to_json
949
+ rescue StandardError => e
950
+ { error: e.message }.to_json
951
+ end
952
+ end
953
+
954
+ tool "get_forecast" do
955
+ description "Get 5-day weather forecast"
956
+
957
+ parameter :location do
958
+ type :string
959
+ required true
960
+ description "City name or ZIP code"
961
+ end
962
+
963
+ execute do |params|
964
+ require 'net/http'
965
+ require 'json'
966
+
967
+ api_key = ENV['WEATHER_API_KEY']
968
+ url = "https://api.openweathermap.org/data/2.5/forecast?q=#{params['location']}&appid=#{api_key}"
969
+ response = Net::HTTP.get(URI(url))
970
+ data = JSON.parse(response)
971
+
972
+ forecast = data['list'].map do |item|
973
+ {
974
+ datetime: item['dt_txt'],
975
+ temperature: item['main']['temp'],
976
+ description: item['weather'].first['description']
977
+ }
978
+ end
979
+
980
+ { location: data['city']['name'], forecast: forecast }.to_json
981
+ rescue StandardError => e
982
+ { error: e.message }.to_json
983
+ end
984
+ end
985
+ end
986
+
987
+ constraints do
988
+ timeout '10s'
989
+ requests_per_minute 30 # Respect API rate limits
990
+ daily_budget 500 # $5/day
991
+ end
992
+ end
993
+ ```
994
+
995
+ ## Testing MCP Tools
996
+
997
+ ### Using curl
998
+
999
+ **List available tools:**
1000
+ ```bash
1001
+ curl -X POST http://localhost:8080/mcp \
1002
+ -H "Content-Type: application/json" \
1003
+ -d '{
1004
+ "jsonrpc": "2.0",
1005
+ "method": "tools/list",
1006
+ "id": 1
1007
+ }'
1008
+ ```
1009
+
1010
+ **Call a tool:**
1011
+ ```bash
1012
+ curl -X POST http://localhost:8080/mcp \
1013
+ -H "Content-Type: application/json" \
1014
+ -d '{
1015
+ "jsonrpc": "2.0",
1016
+ "method": "tools/call",
1017
+ "params": {
1018
+ "name": "process_csv",
1019
+ "arguments": {
1020
+ "csv_data": "name,age\nAlice,30\nBob,25"
1021
+ }
1022
+ },
1023
+ "id": 2
1024
+ }'
1025
+ ```
1026
+
1027
+ ### Using RSpec
1028
+
1029
+ ```ruby
1030
+ require 'spec_helper'
1031
+
1032
+ RSpec.describe 'MCP Tools' do
1033
+ let(:mcp_def) { LanguageOperator::Dsl::McpServerDefinition.new('test-agent') }
1034
+
1035
+ before do
1036
+ mcp_def.tool('greet') do
1037
+ description 'Greet a user'
1038
+ parameter :name do
1039
+ type :string
1040
+ required true
1041
+ end
1042
+ execute do |params|
1043
+ "Hello, #{params['name']}!"
1044
+ end
1045
+ end
1046
+ end
1047
+
1048
+ it 'executes tool successfully' do
1049
+ tool = mcp_def.tools['greet']
1050
+ result = tool.call('name' => 'Alice')
1051
+ expect(result).to eq('Hello, Alice!')
1052
+ end
1053
+
1054
+ it 'validates required parameters' do
1055
+ tool = mcp_def.tools['greet']
1056
+ expect {
1057
+ tool.call({}) # Missing required 'name' parameter
1058
+ }.to raise_error(ArgumentError, /Missing required parameter/)
1059
+ end
1060
+ end
1061
+ ```
1062
+
1063
+ ### Integration Testing
1064
+
1065
+ ```ruby
1066
+ # Test full MCP server
1067
+ agent_def = LanguageOperator::Dsl.agent_registry.get('data-processor-mcp')
1068
+
1069
+ # Start server in test mode
1070
+ # Make HTTP requests to /mcp endpoint
1071
+ # Verify responses match MCP protocol
1072
+ ```
1073
+
1074
+ ## Best Practices
1075
+
1076
+ ### Tool Design
1077
+
1078
+ 1. **Keep tools focused** - Each tool should do one thing well
1079
+ 2. **Use clear names** - Tool names should describe what they do
1080
+ 3. **Write good descriptions** - Help LLMs understand when to use the tool
1081
+ 4. **Validate inputs** - Use parameter validation to prevent errors
1082
+ 5. **Handle errors gracefully** - Return error information, don't crash
1083
+
1084
+ ### Parameter Design
1085
+
1086
+ 1. **Use required for critical params** - Make essential parameters required
1087
+ 2. **Provide defaults** - Set sensible defaults for optional parameters
1088
+ 3. **Use enums for choices** - Restrict to valid values when applicable
1089
+ 4. **Validate formats** - Use built-in or custom validators
1090
+ 5. **Document clearly** - Write clear parameter descriptions
1091
+
1092
+ ### Error Handling
1093
+
1094
+ 1. **Always rescue exceptions** - Prevent tools from crashing
1095
+ 2. **Return structured errors** - Use consistent error format
1096
+ 3. **Include error details** - Return error type and message
1097
+ 4. **Log errors** - Enable debugging with proper logging
1098
+
1099
+ ```ruby
1100
+ execute do |params|
1101
+ begin
1102
+ result = risky_operation(params)
1103
+ { success: true, result: result }.to_json
1104
+ rescue StandardError => e
1105
+ logger.error("Tool execution failed: #{e.message}")
1106
+ {
1107
+ success: false,
1108
+ error: e.message,
1109
+ error_type: e.class.name
1110
+ }.to_json
1111
+ end
1112
+ end
1113
+ ```
1114
+
1115
+ ### Performance
1116
+
1117
+ 1. **Set timeouts** - Prevent tools from hanging
1118
+ 2. **Limit rate** - Use constraints to control usage
1119
+ 3. **Cache results** - Cache expensive operations when appropriate
1120
+ 4. **Monitor usage** - Track tool execution metrics
1121
+
1122
+ ```ruby
1123
+ agent "mcp-server" do
1124
+ as_mcp_server do
1125
+ # Tools...
1126
+ end
1127
+
1128
+ constraints do
1129
+ timeout '30s' # Per-request timeout
1130
+ requests_per_minute 60
1131
+ daily_budget 1000
1132
+ end
1133
+ end
1134
+ ```
1135
+
1136
+ ### Security
1137
+
1138
+ 1. **Validate all inputs** - Never trust user input
1139
+ 2. **Sanitize parameters** - Prevent injection attacks
1140
+ 3. **Limit access** - Use authentication on MCP endpoints
1141
+ 4. **Avoid secrets in responses** - Don't leak sensitive data
1142
+ 5. **Log security events** - Monitor for abuse
1143
+
1144
+ ```ruby
1145
+ parameter :sql_query do
1146
+ type :string
1147
+ required true
1148
+ validate ->(value) {
1149
+ # Prevent SQL injection
1150
+ return "Invalid query" if value.match?(/;\s*(DROP|DELETE|UPDATE)/i)
1151
+ true
1152
+ }
1153
+ end
1154
+ ```
1155
+
1156
+ ### Testing
1157
+
1158
+ 1. **Test tool execution** - Verify tools work correctly
1159
+ 2. **Test validation** - Ensure parameter validation works
1160
+ 3. **Test error cases** - Verify error handling
1161
+ 4. **Test edge cases** - Test boundary conditions
1162
+ 5. **Integration test** - Test full MCP protocol
1163
+
1164
+ ### Documentation
1165
+
1166
+ 1. **Document each tool** - Explain purpose and usage
1167
+ 2. **Document parameters** - Describe each parameter clearly
1168
+ 3. **Provide examples** - Show example calls and responses
1169
+ 4. **Document errors** - Explain possible error conditions
1170
+ 5. **Keep docs updated** - Update when tools change
1171
+
1172
+ ## See Also
1173
+
1174
+ - [Agent Reference](agent-reference.md) - Complete agent DSL reference
1175
+ - [Chat Endpoints](chat-endpoints.md) - OpenAI-compatible endpoint guide
1176
+ - [Webhooks](webhooks.md) - Reactive agent configuration
1177
+ - [Best Practices](best-practices.md) - Production deployment patterns