Skip to content

Comments

TAP: Add MCP client helper and run_sql_readonly validation#5372

Open
wazir-ahmed wants to merge 2 commits intov3.0from
tap-mcp-client
Open

TAP: Add MCP client helper and run_sql_readonly validation#5372
wazir-ahmed wants to merge 2 commits intov3.0from
tap-mcp-client

Conversation

@wazir-ahmed
Copy link
Member

@wazir-ahmed wazir-ahmed commented Feb 13, 2026

  • Add MCPClient class for testing ProxySQL's MCP endpoints via HTTP/JSON-RPC
  • Add TAP test for run_sql_readonly query tool validation
  • Update AI test group configuration

Summary by CodeRabbit

  • New Features

    • Enabled MCP integration for test runs and added test-time configuration to connect to MCP.
  • Tests

    • Added a C++ TAP test validating MCP read-only SQL behavior and a new MCP test group.
    • Marked the older shell-based validation script as deprecated.
  • Chores

    • Added an MCP client to the test build and introduced new MCP connection options; removed a legacy test environment export.

- Add `MCPClient` class for testing ProxySQL's MCP endpoints
  via HTTP/JSON-RPC
- Add TAP test for `run_sql_readonly` query tool validation
- Update AI test group configuration

Signed-off-by: Wazir Ahmed <wazir@proxysql.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello @wazir-ahmed, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the testing framework for ProxySQL's Model Context Protocol (MCP). It introduces a robust C++ client for interacting with MCP endpoints, which is then leveraged to create a comprehensive test for the run_sql_readonly query tool. This ensures the tool's validation logic for read-only SQL operations is functioning as expected, improving the reliability of MCP-related functionalities. The changes also involve updating the AI test group to integrate and properly configure this new testing component.

Highlights

  • New MCP Client: A new MCPClient C++ class was introduced to simplify testing ProxySQL's Model Context Protocol (MCP) endpoints via HTTP/JSON-RPC.
  • run_sql_readonly Validation Test: A new TAP test (mcp_query_run_sql_readonly-t.cpp) was added to validate the run_sql_readonly query tool, ensuring it correctly rejects non-read-only queries and accepts valid ones. This new C++ test replaces an older shell script.
  • AI Test Group Configuration: The AI test group configuration was updated to include the new MCP test and enable necessary MCP module settings.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • test/tap/groups/ai/env.sh
    • Removed the TEST_PY_TAP_INCL environment variable export.
  • test/tap/groups/ai/pre-proxysql.sql
    • Added SQL commands to enable and configure the MCP module for the AI test group, including setting host, port, user, and password for the MySQL backend.
  • test/tap/groups/groups.json
    • Added mcp_query_run_sql_readonly-t to the ai-g1 test group.
  • test/tap/tap/Makefile
    • Updated build rules to compile mcp_client.cpp and link mcp_client.o into libtap_mariadb.a, libtap_mysql57.a, and libtap_mysql8.a.
  • test/tap/tap/command_line.cpp
    • Implemented parsing of TAP_MCP_PORT and TAP_MCP_AUTH_TOKEN environment variables.
    • Added logic to free mcp_auth_token in the destructor.
  • test/tap/tap/command_line.h
    • Added mcp_port and mcp_auth_token members to the CommandLine class for MCP connection parameters.
  • test/tap/tap/mcp_client.cpp
    • Implemented the MCPClient class, providing functionality for MCP server connectivity, tool invocation, and robust error handling for JSON-RPC requests.
  • test/tap/tap/mcp_client.h
    • Defined the MCPClient class for interacting with ProxySQL's MCP endpoints.
    • Defined the MCPResponse class, including multi-layer error classification (TRANSPORT, HTTP, JSON_RPC, MCP) and result access.
  • test/tap/tests/mcp_query_run_sql_readonly-t.cpp
    • Added a new C++ TAP test to validate the run_sql_readonly MCP tool, covering various blocked and allowed SQL queries.
  • test/tap/tests/mcp_rules_testing/test_run_sql_readonly_validation.sh
    • Deprecated this shell script, indicating that the new C++ TAP test is its replacement.
Activity
  • No activity found in the provided context.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

Adds an MCP JSON‑RPC client and tests: new C++ MCP client library with libcurl, CLI and Makefile integration, MCP test group registration and proxysql MCP config, and a new TAP C++ test validating run_sql_readonly behavior.

Changes

