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 +4 -4
- data/README.md +14 -6
- data/Rakefile +0 -1
- data/lib/rails-pg-extras-mcp.rb +59 -0
- data/lib/rails_pg_extras_mcp/version.rb +1 -1
- data/spec/smoke_spec.rb +5 -62
- metadata +2 -3
- data/rails-pg-extras-diagnose.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8d771e114f631fe7a9708fca02ae9466ab30a3da437ad14bf2085ec3a723592
|
4
|
+
data.tar.gz: e96491dbe241a9bb66484e8bc9088cdb1d933f09ae62a1d89d9b65b44e5ebad5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9aefce0884fb505759dcaafbadbfdbcf821826400273c74f20a1a5d8a69cc41e81d4130789f5b07f36cb5b526e75c2c6b01ac6356562f78233769de582403221
|
7
|
+
data.tar.gz: 0ec7f68987e6ee2e358745827d060e2723f9f68c53cdf2232b051ad6d723d8f873e325acbe52a1e46d2c0e6df9945a376abecab2dd93a75666045e4f57763891
|
data/README.md
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# Rails PG Extras MCP [](https://badge.fury.io/rb/rails-pg-extras-mcp) [](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
|
-
|
5
|
-
|
6
|
-
A tool for those adventurous enough to connect LLMs directly to the database.
|
5
|
+

|
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
|
-
|
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
|
-
|
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
|
-
|
60
|
+
The project is in an early beta, so proceed with caution.
|
data/Rakefile
CHANGED
data/lib/rails-pg-extras-mcp.rb
CHANGED
@@ -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
|
|
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
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
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-
|
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
|