actionmcp 0.102.0 → 0.104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +46 -3
- data/app/models/action_mcp/session.rb +6 -5
- data/lib/action_mcp/configuration.rb +44 -8
- data/lib/action_mcp/server/base_session.rb +5 -1
- data/lib/action_mcp/test_helper/session_store_assertions.rb +0 -70
- data/lib/action_mcp/version.rb +1 -1
- data/lib/action_mcp.rb +0 -1
- data/lib/generators/action_mcp/identifier/templates/identifier.rb.erb +4 -4
- data/lib/generators/action_mcp/install/templates/mcp.yml +11 -1
- data/lib/generators/action_mcp/tool/templates/tool.rb.erb +2 -2
- metadata +1 -26
- data/lib/action_mcp/client/active_record_session_store.rb +0 -57
- data/lib/action_mcp/client/base.rb +0 -225
- data/lib/action_mcp/client/blueprint.rb +0 -163
- data/lib/action_mcp/client/catalog.rb +0 -164
- data/lib/action_mcp/client/collection.rb +0 -168
- data/lib/action_mcp/client/elicitation.rb +0 -34
- data/lib/action_mcp/client/json_rpc_handler.rb +0 -202
- data/lib/action_mcp/client/logging.rb +0 -19
- data/lib/action_mcp/client/messaging.rb +0 -28
- data/lib/action_mcp/client/prompt_book.rb +0 -117
- data/lib/action_mcp/client/prompts.rb +0 -47
- data/lib/action_mcp/client/request_timeouts.rb +0 -74
- data/lib/action_mcp/client/resources.rb +0 -100
- data/lib/action_mcp/client/roots.rb +0 -13
- data/lib/action_mcp/client/server.rb +0 -60
- data/lib/action_mcp/client/session_store.rb +0 -39
- data/lib/action_mcp/client/session_store_factory.rb +0 -27
- data/lib/action_mcp/client/streamable_client.rb +0 -264
- data/lib/action_mcp/client/streamable_http_transport.rb +0 -306
- data/lib/action_mcp/client/test_session_store.rb +0 -84
- data/lib/action_mcp/client/toolbox.rb +0 -199
- data/lib/action_mcp/client/tools.rb +0 -47
- data/lib/action_mcp/client/transport.rb +0 -137
- data/lib/action_mcp/client/volatile_session_store.rb +0 -38
- data/lib/action_mcp/client.rb +0 -71
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f008e25bbf68f4c85a29052acb37e59324d302fe5b53c209f7370e80c62e21e
|
|
4
|
+
data.tar.gz: 8d436c6029b33e6e46b43689ea9ab063b7e8474146263d72bbbfc888fffb4b56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f3bf909be5df38c2ca0377ac0773d6b61bfd776f25b2148aae0d218241ee80879ab43fd49dbc6b206985cf9e96a6ffe421ff0158dec48f9d9368690342b6419
|
|
7
|
+
data.tar.gz: 75ad95eb4c7bd7b309e2db5ae7f47722c620e1d585aed0c30f186eaec55bfa4637b99865fe7613e01b7eb217e7e6d28555b8b8ef4695c14c21a97fbbd8e94c52
|
data/README.md
CHANGED
|
@@ -46,6 +46,14 @@ In short, ActionMCP helps you build an MCP server (the component that exposes ca
|
|
|
46
46
|
|
|
47
47
|
> **Client connections:** The client part of ActionMCP is meant to connect to remote MCP servers only. Connecting to local processes (such as via STDIO) is not supported.
|
|
48
48
|
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
- **Ruby**: 3.4.8+ or 4.0.0+
|
|
52
|
+
- **Rails**: 8.1.1+
|
|
53
|
+
- **Database**: PostgreSQL, MySQL, or SQLite3
|
|
54
|
+
|
|
55
|
+
ActionMCP is tested against Ruby 3.4.8 and 4.0.0 with Rails 8.1.1+.
|
|
56
|
+
|
|
49
57
|
## Installation
|
|
50
58
|
|
|
51
59
|
To start using ActionMCP, add it to your project:
|
|
@@ -179,7 +187,7 @@ For tools that perform sensitive operations (file system access, database modifi
|
|
|
179
187
|
class FileSystemTool < ApplicationMCPTool
|
|
180
188
|
tool_name "read_file"
|
|
181
189
|
description "Read contents of a file"
|
|
182
|
-
|
|
190
|
+
|
|
183
191
|
# Require explicit consent before execution
|
|
184
192
|
requires_consent!
|
|
185
193
|
|
|
@@ -392,7 +400,7 @@ ActionMCP provides comprehensive documentation across multiple specialized guide
|
|
|
392
400
|
- **[Installation & Configuration](README.md#installation)** - Initial setup, database migrations, and basic configuration
|
|
393
401
|
- **[Authentication with Gateway](README.md#authentication-with-gateway)** - User authentication and authorization patterns
|
|
394
402
|
|
|
395
|
-
### Component Development
|
|
403
|
+
### Component Development
|
|
396
404
|
- **[📋 TOOLS.MD](TOOLS.MD)** - Complete guide to developing MCP tools
|
|
397
405
|
- Generator usage and best practices
|
|
398
406
|
- Property definitions, validation, and consent management
|
|
@@ -462,6 +470,12 @@ module Tron
|
|
|
462
470
|
config.action_mcp.version = "1.2.3" # defaults to "0.0.1"
|
|
463
471
|
config.action_mcp.logging_enabled = true # defaults to true
|
|
464
472
|
config.action_mcp.logging_level = :info # defaults to :info, can be :debug, :info, :warn, :error, :fatal
|
|
473
|
+
|
|
474
|
+
# Server instructions - helps LLMs understand the server's purpose
|
|
475
|
+
config.action_mcp.server_instructions = [
|
|
476
|
+
"Use this server to access and control Tron system programs",
|
|
477
|
+
"Helpful for managing system processes and user data"
|
|
478
|
+
]
|
|
465
479
|
end
|
|
466
480
|
end
|
|
467
481
|
```
|
|
@@ -513,6 +527,35 @@ production:
|
|
|
513
527
|
max_queue: 500 # Maximum number of tasks that can be queued
|
|
514
528
|
```
|
|
515
529
|
|
|
530
|
+
### Server Instructions
|
|
531
|
+
|
|
532
|
+
Server instructions help LLMs understand **what your server is for** and **when to use it**. They describe the server's purpose and goal, not technical details like rate limits or authentication (tools are self-documented via their own descriptions).
|
|
533
|
+
|
|
534
|
+
Instructions are returned at the top level of the MCP initialization response.
|
|
535
|
+
|
|
536
|
+
You can configure server instructions in your `config/mcp.yml` file:
|
|
537
|
+
|
|
538
|
+
```yaml
|
|
539
|
+
shared:
|
|
540
|
+
# Describe the server's purpose - helps LLMs know when to use this server
|
|
541
|
+
server_instructions:
|
|
542
|
+
- "Use this server to manage Fizzy project tickets and workflows"
|
|
543
|
+
- "Helpful for tracking bugs, features, and sprint planning"
|
|
544
|
+
|
|
545
|
+
development:
|
|
546
|
+
# Development-specific purpose description
|
|
547
|
+
server_instructions:
|
|
548
|
+
- "Development server for testing Fizzy integration"
|
|
549
|
+
- "Use for prototyping ticket management workflows"
|
|
550
|
+
|
|
551
|
+
production:
|
|
552
|
+
# Production-specific purpose description
|
|
553
|
+
server_instructions:
|
|
554
|
+
- "Production Fizzy server for managing live project data"
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
Instructions are sent as a single string (joined by newlines) at the top level of the initialization response, helping LLMs understand your server's purpose.
|
|
558
|
+
|
|
516
559
|
#### SolidMCP (Database-backed, Recommended)
|
|
517
560
|
|
|
518
561
|
For SolidMCP, add it to your Gemfile:
|
|
@@ -1042,7 +1085,7 @@ class MyTool < ApplicationMCPTool
|
|
|
1042
1085
|
report_error("Clear error message for the LLM")
|
|
1043
1086
|
return
|
|
1044
1087
|
end
|
|
1045
|
-
|
|
1088
|
+
|
|
1046
1089
|
# Normal processing
|
|
1047
1090
|
render(text: "Success message")
|
|
1048
1091
|
end
|
|
@@ -140,11 +140,15 @@ module ActionMCP
|
|
|
140
140
|
end
|
|
141
141
|
|
|
142
142
|
def server_capabilities_payload
|
|
143
|
-
{
|
|
143
|
+
payload = {
|
|
144
144
|
protocolVersion: protocol_version || ActionMCP::DEFAULT_PROTOCOL_VERSION,
|
|
145
145
|
serverInfo: server_info,
|
|
146
146
|
capabilities: server_capabilities
|
|
147
147
|
}
|
|
148
|
+
# Add instructions at top level if configured
|
|
149
|
+
instructions = ActionMCP.configuration.instructions
|
|
150
|
+
payload[:instructions] = instructions if instructions
|
|
151
|
+
payload
|
|
148
152
|
end
|
|
149
153
|
|
|
150
154
|
def server_capabilities
|
|
@@ -359,10 +363,7 @@ module ActionMCP
|
|
|
359
363
|
|
|
360
364
|
# This will keep the version and name of the server when this session was created
|
|
361
365
|
def set_server_info
|
|
362
|
-
self.server_info =
|
|
363
|
-
name: ActionMCP.configuration.name,
|
|
364
|
-
version: ActionMCP.configuration.version
|
|
365
|
-
}
|
|
366
|
+
self.server_info = ActionMCP.configuration.server_info
|
|
366
367
|
end
|
|
367
368
|
|
|
368
369
|
# This can be overridden by the application in future versions
|
|
@@ -44,12 +44,12 @@ module ActionMCP
|
|
|
44
44
|
:max_queue,
|
|
45
45
|
:polling_interval,
|
|
46
46
|
:connects_to,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
# --- Tasks Options (MCP 2025-11-25) ---
|
|
48
|
+
:tasks_enabled,
|
|
49
|
+
:tasks_list_enabled,
|
|
50
|
+
:tasks_cancel_enabled,
|
|
51
|
+
# --- Schema Validation Options ---
|
|
52
|
+
:validate_structured_content
|
|
53
53
|
|
|
54
54
|
def initialize
|
|
55
55
|
@logging_enabled = false
|
|
@@ -74,6 +74,9 @@ module ActionMCP
|
|
|
74
74
|
# Schema validation - disabled by default for backward compatibility
|
|
75
75
|
@validate_structured_content = false
|
|
76
76
|
|
|
77
|
+
# Server instructions - empty by default
|
|
78
|
+
@server_instructions = []
|
|
79
|
+
|
|
77
80
|
# Gateway - resolved lazily to account for Zeitwerk autoloading
|
|
78
81
|
@gateway_class_name = nil
|
|
79
82
|
|
|
@@ -91,6 +94,30 @@ module ActionMCP
|
|
|
91
94
|
@version || (has_rails_version ? Rails.application.version.to_s : "0.0.1")
|
|
92
95
|
end
|
|
93
96
|
|
|
97
|
+
# Server information (name and version only)
|
|
98
|
+
def server_info
|
|
99
|
+
{
|
|
100
|
+
name: name,
|
|
101
|
+
version: version
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Instructions for LLMs about the server's purpose (joined as string for MCP payload)
|
|
106
|
+
def instructions
|
|
107
|
+
return nil if server_instructions.nil? || server_instructions.empty?
|
|
108
|
+
|
|
109
|
+
server_instructions.join("\n")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Custom getter/setter to ensure array elements are strings
|
|
113
|
+
def server_instructions
|
|
114
|
+
@server_instructions
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def server_instructions=(value)
|
|
118
|
+
@server_instructions = parse_instructions(value)
|
|
119
|
+
end
|
|
120
|
+
|
|
94
121
|
def gateway_class
|
|
95
122
|
# Resolve gateway class lazily to account for Zeitwerk autoloading
|
|
96
123
|
# This allows ApplicationGateway to be loaded from app/mcp even if the
|
|
@@ -343,9 +370,14 @@ module ActionMCP
|
|
|
343
370
|
@client_session_store_type = config["client_session_store_type"].to_sym
|
|
344
371
|
end
|
|
345
372
|
|
|
346
|
-
|
|
373
|
+
if config["server_session_store_type"]
|
|
374
|
+
@server_session_store_type = config["server_session_store_type"].to_sym
|
|
375
|
+
end
|
|
347
376
|
|
|
348
|
-
|
|
377
|
+
# Extract server instructions
|
|
378
|
+
if config["server_instructions"]
|
|
379
|
+
@server_instructions = parse_instructions(config["server_instructions"])
|
|
380
|
+
end
|
|
349
381
|
end
|
|
350
382
|
|
|
351
383
|
def should_include_all?(type)
|
|
@@ -364,6 +396,10 @@ module ActionMCP
|
|
|
364
396
|
false
|
|
365
397
|
end
|
|
366
398
|
|
|
399
|
+
def parse_instructions(instructions)
|
|
400
|
+
Array(instructions).map(&:to_s)
|
|
401
|
+
end
|
|
402
|
+
|
|
367
403
|
def ensure_mcp_components_loaded
|
|
368
404
|
# Only load if we haven't loaded yet - but in development, always reload
|
|
369
405
|
return if @mcp_components_loaded && !Rails.env.development?
|
|
@@ -128,11 +128,15 @@ module ActionMCP
|
|
|
128
128
|
|
|
129
129
|
# Capability methods
|
|
130
130
|
def server_capabilities_payload
|
|
131
|
-
{
|
|
131
|
+
payload = {
|
|
132
132
|
protocolVersion: ActionMCP::LATEST_VERSION,
|
|
133
133
|
serverInfo: server_info,
|
|
134
134
|
capabilities: server_capabilities
|
|
135
135
|
}
|
|
136
|
+
# Add instructions at top level if configured
|
|
137
|
+
instructions = ActionMCP.configuration.instructions
|
|
138
|
+
payload[:instructions] = instructions if instructions
|
|
139
|
+
payload
|
|
136
140
|
end
|
|
137
141
|
|
|
138
142
|
def set_protocol_version(version)
|
|
@@ -51,64 +51,6 @@ module ActionMCP
|
|
|
51
51
|
message || "Expected #{expected} session operations#{type_desc}, got #{actual}"
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
# Client session store assertions
|
|
55
|
-
def assert_client_session_saved(session_id, message = nil)
|
|
56
|
-
assert client_session_store.session_saved?(session_id),
|
|
57
|
-
message || "Expected client session #{session_id} to have been saved"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def assert_client_session_not_saved(session_id, message = nil)
|
|
61
|
-
assert_not client_session_store.session_saved?(session_id),
|
|
62
|
-
message || "Expected client session #{session_id} not to have been saved"
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def assert_client_session_loaded(session_id, message = nil)
|
|
66
|
-
assert client_session_store.session_loaded?(session_id),
|
|
67
|
-
message || "Expected client session #{session_id} to have been loaded"
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def assert_client_session_not_loaded(session_id, message = nil)
|
|
71
|
-
assert_not client_session_store.session_loaded?(session_id),
|
|
72
|
-
message || "Expected client session #{session_id} not to have been loaded"
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def assert_client_session_updated(session_id, message = nil)
|
|
76
|
-
assert client_session_store.session_updated?(session_id),
|
|
77
|
-
message || "Expected client session #{session_id} to have been updated"
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def assert_client_session_not_updated(session_id, message = nil)
|
|
81
|
-
assert_not client_session_store.session_updated?(session_id),
|
|
82
|
-
message || "Expected client session #{session_id} not to have been updated"
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def assert_client_session_deleted(session_id, message = nil)
|
|
86
|
-
assert client_session_store.session_deleted?(session_id),
|
|
87
|
-
message || "Expected client session #{session_id} to have been deleted"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def assert_client_session_not_deleted(session_id, message = nil)
|
|
91
|
-
assert_not client_session_store.session_deleted?(session_id),
|
|
92
|
-
message || "Expected client session #{session_id} not to have been deleted"
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def assert_client_session_operation_count(expected, type = nil, message = nil)
|
|
96
|
-
actual = client_session_store.operation_count(type)
|
|
97
|
-
type_desc = type ? " of type #{type}" : ""
|
|
98
|
-
assert_equal expected, actual,
|
|
99
|
-
message || "Expected #{expected} client session operations#{type_desc}, got #{actual}"
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def assert_client_session_data_includes(session_id, expected_data, message = nil)
|
|
103
|
-
saved_data = client_session_store.last_saved_data(session_id)
|
|
104
|
-
assert saved_data, "No saved data found for session #{session_id}"
|
|
105
|
-
|
|
106
|
-
expected_data.each do |key, value|
|
|
107
|
-
assert_equal value, saved_data[key],
|
|
108
|
-
message || "Expected session #{session_id} data to include #{key}: #{value}"
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
54
|
private
|
|
113
55
|
|
|
114
56
|
def server_session_store
|
|
@@ -117,18 +59,6 @@ module ActionMCP
|
|
|
117
59
|
|
|
118
60
|
store
|
|
119
61
|
end
|
|
120
|
-
|
|
121
|
-
def client_session_store
|
|
122
|
-
# This would need to be set by the test or could use a thread-local variable
|
|
123
|
-
# For now, we'll assume it's available as an instance variable
|
|
124
|
-
store = @client_session_store || Thread.current[:test_client_session_store]
|
|
125
|
-
unless store
|
|
126
|
-
raise "Client session store not set. Set @client_session_store or Thread.current[:test_client_session_store]"
|
|
127
|
-
end
|
|
128
|
-
raise "Client session store is not a TestSessionStore" unless store.is_a?(ActionMCP::Client::TestSessionStore)
|
|
129
|
-
|
|
130
|
-
store
|
|
131
|
-
end
|
|
132
62
|
end
|
|
133
63
|
end
|
|
134
64
|
end
|
data/lib/action_mcp/version.rb
CHANGED
data/lib/action_mcp.rb
CHANGED
|
@@ -29,7 +29,6 @@ end.setup
|
|
|
29
29
|
|
|
30
30
|
module ActionMCP
|
|
31
31
|
require_relative "action_mcp/version"
|
|
32
|
-
require_relative "action_mcp/client"
|
|
33
32
|
|
|
34
33
|
# Error raised when structured content doesn't match the declared output_schema
|
|
35
34
|
class StructuredContentValidationError < StandardError; end
|
|
@@ -22,14 +22,14 @@ class <%= class_name %> < ActionMCP::GatewayIdentifier
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
24
|
# Add any custom helper methods here
|
|
25
|
-
#
|
|
25
|
+
#
|
|
26
26
|
# Example helper methods:
|
|
27
|
-
#
|
|
27
|
+
#
|
|
28
28
|
# def extract_credentials_from_request
|
|
29
29
|
# # Custom extraction logic
|
|
30
30
|
# end
|
|
31
|
-
#
|
|
31
|
+
#
|
|
32
32
|
# def validate_credentials(credentials)
|
|
33
33
|
# # Custom validation logic
|
|
34
34
|
# end
|
|
35
|
-
end
|
|
35
|
+
end
|
|
@@ -16,6 +16,11 @@ shared:
|
|
|
16
16
|
# Server-specific session store type (falls back to session_store_type if not specified)
|
|
17
17
|
# server_session_store_type: active_record
|
|
18
18
|
|
|
19
|
+
# Server instructions - helps LLMs understand the server's purpose
|
|
20
|
+
# Describe what the server is for, not technical details (tools are self-documented)
|
|
21
|
+
# server_instructions:
|
|
22
|
+
# - "Use this server to manage project tickets and workflows"
|
|
23
|
+
# - "Helpful for tracking bugs, features, and sprint planning"
|
|
19
24
|
|
|
20
25
|
# MCP capability profiles
|
|
21
26
|
profiles:
|
|
@@ -46,6 +51,11 @@ development:
|
|
|
46
51
|
# Use simple pub/sub adapter for development
|
|
47
52
|
adapter: simple
|
|
48
53
|
|
|
54
|
+
# Development-specific purpose description
|
|
55
|
+
# server_instructions:
|
|
56
|
+
# - "Development server for testing your MCP integration"
|
|
57
|
+
# - "Use for prototyping and experimenting with tools"
|
|
58
|
+
|
|
49
59
|
# Session store examples for development
|
|
50
60
|
# Use volatile client sessions for faster development
|
|
51
61
|
# client_session_store_type: volatile
|
|
@@ -106,4 +116,4 @@ production:
|
|
|
106
116
|
# channel_prefix: my_mcp_app_production
|
|
107
117
|
# min_threads: 10 # Minimum number of threads in the pool
|
|
108
118
|
# max_threads: 20 # Maximum number of threads in the pool
|
|
109
|
-
# max_queue: 500 # Maximum number of tasks that can be queued
|
|
119
|
+
# max_queue: 500 # Maximum number of tasks that can be queued
|
|
@@ -34,12 +34,12 @@ class <%= class_name %> < ApplicationMCPTool
|
|
|
34
34
|
|
|
35
35
|
# Uncomment to allow additional properties beyond those defined above:
|
|
36
36
|
# additional_properties true # Allow any additional properties
|
|
37
|
-
# additional_properties false # Explicitly disallow additional properties
|
|
37
|
+
# additional_properties false # Explicitly disallow additional properties
|
|
38
38
|
# additional_properties({"type" => "string"}) # Allow additional properties but restrict to strings
|
|
39
39
|
|
|
40
40
|
def perform
|
|
41
41
|
render(text: "Processing <%= properties.map { |p| p[:name] }.join(', ') %>")
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
# If additional_properties is enabled, you can access extra parameters:
|
|
44
44
|
# extra_params = additional_params
|
|
45
45
|
# extra_params.each do |key, value|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: actionmcp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.104.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abdelkader Boudih
|
|
@@ -173,31 +173,6 @@ files:
|
|
|
173
173
|
- lib/action_mcp/base_response.rb
|
|
174
174
|
- lib/action_mcp/callbacks.rb
|
|
175
175
|
- lib/action_mcp/capability.rb
|
|
176
|
-
- lib/action_mcp/client.rb
|
|
177
|
-
- lib/action_mcp/client/active_record_session_store.rb
|
|
178
|
-
- lib/action_mcp/client/base.rb
|
|
179
|
-
- lib/action_mcp/client/blueprint.rb
|
|
180
|
-
- lib/action_mcp/client/catalog.rb
|
|
181
|
-
- lib/action_mcp/client/collection.rb
|
|
182
|
-
- lib/action_mcp/client/elicitation.rb
|
|
183
|
-
- lib/action_mcp/client/json_rpc_handler.rb
|
|
184
|
-
- lib/action_mcp/client/logging.rb
|
|
185
|
-
- lib/action_mcp/client/messaging.rb
|
|
186
|
-
- lib/action_mcp/client/prompt_book.rb
|
|
187
|
-
- lib/action_mcp/client/prompts.rb
|
|
188
|
-
- lib/action_mcp/client/request_timeouts.rb
|
|
189
|
-
- lib/action_mcp/client/resources.rb
|
|
190
|
-
- lib/action_mcp/client/roots.rb
|
|
191
|
-
- lib/action_mcp/client/server.rb
|
|
192
|
-
- lib/action_mcp/client/session_store.rb
|
|
193
|
-
- lib/action_mcp/client/session_store_factory.rb
|
|
194
|
-
- lib/action_mcp/client/streamable_client.rb
|
|
195
|
-
- lib/action_mcp/client/streamable_http_transport.rb
|
|
196
|
-
- lib/action_mcp/client/test_session_store.rb
|
|
197
|
-
- lib/action_mcp/client/toolbox.rb
|
|
198
|
-
- lib/action_mcp/client/tools.rb
|
|
199
|
-
- lib/action_mcp/client/transport.rb
|
|
200
|
-
- lib/action_mcp/client/volatile_session_store.rb
|
|
201
176
|
- lib/action_mcp/configuration.rb
|
|
202
177
|
- lib/action_mcp/console_detector.rb
|
|
203
178
|
- lib/action_mcp/content.rb
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ActionMCP
|
|
4
|
-
module Client
|
|
5
|
-
# ActiveRecord-backed session store for production
|
|
6
|
-
class ActiveRecordSessionStore
|
|
7
|
-
include SessionStore
|
|
8
|
-
|
|
9
|
-
def load_session(session_id)
|
|
10
|
-
session = ActionMCP::Session.find_by(id: session_id)
|
|
11
|
-
return nil unless session
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
id: session.id,
|
|
15
|
-
protocol_version: session.protocol_version,
|
|
16
|
-
client_info: session.client_info,
|
|
17
|
-
client_capabilities: session.client_capabilities,
|
|
18
|
-
server_info: session.server_info,
|
|
19
|
-
server_capabilities: session.server_capabilities,
|
|
20
|
-
created_at: session.created_at,
|
|
21
|
-
updated_at: session.updated_at
|
|
22
|
-
}
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def save_session(session_id, session_data)
|
|
26
|
-
session = ActionMCP::Session.find_or_initialize_by(id: session_id)
|
|
27
|
-
|
|
28
|
-
# Only assign attributes that exist in the database
|
|
29
|
-
attributes = {}
|
|
30
|
-
attributes[:protocol_version] = session_data[:protocol_version] if session_data.key?(:protocol_version)
|
|
31
|
-
attributes[:client_info] = session_data[:client_info] if session_data.key?(:client_info)
|
|
32
|
-
attributes[:client_capabilities] = session_data[:client_capabilities] if session_data.key?(:client_capabilities)
|
|
33
|
-
attributes[:server_info] = session_data[:server_info] if session_data.key?(:server_info)
|
|
34
|
-
attributes[:server_capabilities] = session_data[:server_capabilities] if session_data.key?(:server_capabilities)
|
|
35
|
-
|
|
36
|
-
# Store any extra data in a jsonb column if available
|
|
37
|
-
# For now, we'll skip last_event_id and session_data as they don't exist in the DB
|
|
38
|
-
|
|
39
|
-
session.assign_attributes(attributes)
|
|
40
|
-
session.save!
|
|
41
|
-
session_data
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def delete_session(session_id)
|
|
45
|
-
ActionMCP::Session.find_by(id: session_id)&.destroy
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def session_exists?(session_id)
|
|
49
|
-
ActionMCP::Session.exists?(id: session_id)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def cleanup_expired_sessions(older_than: 24.hours.ago)
|
|
53
|
-
ActionMCP::Session.where("updated_at < ?", older_than).delete_all
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|