Cohort / File(s) Summary
MCP Client library
test/tap/tap/mcp_client.h, test/tap/tap/mcp_client.cpp
New MCP client: MCPErrorType, MCPResponse, MCPClient classes; curl-based JSON‑RPC request/response handling, auth token support, server check, and tool invocation APIs.
Build integration
test/tap/tap/Makefile
Added mcp_client.o build rule (depends on libcurl) and included it into libtap_mariadb.a, libtap_mysql57.a, and libtap_mysql8.a.
Command-line / env handling
test/tap/tap/command_line.h, test/tap/tap/command_line.cpp
Added mcp_port and mcp_auth_token to CommandLine; read TAP_MCP_PORT and TAP_MCP_AUTH_TOKEN from environment; free auth token in destructor.
Test group & proxysql setup
test/tap/groups/ai/env.sh, test/tap/groups/ai/pre-proxysql.sql, test/tap/groups/groups.json
Removed TEST_PY_TAP_INCL export from env.sh; added SQL snippet to enable/configure MCP in pre-proxysql.sql; registered new test group mcp_query_run_sql_readonly-t mapped to ai-g1.
New TAP test
test/tap/tests/mcp_query_run_sql_readonly-t.cpp
New C++ TAP test exercising run_sql_readonly via MCP: test matrices for blocked (11) and allowed (9) queries, helpers for data/setup, assertions for errors and success.
Deprecated script notice
test/tap/tests/mcp_rules_testing/test_run_sql_readonly_validation.sh
Added deprecation notice pointing to the new C++ TAP test.

Sequence Diagram(s)

sequenceDiagram
    participant Test as TAP Test
    participant MCP as MCP Server
    participant MySQL as MySQL DB

    Test->>MCP: MCPClient.check_server()
    MCP-->>Test: status/result
    Test->>MySQL: prepare test DB/data
    MySQL-->>Test: ready
    loop per query
      Test->>MCP: MCPClient.call_tool("config","run_sql_readonly", args)
      MCP->>MySQL: execute SQL (readonly enforcement)
      MySQL-->>MCP: result or error
      MCP-->>Test: JSON-RPC response (result/error)
      Test->>Test: validate MCPResponse (success or expected error)
    end
    Test->>MySQL: cleanup
    MySQL-->>Test: done
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • renecannao
  • rahim-kanji

Poem

🐰 I hopped in with curl and a JSON-filled sack,
I asked ProxySQL nicely to run SQL read-only back,
With tokens and ports and a test matrix bright,
The client and server danced through the night,
Hooray — the queries behaved just right! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main changes: introducing an MCP client helper class and a TAP test for run_sql_readonly validation, which align with the core file additions (mcp_client.h/cpp) and the new test file.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into v3.0

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tap-mcp-client

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@wazir-ahmed wazir-ahmed changed the title TAP: Add MCP client helper and run_sql_readonly validation test TAP: Add MCP client helper and run_sql_readonly validation test Feb 13, 2026
@wazir-ahmed wazir-ahmed changed the title TAP: Add MCP client helper and run_sql_readonly validation test TAP: Add MCP client helper and run_sql_readonly validation Feb 13, 2026
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a C++ MCPClient for testing ProxySQL's MCP endpoints and adds a new TAP test for run_sql_readonly validation. The overall implementation of the MCPClient is robust, with good error handling and a clean interface. The new test successfully validates the rejection of non-read-only queries.

However, there are several areas for improvement. The new test file mcp_query_run_sql_readonly-t.cpp uses raw pointers and goto for cleanup, which should be replaced with RAII constructs like std::unique_ptr for better resource management and code clarity. A significant portion of the new tests ("Allowed Query Tests") are commented out because they are failing, which suggests the feature or test is incomplete and should be addressed before merging. Additionally, there are some minor issues like hardcoded credentials in a SQL script and inconsistent use of functions for string-to-integer conversion in mcp_client.cpp.

