Skip to content

Commit d7d43a8

Browse files
- Slowly evolving.
1 parent e87d13e commit d7d43a8

File tree

6 files changed

+251
-205
lines changed

6 files changed

+251
-205
lines changed

.vscode/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
!launch.json
44
!settings.json
55
!example.env
6+
!mcp.json

.vscode/mcp.json

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"inputs": [
3+
{
4+
"type": "pickString",
5+
"id": "pg_url",
6+
"description": "PostgreSQL URL (e.g. postgresql://user:[email protected]:5432/mydb)",
7+
"options": [
8+
"postgresql://stackql:[email protected]:7432/stackql"
9+
],
10+
"default": "postgresql://stackql:[email protected]:7432/stackql"
11+
},
12+
{
13+
"type": "pickString",
14+
"id": "registryString",
15+
"description": "Registry Configuration",
16+
"options": [
17+
"{ \"url\": \"file://${workspaceFolder}/test/registry-sandbox\", \"localDocRoot\": \"${workspaceFolder}/test/registry-sandbox\", \"verifyConfig\": { \"nopVerify\": true } }",
18+
"{ \"url\": \"file://${workspaceFolder}/test/registry\", \"localDocRoot\": \"${workspaceFolder}/test/registry\", \"verifyConfig\": { \"nopVerify\": true } }",
19+
"{ \"url\": \"file://${workspaceFolder}/test/registry-mocked\", \"localDocRoot\": \"${workspaceFolder}/test/registry-mocked\", \"verifyConfig\": { \"nopVerify\": true } }",
20+
"{ \"url\": \"file://${workspaceFolder}/test/registry-mocked-native\", \"localDocRoot\": \"${workspaceFolder}/test/registry-mocked-native\", \"verifyConfig\": { \"nopVerify\": true } }",
21+
"{ \"url\": \"file://${workspaceFolder}/test/registry-advanced\", \"localDocRoot\": \"${workspaceFolder}/test/registry-advanced\", \"verifyConfig\": { \"nopVerify\": true } }",
22+
"{ \"url\": \"file://${workspaceFolder}/build/.stackql\", \"localDocRoot\": \"${workspaceFolder}/build/.stackql\", \"verifyConfig\": { \"nopVerify\": true } }",
23+
"{ \"url\": \"file://${workspaceFolder}/docs/examples/empty-registry\", \"localDocRoot\": \"${workspaceFolder}/docs/examples/empty-registry\" }",
24+
"{ \"url\": \"https://cdn.statically.io/gh/stackql/stackql-provider-registry/main/providers\", \"localDocRoot\": \"${workspaceFolder}/test/registry\" }",
25+
"{ \"url\": \"https://cdn.statically.io/gh/stackql/stackql-provider-registry/dev/providers\" }",
26+
"{ \"url\": \"https://registry-dev.stackql.app/providers\" }",
27+
"{ \"url\": \"https://registry.stackql.app/providers\" }",
28+
"{\"url\": \"http://localhost:1094/gh/stackql/stackql-provider-registry/main/providers\", \"verifyConfig\": {\"nopVerify\": true}}",
29+
],
30+
"default": "{ \"url\": \"file://${workspaceFolder}/test/registry\", \"localDocRoot\": \"${workspaceFolder}/test/registry\", \"verifyConfig\": { \"nopVerify\": true } }"
31+
},
32+
{
33+
"type": "pickString",
34+
"id": "authString",
35+
"description": "Auth Input arg String",
36+
"default": "{}",
37+
"options": [
38+
"{ \"local_openssl\": { \"type\": \"null_auth\"}, \"azure\": { \"type\": \"azure_default\" }, \"digitalocean\": { \"type\": \"bearer\", \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/digitalocean-key.txt\" }, \"google\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/stackql-security-reviewer.json\" }, \"googleadmin\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/ryuk-it-query.json\" }, \"okta\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/okta-token.txt\", \"type\": \"api_key\", \"valuePrefix\": \"SSWS \" }, \"github\": { \"credentialsenvvar\": \"STACKQL_GITHUB_TOKEN\", \"type\": \"api_key\", \"valuePrefix\": \"Bearer \" }, \"aws\": { \"type\": \"aws_signing_v4\", \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/aws-secret-key.txt\", \"keyID\": \"AKIA376P4FQSS2ONB2NS\" }, \"netlify\": { \"type\": \"api_key\", \"valuePrefix\": \"Bearer \", \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/netlify-token.txt\" }, \"k8s\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/k8s-token.txt\", \"type\": \"api_key\", \"valuePrefix\": \"Bearer \" }, \"sumologic\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/sumologic-token.txt\", \"type\": \"basic\" } }",
39+
"{ \"google\": { \"credentialsfilepath\": \"${workspaceFolder}/test/assets/credentials/dummy/google/functional-test-dummy-sa-key.json\" }, \"googleadmin\": { \"credentialsfilepath\": \"${workspaceFolder}/test/assets/credentials/dummy/google/functional-test-dummy-sa-key.json\" }, \"okta\": { \"credentialsfilepath\": \"${workspaceFolder}/test/assets/credentials/dummy/okta/api-key.txt\", \"type\": \"api_key\", \"valuePrefix\": \"SSWS \" }, \"github\": { \"credentialsenvvar\": \"STACKQL_GITHUB_TOKEN\", \"type\": \"api_key\", \"valuePrefix\": \"Bearer \" }, \"aws\": { \"type\": \"aws_signing_v4\", \"credentialsfilepath\": \"${workspaceFolder}/test/assets/credentials/dummy/aws/functional-test-dummy-aws-key.txt\", \"keyID\": \"AKIA376P4FQSS2ONB2NS\" }, \"netlify\": { \"type\": \"api_key\", \"valuePrefix\": \"Bearer \", \"credentialsfilepath\": \"${workspaceFolder}/test/assets/credentials/dummy/netlify/netlify-token.txt\" }, \"k8s\": { \"credentialsfilepath\": \"${workspaceFolder}/test/assets/credentials/dummy/k8s/k8s-token.txt\", \"type\": \"api_key\", \"valuePrefix\": \"Bearer \" }, \"sumologic\": { \"credentialsfilepath\": \"${workspaceFolder}/test/assets/credentials/dummy/sumologic/sumologic-token.txt\", \"type\": \"basic\" } }",
40+
"{ \"pgi\": { \"type\": \"sql_data_source::postgres\", \"sqlDataSource\": { \"dsn\": \"postgres://stackql:[email protected]:8432\" } }, \"azure\": { \"type\": \"azure_default\" }, \"google\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/stackql-security-reviewer.json\" }, \"okta\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/okta-token.txt\", \"type\": \"api_key\", \"valuePrefix\": \"SSWS \" }, \"github\": { \"credentialsenvvar\": \"STACKQL_GITHUB_TOKEN\", \"type\": \"api_key\", \"valuePrefix\": \"Bearer \" }, \"aws\": { \"type\": \"aws_signing_v4\", \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/aws-secret-key.txt\", \"keyID\": \"AKIA376P4FQSS2ONB2NS\" }, \"netlify\": { \"type\": \"api_key\", \"valuePrefix\": \"Bearer \", \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/netlify-token.txt\" }, \"k8s\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/k8s-token.txt\", \"type\": \"api_key\", \"valuePrefix\": \"Bearer \" }, \"sumologic\": { \"credentialsfilepath\": \"${workspaceFolder}/cicd/keys/integration/sumologic-token.txt\", \"type\": \"basic\" } }",
41+
"{ \"digitalocean\": { \"username_var\": \"DUMMY_DIGITALOCEAN_USERNAME\", \"password_var\": \"DUMMY_DIGITALOCEAN_PASSWORD\", \"type\": \"bearer\" }, \"azure\": {\"type\": \"api_key\", \"valuePrefix\": \"Bearer \", \"credentialsenvvar\": \"AZ_ACCESS_TOKEN\"} }",
42+
"{}"
43+
]
44+
},
45+
],
46+
"servers": {
47+
"postgres": {
48+
"command": "docker",
49+
"args": [
50+
"run",
51+
"-i",
52+
"--rm",
53+
"mcp/postgres",
54+
"postgresql://stackql:[email protected]:8432/stackql"
55+
]
56+
},
57+
"stackqlLocal": {
58+
"type": "stdio",
59+
"command": "${workspaceFolder}/build/stackql",
60+
"args": [
61+
"mcp",
62+
"--tls.allowInsecure",
63+
"--auth=${input:authString}",
64+
"--registry=${input:registryString}"
65+
]
66+
}
67+
}
68+
}

