Skip to content

Commit 9f19f6b

Browse files
improve-mcp (#584)
* improve-mcp Summary: - Expanded MCP funtionality and useful response schemata. - Better documentation. - MCP tool `query_v2` retained as legacy for now. - Added robot test `MCP HTTPS Server JSON DTO Greet`. - Added robot test `MCP HTTPS Server JSON DTO Server Info`. - Added robot test `MCP HTTPS Server JSON DTO DB Identity`. - Added robot test `MCP HTTPS Server JSON DTO Query V2 JSON`. - Added robot test `MCP HTTPS Server Query Exec Text`. - Added robot test `MCP HTTPS Server JSON DTO Query Exec JSON`. - Added robot test `MCP HTTPS Server JSON DTO Meta Get Foreign Keys`. - Added robot test `MCP HTTPS Server JSON DTO Meta Find Relationships`. * - Renamed robot test `MCP HTTPS Server JSON DTO Query V2 JSON` -> `MCP HTTPS Server JSON DTO Query V3 JSON`.
1 parent 9147d7a commit 9f19f6b

File tree

7 files changed

+584
-201
lines changed

7 files changed

+584
-201
lines changed

internal/stackql/mcpbackend/mcp_reverse_proxy_backend_service.go

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/sirupsen/logrus"
1010
"github.com/stackql/stackql/internal/stackql/handler"
1111
"github.com/stackql/stackql/pkg/mcp_server"
12+
"github.com/stackql/stackql/pkg/mcp_server/dto"
1213
)
1314