My feedback focuses on improving code quality, maintainability, and robustness.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@test/tap/groups/ai/pre-proxysql.sql`:
- Around line 7-8: The test uses the wrong singular MCP variable names causing
silent misconfiguration: open test/tap/tests/mcp_query_run_sql_readonly-t.cpp,
find where it sets or references "mcp-mysql_host" and "mcp-mysql_port" (look for
setenv/putenv or string refs in the test setup) and change them to the
documented plural names "mcp-mysql_hosts" and "mcp-mysql_ports" so they match
the SQL fixture and doc/MCP/VARIABLES.md; update any related assertions or
helper calls that expect the singular names to use the new plural identifiers.

In `@test/tap/tap/mcp_client.h`:
- Around line 226-228: The doc example incorrectly accesses the private member
result_ via resp.result; update the example to call the public accessor
resp.get_result() instead (so use resp.get_result()["results"]) to match the
actual API and avoid direct member access of result_ (search for the snippet
using resp.result or direct result_ access in the example and replace with
resp.get_result()).
- Around line 44-47: The doc example passes resp.get_error_message() (which
returns const std::string&) to diag with a %s format specifier; update the call
in the error branch to pass resp.get_error_message().c_str() so the %s receives
a const char*, e.g. keep diag("Tool error: %s (code %d)",
resp.get_error_message().c_str(), resp.get_error_code()) using the existing
resp.get_error_code() and diag call sites.

In `@test/tap/tests/mcp_query_run_sql_readonly-t.cpp`:
- Around line 215-227: test_query_allowed is constructing args without the
"schema" key while test_query_rejected includes {"schema","test"}, causing
mismatched behavior when run_sql_readonly expects a schema; update
test_query_allowed to include the same schema argument (e.g., add
{"schema","test"} to the json args passed to
MCPClient::call_tool("query","run_sql_readonly", args)) so both tests use
consistent inputs for validation and routing.
- Line 80: The TAP plan declares 20 tests via plan(20) but only 11 actually run
because the nine "allowed query" tests were commented out; update the test plan
or restore the tests so they match: either change the plan(20) call to plan(11)
to reflect the current active tests, or re-enable the nine commented "allowed
query" tests so the total executed tests matches 20; locate the plan(20)
invocation and the commented-out allowed query test blocks in
test/tap/tests/mcp_query_run_sql_readonly-t.cpp (identify the plan(20) symbol
and the nearby allowed-query test cases) and make a consistent change.
🧹 Nitpick comments (4)
test/tap/tap/command_line.cpp (1)

242-254: Minor inconsistency: TAP_MCP_PORT here vs TAP_MCPPORT in mcp_client.cpp.

CommandLine::getEnv() reads TAP_MCP_PORT (line 244), but MCPClient's constructor fallback (mcp_client.cpp, line 28) reads TAP_MCPPORT (no underscore separator). Since the test creates MCPClient with the explicit port from CommandLine, this won't cause a runtime bug, but the inconsistent naming could confuse users who try to set the env var directly.

Consider aligning both to use the same env var name.

test/tap/tap/mcp_client.cpp (2)

88-104: Consider calling curl_global_init / curl_global_cleanup.

curl_easy_init() will auto-call curl_global_init() on first use, but the libcurl docs warn this auto-initialization is not thread-safe. Since the TAP libraries are now linked into all test binaries (not just MCP tests), any test that happens to initialize curl concurrently could hit undefined behavior.

A static init/cleanup (e.g., via a RAII wrapper or an explicit init in main) would be safer.


369-399: check_server does not add auth token for the "config" endpoint.

call_tool adds an Authorization header if there's a token configured for the endpoint, but check_server builds its own request directly without checking auth_tokens_. If the MCP server requires authentication on the config endpoint, this health check will fail.

Consider reusing the auth token logic or delegating to call_tool.

test/tap/tap/mcp_client.h (1)

10-10: using json alias in header leaks into all includers.

This type alias at namespace scope will propagate to every translation unit that includes this header. For a test-internal library this is likely fine, but if the header is ever included more broadly it could cause name collisions.

- Replace per-endpoint auth token map with single token field
- Remove automatic reading of TAP_ADMINHOST/TAP_MCPPORT env vars
  (users should pass these via CommandLine)
- Fix MCP MySQL config variable names (host→hosts, port→ports)
- Re-enable allowed query tests with required schema parameter

Signed-off-by: Wazir Ahmed <wazir@proxysql.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/tap/tap/mcp_client.cpp`:
- Around line 355-385: check_server() is missing the Authorization header so
requests fail when auth_token_ is set; update MCPClient::check_server to append
an "Authorization: Bearer <auth_token_>" header when auth_token_ is non-empty
(same pattern used in call_tool), e.g. build headers with curl_slist_append
including Content-Type and the Authorization header, set CURLOPT_HTTPHEADER to
that list before curl_easy_perform, and ensure you still call
curl_slist_free_all(headers) after the request; reference
MCPClient::check_server, auth_token_, and call_tool to mirror the existing auth
header construction and cleanup.
🧹 Nitpick comments (3)
test/tap/tap/mcp_client.h (2)

9-9: using directive in header pollutes every includer's namespace.

using json = nlohmann::json; at file scope in a header forces the json alias onto every translation unit that includes this file. Consider moving it inside the class or using nlohmann::json explicitly in the header, and letting .cpp files define their own alias.

For a test-only utility this is low-risk, but worth noting.


171-180: Public setters weaken encapsulation of MCPResponse.

These setters are documented as "for MCPClient use" but are fully public, meaning any consumer can mutate response state. A friend class MCPClient declaration with private setters would enforce this contract at compile time.

Given this is test infrastructure, this is a minor concern.

test/tap/tap/mcp_client.cpp (1)

190-271: MCP error type is pre-set before validation, which works but is subtle.

Line 194 sets error_type_ to MCPErrorType::MCP as a "default" for the entire MCP validation section, and it's only overridden to NONE on the success path (line 257). This works correctly, but the "guilty until proven innocent" approach could be confusing to future maintainers.

A comment at line 194 clarifying the intent (e.g., "Default to MCP error; cleared on success") would help.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
4 Security Hotspots
D Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

renecannao added a commit that referenced this pull request Feb 17, 2026
…g model

This commit ports the TAP MCP client test coverage from PR #5372 to the new MCP profiles architecture, replacing legacy direct backend variable assumptions with target/profile-based routing.

What was updated:
- Reworked test setup to use `mcp_target_profiles` + `mcp_auth_profiles` rather than legacy `mcp-mysql_*` config variables.
- Updated MCP request payloads and helper flows to route via `target_id`.
- Aligned assertions with profile-backed runtime behavior and removed obsolete expectations tied to static mysql host/user/password globals.

Why this was needed:
- The previous tests were written before MCP target/profile routing existed.
- Without this update, TAP coverage would exercise deprecated paths and miss regressions in the current MCP execution model.

Result:
- Test suite now validates the same functional intent as PR #5372 but against the current profile-driven MCP routing implementation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants