Skip to content

feat(mcp): expose run command as an MCP tool - #1039

Open
LikhinMN wants to merge 9 commits into
scanapi:mainfrom
LikhinMN:feature/mcp-run-tool
Open

feat(mcp): expose run command as an MCP tool#1039
LikhinMN wants to merge 9 commits into
scanapi:mainfrom
LikhinMN:feature/mcp-run-tool

Conversation

@LikhinMN

@LikhinMN LikhinMN commented Aug 4, 2026

Copy link
Copy Markdown

Fixes #939

Proposed Changes

  • Extracted test results context logic out to scanapi.context.build_context so the execution output payload can be properly shared between the CLI reporter and MCP server.
  • Refactored scan() in scanapi.scan into run_scan(). This decouples the sys.exit() logic from execution, enabling the long-running MCP server to execute test suites natively.
  • Introduced mcp>=1.0.0 as a dependency.
  • Defined the MCP server in scanapi/mcp/server.py with a run tool matching the current CLI behavior!

Tests

  • Added backwards compatibility by retaining existing CLI features, updated unit tests to adapt to the extracted context dictionary format (tests/unit/test_reporter.py). All 391 unit tests are passing!

@LikhinMN
LikhinMN requested review from a team as code owners August 4, 2026 03:47
Copilot AI lite review requested due to automatic review settings August 4, 2026 03:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR exposes ScanAPI’s existing run execution flow through an MCP server tool, while refactoring scan execution to return a reusable, structured “execution context” that can be shared between the CLI reporter and MCP responses.

Changes:

  • Extracted execution context creation into scanapi.context.build_context() and reused it from Reporter._build_context().
  • Refactored scan() into run_scan() + CLI wrapper to decouple sys.exit() from execution for long-running MCP usage.
  • Added an MCP server (scanapi/mcp/server.py) with a run tool and introduced mcp>=1.0.0 as a dependency.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
uv.lock Locks new dependency set including mcp and transitive requirements.
pyproject.toml Adds mcp>=1.0.0 to core dependencies.
scanapi/context.py Introduces shared context builder for scan execution results/summary.
scanapi/scan.py Adds run_scan() returning context; keeps CLI scan() for legacy behavior.
scanapi/reporter.py Switches reporter context building to reuse scanapi.context.build_context().
scanapi/mcp/server.py Implements MCP server and run tool wrapping existing scan flow.
scanapi/mcp/init.py Declares MCP package module.
tests/unit/test_reporter.py Updates reporter unit tests for the new context shape.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scanapi/context.py Outdated
Comment on lines +37 to +42
"session": {
"errors": session.errors,
"failures": session.failures,
"successes": session.successes,
"exit_code": session.exit_code,
},
Comment thread tests/unit/test_reporter.py Outdated
Comment on lines +101 to +106
"session": {
"errors": 0,
"failures": 0,
"successes": 0,
"exit_code": ExitCode.OK,
},
Comment thread scanapi/mcp/server.py
Comment on lines +37 to +45
# Save preferences to the global settings
settings.save_preferences(
spec_path=spec_path,
output_path=output_path,
no_report=no_report,
config_path=config_path,
template=template,
open_browser=browser,
)
Comment thread scanapi/mcp/server.py Outdated
Comment on lines +47 to +55
context = run_scan()

# Generate report if needed
if not no_report:
from scanapi.scan import _write

_write(context["results"])

return {"summary": context["summary"], "results": context["results"]}
Copilot AI review requested due to automatic review settings August 4, 2026 03:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

scanapi/scan.py:73

  • The docstring has a grammatical error ("tries to scans"). This is user-facing documentation and should be corrected.
def scan():
    """Caller function that tries to scans the file and write the report."""
    results = run_scan()

scanapi/mcp/server.py:6

  • This new MCP server module is excluded from coverage (# pragma: no cover) and there are currently no unit tests covering the MCP run tool behavior (argument mapping, error handling, and JSON-serializable output). Given the repo has extensive unit tests elsewhere, adding at least a small unit test suite for this integration would help prevent regressions.
from mcp.server.fastmcp import FastMCP

from scanapi.scan import run_scan  # pragma: no cover
from scanapi.settings import settings  # pragma: no cover
from scanapi.cli import configure_logging  # pragma: no cover

Comment thread scanapi/mcp/server.py
Comment on lines +47 to +68
results = run_scan()

# Generate report if needed
if not no_report:
from scanapi.scan import _write

_write(results)

from scanapi.session import session

total_tests = session.successes + session.failures + session.errors

return {
"summary": {
"requests": len(results),
"tests": total_tests,
"passed": session.successes,
"failed": session.failures,
"success": session.succeed,
},
"results": results,
}
Copilot AI review requested due to automatic review settings August 4, 2026 03:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.

Suppressed comments (4)

scanapi/mcp/server.py:66

  • The MCP tool currently returns raw results, which can contain requests.Response objects (and other non-JSON-serializable values). FastMCP transports typically JSON-encode tool results, so this can fail at runtime.

Return a JSON-safe representation (e.g., the serialized_results computed above) instead of the raw objects.

            "requests": len(results),
            "tests": total_tests,
            "passed": session.successes,
            "failed": session.failures,

scanapi/scan.py:85

  • The write_output() docstring mentions --no_report and --browser without backticks, but the actual CLI flags are --no-report and --browser (see scanapi/cli.py). Updating this avoids misleading documentation.
    """When the user passed the `--no-report` flag: prints the test results to
    the console output.
    When the user did not pass the `--no_report flag`: writes the results on a
    report file and opens it using a browser, if the --browser flag is present.

scanapi/scan.py:72

  • Grammar: the scan() docstring reads "tries to scans". This should be corrected for clarity.
def scan():
    """Caller function that tries to scans the file and write the report."""

scanapi/mcp/server.py:15

  • There is no unit test coverage for the new MCP run tool. The repo has extensive unit tests for the CLI scan flow, so adding a small unit test that calls scanapi.mcp.server.run() directly (mocking run_scan / write_output and validating the returned summary/result shape) would help prevent regressions.


@mcp.tool()

Comment thread scanapi/mcp/server.py
Comment on lines +37 to +54
configure_logging(log_level)

# Save preferences to the global settings
settings.save_preferences(
spec_path=spec_path,
output_path=output_path,
no_report=no_report,
config_path=config_path,
template=template,
open_browser=browser,
)

results = run_scan()

# Generate report if needed
if not no_report:
write_output(results)

Copilot AI review requested due to automatic review settings August 4, 2026 04:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 4, 2026 04:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 4, 2026 04:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the First Contribution First contribution to the project. label Aug 4, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thank you for supporting ScanAPI, and congratulations on your first contribution! A project committer will shortly review your contribution.

In the mean time, if you haven't had a chance please skim over the First Pull Request Guide which all pull requests must adhere to.

We hope to see you around!

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

📌 Esta mensagem está tanto em português quanto em inglês (mais abaixo) — assim todo mundo consegue acompanhar!
📌 This message is in both Portuguese and English (further down) — so everyone can follow along!

🇧🇷 Português

👋 Olá!

Este PR está obsoleto porque ficou aberto por 30 dias sem atividade. Remova o rótulo de stale ou comente, caso contrário ele será fechado em 15 dias.

🇬🇧 English

Hey there! 👋

This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 15 days.

@github-actions github-actions Bot added the Stale label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

First Contribution First contribution to the project. Stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose run command as an MCP tool

2 participants