Skip to content

Commit 4cb9ea0

Browse files
minimise-mcp (#596)
Summary: - Add CI check for `go.sum` consistency. - Updated high level design diagram. - MCP server amendments: - Remove namespaced tools. - Tool descriptions tagged with future proofing and deprecations. - Removed robot tests for excised tools.
1 parent 26287c8 commit 4cb9ea0

File tree

6 files changed

+41
-209
lines changed

6 files changed

+41
-209
lines changed

.github/workflows/build.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,18 @@ jobs:
335335
check-latest: true
336336
cache: true
337337
id: go
338+
339+
- name: Check go sum coherence
340+
run: |
341+
cp go.sum go.sum.bkp
342+
sumDiff="$(diff go.sum go.sum.bkp)" || true;
343+
if [ "$sumDiff" = "" ]; then
344+
echo "go.sum check passed"
345+
else
346+
echo "go.sum is inconsistent, might be time to run 'go mod tidy' and commit";
347+
exit 1;
348+
fi
349+
338350
339351
- name: Setup Python
340352
uses: actions/setup-python@v5.0.0

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11

2+
# CI staging
3+
go.sum.bkp
4+
25
# Windows
36
*.exe
47

-20.1 KB
Loading

docs/diagrams/plantuml/hld-components.puml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,44 @@
11
@startuml
22

3-
node "Openapi-StackQL" as OpenapiStackQL
4-
node "StackQL Parser" as StackQLParser
3+
node "any-sdk" as AnySdk
4+
node "stackql-parser" as StackQLParser
55
node "psql-wire" as PsqlWire
6+
node "stackql-provider-registry" as ProviderRegistry
7+
node "stackql-go-sqlite3" as StackqlSqlite
8+
node "postgres" as Postgres
9+
node "postgres clients\neg: libpq" as PostgresClient
10+
node "AI agents\neg: Claude Code" as AIAgent
611

712
[Shell] ..> [Command Runner]
813
[Exec] ..> [Command Runner]
914
[Command Runner] ..> [Driver]
15+
PostgresClient -> [Server]
1016
[Server] ..> [Driver]
1117
[Server] ..> [Wire Server]
1218
[Wire Server] ..> PsqlWire
19+
[MCP Server] ..> [Driver]
20+
AIAgent -> [MCP Server]
1321
[Driver] ..> [Query Submitter]
1422
[Query Submitter] ..> [Plan Builder]
1523
[Plan Builder] ..> [Initial Passes Screener Analyzer] : Mature the AST
1624
[Initial Passes Screener Analyzer] ..> [Initial Passes Screener Analyzer] : Nested Indirection
1725
[Initial Passes Screener Analyzer] ..> [Indirect] : Indirect Expansion
26+
[Initial Passes Screener Analyzer] ..> ProviderRegistry
1827
[Plan Builder] ..> [Parser]
1928
[Indirect] ..> [Parser]
2029
[Parser] ..> StackQLParser
2130
[Plan Builder] ..> [Route Pass]
2231
[Plan Builder] ..> [Primitive Builder]
2332
[Primitive Builder] ..> [Primitive Graph]
2433
[Plan Builder] ..> [Primitive Graph]
25-
[Primitive Builder] ..> OpenapiStackQL
34+
[Primitive Graph] ..> [Executor]
35+
[Executor] ..> [Relational Algebra]
36+
[Executor] ..> ProviderRegistry
37+
[Relational Algebra] ..> StackqlSqlite
38+
[Relational Algebra] -> Postgres
39+
[Primitive Builder] ..> AnySdk
2640
[Route Pass] ..> [Parameter Router]
27-
[Parameter Router] ..> OpenapiStackQL
41+
[Parameter Router] ..> AnySdk
2842
[Route Pass] ..> [Route Pass] : Nesting / Composition
2943

3044

pkg/mcp_server/server.go

Lines changed: 6 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
166166
server,
167167
&mcp.Tool{
168168
Name: "query_v2",
169-
Description: "Execute a SQL query. Please adhere to the expected parameters. Returns a textual response",
169+
Description: "Deprecated: Please switch to query_v3. Execute a SQL query. Please adhere to the expected parameters. Returns a textual response",
170170
// Input and output schemas can be defined here if needed.
171171
},
172172
func(ctx context.Context, req *mcp.CallToolRequest, arg dto.QueryInput) (*mcp.CallToolResult, any, error) {
@@ -279,7 +279,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
279279
server,
280280
&mcp.Tool{
281281
Name: "prompt_write_safe_select_tool",
282-
Description: "Prompt: guidelines for writing safe SELECT queries.",
282+
Description: "PLACEHOLDER Future proofing: prompt guidelines for writing safe SELECT queries.",
283283
},
284284
func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) {
285285
result, err := backend.PromptWriteSafeSelectTool(ctx, args)
@@ -292,25 +292,6 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
292292
},
293293
)
294294

