rails-pg-extras-mcp 0.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2b38c7170279b40f497842e8b52683e94ec21ed567f9081ca4e0041fac00cc0
4
- data.tar.gz: d099ef809db25a1cadacc15faea3fc6bc7ba49dc8e60f985f7e1835ce962e127
3
+ metadata.gz: e8d771e114f631fe7a9708fca02ae9466ab30a3da437ad14bf2085ec3a723592
4
+ data.tar.gz: e96491dbe241a9bb66484e8bc9088cdb1d933f09ae62a1d89d9b65b44e5ebad5
5
5
  SHA512:
6
- metadata.gz: c4fd58adbed92be275183094e26afb12ef156a214170f55c5e3e563d39e2fabdf59b4c7676401f97b820346e5173feef8630d41343d48d4d086961ece3dd4c93
7
- data.tar.gz: f8365a1506c36a6c9475bddadce4d97a0651b4a20e5a05100020ccfb49730f0691407e805503bc462403e24de9a800ad072984dfc8f452797cd11c560ae1a9c9
6
+ metadata.gz: 9aefce0884fb505759dcaafbadbfdbcf821826400273c74f20a1a5d8a69cc41e81d4130789f5b07f36cb5b526e75c2c6b01ac6356562f78233769de582403221
7
+ data.tar.gz: 0ec7f68987e6ee2e358745827d060e2723f9f68c53cdf2232b051ad6d723d8f873e325acbe52a1e46d2c0e6df9945a376abecab2dd93a75666045e4f57763891
data/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # Rails PG Extras MCP [![Gem Version](https://badge.fury.io/rb/rails-pg-extras-mcp.svg)](https://badge.fury.io/rb/rails-pg-extras-mcp) [![GH Actions](https://github.com/pawurb/rails-pg-extras-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/pawurb/rails-pg-extras-mcp/actions)
2
2
 
