airbyte_ops_mcp.mcp.regression_tests
MCP tools for connector regression tests.
This module provides MCP tools for triggering regression tests on Airbyte Cloud connections via GitHub Actions workflows. Regression tests can run in two modes:
- Single version mode: Tests a connector version against a connection config
- Comparison mode: Compares a target version against a control (baseline) version
Tests run asynchronously in GitHub Actions and results can be polled via workflow status.
Note: The term "regression tests" encompasses all connector validation testing. The term "live tests" is reserved for scenarios where actual Cloud connections are pinned to pre-release versions for real-world validation.
MCP reference
MCP primitives registered by the regression_tests module of the airbyte-internal-ops server: 1 tool(s), 0 prompt(s), 0 resource(s).
Tools (1)
run_regression_tests
Hints: open-world
Start a regression test run via GitHub Actions workflow.
This tool triggers the regression test workflow which builds the connector from the specified PR and runs tests against it.
Supports both OSS connectors (from airbytehq/airbyte) and enterprise connectors (from airbytehq/airbyte-enterprise). Use the 'repo' parameter to specify which repository contains the connector PR.
- skip_compare=False (default): Comparison mode - compares the PR version against the baseline (control) version.
- skip_compare=True: Single-version mode - runs tests without comparison.
If connection_id is provided, config/catalog are fetched from Airbyte Cloud. Otherwise, GSM integration test secrets are used.
Returns immediately with a run_id and workflow URL. Check the workflow URL to monitor progress and view results.
Requires GITHUB_CI_WORKFLOW_TRIGGER_PAT or GITHUB_TOKEN environment variable with 'actions:write' permission.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | Connector name to build from source (e.g., 'source-pokeapi'). Required. |
pr |
integer |
yes | — | PR number to checkout and build from (e.g., 70847). Required. The PR must be from the repository specified by the 'repo' parameter. |
repo |
enum("airbyte", "airbyte-enterprise") |
yes | — | Repository where the connector PR is located. Use 'airbyte' for OSS connectors (default) or 'airbyte-enterprise' for enterprise connectors. |
connection_id |
string | null |
no | null |
Airbyte Cloud connection ID to fetch config/catalog from. If not provided, uses GSM integration test secrets. |
skip_compare |
boolean |
no | false |
If True, skip comparison and run single-version tests only. If False (default), run comparison tests (target vs control versions). |
skip_read_action |
boolean |
no | false |
If True, skip the read action (run only spec, check, discover). If False (default), run all verbs including read. |
override_test_image |
string | null |
no | null |
Override test connector image with tag (e.g., 'airbyte/source-github:1.0.0'). Ignored if skip_compare=False. |
override_control_image |
string | null |
no | null |
Override control connector image (baseline version) with tag. Ignored if skip_compare=True. |
workspace_id |
string | enum("266ebdfe-0d7b-4540-9817-de7e4505ba61") | null |
no | null |
Optional Airbyte Cloud workspace ID (UUID) or alias. If provided with connection_id, validates that the connection belongs to this workspace before triggering tests. Accepts '@devin-ai-sandbox' as an alias for the Devin AI sandbox workspace. |
selected_streams |
array<string> | null |
no | null |
List of stream names to include in the read. Only these streams will be included in the configured catalog. This is useful to limit data volume by testing only specific streams. If not provided, all streams are tested. |
enable_debug_logs |
boolean |
no | false |
Enable debug-level logging for regression test output. Also passed as LOG_LEVEL=DEBUG to the connector Docker container. |
with_state |
boolean | null |
no | null |
Fetch and pass the connection's current state to the read command, producing a warm read instead of a cold read. Defaults to True when connection_id is provided, False otherwise. Has no effect unless the command is read. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "Connector name to build from source (e.g., 'source-pokeapi'). Required.",
"type": "string"
},
"pr": {
"description": "PR number to checkout and build from (e.g., 70847). Required. The PR must be from the repository specified by the 'repo' parameter.",
"type": "integer"
},
"repo": {
"description": "Repository where the connector PR is located. Use 'airbyte' for OSS connectors (default) or 'airbyte-enterprise' for enterprise connectors.",
"enum": [
"airbyte",
"airbyte-enterprise"
],
"type": "string"
},
"connection_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Airbyte Cloud connection ID to fetch config/catalog from. If not provided, uses GSM integration test secrets."
},
"skip_compare": {
"default": false,
"description": "If True, skip comparison and run single-version tests only. If False (default), run comparison tests (target vs control versions).",
"type": "boolean"
},
"skip_read_action": {
"default": false,
"description": "If True, skip the read action (run only spec, check, discover). If False (default), run all verbs including read.",
"type": "boolean"
},
"override_test_image": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Override test connector image with tag (e.g., 'airbyte/source-github:1.0.0'). Ignored if skip_compare=False."
},
"override_control_image": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Override control connector image (baseline version) with tag. Ignored if skip_compare=True."
},
"workspace_id": {
"anyOf": [
{
"type": "string"
},
{
"description": "Workspace ID aliases that can be used in place of UUIDs.\n\nEach member's name is the alias (e.g., \"@devin-ai-sandbox\") and its value\nis the actual workspace UUID. Use `WorkspaceAliasEnum.resolve()` to\nresolve aliases to actual IDs.",
"enum": [
"266ebdfe-0d7b-4540-9817-de7e4505ba61"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional Airbyte Cloud workspace ID (UUID) or alias. If provided with connection_id, validates that the connection belongs to this workspace before triggering tests. Accepts '@devin-ai-sandbox' as an alias for the Devin AI sandbox workspace."
},
"selected_streams": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "List of stream names to include in the read. Only these streams will be included in the configured catalog. This is useful to limit data volume by testing only specific streams. If not provided, all streams are tested."
},
"enable_debug_logs": {
"default": false,
"description": "Enable debug-level logging for regression test output. Also passed as `LOG_LEVEL=DEBUG` to the connector Docker container.",
"type": "boolean"
},
"with_state": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"description": "Fetch and pass the connection's current state to the read command, producing a warm read instead of a cold read. Defaults to `True` when `connection_id` is provided, `False` otherwise. Has no effect unless the command is `read`."
}
},
"required": [
"connector_name",
"pr",
"repo"
],
"type": "object"
}
Show output JSON schema
{
"description": "Response from starting a regression test via GitHub Actions workflow.",
"properties": {
"run_id": {
"description": "Unique identifier for the test run (internal tracking ID)",
"type": "string"
},
"status": {
"description": "Initial status of the test run",
"enum": [
"queued",
"running",
"succeeded",
"failed"
],
"type": "string"
},
"message": {
"description": "Human-readable status message",
"type": "string"
},
"workflow_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "URL to view the GitHub Actions workflow file"
},
"github_run_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "GitHub Actions workflow run ID (use with check_ci_workflow_status)"
},
"github_run_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Direct URL to the GitHub Actions workflow run"
}
},
"required": [
"run_id",
"status",
"message"
],
"type": "object"
}
1# Copyright (c) 2025 Airbyte, Inc., all rights reserved. 2"""MCP tools for connector regression tests. 3 4This module provides MCP tools for triggering regression tests on Airbyte Cloud 5connections via GitHub Actions workflows. Regression tests can run in two modes: 6- Single version mode: Tests a connector version against a connection config 7- Comparison mode: Compares a target version against a control (baseline) version 8 9Tests run asynchronously in GitHub Actions and results can be polled via workflow status. 10 11Note: The term "regression tests" encompasses all connector validation testing. 12The term "live tests" is reserved for scenarios where actual Cloud connections 13are pinned to pre-release versions for real-world validation. 14 15## MCP reference 16 17.. include:: ../../../docs/mcp-generated/regression_tests.md 18 :start-line: 2 19""" 20 21from __future__ import annotations 22 23__all__: list[str] = [] 24 25import uuid 26from datetime import datetime 27from enum import Enum 28from typing import Annotated, Any 29 30import requests 31from airbyte.cloud import CloudWorkspace 32from airbyte.cloud.auth import resolve_cloud_client_id, resolve_cloud_client_secret 33from airbyte.exceptions import ( 34 AirbyteMissingResourceError, 35 AirbyteWorkspaceMismatchError, 36) 37from fastmcp import FastMCP 38from fastmcp_extensions import mcp_tool, register_mcp_tools 39from pydantic import BaseModel, Field 40 41from airbyte_ops_mcp.constants import WorkspaceAliasEnum 42from airbyte_ops_mcp.github_actions import ( 43 resolve_default_workflow_branch, 44 trigger_workflow_dispatch, 45) 46from airbyte_ops_mcp.github_api import ( 47 GITHUB_API_BASE, 48 resolve_ci_trigger_github_token, 49) 50from airbyte_ops_mcp.mcp.prerelease import ConnectorRepo 51 52# ============================================================================= 53# GitHub Workflow Configuration 54# ============================================================================= 55 56REGRESSION_TEST_REPO_OWNER = "airbytehq" 57REGRESSION_TEST_REPO_NAME = "airbyte-ops-mcp" 58REGRESSION_TEST_DEFAULT_BRANCH = "main" 59# Unified regression test workflow (handles both single-version and comparison modes) 60REGRESSION_TEST_WORKFLOW_FILE = "connector-regression-test.yml" 61 62 63# ============================================================================= 64# Workspace Validation Helpers 65# ============================================================================= 66 67 68def validate_connection_workspace( 69 connection_id: str, 70 workspace_id: str, 71) -> None: 72 """Validate that a connection belongs to the expected workspace. 73 74 Uses PyAirbyte's CloudConnection.check_is_valid() method to verify that 75 the connection exists and belongs to the specified workspace. 76 77 Raises: 78 ValueError: If Airbyte Cloud credentials are missing. 79 AirbyteWorkspaceMismatchError: If connection belongs to a different workspace. 80 AirbyteMissingResourceError: If connection is not found. 81 """ 82 client_id = resolve_cloud_client_id() 83 client_secret = resolve_cloud_client_secret() 84 if not client_id or not client_secret: 85 raise ValueError( 86 "Missing Airbyte Cloud credentials. " 87 "Set AIRBYTE_CLOUD_CLIENT_ID and AIRBYTE_CLOUD_CLIENT_SECRET env vars." 88 ) 89 90 workspace = CloudWorkspace( 91 workspace_id=workspace_id, 92 client_id=client_id, 93 client_secret=client_secret, 94 ) 95 connection = workspace.get_connection(connection_id) 96 connection.check_is_valid() 97 98 99def _get_workflow_run_status( 100 owner: str, 101 repo: str, 102 run_id: int, 103 token: str, 104) -> dict[str, Any]: 105 """Get workflow run details from GitHub API. 106 107 Args: 108 owner: Repository owner (e.g., "airbytehq") 109 repo: Repository name (e.g., "airbyte-ops-mcp") 110 run_id: Workflow run ID 111 token: GitHub API token 112 113 Returns: 114 Workflow run data dictionary. 115 116 Raises: 117 ValueError: If workflow run not found. 118 requests.HTTPError: If API request fails. 119 """ 120 url = f"{GITHUB_API_BASE}/repos/{owner}/{repo}/actions/runs/{run_id}" 121 headers = { 122 "Authorization": f"Bearer {token}", 123 "Accept": "application/vnd.github+json", 124 "X-GitHub-Api-Version": "2022-11-28", 125 } 126 127 response = requests.get(url, headers=headers, timeout=30) 128 if response.status_code == 404: 129 raise ValueError(f"Workflow run {owner}/{repo}/actions/runs/{run_id} not found") 130 response.raise_for_status() 131 132 return response.json() 133 134 135# ============================================================================= 136# Pydantic Models for Test Results 137# ============================================================================= 138 139 140class TestRunStatus(str, Enum): 141 """Status of a test run.""" 142 143 QUEUED = "queued" 144 RUNNING = "running" 145 SUCCEEDED = "succeeded" 146 FAILED = "failed" 147 148 149class TestOutcome(str, Enum): 150 """Outcome of a test (execution or comparison).""" 151 152 PENDING = "pending" 153 RUNNING = "running" 154 PASSED = "passed" 155 FAILED = "failed" 156 SKIPPED = "skipped" 157 158 159class ValidationResultModel(BaseModel): 160 """Result of a single validation check.""" 161 162 name: str = Field(description="Name of the validation check") 163 passed: bool = Field(description="Whether the validation passed") 164 message: str = Field(description="Human-readable result message") 165 errors: list[str] = Field( 166 default_factory=list, 167 description="List of error messages if validation failed", 168 ) 169 170 171class StreamComparisonResultModel(BaseModel): 172 """Result of comparing a single stream between control and target.""" 173 174 stream_name: str = Field(description="Name of the stream") 175 passed: bool = Field(description="Whether all comparisons passed") 176 control_record_count: int = Field(description="Number of records in control") 177 target_record_count: int = Field(description="Number of records in target") 178 missing_pks: list[str] = Field( 179 default_factory=list, 180 description="Primary keys present in control but missing in target", 181 ) 182 differing_records: int = Field( 183 default=0, 184 description="Number of records that differ between control and target", 185 ) 186 message: str = Field(description="Human-readable comparison summary") 187 188 189class RegressionTestExecutionResult(BaseModel): 190 """Results from executing the connector (validations and record counts).""" 191 192 outcome: TestOutcome = Field(description="Outcome of the execution") 193 catalog_validations: list[ValidationResultModel] = Field( 194 default_factory=list, 195 description="Results of catalog validation checks", 196 ) 197 record_validations: list[ValidationResultModel] = Field( 198 default_factory=list, 199 description="Results of record validation checks", 200 ) 201 record_count: int = Field( 202 default=0, 203 description="Total number of records read", 204 ) 205 error_message: str | None = Field( 206 default=None, 207 description="Error message if the execution failed", 208 ) 209 210 211class RegressionTestComparisonResult(BaseModel): 212 """Results from comparing target vs control connector versions.""" 213 214 outcome: TestOutcome = Field(description="Outcome of the comparison") 215 baseline_version: str | None = Field( 216 default=None, 217 description="Version of the baseline (control) connector", 218 ) 219 stream_comparisons: list[StreamComparisonResultModel] = Field( 220 default_factory=list, 221 description="Per-stream comparison results", 222 ) 223 error_message: str | None = Field( 224 default=None, 225 description="Error message if the comparison failed", 226 ) 227 228 229class RegressionTestResult(BaseModel): 230 """Complete result of a regression test run.""" 231 232 run_id: str = Field(description="Unique identifier for this test run") 233 connection_id: str = Field(description="The connection being tested") 234 workspace_id: str = Field(description="The workspace containing the connection") 235 status: TestRunStatus = Field(description="Overall status of the test run") 236 target_version: str | None = Field( 237 default=None, 238 description="Version of the target connector being tested", 239 ) 240 baseline_version: str | None = Field( 241 default=None, 242 description="Version of the baseline connector (if comparison mode)", 243 ) 244 evaluation_mode: str = Field( 245 default="diagnostic", 246 description="Evaluation mode used (diagnostic or strict)", 247 ) 248 compare_versions: bool = Field( 249 default=False, 250 description="Whether comparison mode was used (target vs control)", 251 ) 252 execution_result: RegressionTestExecutionResult | None = Field( 253 default=None, 254 description="Results from executing the connector (validations and record counts)", 255 ) 256 comparison_result: RegressionTestComparisonResult | None = Field( 257 default=None, 258 description="Results from comparing target vs control connector versions", 259 ) 260 artifacts: dict[str, str] = Field( 261 default_factory=dict, 262 description="Paths to generated artifacts (JSONL, DuckDB, HAR files)", 263 ) 264 human_summary: str = Field( 265 default="", 266 description="Human-readable summary of the test results", 267 ) 268 started_at: datetime | None = Field( 269 default=None, 270 description="When the test run started", 271 ) 272 completed_at: datetime | None = Field( 273 default=None, 274 description="When the test run completed", 275 ) 276 test_description: str | None = Field( 277 default=None, 278 description="Optional description/context for this test run", 279 ) 280 281 282class RunRegressionTestsResponse(BaseModel): 283 """Response from starting a regression test via GitHub Actions workflow.""" 284 285 run_id: str = Field( 286 description="Unique identifier for the test run (internal tracking ID)" 287 ) 288 status: TestRunStatus = Field(description="Initial status of the test run") 289 message: str = Field(description="Human-readable status message") 290 workflow_url: str | None = Field( 291 default=None, 292 description="URL to view the GitHub Actions workflow file", 293 ) 294 github_run_id: int | None = Field( 295 default=None, 296 description="GitHub Actions workflow run ID (use with check_ci_workflow_status)", 297 ) 298 github_run_url: str | None = Field( 299 default=None, 300 description="Direct URL to the GitHub Actions workflow run", 301 ) 302 303 304# ============================================================================= 305# MCP Tools 306# ============================================================================= 307 308 309@mcp_tool( 310 read_only=False, 311 idempotent=False, 312 open_world=True, 313) 314def run_regression_tests( 315 connector_name: Annotated[ 316 str, 317 "Connector name to build from source (e.g., 'source-pokeapi'). Required.", 318 ], 319 pr: Annotated[ 320 int, 321 "PR number to checkout and build from (e.g., 70847). Required. " 322 "The PR must be from the repository specified by the 'repo' parameter.", 323 ], 324 repo: Annotated[ 325 ConnectorRepo, 326 "Repository where the connector PR is located. " 327 "Use 'airbyte' for OSS connectors (default) or 'airbyte-enterprise' for enterprise connectors.", 328 ], 329 connection_id: Annotated[ 330 str | None, 331 "Airbyte Cloud connection ID to fetch config/catalog from. " 332 "If not provided, uses GSM integration test secrets.", 333 ] = None, 334 skip_compare: Annotated[ 335 bool, 336 "If True, skip comparison and run single-version tests only. " 337 "If False (default), run comparison tests (target vs control versions).", 338 ] = False, 339 skip_read_action: Annotated[ 340 bool, 341 "If True, skip the read action (run only spec, check, discover). " 342 "If False (default), run all verbs including read.", 343 ] = False, 344 override_test_image: Annotated[ 345 str | None, 346 "Override test connector image with tag (e.g., 'airbyte/source-github:1.0.0'). " 347 "Ignored if skip_compare=False.", 348 ] = None, 349 override_control_image: Annotated[ 350 str | None, 351 "Override control connector image (baseline version) with tag. " 352 "Ignored if skip_compare=True.", 353 ] = None, 354 workspace_id: Annotated[ 355 str | WorkspaceAliasEnum | None, 356 "Optional Airbyte Cloud workspace ID (UUID) or alias. If provided with connection_id, " 357 "validates that the connection belongs to this workspace before triggering tests. " 358 "Accepts '@devin-ai-sandbox' as an alias for the Devin AI sandbox workspace.", 359 ] = None, 360 selected_streams: Annotated[ 361 list[str] | None, 362 "List of stream names to include in the read. Only these streams will be included " 363 "in the configured catalog. This is useful to limit data volume by testing only " 364 "specific streams. If not provided, all streams are tested.", 365 ] = None, 366 enable_debug_logs: Annotated[ 367 bool, 368 "Enable debug-level logging for regression test output. " 369 "Also passed as `LOG_LEVEL=DEBUG` to the connector Docker container.", 370 ] = False, 371 with_state: Annotated[ 372 bool | None, 373 "Fetch and pass the connection's current state to the read command, " 374 "producing a warm read instead of a cold read. Defaults to `True` when " 375 "`connection_id` is provided, `False` otherwise. Has no effect unless " 376 "the command is `read`.", 377 ] = None, 378) -> RunRegressionTestsResponse: 379 """Start a regression test run via GitHub Actions workflow. 380 381 This tool triggers the regression test workflow which builds the connector 382 from the specified PR and runs tests against it. 383 384 Supports both OSS connectors (from airbytehq/airbyte) and enterprise connectors 385 (from airbytehq/airbyte-enterprise). Use the 'repo' parameter to specify which 386 repository contains the connector PR. 387 388 - skip_compare=False (default): Comparison mode - compares the PR version 389 against the baseline (control) version. 390 - skip_compare=True: Single-version mode - runs tests without comparison. 391 392 If connection_id is provided, config/catalog are fetched from Airbyte Cloud. 393 Otherwise, GSM integration test secrets are used. 394 395 Returns immediately with a run_id and workflow URL. Check the workflow URL 396 to monitor progress and view results. 397 398 Requires GITHUB_CI_WORKFLOW_TRIGGER_PAT or GITHUB_TOKEN environment variable 399 with 'actions:write' permission. 400 """ 401 # Resolve workspace ID alias 402 resolved_workspace_id = WorkspaceAliasEnum.resolve(workspace_id) 403 404 # Generate a unique run ID for tracking 405 run_id = str(uuid.uuid4()) 406 407 # Get GitHub token 408 try: 409 token = resolve_ci_trigger_github_token() 410 except ValueError as e: 411 return RunRegressionTestsResponse( 412 run_id=run_id, 413 status=TestRunStatus.FAILED, 414 message=str(e), 415 workflow_url=None, 416 ) 417 418 # Validate workspace membership if workspace_id and connection_id are provided 419 if resolved_workspace_id and connection_id: 420 try: 421 validate_connection_workspace(connection_id, resolved_workspace_id) 422 except ( 423 ValueError, 424 AirbyteWorkspaceMismatchError, 425 AirbyteMissingResourceError, 426 ) as e: 427 return RunRegressionTestsResponse( 428 run_id=run_id, 429 status=TestRunStatus.FAILED, 430 message=str(e), 431 workflow_url=None, 432 ) 433 434 # Build workflow inputs - connector_name, pr, and repo are required 435 workflow_inputs: dict[str, str] = { 436 "connector_name": connector_name, 437 "pr": str(pr), 438 "repo": repo, 439 } 440 441 # Add optional inputs 442 if connection_id: 443 workflow_inputs["connection_id"] = connection_id 444 if skip_compare: 445 workflow_inputs["skip_compare"] = "true" 446 if skip_read_action: 447 workflow_inputs["skip_read_action"] = "true" 448 if override_test_image: 449 workflow_inputs["override_test_image"] = override_test_image 450 if override_control_image: 451 workflow_inputs["override_control_image"] = override_control_image 452 if selected_streams: 453 workflow_inputs["selected_streams"] = ",".join(selected_streams) 454 if enable_debug_logs: 455 workflow_inputs["enable_debug_logs"] = "true" 456 if with_state is True: 457 workflow_inputs["with_state"] = "true" 458 elif with_state is False: 459 workflow_inputs["with_state"] = "false" 460 461 mode_description = "single-version" if skip_compare else "comparison" 462 463 dispatch_result = trigger_workflow_dispatch( 464 owner=REGRESSION_TEST_REPO_OWNER, 465 repo=REGRESSION_TEST_REPO_NAME, 466 workflow_file=REGRESSION_TEST_WORKFLOW_FILE, 467 ref=resolve_default_workflow_branch(REGRESSION_TEST_DEFAULT_BRANCH), 468 inputs=workflow_inputs, 469 token=token, 470 ) 471 472 view_url = dispatch_result.run_url or dispatch_result.workflow_url 473 connection_info = f" for connection {connection_id}" if connection_id else "" 474 repo_info = f" from {repo}" if repo != ConnectorRepo.AIRBYTE else "" 475 return RunRegressionTestsResponse( 476 run_id=run_id, 477 status=TestRunStatus.QUEUED, 478 message=( 479 f"{mode_description.capitalize()} regression test workflow triggered " 480 f"for {connector_name} (PR #{pr}{repo_info}){connection_info}. View progress at: {view_url}" 481 ), 482 workflow_url=dispatch_result.workflow_url, 483 github_run_id=dispatch_result.run_id, 484 github_run_url=dispatch_result.run_url, 485 ) 486 487 488# ============================================================================= 489# Registration 490# ============================================================================= 491 492 493def register_regression_tests_tools(app: FastMCP) -> None: 494 """Register regression tests tools with the FastMCP app. 495 496 Args: 497 app: FastMCP application instance 498 """ 499 register_mcp_tools(app, mcp_module=__name__)