1415
type stackqlMCPReverseProxyService struct {
@@ -59,8 +60,8 @@ func (b *stackqlMCPReverseProxyService) Close() error {
5960
}
6061

6162
// Server and environment info
62-
func (b *stackqlMCPReverseProxyService) ServerInfo(ctx context.Context, args any) (mcp_server.ServerInfoOutput, error) {
63-
return mcp_server.ServerInfoOutput{
63+
func (b *stackqlMCPReverseProxyService) ServerInfo(ctx context.Context, args any) (dto.ServerInfoOutput, error) {
64+
return dto.ServerInfoOutput{
6465
Name: "Stackql MCP Reverse Proxy Service",
6566
Info: "This is the Stackql MCP Reverse Proxy Service.",
6667
IsReadOnly: b.isReadOnly,
@@ -74,7 +75,7 @@ func (b *stackqlMCPReverseProxyService) DBIdentity(ctx context.Context, args any
7475
}, nil
7576
}
7677

77-
func (b *stackqlMCPReverseProxyService) Greet(ctx context.Context, args mcp_server.GreetInput) (string, error) {
78+
func (b *stackqlMCPReverseProxyService) Greet(ctx context.Context, args dto.GreetInput) (string, error) {
7879
return "Hi " + args.Name, nil
7980
}
8081

@@ -180,7 +181,7 @@ func (b *stackqlMCPReverseProxyService) renderQueryResults(query string, format
180181
}
181182
}
182183

183-
func (b *stackqlMCPReverseProxyService) RunQuery(ctx context.Context, args mcp_server.QueryInput) (string, error) {
184+
func (b *stackqlMCPReverseProxyService) RunQuery(ctx context.Context, args dto.QueryInput) (string, error) {
184185
if args.Format == "" {
185186
args.Format = b.getDefaultFormat()
186187
}
@@ -202,75 +203,75 @@ func (b *stackqlMCPReverseProxyService) RunQuery(ctx context.Context, args mcp_s
202203
}
203204
}
204205

205-
func (b *stackqlMCPReverseProxyService) RunQueryJSON(ctx context.Context, input mcp_server.QueryJSONInput) ([]map[string]interface{}, error) {
206+
func (b *stackqlMCPReverseProxyService) RunQueryJSON(ctx context.Context, input dto.QueryJSONInput) ([]map[string]interface{}, error) {
206207
return b.query(ctx, input.SQL, input.RowLimit)
207208
}
208209

209-
// func (b *stackqlMCPReverseProxyService) ListTableResources(ctx context.Context, hI mcp_server.HierarchyInput) ([]string, error) {
210+
// func (b *stackqlMCPReverseProxyService) ListTableResources(ctx context.Context, hI dto.HierarchyInput) ([]string, error) {
210211

211212
// TODO: implement the remaining methods, using the db connection as sole sql data source
212213

213214
// return []string{}, nil
214215
// }
215216

216-
func (b *stackqlMCPReverseProxyService) ReadTableResource(ctx context.Context, hI mcp_server.HierarchyInput) ([]map[string]interface{}, error) {
217+
func (b *stackqlMCPReverseProxyService) ReadTableResource(ctx context.Context, hI dto.HierarchyInput) ([]map[string]interface{}, error) {
217218
if hI.Provider == "" || hI.Service == "" || hI.Resource == "" {
218219
return nil, fmt.Errorf("provider, service, and resource must be specified")
219220
}
220221
query := fmt.Sprintf("SELECT * FROM %s.%s", hI.Service, hI.Resource)
221222
return b.query(ctx, query, hI.RowLimit)
222223
}
223224

224-
func (b *stackqlMCPReverseProxyService) PromptWriteSafeSelectTool(ctx context.Context, args mcp_server.HierarchyInput) (string, error) {
225+
func (b *stackqlMCPReverseProxyService) PromptWriteSafeSelectTool(ctx context.Context, args dto.HierarchyInput) (string, error) {
225226
return mcp_server.ExplainerPromptWriteSafeSelectTool, nil
226227
}
227228

228229
// func (b *stackqlMCPReverseProxyService) PromptExplainPlanTipsTool(ctx context.Context) (string, error) {
229230
// return "stub", nil
230231
// }
231232

232-
func (b *stackqlMCPReverseProxyService) DescribeTable(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
233+
func (b *stackqlMCPReverseProxyService) DescribeTable(ctx context.Context, hI dto.HierarchyInput) (string, error) {
233234
q, qErr := b.interrogator.GetDescribeTable(hI)
234235
if qErr != nil {
235236
return "", qErr
236237
}
237238
return b.renderQueryResults(q, hI.Format, hI.RowLimit)
238239
}
239240

240-
func (b *stackqlMCPReverseProxyService) GetForeignKeys(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
241+
func (b *stackqlMCPReverseProxyService) GetForeignKeys(ctx context.Context, hI dto.HierarchyInput) (string, error) {
241242
return b.interrogator.GetForeignKeys(hI)
242243
}
243244

244-
func (b *stackqlMCPReverseProxyService) FindRelationships(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
245+
func (b *stackqlMCPReverseProxyService) FindRelationships(ctx context.Context, hI dto.HierarchyInput) (string, error) {
245246
return b.interrogator.FindRelationships(hI)
246247
}
247248

248249
func (b *stackqlMCPReverseProxyService) ListProviders(ctx context.Context) (string, error) {
249-
q, qErr := b.interrogator.GetShowProviders(mcp_server.HierarchyInput{}, "")
250+
q, qErr := b.interrogator.GetShowProviders(dto.HierarchyInput{}, "")
250251
if qErr != nil {
251252
return "", qErr
252253
}
253254
return b.renderQueryResults(q, "", unlimitedRowLimit)
254255
}
255256

256-
func (b *stackqlMCPReverseProxyService) ListServices(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
257+
func (b *stackqlMCPReverseProxyService) ListServices(ctx context.Context, hI dto.HierarchyInput) (string, error) {
257258
q, qErr := b.interrogator.GetShowServices(hI, "")
258259
if qErr != nil {
259260
return "", qErr
260261
}
261262
return b.renderQueryResults(q, hI.Format, hI.RowLimit)
262263
}
263264

264-
func (b *stackqlMCPReverseProxyService) ListResources(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
265+
func (b *stackqlMCPReverseProxyService) ListResources(ctx context.Context, hI dto.HierarchyInput) (string, error) {
265266
q, qErr := b.interrogator.GetShowResources(hI, "")
266267
if qErr != nil {
267268
return "", qErr
268269
}
269270
return b.renderQueryResults(q, hI.Format, hI.RowLimit)
270271
}
271272

272-
func (b *stackqlMCPReverseProxyService) ListTablesJSON(ctx context.Context, input mcp_server.ListTablesInput) ([]map[string]interface{}, error) {
273-
hI := mcp_server.HierarchyInput{}
273+
func (b *stackqlMCPReverseProxyService) ListTablesJSON(ctx context.Context, input dto.ListTablesInput) ([]map[string]interface{}, error) {
274+
hI := dto.HierarchyInput{}
274275
likeStr := ""
275276
if input.Hierarchy != nil {
276277
hI = *input.Hierarchy
@@ -285,15 +286,15 @@ func (b *stackqlMCPReverseProxyService) ListTablesJSON(ctx context.Context, inpu
285286
return b.query(ctx, q, input.RowLimit)
286287
}
287288

288-
func (b *stackqlMCPReverseProxyService) ListTablesJSONPage(ctx context.Context, input mcp_server.ListTablesPageInput) (map[string]interface{}, error) {
289+
func (b *stackqlMCPReverseProxyService) ListTablesJSONPage(ctx context.Context, input dto.ListTablesPageInput) (map[string]interface{}, error) {
289290
return map[string]interface{}{}, nil
290291
}
291292

292-
func (b *stackqlMCPReverseProxyService) ListTables(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
293+
func (b *stackqlMCPReverseProxyService) ListTables(ctx context.Context, hI dto.HierarchyInput) (string, error) {
293294
return b.ListResources(ctx, hI)
294295
}
295296

296-
func (b *stackqlMCPReverseProxyService) ListMethods(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
297+
func (b *stackqlMCPReverseProxyService) ListMethods(ctx context.Context, hI dto.HierarchyInput) (string, error) {
297298
q, qErr := b.interrogator.GetShowMethods(hI)
298299
if qErr != nil {
299300
return "", qErr

internal/stackql/mcpbackend/mcp_service_stackql.go

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/stackql/stackql/internal/stackql/handler"
1313
"github.com/stackql/stackql/internal/stackql/internal_data_transfer/internaldto"
1414
"github.com/stackql/stackql/pkg/mcp_server"
15+
"github.com/stackql/stackql/pkg/mcp_server/dto"
1516
"github.com/stackql/stackql/pkg/presentation"
1617
)
1718

@@ -54,17 +55,17 @@ type StackqlInterrogator interface {
5455
// This struct is responsible for interrogating the StackQL engine.
5556
// Each method provides the requisite query string.
5657

57-
GetShowProviders(mcp_server.HierarchyInput, string) (string, error)
58-
GetShowServices(mcp_server.HierarchyInput, string) (string, error)
59-
GetShowResources(mcp_server.HierarchyInput, string) (string, error)
60-
GetShowMethods(mcp_server.HierarchyInput) (string, error)
61-
// GetShowTables(mcp_server.HierarchyInput) (string, error)
62-
GetDescribeTable(mcp_server.HierarchyInput) (string, error)
63-
GetForeignKeys(mcp_server.HierarchyInput) (string, error)
64-
FindRelationships(mcp_server.HierarchyInput) (string, error)
65-
GetQuery(mcp_server.QueryInput) (string, error)
66-
GetQueryJSON(mcp_server.QueryJSONInput) (string, error)
67-
// GetListTableResources(mcp_server.HierarchyInput) (string, error)
58+
GetShowProviders(dto.HierarchyInput, string) (string, error)
59+
GetShowServices(dto.HierarchyInput, string) (string, error)
60+
GetShowResources(dto.HierarchyInput, string) (string, error)
61+
GetShowMethods(dto.HierarchyInput) (string, error)
62+
// GetShowTables(dto.HierarchyInput) (string, error)
63+
GetDescribeTable(dto.HierarchyInput) (string, error)
64+
GetForeignKeys(dto.HierarchyInput) (string, error)
65+
FindRelationships(dto.HierarchyInput) (string, error)
66+
GetQuery(dto.QueryInput) (string, error)
67+
GetQueryJSON(dto.QueryJSONInput) (string, error)
68+
// GetListTableResources(dto.HierarchyInput) (string, error)
6869
// GetReadTableResource(mcp_server.HierarchyInput) (string, error)
6970
GetPromptWriteSafeSelectTool() (string, error)
7071
// GetPromptExplainPlanTipsTool() (string, error)
@@ -78,7 +79,7 @@ func NewSimpleStackqlInterrogator() StackqlInterrogator {
7879
return &simpleStackqlInterrogator{}
7980
}
8081

81-
func (s *simpleStackqlInterrogator) GetShowProviders(_ mcp_server.HierarchyInput, likeStr string) (string, error) {
82+
func (s *simpleStackqlInterrogator) GetShowProviders(_ dto.HierarchyInput, likeStr string) (string, error) {
8283
sb := strings.Builder{}
8384
sb.WriteString("SHOW PROVIDERS")
8485
if likeStr != "" {
@@ -89,7 +90,7 @@ func (s *simpleStackqlInterrogator) GetShowProviders(_ mcp_server.HierarchyInput
8990
return sb.String(), nil
9091
}
9192

92-
func (s *simpleStackqlInterrogator) GetShowServices(hI mcp_server.HierarchyInput, likeStr string) (string, error) {
93+
func (s *simpleStackqlInterrogator) GetShowServices(hI dto.HierarchyInput, likeStr string) (string, error) {
9394
sb := strings.Builder{}
9495
sb.WriteString("SHOW SERVICES")
9596
if hI.Provider == "" {
@@ -105,7 +106,7 @@ func (s *simpleStackqlInterrogator) GetShowServices(hI mcp_server.HierarchyInput
105106
return sb.String(), nil
106107
}
107108

108-
func (s *simpleStackqlInterrogator) GetShowResources(hI mcp_server.HierarchyInput, likeString string) (string, error) {
109+
func (s *simpleStackqlInterrogator) GetShowResources(hI dto.HierarchyInput, likeString string) (string, error) {
109110
sb := strings.Builder{}
110111
sb.WriteString("SHOW RESOURCES")
111112
if hI.Provider == "" || hI.Service == "" {
@@ -125,7 +126,7 @@ func (s *simpleStackqlInterrogator) GetShowResources(hI mcp_server.HierarchyInpu
125126
return sb.String(), nil
126127
}
127128

128-
func (s *simpleStackqlInterrogator) GetShowMethods(hI mcp_server.HierarchyInput) (string, error) {
129+
func (s *simpleStackqlInterrogator) GetShowMethods(hI dto.HierarchyInput) (string, error) {
129130
sb := strings.Builder{}
130131
sb.WriteString("SHOW METHODS")
131132
if hI.Provider == "" || hI.Service == "" || hI.Resource == "" {
@@ -144,7 +145,7 @@ func (s *simpleStackqlInterrogator) GetShowMethods(hI mcp_server.HierarchyInput)
144145
return sb.String(), nil
145146
}
146147

147-
func (s *simpleStackqlInterrogator) GetDescribeTable(hI mcp_server.HierarchyInput) (string, error) {
148+
func (s *simpleStackqlInterrogator) GetDescribeTable(hI dto.HierarchyInput) (string, error) {
148149
sb := strings.Builder{}
149150
sb.WriteString("DESCRIBE TABLE")
150151
if hI.Provider == "" || hI.Service == "" || hI.Resource == "" {
@@ -163,22 +164,22 @@ func (s *simpleStackqlInterrogator) GetDescribeTable(hI mcp_server.HierarchyInpu
163164
return sb.String(), nil
164165
}
165166

166-
func (s *simpleStackqlInterrogator) GetForeignKeys(hI mcp_server.HierarchyInput) (string, error) {
167+
func (s *simpleStackqlInterrogator) GetForeignKeys(hI dto.HierarchyInput) (string, error) {
167168
return mcp_server.ExplainerForeignKeyStackql, nil
168169
}
169170

170-
func (s *simpleStackqlInterrogator) FindRelationships(hI mcp_server.HierarchyInput) (string, error) {
171+
func (s *simpleStackqlInterrogator) FindRelationships(hI dto.HierarchyInput) (string, error) {
171172
return mcp_server.ExplainerFindRelationships, nil
172173
}
173174

174-
func (s *simpleStackqlInterrogator) GetQuery(qI mcp_server.QueryInput) (string, error) {
175+
func (s *simpleStackqlInterrogator) GetQuery(qI dto.QueryInput) (string, error) {
175176
if qI.SQL == "" {
176177
return "", fmt.Errorf("no SQL provided")
177178
}
178179
return qI.SQL, nil
179180
}
180181

181-
func (s *simpleStackqlInterrogator) GetQueryJSON(qI mcp_server.QueryJSONInput) (string, error) {
182+
func (s *simpleStackqlInterrogator) GetQueryJSON(qI dto.QueryJSONInput) (string, error) {
182183
if qI.SQL == "" {
183184
return "", fmt.Errorf("no SQL provided")
184185
}
@@ -274,8 +275,8 @@ func (b *stackqlMCPService) Close() error {
274275
}
275276

276277
// Server and environment info
277-
func (b *stackqlMCPService) ServerInfo(ctx context.Context, args any) (mcp_server.ServerInfoOutput, error) {
278-
return mcp_server.ServerInfoOutput{
278+
func (b *stackqlMCPService) ServerInfo(ctx context.Context, args any) (dto.ServerInfoOutput, error) {
279+
return dto.ServerInfoOutput{
279280
Name: "Stackql MCP Service",
280281
Info: "This is the Stackql MCP Service.",
281282
IsReadOnly: b.isReadOnly,
@@ -289,11 +290,11 @@ func (b *stackqlMCPService) DBIdentity(ctx context.Context, args any) (map[strin
289290
}, nil
290291
}
291292

292-
func (b *stackqlMCPService) Greet(ctx context.Context, args mcp_server.GreetInput) (string, error) {
293+
func (b *stackqlMCPService) Greet(ctx context.Context, args dto.GreetInput) (string, error) {
293294
return "Hi " + args.Name, nil
294295
}
295296

296-
func (b *stackqlMCPService) RunQuery(ctx context.Context, args mcp_server.QueryInput) (string, error) {
297+
func (b *stackqlMCPService) RunQuery(ctx context.Context, args dto.QueryInput) (string, error) {
297298
q, qErr := b.interrogator.GetQuery(args)
298299
if qErr != nil {
299300
return "", qErr
@@ -302,7 +303,7 @@ func (b *stackqlMCPService) RunQuery(ctx context.Context, args mcp_server.QueryI
302303
return rv, nil
303304
}
304305

305-
func (b *stackqlMCPService) RunQueryJSON(ctx context.Context, input mcp_server.QueryJSONInput) ([]map[string]interface{}, error) {
306+
func (b *stackqlMCPService) RunQueryJSON(ctx context.Context, input dto.QueryJSONInput) ([]map[string]interface{}, error) {
306307
q := input.SQL
307308
if q == "" {
308309
return nil, fmt.Errorf("no SQL provided")
@@ -322,16 +323,16 @@ func (b *stackqlMCPService) RunQueryJSON(ctx context.Context, input mcp_server.Q
322323
// return []map[string]interface{}{}, nil
323324
// }
324325

325-
func (b *stackqlMCPService) PromptWriteSafeSelectTool(ctx context.Context, args mcp_server.HierarchyInput) (string, error) {
326+
func (b *stackqlMCPService) PromptWriteSafeSelectTool(ctx context.Context, args dto.HierarchyInput) (string, error) {
326327
return b.interrogator.GetPromptWriteSafeSelectTool()
327328
}
328329

329330
// func (b *stackqlMCPService) PromptExplainPlanTipsTool(ctx context.Context) (string, error) {
330331
// return "stub", nil
331332
// }
332333

333-
func (b *stackqlMCPService) ListTablesJSON(ctx context.Context, input mcp_server.ListTablesInput) ([]map[string]interface{}, error) {
334-
hI := mcp_server.HierarchyInput{}
334+
func (b *stackqlMCPService) ListTablesJSON(ctx context.Context, input dto.ListTablesInput) ([]map[string]interface{}, error) {
335+
hI := dto.HierarchyInput{}
335336
likeStr := ""
336337
if input.Hierarchy != nil {
337338
hI = *input.Hierarchy
@@ -350,15 +351,15 @@ func (b *stackqlMCPService) ListTablesJSON(ctx context.Context, input mcp_server
350351
return results, nil
351352
}
352353

353-
func (b *stackqlMCPService) ListTablesJSONPage(ctx context.Context, input mcp_server.ListTablesPageInput) (map[string]interface{}, error) {
354+
func (b *stackqlMCPService) ListTablesJSONPage(ctx context.Context, input dto.ListTablesPageInput) (map[string]interface{}, error) {
354355
return map[string]interface{}{}, nil
355356
}
356357

357-
func (b *stackqlMCPService) ListTables(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
358+
func (b *stackqlMCPService) ListTables(ctx context.Context, hI dto.HierarchyInput) (string, error) {
358359
return b.ListResources(ctx, hI)
359360
}
360361

361-
func (b *stackqlMCPService) ListMethods(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
362+
func (b *stackqlMCPService) ListMethods(ctx context.Context, hI dto.HierarchyInput) (string, error) {
362363
q, qErr := b.interrogator.GetShowMethods(hI)
363364
if qErr != nil {
364365
return "", qErr
@@ -450,7 +451,7 @@ func (b *stackqlMCPService) renderQueryResults(query string, format string, rowL
450451
}
451452
}
452453

453-
func (b *stackqlMCPService) DescribeTable(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
454+
func (b *stackqlMCPService) DescribeTable(ctx context.Context, hI dto.HierarchyInput) (string, error) {
454455
q, qErr := b.interrogator.GetDescribeTable(hI)
455456
if qErr != nil {
456457
return "", qErr
@@ -459,24 +460,24 @@ func (b *stackqlMCPService) DescribeTable(ctx context.Context, hI mcp_server.Hie
459460
return rv, nil
460461
}
461462

462-
func (b *stackqlMCPService) GetForeignKeys(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
463+
func (b *stackqlMCPService) GetForeignKeys(ctx context.Context, hI dto.HierarchyInput) (string, error) {
463464
return b.interrogator.GetForeignKeys(hI)
464465
}
465466

466-
func (b *stackqlMCPService) FindRelationships(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
467+
func (b *stackqlMCPService) FindRelationships(ctx context.Context, hI dto.HierarchyInput) (string, error) {
467468
return b.interrogator.FindRelationships(hI)
468469
}
469470

470471
func (b *stackqlMCPService) ListProviders(ctx context.Context) (string, error) {
471-
q, qErr := b.interrogator.GetShowProviders(mcp_server.HierarchyInput{}, "")
472+
q, qErr := b.interrogator.GetShowProviders(dto.HierarchyInput{}, "")
472473
if qErr != nil {
473474
return "", qErr
474475
}
475476
rv := b.renderQueryResults(q, "", unlimitedRowLimit)
476477
return rv, nil
477478
}
478479

479-
func (b *stackqlMCPService) ListServices(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
480+
func (b *stackqlMCPService) ListServices(ctx context.Context, hI dto.HierarchyInput) (string, error) {
480481
q, qErr := b.interrogator.GetShowServices(hI, "")
481482
if qErr != nil {
482483
return "", qErr
@@ -485,7 +486,7 @@ func (b *stackqlMCPService) ListServices(ctx context.Context, hI mcp_server.Hier
485486
return rv, nil
486487
}
487488

488-
func (b *stackqlMCPService) ListResources(ctx context.Context, hI mcp_server.HierarchyInput) (string, error) {
489+
func (b *stackqlMCPService) ListResources(ctx context.Context, hI dto.HierarchyInput) (string, error) {
489490
q, qErr := b.interrogator.GetShowResources(hI, "")
490491
if qErr != nil {
491492
return "", qErr

0 commit comments

Comments
 (0)