3
+ MCP ([Model Context Protocol](https://modelcontextprotocol.io/introduction)) interface for [rails-pg-extras](https://github.com/pawurb/rails-pg-extras) gem. It enables PostgreSQL metadata and performance analysis with a simple LLM prompt.
3
4
 
4
- MCP ([Model Context Protocol](https://modelcontextprotocol.io/introduction)) interface for [rails-pg-extras](https://github.com/pawurb/rails-pg-extras) gem.
5
-
6
- A tool for those adventurous enough to connect LLMs directly to the database.
5
+ ![LLM interface](https://github.com/pawurb/rails-pg-extras/raw/main/pg-extras-mcp.png)
7
6
 
8
7
  ## Installation
9
8
 
@@ -12,7 +11,7 @@ bundle add rails-pg-extras
12
11
  bundle add rails-pg-extras-mcp
13
12
  ```
14
13
 
15
- Library supports MCP protocol via HTTP SSE interface.
14
+ The library supports MCP protocol via HTTP SSE interface.
16
15
 
17
16
  `config/routes.rb`
18
17
 
@@ -45,8 +44,17 @@ and in your LLM of choice:
45
44
 
46
45
  You can now ask LLM questions about the metadata and performance metrics of your database.
47
46
 
48
- ![LLM interface](https://github.com/pawurb/rails-pg-extras/raw/main/pg-extras-mcp.png)
47
+ ## Optional EXPLAIN ANALYZE support
48
+
49
+ [`calls`](https://github.com/pawurb/rails-pg-extras?tab=readme-ov-file#calls) and [`outliers`](https://github.com/pawurb/rails-pg-extras?tab=readme-ov-file#outliers) methods return a list of bottleneck queries. LLM can get better insights into these queries by performing `EXPLAIN` and `EXPLAIN ANALYZE` analysis. MCP server exposes two optional methods for this purpose: `explain` and `explain_analyze`.
50
+
51
+ You can enable them by setting the following `ENV` variables:
52
+
53
+ `ENV['PG_EXTRAS_MCP_EXPLAIN_ENABLED'] = 'true'`
54
+ `ENV['PG_EXTRAS_MCP_EXPLAIN_ANALYZE_ENABLED'] = 'true'`
55
+
56
+ Enabling these features means that an LLM, can run arbitrary queries in your database. The execution context is wrapped in a transaction and rolled back, so, in theory, any data modification should not be possible. But it's advised to configure a read-only permission if you want to use these features. By specifying `ENV['RAILS_PG_EXTRAS_DATABASE_URL']` you can overwrite the default Rails ActiveRecord database connection to restrict an access scope.
49
57
 
50
58
  ## Status
51
59
 
52
- Project is in an early beta, so proceed with caution.
60
+ The project is in an early beta, so proceed with caution.
data/Rakefile CHANGED
@@ -2,4 +2,3 @@ require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
-
@@ -63,6 +63,63 @@ class DiagnoseTool < FastMcp::Tool
63
63
  end
64
64
  end
65
65
 
66
+ class ExplainBaseTool < FastMcp::Tool
67
+ DENYLIST = %w[
68
+ delete,
69
+ insert,
70
+ update,
71
+ truncate,
72
+ drop,
73
+ alter,
74
+ create,
75
+ grant,
76
+ begin,
77
+ commit,
78
+ ]
79
+
80
+ arguments do
81
+ required(:query).filled(:string).description("The query to debug")
82
+ end
83
+
84
+ def call(query:)
85
+ connection = RailsPgExtras.connection
86
+
87
+ if DENYLIST.any? { |deny| query.downcase.include?(deny) }
88
+ raise "This query is not allowed. It contains a denied keyword. Denylist: #{DENYLIST.join(", ")}"
89
+ end
90
+
91
+ connection.execute("BEGIN")
92
+ result = connection.execute("#{query}")
93
+ connection.execute("ROLLBACK")
94
+
95
+ result.to_a
96
+ end
97
+ end
98
+
99
+ class ExplainTool < ExplainBaseTool
100
+ description "EXPLAIN a query. It must be an SQL string, without the EXPLAIN prefix"
101
+
102
+ def self.name
103
+ "explain_analyze"
104
+ end
105
+
106
+ def call(query:)
107
+ super(query: "EXPLAIN #{query}")
108
+ end
109
+ end
110
+
111
+ class ExplainAnalyzeTool < ExplainBaseTool
112
+ description "EXPLAIN ANALYZE a query. It must be an SQL string, without the EXPLAIN ANALYZE prefix"
113
+
114
+ def self.name
115
+ "explain_analyze"
116
+ end
117
+
118
+ def call(query:)
119
+ super(query: "EXPLAIN ANALYZE #{query}")
120
+ end
121
+ end
122
+
66
123
  class ReadmeResource < FastMcp::Resource
67
124
  uri "https://raw.githubusercontent.com/pawurb/rails-pg-extras/refs/heads/main/README.md"
68
125
  resource_name "README"
@@ -93,6 +150,8 @@ module RailsPgExtrasMcp
93
150
  server.register_tools(MissingFkConstraintsTool)
94
151
  server.register_tools(MissingFkIndexesTool)
95
152
  server.register_tools(*QUERY_TOOL_CLASSES)
153
+ server.register_tools(ExplainTool) if ENV["PG_EXTRAS_MCP_EXPLAIN_ENABLED"] == "true"
154
+ server.register_tools(ExplainAnalyzeTool) if ENV["PG_EXTRAS_MCP_EXPLAIN_ANALYZE_ENABLED"] == "true"
96
155
 
97
156
  server.register_resource(ReadmeResource)
98
157
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsPgExtrasMcp
4
- VERSION = "0.0.1"
4
+ VERSION = "0.1.0"
5
5
  end
data/spec/smoke_spec.rb CHANGED
@@ -3,67 +3,10 @@
3
3
  require "spec_helper"
4
4
  require "rails-pg-extras"
5
5
 
6
- describe RailsPgExtras do
7
- SKIP_QUERIES = %i[
8
- kill_all
9
- table_schema
10
- table_foreign_keys
11
- ]
12
-
13
- RailsPgExtras::QUERIES.reject { |q| SKIP_QUERIES.include?(q) }.each do |query_name|
14
- it "#{query_name} query can be executed" do
15
- expect do
16
- RailsPgExtras.run_query(
17
- query_name: query_name,
18
- in_format: :hash,
19
- )
20
- end.not_to raise_error
21
- end
22
- end
23
-
24
- it "runs the custom methods" do
25
- expect do
26
- RailsPgExtras.diagnose(in_format: :hash)
27
- end.not_to raise_error
28
-
29
- expect do
30
- RailsPgExtras.index_info(in_format: :hash)
31
- end.not_to raise_error
32
-
33
- expect do
34
- RailsPgExtras.table_info(in_format: :hash)
35
- end.not_to raise_error
36
- end
37
-
38
- it "collecting queries data works" do
39
- output = RailsPgExtras.measure_queries { RailsPgExtras.diagnose(in_format: :hash) }
40
- expect(output.fetch(:count) > 0).to eq(true)
41
- end
42
-
43
- it "supports custom RAILS_PG_EXTRAS_DATABASE_URL" do
44
- ENV["RAILS_PG_EXTRAS_DATABASE_URL"] = ENV["DATABASE_URL"]
45
- puts ENV["RAILS_PG_EXTRAS_DATABASE_URL"]
46
-
47
- expect do
48
- RailsPgExtras.calls
49
- end.not_to raise_error
50
-
51
- ENV["RAILS_PG_EXTRAS_DATABASE_URL"] = nil
52
- end
53
-
54
- describe "missing_fk_indexes" do
55
- it "works" do
56
- expect {
57
- RailsPgExtras.missing_fk_indexes
58
- }.not_to raise_error
59
- end
60
- end
61
-
62
- describe "missing_fk_constraints" do
63
- it "works" do
64
- expect {
65
- RailsPgExtras.missing_fk_constraints
66
- }.not_to raise_error
67
- end
6
+ describe RailsPgExtrasMcp do
7
+ it "works" do
8
+ expect {
9
+ RailsPgExtrasMcp::App.build
10
+ }.not_to raise_error
68
11
  end
69
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-pg-extras-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-12 00:00:00.000000000 Z
11
+ date: 2025-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails-pg-extras
@@ -112,7 +112,6 @@ files:
112
112
  - lib/rails-pg-extras-mcp.rb
113
113
  - lib/rails_pg_extras_mcp/version.rb
114
114
  - pg-extras-mcp.png
115
- - rails-pg-extras-diagnose.png
116
115
  - rails-pg-extras-mcp.gemspec
117
116
  - spec/smoke_spec.rb
118
117
  - spec/spec_helper.rb
Binary file