295-
// mcp.AddTool(
296-
// server,
297-
// &mcp.Tool{
298-
// Name: "prompt_explain_plan_tips_tool",
299-
// Description: "Prompt: tips for reading EXPLAIN ANALYZE output.",
300-
// },
301-
// func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
302-
// result, err := backend.PromptExplainPlanTipsTool(ctx)
303-
// if err != nil {
304-
// return nil, nil, err
305-
// }
306-
// return &mcp.CallToolResult{
307-
// Content: []mcp.Content{
308-
// &mcp.TextContent{Text: result},
309-
// },
310-
// }, result, nil
311-
// },
312-
// )
313-
314295
mcp.AddTool(
315296
server,
316297
&mcp.Tool{
@@ -338,7 +319,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
338319
server,
339320
&mcp.Tool{
340321
Name: "list_tables_json_page",
341-
Description: "List tables with pagination and filters, returns JSON.",
322+
Description: "Future proofing: List tables with pagination and filters, returns JSON.",
342323
},
343324
func(ctx context.Context, req *mcp.CallToolRequest, args dto.ListTablesPageInput) (*mcp.CallToolResult, any, error) {
344325
result, err := backend.ListTablesJSONPage(ctx, args)
@@ -429,7 +410,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
429410
server,
430411
&mcp.Tool{
431412
Name: "describe_table",
432-
Description: "Get detailed information about a table.",
413+
Description: "PLACEHOLDER Future proofing: Get detailed information about a table.",
433414
},
434415
func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) {
435416
result, err := backend.DescribeTable(ctx, args)
@@ -446,7 +427,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
446427
server,
447428
&mcp.Tool{
448429
Name: "get_foreign_keys",
449-
Description: "Get foreign key information for a table.",
430+
Description: "PLACEHOLDER Future proofing: Get foreign key information for a table.",
450431
},
451432
func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) {
452433
result, err := backend.GetForeignKeys(ctx, args)
@@ -463,7 +444,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
463444
server,
464445
&mcp.Tool{
465446
Name: "find_relationships",
466-
Description: "Find explicit and implied relationships for a table.",
447+
Description: "PLACEHOLDER Future proofing: Find explicit and implied relationships for a table.",
467448
},
468449
func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) {
469450
result, err := backend.FindRelationships(ctx, args)
@@ -476,10 +457,6 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe
476457
},
477458
)
478459

479-
// --- new: register namespaced meta.* and query.* tools ---
480-
registerNamespacedTools(server, backend, logger)
481-
// ---------------------------------------------------------
482-
483460
return &simpleMCPServer{
484461
config: config,
485462
backend: backend,
@@ -553,137 +530,3 @@ func (s *simpleMCPServer) Stop() error {
553530
s.logger.Printf("MCP server stopped")
554531
return nil
555532
}
556-
557-
// registerNamespacedTools adds meta.* and query.* tools (namespaced variants).
558-
//
559-
//nolint:gocognit,funlen // ok for now
560-
func registerNamespacedTools(server *mcp.Server, backend Backend, logger *logrus.Logger) {
561-
// meta.server_info
562-
mcp.AddTool(
563-
server,
564-
&mcp.Tool{
565-
Name: "meta.server_info",
566-
Description: "Namespaced: Get server information.",
567-
},
568-
func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, dto.ServerInfoDTO, error) {
569-
info, err := backend.ServerInfo(ctx, nil)
570-
if err != nil {
571-
return nil, dto.ServerInfoDTO{}, err
572-
}
573-
out := dto.ServerInfoDTO{Name: info.Name, Info: info.Info, IsReadOnly: info.IsReadOnly}
574-
bytesOut, _ := json.Marshal(out)
575-
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil
576-
},
577-
)
578-
579-
// meta.db_identity
580-
mcp.AddTool(
581-
server,
582-
&mcp.Tool{
583-
Name: "meta.db_identity",
584-
Description: "Namespaced: Get current database identity.",
585-
},
586-
func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, dto.DBIdentityDTO, error) {
587-
id, err := backend.DBIdentity(ctx, nil)
588-
if err != nil {
589-
return nil, dto.DBIdentityDTO{}, err
590-
}
591-
out := dto.DBIdentityDTO{Identity: fmt.Sprintf("%v", id["identity"])}
592-
bytesOut, _ := json.Marshal(out)
593-
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil
594-
},
595-
)
596-
597-
mcp.AddTool(
598-
server,
599-
&mcp.Tool{
600-
Name: "query.exec_text",
601-
Description: "Namespaced: Execute SQL returning textual result.",
602-
},
603-
func(ctx context.Context, req *mcp.CallToolRequest, arg dto.QueryInput) (*mcp.CallToolResult, any, error) {
604-
logger.Infof("query.exec_text SQL: %s", arg.SQL)
605-
rawText, err := backend.RunQuery(ctx, arg)
606-
if err != nil {
607-
return nil, nil, err
608-
}
609-
out := dto.QueryResultDTO{Raw: rawText, Format: "text"}
610-
bytesOut, _ := json.Marshal(out)
611-
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil
612-
},
613-
)
614-
615-
mcp.AddTool(
616-
server,
617-
&mcp.Tool{
618-
Name: "query.exec_json",
619-
Description: "Namespaced: Execute SQL returning JSON array as text.",
620-
},
621-
func(ctx context.Context, req *mcp.CallToolRequest, arg dto.QueryJSONInput) (*mcp.CallToolResult, any, error) {
622-
rows, err := backend.RunQueryJSON(ctx, arg)
623-
if err != nil {
624-
return nil, nil, err
625-
}
626-
dtObj := dto.QueryResultDTO{
627-
Rows: rows,
628-
RowCount: len(rows),
629-
Format: "json",
630-
}
631-
bytesOut, _ := json.Marshal(dtObj)
632-
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, dtObj, nil
633-
},
634-
)
635-
636-
// meta_describe_table
637-
mcp.AddTool(
638-
server,
639-
&mcp.Tool{
640-
Name: "meta_describe_table",
641-
Description: "Describe a stackql relation. This publishes the bullk of the columns returned from a SELECT.",
642-
},
643-
func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) {
644-
result, err := backend.DescribeTable(ctx, args)
645-
if err != nil {
646-
return nil, nil, err
647-
}
648-
out := dto.QueryResultDTO{Rows: result, RowCount: len(result), Format: "json"}
649-
bytesOut, _ := json.Marshal(out)
650-
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil
651-
},
652-
)
653-
654-
// meta.get_foreign_keys
655-
mcp.AddTool(
656-
server,
657-
&mcp.Tool{
658-
Name: "meta.get_foreign_keys",
659-
Description: "Namespaced: Get foreign keys for a table.",
660-
},
661-
func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) {
662-
result, err := backend.GetForeignKeys(ctx, args)
663-
if err != nil {
664-
return nil, nil, err
665-
}
666-
out := dto.QueryResultDTO{Rows: result, RowCount: len(result), Format: "json"}
667-
bytesOut, _ := json.Marshal(out)
668-
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil
669-
},
670-
)
671-
672-
// meta.find_relationships
673-
mcp.AddTool(
674-
server,
675-
&mcp.Tool{
676-
Name: "meta.find_relationships",
677-
Description: "Namespaced: Find relationships for a table.",
678-
},
679-
func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) {
680-
result, err := backend.FindRelationships(ctx, args)
681-
if err != nil {
682-
return nil, nil, err
683-
}
684-
out := dto.SimpleTextDTO{Text: result}
685-
bytesOut, _ := json.Marshal(out)
686-
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil
687-
},
688-
)
689-
}

