From e4465b8ca16a96e21ed4dbd5a4cd29b6385b74e9 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 5 Dec 2025 14:12:09 +0545 Subject: [PATCH] minimise-mcp 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. --- .github/workflows/build.yml | 12 ++ .gitignore | 3 + docs/diagrams/plantuml/hld-components.png | Bin 53570 -> 32939 bytes docs/diagrams/plantuml/hld-components.puml | 22 ++- pkg/mcp_server/server.go | 169 +-------------------- test/robot/functional/mcp.robot | 44 +----- 6 files changed, 41 insertions(+), 209 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 181939a5..a4afd97a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -335,6 +335,18 @@ jobs: check-latest: true cache: true id: go + + - name: Check go sum coherence + run: | + cp go.sum go.sum.bkp + sumDiff="$(diff go.sum go.sum.bkp)" || true; + if [ "$sumDiff" = "" ]; then + echo "go.sum check passed" + else + echo "go.sum is inconsistent, might be time to run 'go mod tidy' and commit"; + exit 1; + fi + - name: Setup Python uses: actions/setup-python@v5.0.0 diff --git a/.gitignore b/.gitignore index 5a47f250..2400fdb4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ +# CI staging +go.sum.bkp + # Windows *.exe diff --git a/docs/diagrams/plantuml/hld-components.png b/docs/diagrams/plantuml/hld-components.png index 9f7712541f4e98061b7d9570e2af3880dd8e4385..c26a1683599ceea4ff482f069b5550ee0c92d3e3 100644 GIT binary patch literal 32939 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 XmC3T}L7zhi@Sl{JoM^f5cfbDy>|45| literal 53570 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

>)!+y&ZQnkRATqvXP*a@_~z1`hE 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 diff --git a/docs/diagrams/plantuml/hld-components.puml b/docs/diagrams/plantuml/hld-components.puml index f561cc37..84965736 100644 --- a/docs/diagrams/plantuml/hld-components.puml +++ b/docs/diagrams/plantuml/hld-components.puml @@ -1,20 +1,29 @@ @startuml -node "Openapi-StackQL" as OpenapiStackQL -node "StackQL Parser" as StackQLParser +node "any-sdk" as AnySdk +node "stackql-parser" as StackQLParser node "psql-wire" as PsqlWire +node "stackql-provider-registry" as ProviderRegistry +node "stackql-go-sqlite3" as StackqlSqlite +node "postgres" as Postgres +node "postgres clients\neg: libpq" as PostgresClient +node "AI agents\neg: Claude Code" as AIAgent [Shell] ..> [Command Runner] [Exec] ..> [Command Runner] [Command Runner] ..> [Driver] +PostgresClient -> [Server] [Server] ..> [Driver] [Server] ..> [Wire Server] [Wire Server] ..> PsqlWire +[MCP Server] ..> [Driver] +AIAgent -> [MCP Server] [Driver] ..> [Query Submitter] [Query Submitter] ..> [Plan Builder] [Plan Builder] ..> [Initial Passes Screener Analyzer] : Mature the AST [Initial Passes Screener Analyzer] ..> [Initial Passes Screener Analyzer] : Nested Indirection [Initial Passes Screener Analyzer] ..> [Indirect] : Indirect Expansion +[Initial Passes Screener Analyzer] ..> ProviderRegistry [Plan Builder] ..> [Parser] [Indirect] ..> [Parser] [Parser] ..> StackQLParser @@ -22,9 +31,14 @@ node "psql-wire" as PsqlWire [Plan Builder] ..> [Primitive Builder] [Primitive Builder] ..> [Primitive Graph] [Plan Builder] ..> [Primitive Graph] -[Primitive Builder] ..> OpenapiStackQL +[Primitive Graph] ..> [Executor] +[Executor] ..> [Relational Algebra] +[Executor] ..> ProviderRegistry +[Relational Algebra] ..> StackqlSqlite +[Relational Algebra] -> Postgres +[Primitive Builder] ..> AnySdk [Route Pass] ..> [Parameter Router] -[Parameter Router] ..> OpenapiStackQL +[Parameter Router] ..> AnySdk [Route Pass] ..> [Route Pass] : Nesting / Composition diff --git a/pkg/mcp_server/server.go b/pkg/mcp_server/server.go index f6cff8e3..7c2b48a6 100644 --- a/pkg/mcp_server/server.go +++ b/pkg/mcp_server/server.go @@ -166,7 +166,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe server, &mcp.Tool{ Name: "query_v2", - Description: "Execute a SQL query. Please adhere to the expected parameters. Returns a textual response", + Description: "Deprecated: Please switch to query_v3. Execute a SQL query. Please adhere to the expected parameters. Returns a textual response", // Input and output schemas can be defined here if needed. }, 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 server, &mcp.Tool{ Name: "prompt_write_safe_select_tool", - Description: "Prompt: guidelines for writing safe SELECT queries.", + Description: "PLACEHOLDER Future proofing: prompt guidelines for writing safe SELECT queries.", }, func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) { result, err := backend.PromptWriteSafeSelectTool(ctx, args) @@ -292,25 +292,6 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe }, ) - // mcp.AddTool( - // server, - // &mcp.Tool{ - // Name: "prompt_explain_plan_tips_tool", - // Description: "Prompt: tips for reading EXPLAIN ANALYZE output.", - // }, - // func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) { - // result, err := backend.PromptExplainPlanTipsTool(ctx) - // if err != nil { - // return nil, nil, err - // } - // return &mcp.CallToolResult{ - // Content: []mcp.Content{ - // &mcp.TextContent{Text: result}, - // }, - // }, result, nil - // }, - // ) - mcp.AddTool( server, &mcp.Tool{ @@ -338,7 +319,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe server, &mcp.Tool{ Name: "list_tables_json_page", - Description: "List tables with pagination and filters, returns JSON.", + Description: "Future proofing: List tables with pagination and filters, returns JSON.", }, func(ctx context.Context, req *mcp.CallToolRequest, args dto.ListTablesPageInput) (*mcp.CallToolResult, any, error) { result, err := backend.ListTablesJSONPage(ctx, args) @@ -429,7 +410,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe server, &mcp.Tool{ Name: "describe_table", - Description: "Get detailed information about a table.", + Description: "PLACEHOLDER Future proofing: Get detailed information about a table.", }, func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) { result, err := backend.DescribeTable(ctx, args) @@ -446,7 +427,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe server, &mcp.Tool{ Name: "get_foreign_keys", - Description: "Get foreign key information for a table.", + Description: "PLACEHOLDER Future proofing: Get foreign key information for a table.", }, func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) { result, err := backend.GetForeignKeys(ctx, args) @@ -463,7 +444,7 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe server, &mcp.Tool{ Name: "find_relationships", - Description: "Find explicit and implied relationships for a table.", + Description: "PLACEHOLDER Future proofing: Find explicit and implied relationships for a table.", }, func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) { result, err := backend.FindRelationships(ctx, args) @@ -476,10 +457,6 @@ func newMCPServer(config *Config, backend Backend, logger *logrus.Logger) (MCPSe }, ) - // --- new: register namespaced meta.* and query.* tools --- - registerNamespacedTools(server, backend, logger) - // --------------------------------------------------------- - return &simpleMCPServer{ config: config, backend: backend, @@ -553,137 +530,3 @@ func (s *simpleMCPServer) Stop() error { s.logger.Printf("MCP server stopped") return nil } - -// registerNamespacedTools adds meta.* and query.* tools (namespaced variants). -// -//nolint:gocognit,funlen // ok for now -func registerNamespacedTools(server *mcp.Server, backend Backend, logger *logrus.Logger) { - // meta.server_info - mcp.AddTool( - server, - &mcp.Tool{ - Name: "meta.server_info", - Description: "Namespaced: Get server information.", - }, - func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, dto.ServerInfoDTO, error) { - info, err := backend.ServerInfo(ctx, nil) - if err != nil { - return nil, dto.ServerInfoDTO{}, err - } - out := dto.ServerInfoDTO{Name: info.Name, Info: info.Info, IsReadOnly: info.IsReadOnly} - bytesOut, _ := json.Marshal(out) - return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil - }, - ) - - // meta.db_identity - mcp.AddTool( - server, - &mcp.Tool{ - Name: "meta.db_identity", - Description: "Namespaced: Get current database identity.", - }, - func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, dto.DBIdentityDTO, error) { - id, err := backend.DBIdentity(ctx, nil) - if err != nil { - return nil, dto.DBIdentityDTO{}, err - } - out := dto.DBIdentityDTO{Identity: fmt.Sprintf("%v", id["identity"])} - bytesOut, _ := json.Marshal(out) - return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil - }, - ) - - mcp.AddTool( - server, - &mcp.Tool{ - Name: "query.exec_text", - Description: "Namespaced: Execute SQL returning textual result.", - }, - func(ctx context.Context, req *mcp.CallToolRequest, arg dto.QueryInput) (*mcp.CallToolResult, any, error) { - logger.Infof("query.exec_text SQL: %s", arg.SQL) - rawText, err := backend.RunQuery(ctx, arg) - if err != nil { - return nil, nil, err - } - out := dto.QueryResultDTO{Raw: rawText, Format: "text"} - bytesOut, _ := json.Marshal(out) - return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil - }, - ) - - mcp.AddTool( - server, - &mcp.Tool{ - Name: "query.exec_json", - Description: "Namespaced: Execute SQL returning JSON array as text.", - }, - func(ctx context.Context, req *mcp.CallToolRequest, arg dto.QueryJSONInput) (*mcp.CallToolResult, any, error) { - rows, err := backend.RunQueryJSON(ctx, arg) - if err != nil { - return nil, nil, err - } - dtObj := dto.QueryResultDTO{ - Rows: rows, - RowCount: len(rows), - Format: "json", - } - bytesOut, _ := json.Marshal(dtObj) - return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, dtObj, nil - }, - ) - - // meta_describe_table - mcp.AddTool( - server, - &mcp.Tool{ - Name: "meta_describe_table", - Description: "Describe a stackql relation. This publishes the bullk of the columns returned from a SELECT.", - }, - func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) { - result, err := backend.DescribeTable(ctx, args) - if err != nil { - return nil, nil, err - } - out := dto.QueryResultDTO{Rows: result, RowCount: len(result), Format: "json"} - bytesOut, _ := json.Marshal(out) - return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil - }, - ) - - // meta.get_foreign_keys - mcp.AddTool( - server, - &mcp.Tool{ - Name: "meta.get_foreign_keys", - Description: "Namespaced: Get foreign keys for a table.", - }, - func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) { - result, err := backend.GetForeignKeys(ctx, args) - if err != nil { - return nil, nil, err - } - out := dto.QueryResultDTO{Rows: result, RowCount: len(result), Format: "json"} - bytesOut, _ := json.Marshal(out) - return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil - }, - ) - - // meta.find_relationships - mcp.AddTool( - server, - &mcp.Tool{ - Name: "meta.find_relationships", - Description: "Namespaced: Find relationships for a table.", - }, - func(ctx context.Context, req *mcp.CallToolRequest, args dto.HierarchyInput) (*mcp.CallToolResult, any, error) { - result, err := backend.FindRelationships(ctx, args) - if err != nil { - return nil, nil, err - } - out := dto.SimpleTextDTO{Text: result} - bytesOut, _ := json.Marshal(out) - return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: string(bytesOut)}}}, out, nil - }, - ) -} diff --git a/test/robot/functional/mcp.robot b/test/robot/functional/mcp.robot index eeeeefbf..da2fbfd8 100644 --- a/test/robot/functional/mcp.robot +++ b/test/robot/functional/mcp.robot @@ -325,46 +325,6 @@ MCP HTTPS Server JSON DTO Query V3 JSON ${row_count}= Get From Dictionary ${query_obj} row_count Should Be True ${row_count} > 0 -MCP HTTPS Server Query Exec Text - Pass Execution If "%{IS_SKIP_MCP_TEST=false}" == "true" Some platforms do not have the MCP client available - # Future proofing: raw text format reserved; may gain structured hints later. - ${ns_query_text}= Run Process - ... ${STACKQL_MCP_CLIENT_EXE} - ... exec - ... \-\-client\-type\=http - ... \-\-url\=https://127.0.0.1:9004 - ... \-\-client\-cfg - ... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true } - ... \-\-exec.action - ... query.exec_text - ... \-\-exec.args - ... {"sql":"SELECT 1 as foo"} - ... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-text.txt - ... stderr=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-text-stderr.txt - Should Be Equal As Integers ${ns_query_text.rc} 0 - Should Contain ${ns_query_text.stdout} foo - -MCP HTTPS Server JSON DTO Query Exec JSON - Pass Execution If "%{IS_SKIP_MCP_TEST=false}" == "true" Some platforms do not have the MCP client available - ${ns_query_json}= Run Process - ... ${STACKQL_MCP_CLIENT_EXE} - ... exec - ... \-\-client\-type\=http - ... \-\-url\=https://127.0.0.1:9004 - ... \-\-client\-cfg - ... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true } - ... \-\-exec.action - ... query.exec_json - ... \-\-exec.args - ... {"sql":"SELECT 1 as foo","row_limit":5} - ... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-json.txt - ... stderr=${CURDIR}${/}tmp${/}MCP-HTTPS-query-exec-json-stderr.txt - Should Be Equal As Integers ${ns_query_json.rc} 0 - ${ns_query_json_obj}= Parse MCP JSON Output ${ns_query_json.stdout} - Should Be Equal ${ns_query_json_obj["format"]} json - ${ns_row_count}= Get From Dictionary ${ns_query_json_obj} row_count - Should Be True ${ns_row_count} >= 0 - MCP HTTPS Server JSON DTO Meta Get Foreign Keys [Documentation] Future proofing: foreign key discovery not yet implemented; placeholder. 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 ... \-\-client\-cfg ... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true } ... \-\-exec.action - ... meta.get_foreign_keys + ... get_foreign_keys ... \-\-exec.args ... {"provider":"google","service":"cloudresourcemanager","resource":"projects"} ... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-meta-get-foreign-keys.txt @@ -395,7 +355,7 @@ MCP HTTPS Server JSON DTO Meta Find Relationships ... \-\-client\-cfg ... { "apply_tls_globally": true, "insecure_skip_verify": true, "ca_file": "test/server/mtls/credentials/pg_server_cert.pem", "promote_leaf_to_ca": true } ... \-\-exec.action - ... meta.find_relationships + ... find_relationships ... \-\-exec.args ... {"provider":"google","service":"cloudresourcemanager","resource":"projects"} ... stdout=${CURDIR}${/}tmp${/}MCP-HTTPS-meta-find-relationships.txt