pkg/mcp_server/backend.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,12 @@ type Backend interface {
202202
// Close gracefully shuts down the backend connection.
203203
Close() error
204204
// Server and environment info
205-
ServerInfo(ctx context.Context) (map[string]interface{}, error)
205+
ServerInfo(ctx context.Context, args any) (serverInfoOutput, error)
206206

207207
// Current DB identity details
208-
DBIdentity(ctx context.Context) (map[string]interface{}, error)
208+
DBIdentity(ctx context.Context, args any) (map[string]any, error)
209+
210+
Greet(ctx context.Context, args greetInput) (string, error)
209211

210212
// Execute a SQL query (legacy signature)
211213
Query(ctx context.Context, sql string, parameters []interface{}, rowLimit int, format string) (string, error)
@@ -214,10 +216,10 @@ type Backend interface {
214216
QueryJSON(ctx context.Context, sql string, parameters []interface{}, rowLimit int) ([]map[string]interface{}, error)
215217

216218
// Execute a SQL query with typed input (preferred)
217-
RunQuery(ctx context.Context, input QueryInput) (string, error)
219+
RunQuery(ctx context.Context, args queryInput) (string, error)
218220

219221
// Execute a SQL query and return JSON rows with typed input (preferred)
220-
RunQueryJSON(ctx context.Context, input QueryJSONInput) ([]map[string]interface{}, error)
222+
RunQueryJSON(ctx context.Context, input queryJSONInput) ([]map[string]interface{}, error)
221223

222224
// List resource URIs for tables in a schema
223225
ListTableResources(ctx context.Context, schema string) ([]string, error)
@@ -231,32 +233,30 @@ type Backend interface {
231233
// Prompt: tips for reading EXPLAIN ANALYZE output
232234
PromptExplainPlanTipsTool(ctx context.Context) (string, error)
233235

234-
// List schemas with filters and return JSON rows
235-
ListSchemasJSON(ctx context.Context, input ListSchemasInput) ([]map[string]interface{}, error)
236-
237-
// List schemas with pagination and filters
238-
ListSchemasJSONPage(ctx context.Context, input ListSchemasPageInput) (map[string]interface{}, error)
239-
240236
// List tables in a schema with optional filters and return JSON rows
241-
ListTablesJSON(ctx context.Context, input ListTablesInput) ([]map[string]interface{}, error)
237+
ListTablesJSON(ctx context.Context, input listTablesInput) ([]map[string]interface{}, error)
242238

243239
// List tables with pagination and filters
244-
ListTablesJSONPage(ctx context.Context, input ListTablesPageInput) (map[string]interface{}, error)
240+
ListTablesJSONPage(ctx context.Context, input listTablesPageInput) (map[string]interface{}, error)
245241

246242
// List all schemas in the database
247-
ListSchemas(ctx context.Context) (string, error)
243+
ListProviders(ctx context.Context) (string, error)
244+
245+
ListServices(ctx context.Context, hI hierarchyInput) (string, error)
246+
247+
ListResources(ctx context.Context, hI hierarchyInput) (string, error)
248248

249249
// List all tables in a specific schema
250-
ListTables(ctx context.Context, dbSchema string) (string, error)
250+
ListTables(ctx context.Context, hI hierarchyInput) (string, error)
251251

252252
// Get detailed information about a table
253-
DescribeTable(ctx context.Context, tableName string, dbSchema string) (string, error)
253+
DescribeTable(ctx context.Context, hI hierarchyInput) (string, error)
254254

255255
// Get foreign key information for a table
256-
GetForeignKeys(ctx context.Context, tableName string, dbSchema string) (string, error)
256+
GetForeignKeys(ctx context.Context, hI hierarchyInput) (string, error)
257257

258258
// Find both explicit and implied relationships for a table
259-
FindRelationships(ctx context.Context, tableName string, dbSchema string) (string, error)
259+
FindRelationships(ctx context.Context, hI hierarchyInput) (string, error)
260260
}
261261

262262
// QueryResult represents the result of a query execution.

pkg/mcp_server/dto.go

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,37 @@ class ListTablesPageInput(BaseModel):
7676
7777
*/
7878

79-
type QueryInput struct {
80-
SQL string `json:"sql" yaml:"sql"`
81-
Parameters []interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
82-
RowLimit int `json:"row_limit" yaml:"row_limit"`
83-
Format string `json:"format" yaml:"format"`
79+
type greetInput struct {
80+
Name string `json:"name" jsonschema:"the person to greet"`
8481
}
8582

86-
type QueryJSONInput struct {
87-
SQL string `json:"sql" yaml:"sql"`
88-
Parameters []interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
89-
RowLimit int `json:"row_limit" yaml:"row_limit"`
83+
type hierarchyInput struct {
84+
Provider string `json:"provider" yaml:"provider"`
85+
Service string `json:"service" yaml:"service"`
86+
Resource string `json:"resource" yaml:"resource"`
87+
Method string `json:"method" yaml:"method"`
9088
}
9189

92-
type ListSchemasInput struct {
90+
type serverInfoOutput struct {
91+
Name string `json:"name" jsonschema:"server name"`
92+
Info string `json:"info" jsonschema:"server info"`
93+
IsReadOnly bool `json:"read_only" jsonschema:"is the database read-only"`
94+
}
95+
96+
type queryInput struct {
97+
SQL string `json:"sql" yaml:"sql"`
98+
Parameters []string `json:"parameters,omitempty" yaml:"parameters,omitempty"`
99+
RowLimit int `json:"row_limit" yaml:"row_limit"`
100+
Format string `json:"format" yaml:"format"`
101+
}
102+
103+
type queryJSONInput struct {
104+
SQL string `json:"sql" yaml:"sql"`
105+
Parameters []string `json:"parameters,omitempty" yaml:"parameters,omitempty"`
106+
RowLimit int `json:"row_limit" yaml:"row_limit"`
107+
}
108+
109+
type listSchemasInput struct {
93110
IncludeSystem bool `json:"include_system" yaml:"include_system"`
94111
IncludeTemp bool `json:"include_temp" yaml:"include_temp"`
95112
RequireUsage bool `json:"require_usage" yaml:"require_usage"`
@@ -98,7 +115,7 @@ type ListSchemasInput struct {
98115
CaseSensitive bool `json:"case_sensitive" yaml:"case_sensitive"`
99116
}
100117

101-
type ListSchemasPageInput struct {
118+
type listSchemasPageInput struct {
102119
IncludeSystem bool `json:"include_system" yaml:"include_system"`
103120
IncludeTemp bool `json:"include_temp" yaml:"include_temp"`
104121
RequireUsage bool `json:"require_usage" yaml:"require_usage"`
@@ -108,19 +125,19 @@ type ListSchemasPageInput struct {
108125
CaseSensitive bool `json:"case_sensitive" yaml:"case_sensitive"`
109126
}
110127

111-
type ListTablesInput struct {
112-
DBSchema *string `json:"db_schema,omitempty" yaml:"db_schema,omitempty"`
113-
NameLike *string `json:"name_like,omitempty" yaml:"name_like,omitempty"`
114-
CaseSensitive bool `json:"case_sensitive" yaml:"case_sensitive"`
115-
TableTypes []string `json:"table_types,omitempty" yaml:"table_types,omitempty"`
116-
RowLimit int `json:"row_limit" yaml:"row_limit"`
128+
type listTablesInput struct {
129+
Hierarchy *hierarchyInput `json:"hierarchy,omitempty" yaml:"hierarchy,omitempty"`
130+
NameLike *string `json:"name_like,omitempty" yaml:"name_like,omitempty"`
131+
CaseSensitive bool `json:"case_sensitive" yaml:"case_sensitive"`
132+
TableTypes []string `json:"table_types,omitempty" yaml:"table_types,omitempty"`
133+
RowLimit int `json:"row_limit" yaml:"row_limit"`
117134
}
118135

119-
type ListTablesPageInput struct {
120-
DBSchema *string `json:"db_schema,omitempty" yaml:"db_schema,omitempty"`
121-
NameLike *string `json:"name_like,omitempty" yaml:"name_like,omitempty"`
122-
CaseSensitive bool `json:"case_sensitive" yaml:"case_sensitive"`
123-
TableTypes []string `json:"table_types,omitempty" yaml:"table_types,omitempty"`
124-
PageSize int `json:"page_size" yaml:"page_size"`
125-
Cursor *string `json:"cursor,omitempty" yaml:"cursor,omitempty"`
136+
type listTablesPageInput struct {
137+
Hierarchy *hierarchyInput `json:"hierarchy,omitempty" yaml:"hierarchy,omitempty"`
138+
NameLike *string `json:"name_like,omitempty" yaml:"name_like,omitempty"`
139+
CaseSensitive bool `json:"case_sensitive" yaml:"case_sensitive"`
140+
TableTypes []string `json:"table_types,omitempty" yaml:"table_types,omitempty"`
141+
PageSize int `json:"page_size" yaml:"page_size"`
142+
Cursor *string `json:"cursor,omitempty" yaml:"cursor,omitempty"`
126143
}

0 commit comments

Comments
 (0)