Skip to content

Commit 675726a

Browse files
authored
Merge pull request #1105 from planetscale/piki/mcp-postgres
Implement all the MCP tools for Postgres
2 parents d46473e + f9b6236 commit 675726a

File tree

6 files changed

+708
-104
lines changed

6 files changed

+708
-104
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ require (
8080
github.com/klauspost/connect-compress/v2 v2.0.0 // indirect
8181
github.com/kr/pretty v0.3.1 // indirect
8282
github.com/kr/text v0.2.0 // indirect
83+
github.com/lib/pq v1.10.9 // indirect
8384
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
8485
github.com/mailru/easyjson v0.7.7 // indirect
8586
github.com/mattn/go-colorable v0.1.14 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
128128
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
129129
github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7 h1:k/1ku0yehLCPqERCHkIHMDqDg1R02AcCScRuHbamU3s=
130130
github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7/go.mod h1:YR/zYthNdWfO8+0IOyHDcIDBBBS2JMnYUIwSsnwmRqU=
131+
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
132+
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
131133
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
132134
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
133135
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=

internal/cmd/mcp/server.go

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type ToolDef struct {
2222

2323
// getToolDefinitions returns the list of all available MCP tools
2424
func getToolDefinitions() []ToolDef {
25+
namingBlurb := ". Two common naming conventions for PlanetScale databases are <org>/<database> and <org>/<database>/<branch>. When the user provides a database identifier in either of these formats, automatically parse and use the org, database, and branch parameters directly - do not perform discovery steps like list_orgs or list_databases. Examples: `acme/widgets` -> org=acme, database=widgets. `acme/widgets/main` -> org=acme, database=widgets, branch=main. If the user provides an identifier like 'org/database' or 'org/database/branch', parse these components directly and skip organizational/database discovery steps."
2526
return []ToolDef{
2627
{
2728
tool: mcp.NewTool("list_orgs",
@@ -33,27 +34,29 @@ func getToolDefinitions() []ToolDef {
3334
tool: mcp.NewTool("list_databases",
3435
mcp.WithDescription("List all databases in an organization"),
3536
mcp.WithString("org",
36-
mcp.Description("The organization name (uses default organization if not specified)"),
37+
mcp.Description("The organization name"),
38+
mcp.Required(),
3739
),
3840
),
3941
handler: HandleListDatabases,
4042
},
4143
{
4244
tool: mcp.NewTool("list_branches",
43-
mcp.WithDescription("List all branches for a database"),
45+
mcp.WithDescription("List all branches for a database"+namingBlurb),
4446
mcp.WithString("database",
4547
mcp.Description("The database name"),
4648
mcp.Required(),
4749
),
4850
mcp.WithString("org",
49-
mcp.Description("The organization name (uses default organization if not specified)"),
51+
mcp.Description("The organization name"),
52+
mcp.Required(),
5053
),
5154
),
5255
handler: HandleListBranches,
5356
},
5457
{
5558
tool: mcp.NewTool("list_keyspaces",
56-
mcp.WithDescription("List all keyspaces within a branch"),
59+
mcp.WithDescription("List all keyspaces within a branch"+namingBlurb),
5760
mcp.WithString("database",
5861
mcp.Description("The database name"),
5962
mcp.Required(),
@@ -63,14 +66,15 @@ func getToolDefinitions() []ToolDef {
6366
mcp.Required(),
6467
),
6568
mcp.WithString("org",
66-
mcp.Description("The organization name (uses default organization if not specified)"),
69+
mcp.Description("The organization name"),
70+
mcp.Required(),
6771
),
6872
),
6973
handler: HandleListKeyspaces,
7074
},
7175
{
7276
tool: mcp.NewTool("list_tables",
73-
mcp.WithDescription("List all tables in a keyspace"),
77+
mcp.WithDescription("List all tables in a keyspace/database"+namingBlurb),
7478
mcp.WithString("database",
7579
mcp.Description("The database name"),
7680
mcp.Required(),
@@ -80,18 +84,21 @@ func getToolDefinitions() []ToolDef {
8084
mcp.Required(),
8185
),
8286
mcp.WithString("keyspace",
83-
mcp.Description("The keyspace name"),
84-
mcp.Required(),
87+
mcp.Description("The keyspace name (for MySQL) or inner database name (for PostgreSQL)"),
88+
),
89+
mcp.WithString("schema",
90+
mcp.Description("Filter tables by schema (PostgreSQL only)"),
8591
),
8692
mcp.WithString("org",
87-
mcp.Description("The organization name (uses default organization if not specified)"),
93+
mcp.Description("The organization name"),
94+
mcp.Required(),
8895
),
8996
),
9097
handler: HandleListTables,
9198
},
9299
{
93100
tool: mcp.NewTool("get_schema",
94-
mcp.WithDescription("Get the SQL schema for tables in a keyspace"),
101+
mcp.WithDescription("Get the SQL schema for tables in a keyspace/database"+namingBlurb),
95102
mcp.WithString("database",
96103
mcp.Description("The database name"),
97104
mcp.Required(),
@@ -101,22 +108,22 @@ func getToolDefinitions() []ToolDef {
101108
mcp.Required(),
102109
),
103110
mcp.WithString("keyspace",
104-
mcp.Description("The keyspace name"),
105-
mcp.Required(),
111+
mcp.Description("The keyspace name (for MySQL) or inner database name (for PostgreSQL)"),
106112
),
107113
mcp.WithString("tables",
108-
mcp.Description("Tables to get schemas for (single name, comma-separated list, or '*' for all tables)"),
114+
mcp.Description("Tables to get schemas for. MySQL: comma-separated list of table names, or '*' for all tables. PostgreSQL: comma-separated list of simple table names in the public schema, qualified schema.table_names, 'schema.*' for all tables in a schema, or '*' for all tables in all schemas"),
109115
mcp.Required(),
110116
),
111117
mcp.WithString("org",
112-
mcp.Description("The organization name (uses default organization if not specified)"),
118+
mcp.Description("The organization name"),
119+
mcp.Required(),
113120
),
114121
),
115122
handler: HandleGetSchema,
116123
},
117124
{
118125
tool: mcp.NewTool("run_query",
119-
mcp.WithDescription("Run a SQL query against a database branch keyspace"),
126+
mcp.WithDescription("Run a SQL query against a database branch keyspace/database"+namingBlurb),
120127
mcp.WithString("database",
121128
mcp.Description("The database name"),
122129
mcp.Required(),
@@ -126,22 +133,22 @@ func getToolDefinitions() []ToolDef {
126133
mcp.Required(),
127134
),
128135
mcp.WithString("keyspace",
129-
mcp.Description("The keyspace name"),
130-
mcp.Required(),
136+
mcp.Description("The keyspace name (for MySQL) or inner database name (for PostgreSQL)"),
131137
),
132138
mcp.WithString("query",
133139
mcp.Description("The SQL query to run (read-only queries only)"),
134140
mcp.Required(),
135141
),
136142
mcp.WithString("org",
137-
mcp.Description("The organization name (uses default organization if not specified)"),
143+
mcp.Description("The organization name"),
144+
mcp.Required(),
138145
),
139146
),
140147
handler: HandleRunQuery,
141148
},
142149
{
143150
tool: mcp.NewTool("get_insights",
144-
mcp.WithDescription("Get recent performance data for a database branch"),
151+
mcp.WithDescription("Get recent performance data for a database branch"+namingBlurb),
145152
mcp.WithString("database",
146153
mcp.Description("The database name"),
147154
mcp.Required(),
@@ -151,7 +158,8 @@ func getToolDefinitions() []ToolDef {
151158
mcp.Required(),
152159
),
153160
mcp.WithString("org",
154-
mcp.Description("The organization name (uses default organization if not specified)"),
161+
mcp.Description("The organization name"),
162+
mcp.Required(),
155163
),
156164
),
157165
handler: HandleGetInsights,
@@ -170,6 +178,20 @@ func ServerCmd(ch *cmdutil.Helper) *cobra.Command {
170178
s := server.NewMCPServer(
171179
"PlanetScale MCP Server",
172180
"0.1.0",
181+
server.WithInstructions(`PlanetScale Database Management tools
182+
183+
These tools provide read-only access to MySQL (Vitess) and PostgreSQL
184+
databases hosted by PlanetScale. The naming convention for PlanetScale
185+
databases is <org>/<database> or <org>/<database>/<branch>, so if the user
186+
refers to databases in this format, they are specifying the org, database,
187+
and possibly branch needed to invoke the tools in this MCP. Usually if
188+
the branch is omitted, the default is "main".
189+
190+
When PlanetScale uses the word "database", it refers to a collection of
191+
database branches (production, development, staging, etc.), each with one
192+
or more replicas. This is distinct from PostgreSQL's notion of a database
193+
as a namespace on a single server, which PlanetScale calls a "keyspace"
194+
for both MySQL and PostgreSQL.`),
173195
)
174196

175197
// Register all tools

0 commit comments

Comments
 (0)