ruby_event_store-mcp 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ff5bf2fc507301e40e1e307280b1e3dcbb7ea00a8babf6dc9bf5684a72a0c0b2
4
+ data.tar.gz: 823bd757d780fb861a7423ca4e80e767662f472dcda92640a95811983f3b0570
5
+ SHA512:
6
+ metadata.gz: 975772a2e847f88f07b84b3d2bca336e6a4e4267e09028e6980d7d0f61c48c691207a6fbbcaa27b593b03e3df9c268eefe51adcffaf53acc8d5a72f9c6121272
7
+ data.tar.gz: 93ec27cded4a7f5e9b45a40bf31cd25a51866d74258117984738a6e03b6f17021d4350030d8f8145449ff61b24e4d4b1666b9aff0e12f4985daf0c013f87a492
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # ruby_event_store-mcp
2
+
3
+ Model Context Protocol (MCP) server for [RubyEventStore](https://railseventstore.org). Exposes your event store as AI tools so Claude (and other MCP clients) can inspect streams, events, and causal relationships directly.
4
+
5
+ ## Installation
6
+
7
+ Add to your Rails app's `Gemfile`:
8
+
9
+ ```ruby
10
+ gem "ruby_event_store-mcp"
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Run from the root of your Rails application:
16
+
17
+ ```bash
18
+ bundle exec res-mcp
19
+ ```
20
+
21
+ The server communicates over stdio using the MCP protocol. Installing the gem only provides the `res-mcp` binary — you still have to register it with your MCP client. Every client takes the same server definition; only the file it lives in differs.
22
+
23
+ ### Claude Code
24
+
25
+ Add a `.mcp.json` to your project root (or run `claude mcp add res -- bundle exec res-mcp`):
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "res": {
31
+ "command": "bundle",
32
+ "args": ["exec", "res-mcp"]
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ Launched from the project directory, Claude Code runs the server there, so no `cwd` is needed. On the next launch Claude Code asks you to trust the server — approve it, then run `/mcp` to confirm `res` is connected with its tools.
39
+
40
+ ### Claude Desktop
41
+
42
+ Add the same block with an explicit `cwd` pointing at your app's root, in `claude_desktop_config.json`:
43
+
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ "res": {
48
+ "command": "bundle",
49
+ "args": ["exec", "res-mcp"],
50
+ "cwd": "/path/to/your/rails/app"
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ Config file locations:
57
+
58
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
59
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
60
+
61
+ ### Other MCP clients
62
+
63
+ Cursor, Windsurf, Cline and others take the same `mcpServers` block in their own config file. VS Code's built-in MCP support uses a `servers` key with `"type": "stdio"` instead. The `bundle exec res-mcp` command is the portable part.
64
+
65
+ ## Requirements
66
+
67
+ - Ruby >= 3.0
68
+ - A Rails application with `Rails.configuration.event_store` configured
69
+
70
+ ## Available tools
71
+
72
+ | Tool | Description |
73
+ |---------------------|------------------------------------------------------------------|
74
+ | `recent` | Most recent events across all streams (default: 20, newest first)|
75
+ | `stream_show` | Event count, version, first/last event for a stream |
76
+ | `stream_events` | List events in a stream (filter by type, time range, limit) |
77
+ | `event_show` | Full event details: data, metadata, timestamps |
78
+ | `event_streams` | All streams an event has been published or linked to |
79
+ | `aggregate_history` | Full event history of an aggregate instance by type and ID |
80
+ | `search` | Search events by type, time range, or stream |
81
+ | `stats` | Total event count and unique event types |
82
+ | `trace` | Causation tree for all events sharing a correlation ID |
data/bin/res-mcp ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/ruby_event_store/mcp"
5
+
6
+ env_file = File.expand_path("config/environment.rb")
7
+
8
+ abort "Could not find config/environment.rb. Run `res-mcp` from the root of your Rails application." unless File.exist?(env_file)
9
+
10
+ require env_file
11
+
12
+ abort <<~MSG unless defined?(Rails) && Rails.configuration.respond_to?(:event_store)
13
+ Could not find event store instance after loading config/environment.rb.
14
+
15
+ Expected Rails.configuration.event_store to be set (standard RES setup).
16
+ MSG
17
+
18
+ RubyEventStore::MCP.server(Rails.configuration.event_store).start
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ class ReadEvents
6
+ def self.of(specification, type: nil, after: nil, before: nil, from: nil, limit: nil)
7
+ specification = specification.of_type(resolve_type(type)) if type
8
+ specification = specification.newer_than(Time.parse(after)) if after
9
+ specification = specification.older_than(Time.parse(before)) if before
10
+ specification = specification.from(from) if from
11
+ limit ? specification.limit(limit.to_i).to_a : specification.to_a
12
+ end
13
+
14
+ def self.resolve_type(name)
15
+ Object.const_get(name)
16
+ rescue NameError
17
+ raise "Unknown event type: #{name}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module RubyEventStore
6
+ module MCP
7
+ class Server
8
+ PROTOCOL_VERSION = "2024-11-05"
9
+
10
+ attr_reader :event_store, :name, :version, :tools
11
+
12
+ def initialize(event_store:, name: "ruby-event-store", version: VERSION)
13
+ @event_store = event_store
14
+ @name = name
15
+ @version = version
16
+ @tools = []
17
+ end
18
+
19
+ def register(tool)
20
+ tools << tool
21
+ self
22
+ end
23
+
24
+ def start(input: $stdin, output: $stdout)
25
+ output.sync = true
26
+ input.each_line do |line|
27
+ request = JSON.parse(line.strip)
28
+ response = handle(request)
29
+ output.puts(JSON.generate(response)) if response
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def handle(request)
36
+ id = request["id"]
37
+ method = request["method"]
38
+
39
+ case method
40
+ when "initialize"
41
+ result = {
42
+ protocolVersion: PROTOCOL_VERSION,
43
+ capabilities: { tools: {} },
44
+ serverInfo: { name: name, version: version }
45
+ }
46
+ jsonrpc_result(id, result)
47
+ when "notifications/initialized"
48
+ nil
49
+ when "tools/list"
50
+ jsonrpc_result(id, { tools: tools.map(&:schema) })
51
+ when "tools/call"
52
+ call_tool(id, request["params"])
53
+ when "ping"
54
+ jsonrpc_result(id, {})
55
+ else
56
+ jsonrpc_error(id, -32601, "Method not found: #{method}")
57
+ end
58
+ rescue => e
59
+ jsonrpc_error(request["id"], -32603, e.message)
60
+ end
61
+
62
+ def call_tool(id, params)
63
+ tool_name = params["name"]
64
+ arguments = params["arguments"] || {}
65
+ tool = tools.find { |t| t.name == tool_name }
66
+ return jsonrpc_result(id, { content: [{ type: "text", text: "Unknown tool: #{tool_name}" }], isError: true }) unless tool
67
+
68
+ result = tool.call(event_store, arguments)
69
+ jsonrpc_result(id, { content: [{ type: "text", text: result }] })
70
+ rescue => e
71
+ jsonrpc_result(id, { content: [{ type: "text", text: "Error: #{e.message}" }], isError: true })
72
+ end
73
+
74
+ def jsonrpc_result(id, result)
75
+ { jsonrpc: "2.0", id: id, result: result }
76
+ end
77
+
78
+ def jsonrpc_error(id, code, message)
79
+ { jsonrpc: "2.0", id: id, error: { code: code, message: message } }
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ module Tools
6
+ class AggregateHistory
7
+ def name
8
+ "aggregate_history"
9
+ end
10
+
11
+ def schema
12
+ {
13
+ name: name,
14
+ description: "Show the full event history of an aggregate instance",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ aggregate_type: { type: "string", description: "Aggregate class name (e.g. Order, Payment::Invoice)" },
19
+ aggregate_id: { type: "string", description: "Aggregate ID (UUID or other identifier)" }
20
+ },
21
+ required: %w[aggregate_type aggregate_id]
22
+ }
23
+ }
24
+ end
25
+
26
+ def call(event_store, args)
27
+ aggregate_type = args.fetch("aggregate_type")
28
+ aggregate_id = args.fetch("aggregate_id")
29
+ stream_name = "#{aggregate_type}$#{aggregate_id}"
30
+ events = events(event_store, stream_name)
31
+ render(stream_name, events)
32
+ end
33
+
34
+ private
35
+
36
+ def events(event_store, stream_name)
37
+ event_store.read.stream(stream_name).to_a
38
+ end
39
+
40
+ def render(stream_name, events)
41
+ header = "Aggregate: #{stream_name}\nEvents: #{events.size}"
42
+ return header if events.empty?
43
+ "#{header}\n\n#{events.map { |e| "#{e.timestamp.iso8601(3)} #{e.event_type} [#{e.event_id}]" }.join("\n")}"
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module RubyEventStore
6
+ module MCP
7
+ module Tools
8
+ class EventShow
9
+ def name
10
+ "event_show"
11
+ end
12
+
13
+ def schema
14
+ {
15
+ name: name,
16
+ description: "Show full event details including data, metadata, and timestamps",
17
+ inputSchema: {
18
+ type: "object",
19
+ properties: {
20
+ event_id: { type: "string", description: "Event ID (UUID)" }
21
+ },
22
+ required: ["event_id"]
23
+ }
24
+ }
25
+ end
26
+
27
+ def call(event_store, args)
28
+ event = event_store.read.event!(args.fetch("event_id"))
29
+ format_event(event)
30
+ end
31
+
32
+ private
33
+
34
+ def format_event(event)
35
+ [
36
+ "Event ID: #{event.event_id}",
37
+ "Type: #{event.event_type}",
38
+ "Timestamp: #{event.timestamp.iso8601(3)}",
39
+ "Valid at: #{event.valid_at.iso8601(3)}",
40
+ "Data: #{JSON.pretty_generate(event.data)}",
41
+ "Metadata: #{JSON.pretty_generate(event.metadata.to_h)}"
42
+ ].join("\n")
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ module Tools
6
+ class EventStreams
7
+ def name
8
+ "event_streams"
9
+ end
10
+
11
+ def schema
12
+ {
13
+ name: name,
14
+ description: "List all streams the event has been published or linked to",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ event_id: { type: "string", description: "Event ID (UUID)" }
19
+ },
20
+ required: ["event_id"]
21
+ }
22
+ }
23
+ end
24
+
25
+ def call(event_store, args)
26
+ streams = event_store.streams_of(args.fetch("event_id"))
27
+ return "(no streams — event not found or not linked to any stream)" if streams.empty?
28
+ format_streams(streams)
29
+ end
30
+
31
+ private
32
+
33
+ def format_streams(streams)
34
+ streams.map(&:name).join("\n")
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ module Tools
6
+ class Recent
7
+ DEFAULT_LIMIT = 20
8
+
9
+ def name
10
+ "recent"
11
+ end
12
+
13
+ def schema
14
+ {
15
+ name: name,
16
+ description: "Show the most recent events across all streams",
17
+ inputSchema: {
18
+ type: "object",
19
+ properties: {
20
+ limit: { type: "integer", description: "Number of events to return (default: #{DEFAULT_LIMIT})" }
21
+ },
22
+ required: []
23
+ }
24
+ }
25
+ end
26
+
27
+ def call(event_store, args)
28
+ limit = args.fetch("limit", DEFAULT_LIMIT).to_i
29
+ events = event_store.read.limit(limit).backward.to_a
30
+ return "(no events)" if events.empty?
31
+ render(events)
32
+ end
33
+
34
+ private
35
+
36
+ def render(events)
37
+ events.map { |e| "#{e.timestamp.iso8601(3)} #{e.event_type} [#{e.event_id}]" }.join("\n")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../read_events"
4
+
5
+ module RubyEventStore
6
+ module MCP
7
+ module Tools
8
+ class Search
9
+ def name
10
+ "search"
11
+ end
12
+
13
+ def schema
14
+ {
15
+ name: name,
16
+ description: "Search events across all streams by type, time range, or stream name",
17
+ inputSchema: {
18
+ type: "object",
19
+ properties: {
20
+ type: { type: "string", description: "Filter by event type class name" },
21
+ after: { type: "string", description: "Filter events newer than timestamp (ISO8601)" },
22
+ before: { type: "string", description: "Filter events older than timestamp (ISO8601)" },
23
+ stream: { type: "string", description: "Limit search to a specific stream" },
24
+ limit: { type: "integer", description: "Max number of events (default: 50)" }
25
+ }
26
+ }
27
+ }
28
+ end
29
+
30
+ def call(event_store, args)
31
+ specification = args.key?("stream") ? event_store.read.stream(args.fetch("stream")) : event_store.read
32
+ events = ReadEvents.of(
33
+ specification,
34
+ type: args["type"],
35
+ after: args["after"],
36
+ before: args["before"],
37
+ limit: args.fetch("limit", 50)
38
+ )
39
+ return "(no events found)" if events.empty?
40
+ format_events(events)
41
+ end
42
+
43
+ private
44
+
45
+ def format_events(events)
46
+ events.map { |e| "#{e.timestamp.iso8601(3)} #{e.event_type} [#{e.event_id}]" }.join("\n")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ module Tools
6
+ class Stats
7
+ def name
8
+ "stats"
9
+ end
10
+
11
+ def schema
12
+ {
13
+ name: name,
14
+ description: "Show event count and unique event types. Use stream to get per-stream stats.",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ stream: { type: "string", description: "Show stats for a specific stream" }
19
+ }
20
+ }
21
+ }
22
+ end
23
+
24
+ def call(event_store, args)
25
+ specification = args.key?("stream") ? event_store.read.stream(args.fetch("stream")) : event_store.read
26
+ format_stats(specification, stream: args["stream"])
27
+ end
28
+
29
+ private
30
+
31
+ def format_stats(specification, stream:)
32
+ lines = []
33
+ lines << "Stream: #{stream}" if stream
34
+ lines << "Events: #{specification.count}"
35
+ lines.concat(format_event_types(specification))
36
+ lines.join("\n")
37
+ end
38
+
39
+ def format_event_types(specification)
40
+ types = specification.map(&:event_type).uniq.sort
41
+ return [] if types.empty?
42
+ ["\nEvent types:"] + types.map { |t| " #{t}" }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../read_events"
4
+
5
+ module RubyEventStore
6
+ module MCP
7
+ module Tools
8
+ class StreamEvents
9
+ def name
10
+ "stream_events"
11
+ end
12
+
13
+ def schema
14
+ {
15
+ name: name,
16
+ description: "List events in a stream with optional filters",
17
+ inputSchema: {
18
+ type: "object",
19
+ properties: {
20
+ stream_name: { type: "string", description: "Stream name" },
21
+ limit: { type: "integer", description: "Max number of events (default: 20)" },
22
+ type: { type: "string", description: "Filter by event type class name" },
23
+ after: { type: "string", description: "Filter events newer than timestamp (ISO8601)" },
24
+ before: { type: "string", description: "Filter events older than timestamp (ISO8601)" },
25
+ from: { type: "string", description: "Start reading from event ID (exclusive)" }
26
+ },
27
+ required: ["stream_name"]
28
+ }
29
+ }
30
+ end
31
+
32
+ def call(event_store, args)
33
+ events = ReadEvents.of(
34
+ event_store.read.stream(args.fetch("stream_name")),
35
+ type: args["type"],
36
+ after: args["after"],
37
+ before: args["before"],
38
+ from: args["from"],
39
+ limit: args.fetch("limit", 20)
40
+ )
41
+ return "(no events)" if events.empty?
42
+ format_events(events)
43
+ end
44
+
45
+ private
46
+
47
+ def format_events(events)
48
+ events.map { |e| "#{e.timestamp.iso8601(3)} #{e.event_type} [#{e.event_id}]" }.join("\n")
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ module Tools
6
+ class StreamShow
7
+ def name
8
+ "stream_show"
9
+ end
10
+
11
+ def schema
12
+ {
13
+ name: name,
14
+ description: "Show event count, version, and first/last event for a stream",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ stream_name: { type: "string", description: "Stream name" }
19
+ },
20
+ required: ["stream_name"]
21
+ }
22
+ }
23
+ end
24
+
25
+ def call(event_store, args)
26
+ stream_name = args.fetch("stream_name")
27
+ specification = event_store.read.stream(stream_name)
28
+ format_stream(stream_name, specification)
29
+ end
30
+
31
+ private
32
+
33
+ def format_stream(stream_name, specification)
34
+ count = specification.count
35
+ lines = ["Stream: #{stream_name}", "Events: #{count}"]
36
+ lines.concat(format_bounds(specification, count)) if count > 0
37
+ lines.join("\n")
38
+ end
39
+
40
+ def format_bounds(specification, count)
41
+ first = specification.first
42
+ last = specification.last
43
+ [
44
+ "Version: #{count - 1}",
45
+ "First: #{first.timestamp.iso8601(3)} (#{first.event_type})",
46
+ "Last: #{last.timestamp.iso8601(3)} (#{last.event_type})"
47
+ ]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ module Tools
6
+ class Trace
7
+ def name
8
+ "trace"
9
+ end
10
+
11
+ def schema
12
+ {
13
+ name: name,
14
+ description: "Show the causation tree for all events sharing a correlation ID",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ correlation_id: { type: "string", description: "Correlation ID (UUID)" }
19
+ },
20
+ required: ["correlation_id"]
21
+ }
22
+ }
23
+ end
24
+
25
+ def call(event_store, args)
26
+ events = events_for(event_store, args.fetch("correlation_id"))
27
+ return "(no events found for correlation ID #{args.fetch("correlation_id")})" if events.empty?
28
+ build_tree(events)
29
+ end
30
+
31
+ private
32
+
33
+ def events_for(event_store, correlation_id)
34
+ event_store.read.stream("$by_correlation_id_#{correlation_id}").to_a
35
+ end
36
+
37
+ def build_tree(events)
38
+ by_causation = events.group_by { |e| e.metadata[:causation_id] }
39
+ roots = root_events(events)
40
+ lines = []
41
+ roots.each do |e|
42
+ lines << "#{e.event_type} [#{e.event_id}]"
43
+ render_children(e, by_causation, "", lines)
44
+ end
45
+ lines.join("\n")
46
+ end
47
+
48
+ def root_events(events)
49
+ event_ids = events.map(&:event_id)
50
+ events.reject { |e| event_ids.include?(e.metadata[:causation_id]) }
51
+ end
52
+
53
+ def render_node(event, by_causation, prefix, lines)
54
+ lines << event_line(event, prefix, "├── ")
55
+ child_prefix = prefix + "│ "
56
+ render_children(event, by_causation, child_prefix, lines)
57
+ end
58
+
59
+ def render_last_node(event, by_causation, prefix, lines)
60
+ lines << event_line(event, prefix, "└── ")
61
+ child_prefix = prefix + " "
62
+ render_children(event, by_causation, child_prefix, lines)
63
+ end
64
+
65
+ def event_line(event, prefix, connector)
66
+ "#{prefix}#{connector}#{event.event_type} [#{event.event_id}]"
67
+ end
68
+
69
+ def render_children(event, by_causation, prefix, lines)
70
+ *non_last, last = by_causation[event.event_id]
71
+ return if last.nil?
72
+ non_last.each { |child| render_node(child, by_causation, prefix, lines) }
73
+ render_last_node(last, by_causation, prefix, lines)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module MCP
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "mcp/version"
4
+ require_relative "mcp/read_events"
5
+ require_relative "mcp/server"
6
+ require_relative "mcp/tools/stream_show"
7
+ require_relative "mcp/tools/stream_events"
8
+ require_relative "mcp/tools/event_show"
9
+ require_relative "mcp/tools/event_streams"
10
+ require_relative "mcp/tools/search"
11
+ require_relative "mcp/tools/stats"
12
+ require_relative "mcp/tools/trace"
13
+ require_relative "mcp/tools/aggregate_history"
14
+ require_relative "mcp/tools/recent"
15
+
16
+ module RubyEventStore
17
+ module MCP
18
+ def self.server(event_store)
19
+ Server
20
+ .new(event_store: event_store)
21
+ .register(Tools::StreamShow.new)
22
+ .register(Tools::StreamEvents.new)
23
+ .register(Tools::EventShow.new)
24
+ .register(Tools::EventStreams.new)
25
+ .register(Tools::Search.new)
26
+ .register(Tools::Stats.new)
27
+ .register(Tools::Trace.new)
28
+ .register(Tools::AggregateHistory.new)
29
+ .register(Tools::Recent.new)
30
+ end
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_event_store-mcp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Arkency
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ruby_event_store
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 1.0.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 1.0.0
26
+ email: dev@arkency.com
27
+ executables:
28
+ - res-mcp
29
+ extensions: []
30
+ extra_rdoc_files:
31
+ - README.md
32
+ files:
33
+ - README.md
34
+ - bin/res-mcp
35
+ - lib/ruby_event_store/mcp.rb
36
+ - lib/ruby_event_store/mcp/read_events.rb
37
+ - lib/ruby_event_store/mcp/server.rb
38
+ - lib/ruby_event_store/mcp/tools/aggregate_history.rb
39
+ - lib/ruby_event_store/mcp/tools/event_show.rb
40
+ - lib/ruby_event_store/mcp/tools/event_streams.rb
41
+ - lib/ruby_event_store/mcp/tools/recent.rb
42
+ - lib/ruby_event_store/mcp/tools/search.rb
43
+ - lib/ruby_event_store/mcp/tools/stats.rb
44
+ - lib/ruby_event_store/mcp/tools/stream_events.rb
45
+ - lib/ruby_event_store/mcp/tools/stream_show.rb
46
+ - lib/ruby_event_store/mcp/tools/trace.rb
47
+ - lib/ruby_event_store/mcp/version.rb
48
+ homepage: https://railseventstore.org
49
+ licenses:
50
+ - MIT
51
+ metadata:
52
+ homepage_uri: https://railseventstore.org
53
+ source_code_uri: https://github.com/RailsEventStore/rails_event_store
54
+ bug_tracker_uri: https://github.com/RailsEventStore/rails_event_store/issues
55
+ rubygems_mfa_required: 'true'
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '3.0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubygems_version: 3.7.1
71
+ specification_version: 4
72
+ summary: Model Context Protocol server for Ruby Event Store
73
+ test_files: []