test/robot/functional/mcp.robot

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -325,46 +325,6 @@ MCP HTTPS Server JSON DTO Query V3 JSON
325325
${row_count}= Get From Dictionary ${query_obj} row_count
326326
Should Be True ${row_count} > 0
327327

328-
MCP HTTPS Server Query Exec Text
329-
Pass Execution If "%{IS_SKIP_MCP_TEST=false}" == "true" Some platforms do not have the MCP client available
330-
# Future proofing: raw text format reserved; may gain structured hints later.
331-
${ns_query_text}= Run Process
332-
... ${STACKQL_MCP_CLIENT_EXE}
333-
... exec
334-
... \-\-client\-type\=http
335-
... \-\-url\=https://127.0.0.1:9004
336-
... \-\-client\-cfg
337-
... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true }
338-
... \-\-exec.action
339-
... query.exec_text
340-
... \-\-exec.args
341-
... {"sql":"SELECT 1 as foo"}
342-
... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-text.txt
343-
... stderr=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-text-stderr.txt
344-
Should Be Equal As Integers ${ns_query_text.rc} 0
345-
Should Contain ${ns_query_text.stdout} foo
346-
347-
MCP HTTPS Server JSON DTO Query Exec JSON
348-
Pass Execution If "%{IS_SKIP_MCP_TEST=false}" == "true" Some platforms do not have the MCP client available
349-
${ns_query_json}= Run Process
350-
... ${STACKQL_MCP_CLIENT_EXE}
351-
... exec
352-
... \-\-client\-type\=http
353-
... \-\-url\=https://127.0.0.1:9004
354-
... \-\-client\-cfg
355-
... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true }
356-
... \-\-exec.action
357-
... query.exec_json
358-
... \-\-exec.args
359-
... {"sql":"SELECT 1 as foo","row_limit":5}
360-
... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-json.txt
361-
... stderr=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-json-stderr.txt
362-
Should Be Equal As Integers ${ns_query_json.rc} 0
363-
${ns_query_json_obj}= Parse MCP JSON Output ${ns_query_json.stdout}
364-
Should Be Equal ${ns_query_json_obj["format"]} json
365-
${ns_row_count}= Get From Dictionary ${ns_query_json_obj} row_count
366-
Should Be True ${ns_row_count} >= 0
367-
368328
MCP HTTPS Server JSON DTO Meta Get Foreign Keys
369329
[Documentation] Future proofing: foreign key discovery not yet implemented; placeholder.
370330
Pass Execution If "%{IS_SKIP_MCP_TEST=false}" == "true" Some platforms do not have the MCP client available
@@ -376,7 +336,7 @@ MCP HTTPS Server JSON DTO Meta Get Foreign Keys
376336
... \-\-client\-cfg
377337
... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true }
378338
... \-\-exec.action
379-
... meta.get_foreign_keys
339+
... get_foreign_keys
380340
... \-\-exec.args
381341
... {"provider":"google","service":"cloudresourcemanager","resource":"projects"}
382342
... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-meta-get-foreign-keys.txt
@@ -395,7 +355,7 @@ MCP HTTPS Server JSON DTO Meta Find Relationships
395355
... \-\-client\-cfg
396356
... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true }
397357
... \-\-exec.action
398-
... meta.find_relationships
358+
... find_relationships
399359
... \-\-exec.args
400360
... {"provider":"google","service":"cloudresourcemanager","resource":"projects"}
401361
... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-meta-find-relationships.txt

0 commit comments

Comments
 (0)