Class: ActionMCP::Session
- Inherits:
-
ApplicationRecord
show all
- Includes:
- MCPConsoleHelpers
- Defined in:
- app/models/action_mcp/session.rb,
app/models/action_mcp/session/task.rb,
app/models/action_mcp/session/message.rb,
app/models/action_mcp/session/resource.rb,
app/models/action_mcp/session/subscription.rb
Overview
Represents an MCP session, which is a connection between a client and a server. Its role is to manage the communication channel and store information about the session, such as client and server capabilities, protocol version, and session status. It also manages the association with messages and subscriptions related to the session.
Defined Under Namespace
Classes: Message, Resource, Subscription, Task
Instance Method Summary
collapse
#message_flow
Instance Method Details
#adapter ⇒ Object
126
127
128
|
# File 'app/models/action_mcp/session.rb', line 126
def adapter
@adapter ||= ActionMCP::Server.server.pubsub
end
|
#close! ⇒ Object
95
96
97
98
99
100
101
102
103
104
105
106
|
# File 'app/models/action_mcp/session.rb', line 95
def close!
dummy_callback = ->(*) { } adapter.unsubscribe(session_key, dummy_callback)
if messages_count.zero?
destroy
nil
else
update!(status: "closed", ended_at: Time.zone.now)
subscriptions.delete_all end
end
|
#consent_granted_for?(key) ⇒ Boolean
Checks if consent has been granted for a specific key
327
328
329
330
|
# File 'app/models/action_mcp/session.rb', line 327
def consent_granted_for?(key)
consents_hash = consents.is_a?(String) ? JSON.parse(consents) : consents
consents_hash&.key?(key) && consents_hash[key] == true
end
|
#grant_consent(key) ⇒ Boolean
Grants consent for a specific key
335
336
337
338
339
340
|
# File 'app/models/action_mcp/session.rb', line 335
def grant_consent(key)
self.consents = JSON.parse(consents) if consents.is_a?(String)
self.consents ||= {}
self.consents[key] = true
save!
end
|
#initialize! ⇒ Object
158
159
160
161
162
163
164
165
|
# File 'app/models/action_mcp/session.rb', line 158
def initialize!
return false if initialized?
self.initialized = true
self.status = "initialized"
save
end
|
#read(data) ⇒ Object
118
119
120
|
# File 'app/models/action_mcp/session.rb', line 118
def read(data)
messages.create!(data: data, direction: role)
end
|
#register_prompt(prompt_class_or_name) ⇒ Object
220
221
222
223
224
225
226
227
228
229
230
231
|
# File 'app/models/action_mcp/session.rb', line 220
def register_prompt(prompt_class_or_name)
prompt_name = normalize_name(prompt_class_or_name, :prompt)
return false unless prompt_exists?(prompt_name)
self.prompt_registry ||= []
unless self.prompt_registry.include?(prompt_name)
self.prompt_registry << prompt_name
save!
send_prompts_list_changed_notification
end
true
end
|
#register_resource_template(template_class_or_name) ⇒ Object
243
244
245
246
247
248
249
250
251
252
253
254
|
# File 'app/models/action_mcp/session.rb', line 243
def register_resource_template(template_class_or_name)
template_name = normalize_name(template_class_or_name, :resource_template)
return false unless resource_template_exists?(template_name)
self.resource_registry ||= []
unless self.resource_registry.include?(template_name)
self.resource_registry << template_name
save!
send_resources_list_changed_notification
end
true
end
|
Registry management methods
197
198
199
200
201
202
203
204
205
206
207
208
|
# File 'app/models/action_mcp/session.rb', line 197
def register_tool(tool_class_or_name)
tool_name = normalize_name(tool_class_or_name, :tool)
return false unless tool_exists?(tool_name)
self.tool_registry ||= []
unless self.tool_registry.include?(tool_name)
self.tool_registry << tool_name
save!
send_tools_list_changed_notification
end
true
end
|
#registered_prompts ⇒ Object
281
282
283
284
285
286
287
288
289
290
291
292
|
# File 'app/models/action_mcp/session.rb', line 281
def registered_prompts
if prompt_registry == [ "*" ]
ActionMCP.configuration.filtered_prompts.map(&:klass)
else
(self.prompt_registry || []).filter_map do |prompt_name|
ActionMCP::PromptsRegistry.find(prompt_name)
rescue StandardError
nil
end
end
end
|
#registered_resource_templates ⇒ Object
294
295
296
297
298
299
300
301
302
303
304
305
|
# File 'app/models/action_mcp/session.rb', line 294
def registered_resource_templates
if resource_registry == [ "*" ]
ActionMCP.configuration.filtered_resources.map(&:klass)
else
(self.resource_registry || []).filter_map do |template_name|
ActionMCP::ResourceTemplatesRegistry.find(template_name)
rescue StandardError
nil
end
end
end
|
Get registered items for this session
267
268
269
270
271
272
273
274
275
276
277
278
279
|
# File 'app/models/action_mcp/session.rb', line 267
def registered_tools
if tool_registry == [ "*" ]
ActionMCP.configuration.filtered_tools.map(&:klass)
else
(self.tool_registry || []).filter_map do |tool_name|
ActionMCP::ToolsRegistry.find(tool_name)
rescue StandardError
nil
end
end
end
|
#resource_subscribe(uri) ⇒ Object
173
174
175
|
# File 'app/models/action_mcp/session.rb', line 173
def resource_subscribe(uri)
subscriptions.find_or_create_by(uri: uri)
end
|
#resource_unsubscribe(uri) ⇒ Object
177
178
179
|
# File 'app/models/action_mcp/session.rb', line 177
def resource_unsubscribe(uri)
subscriptions.find_by(uri: uri)&.destroy
end
|
#revoke_consent(key) ⇒ void
This method returns an undefined value.
Revokes consent for a specific key
345
346
347
348
349
350
351
|
# File 'app/models/action_mcp/session.rb', line 345
def revoke_consent(key)
self.consents = JSON.parse(self.consents) if self.consents.is_a?(String)
return unless consents&.key?(key)
consents.delete(key)
save!
end
|
#send_ping! ⇒ Object
167
168
169
170
171
|
# File 'app/models/action_mcp/session.rb', line 167
def send_ping!
Session.logger.silence do
write(JSON_RPC::Request.new(id: Time.now.to_i, method: "ping"))
end
end
|
#send_progress_notification(progressToken:, progress:, total: nil, message: nil) ⇒ Object
181
182
183
184
185
186
187
188
189
190
|
# File 'app/models/action_mcp/session.rb', line 181
def send_progress_notification(progressToken:, progress:, total: nil, message: nil)
handler = ActionMCP::Server::TransportHandler.new(self)
handler.send_progress_notification(
progressToken: progressToken,
progress: progress,
total: total,
message: message
)
end
|
#send_progress_notification_legacy(token:, value:, message: nil) ⇒ Object
192
193
194
|
# File 'app/models/action_mcp/session.rb', line 192
def send_progress_notification_legacy(token:, value:, message: nil)
send_progress_notification(progressToken: token, progress: value, message: message)
end
|
#server_capabilities ⇒ Object
150
151
152
|
# File 'app/models/action_mcp/session.rb', line 150
def server_capabilities
parsed_json_attribute(super)
end
|
#server_capabilities=(value) ⇒ Object
154
155
156
|
# File 'app/models/action_mcp/session.rb', line 154
def server_capabilities=(value)
super(parsed_json_attribute(value))
end
|
#server_capabilities_payload ⇒ Object
142
143
144
145
146
147
148
|
# File 'app/models/action_mcp/session.rb', line 142
def server_capabilities_payload
{
protocolVersion: protocol_version || ActionMCP::DEFAULT_PROTOCOL_VERSION,
serverInfo: server_info,
capabilities: server_capabilities
}
end
|
#session_key ⇒ Object
122
123
124
|
# File 'app/models/action_mcp/session.rb', line 122
def session_key
"action_mcp:session:#{id}"
end
|
#set_protocol_version(version) ⇒ Object
130
131
132
|
# File 'app/models/action_mcp/session.rb', line 130
def set_protocol_version(version)
update(protocol_version: version)
end
|
#store_client_capabilities(capabilities) ⇒ Object
138
139
140
|
# File 'app/models/action_mcp/session.rb', line 138
def store_client_capabilities(capabilities)
self.client_capabilities = capabilities
end
|
#store_client_info(info) ⇒ Object
134
135
136
|
# File 'app/models/action_mcp/session.rb', line 134
def store_client_info(info)
self.client_info = info
end
|
#unregister_prompt(prompt_class_or_name) ⇒ Object
233
234
235
236
237
238
239
240
241
|
# File 'app/models/action_mcp/session.rb', line 233
def unregister_prompt(prompt_class_or_name)
prompt_name = normalize_name(prompt_class_or_name, :prompt)
self.prompt_registry ||= []
return unless self.prompt_registry.delete(prompt_name)
save!
send_prompts_list_changed_notification
end
|
#unregister_resource_template(template_class_or_name) ⇒ Object
256
257
258
259
260
261
262
263
264
|
# File 'app/models/action_mcp/session.rb', line 256
def unregister_resource_template(template_class_or_name)
template_name = normalize_name(template_class_or_name, :resource_template)
self.resource_registry ||= []
return unless self.resource_registry.delete(template_name)
save!
send_resources_list_changed_notification
end
|
210
211
212
213
214
215
216
217
218
|
# File 'app/models/action_mcp/session.rb', line 210
def unregister_tool(tool_class_or_name)
tool_name = normalize_name(tool_class_or_name, :tool)
self.tool_registry ||= []
return unless self.tool_registry.delete(tool_name)
save!
send_tools_list_changed_notification
end
|
#uses_all_prompts? ⇒ Boolean
312
313
314
|
# File 'app/models/action_mcp/session.rb', line 312
def uses_all_prompts?
prompt_registry == [ "*" ]
end
|
#uses_all_resources? ⇒ Boolean
316
317
318
|
# File 'app/models/action_mcp/session.rb', line 316
def uses_all_resources?
resource_registry == [ "*" ]
end
|
Helper methods to check if using all capabilities
308
309
310
|
# File 'app/models/action_mcp/session.rb', line 308
def uses_all_tools?
tool_registry == [ "*" ]
end
|
#write(data) ⇒ Object
109
110
111
112
113
114
115
116
|
# File 'app/models/action_mcp/session.rb', line 109
def write(data)
if data.is_a?(JSON_RPC::Request) || data.is_a?(JSON_RPC::Response) || data.is_a?(JSON_RPC::Notification)
data = data.to_json
end
data = MultiJson.dump(data) if data.is_a?(Hash)
messages.create!(data: data, direction: writer_role)
end
|