Automation Design
Scope
This document describes automation from a Continuous Testing (CT) point of view.
The CT design has two main flows:
- GitHub Actions and a self-hosted runner
- Jenkins direct execution
The purpose of this document is CT automation. CI/CD remains part of the overall automation boundary, but its flows and implementation details are omitted by default. GitHub Actions CI/CD is mentioned only to distinguish it from the Issue-based CT flows.
CT Documentation Scope
- The default scope of this document is CT.
- Automation flows and diagrams describe CT unless a section explicitly states otherwise.
- CI/CD flows and implementation details are omitted by default.
CI/CD and CT Responsibility
| Area | Orchestrator | Execution Entry | Environment | Purpose |
|---|---|---|---|---|
| GitHub CI/CD | GitHub Actions | .github/workflows/github_pages.yaml |
Ubuntu GitHub-hosted runner | build, deploy, release |
| Runner CT | GitHub Actions | .github/workflows/test_request_local.yaml |
Windows self-hosted runner | Issue-based CT |
| Direct CT | Jenkins | Jenkinsfile |
Windows Jenkins agent | Issue-based direct CT |
GitHub Actions is responsible for both GitHub CI/CD orchestration and the runner CT workflow. The runner CT job itself is executed by the GitHub self-hosted runner.
CI/CD Boundary
- The CI/CD row above is boundary context only.
- CI/CD flow details are intentionally omitted from the remaining sections and diagrams.
Current CT Operating System
- Both CT Main Flows currently target Windows.
test_request_local.yamlexecutes its local steps with PowerShell on the self-hosted runner.Jenkinsfilealso executes checkout and TEST stages with PowerShell on the Jenkins agent.- Shared TEST handlers currently use Windows command forms,
including
ping -n. - Linux support requires shell-independent handlers or separate OS-specific tool implementations.
CT Architecture
CT automation is divided into two independent Main Flows. They use different automation entrypoints and different Local MCP Server entrypoints.
| Main Flow | Issue Label | Automation | Local MCP Server |
|---|---|---|---|
| GitHub Self-hosted Runner | test-request-runner |
GitHub Actions + self-hosted runner | mcp-server-local-runner |
| Jenkins | test-request-direct |
Jenkins webhook pipeline | mcp-server-local-direct |
Both flows share the Python Bridge, MCP runtime, toolsets, TEST result format, and GitHub Issue reporting model.
Main Flow CT
GitHub Runner CT
This flow is selected by the test-request-runner label.
flowchart TD
Issue["GitHub Issue<br/>test-request-runner"]
Workflow["GitHub Actions<br/>test_request_local.yaml"]
Runner["GitHub Self-hosted Runner<br/>Windows / local-dev"]
subgraph Bridge["Shared Python Bridge"]
direction TB
RunBridge["Request Bridge: run_test_request.py<br/>GitHub Issue Request to Local MCP Request"]
ResultBridge["Result Bridge: make_test_result.py<br/>Local MCP Result to GitHub Issue Report"]
end
subgraph MCP["Local MCP"]
direction TB
RunnerMCP["mcp-server-local-runner"]
SharedRuntime["Shared MCP Runtime<br/>runtime.py"]
SharedTools["Shared TEST Tools<br/>Setup / Test / Log<br/>toolsets.py: extensible"]
end
Tools["Selected TEST Tools"]
Result["JSON + MCP Logs"]
Artifact["GitHub Actions Artifact"]
Comment["GitHub Issue TEST Result Comment"]
Issue --> Workflow --> Runner --> RunBridge
RunBridge --> RunnerMCP --> SharedRuntime --> SharedTools --> Tools --> Result
Result --> Artifact
Result --> ResultBridge --> Comment
classDef sharedTools fill:#fff3bf,stroke:#f08c00,stroke-width:4px,color:#000;
class SharedTools sharedTools;
Source behavior:
- The workflow listens for Issue
opened,edited, andreopenedevents. - The job runs only when the Issue has the
test-request-runnerlabel. runs-on: [self-hosted, local-dev]assigns the CT job to the local runner.run_test_request.pyselectsmcp-server-local-runnerfrom the Issue'srunnermode.- GitHub Actions uploads JSON and logs as an artifact.
make_test_result.pyrenders Markdown, andactions/github-scriptposts it to the Issue.
Related sources:
.github/ISSUE_TEMPLATE/test_request_runner.yml.github/workflows/test_request_local.yamlmcp/scripts/run_test_request.pymcp/server_local_runner/server.pymcp/scripts/make_test_result.py
GitHub Issue created with the runner TEST request template:

TEST result reported back to the GitHub Issue:

Sample results:
Jenkins Direct CT
This flow is selected by the test-request-direct label and the jenkins target runner value.
flowchart TD
Issue["GitHub Issue<br/>test-request-direct<br/>Target Runner: jenkins"]
Webhook["GitHub Webhook"]
Jenkins["Jenkins Pipeline<br/>Windows agent<br/>requested ref checkout"]
subgraph Bridge["Shared Python Bridge"]
direction TB
RunBridge["Request Bridge: run_test_request.py<br/>GitHub Issue Request to Local MCP Request"]
ResultBridge["Result Bridge: make_test_result.py<br/>Local MCP Result to GitHub Issue Report"]
end
subgraph MCP["Local MCP"]
direction TB
DirectMCP["mcp-server-local-direct"]
SharedRuntime["Shared MCP Runtime<br/>runtime.py"]
SharedTools["Shared TEST Tools<br/>Setup / Test / Log<br/>toolsets.py: extensible"]
end
Tools["Selected TEST Tools"]
Result["JSON + MCP Logs"]
Artifact["Jenkins Artifact"]
Comment["GitHub Issue TEST Result Comment"]
Issue --> Webhook --> Jenkins --> RunBridge
RunBridge --> DirectMCP --> SharedRuntime --> SharedTools --> Tools --> Result
Result --> Artifact
Result --> ResultBridge --> Comment
classDef sharedTools fill:#fff3bf,stroke:#f08c00,stroke-width:4px,color:#000;
class SharedTools sharedTools;
Source behavior:
- Jenkins accepts the GitHub Issue webhook and reads its number, body, repository, and labels.
- The pipeline continues only for
test-request-directwithTarget Runner: jenkins. - Jenkins checks out the ref requested in the Issue before executing CT.
run_test_request.pyselectsmcp-server-local-directfrom the Issue'sdirectmode.- Jenkins archives the generated result files and posts the Markdown report through the GitHub REST API.
The direct Issue template also allows Target Runner: ai-agent. That is a manual AI Agent execution option, not the Jenkins automated flow described here.
Related sources:
.github/ISSUE_TEMPLATE/test_request_direct.ymlJenkinsfilemcp/scripts/run_test_request.pymcp/server_local_direct/server.pymcp/scripts/make_test_result.py
Shared Python Bridge
The Python Bridge is the common adapter between automation and MCP.
Request and TEST execution
mcp/scripts/run_test_request.py:
Request Bridge Direction
- The request source is a GitHub TEST Request Issue.
- GitHub Actions or Jenkins passes the Issue request to
run_test_request.py. - The request destination is the Local MCP Server selected
by
MCP Server Mode.
- Parses the GitHub Issue Form fields and selected checklist tools.
- Validates the MCP mode and target runner.
- Resolves the requested Git branch, tag, or commit metadata.
- Selects the runner or direct MCP Server entrypoint.
- Sends MCP
initialize,tools/list, andtools/callmessages over stdio. - Aggregates tool results and writes
results/Github-ISSUE-TR-<number>.json.
TEST result reporting
mcp/scripts/make_test_result.py:
Result Bridge Direction
- The result source is the Local MCP TEST result JSON and MCP logs.
make_test_result.pyconverts the Local MCP result into a GitHub Issue Markdown report.- GitHub Actions or Jenkins delivers the report to the original GitHub TEST Request Issue.
- Loads the TEST result JSON.
- Groups tool results by Setup, Test, and Log category.
- Includes the MCP Server name and log paths.
- Renders
results/test-request-comment-<number>.md. - Returns the report to GitHub Actions or Jenkins for Issue commenting.
The bridge does not replace the MCP Server. It selects an MCP Server, calls its tools, and transforms the result for automation reporting.
Two Local MCP Servers
| MCP Server | Mode | Automation Path | Entrypoint |
|---|---|---|---|
mcp-server-local-runner |
runner |
GitHub Actions self-hosted runner | mcp/server_local_runner/server.py |
mcp-server-local-direct |
direct |
Jenkins or direct AI Agent | mcp/server_local_direct/server.py |
The two entrypoints share the same implementation:
mcp/server_local/runtime.py- MCP stdio transport
initialize,tools/list, andtools/call- server and per-tool logging
mcp/server_local/toolsets.py- common tool catalog and handlers
- Setup, Test, and Log tool execution
Shared TEST Tool Extension
- Setup, Test, and Log tools are defined once in
mcp/server_local/toolsets.py. - New tool metadata and a handler extend the shared
TOOL_CATALOG. LOCAL_TOOLSandLOCAL_HANDLERSare generated from that catalog.- Runner MCP and Direct MCP receive the extension together.
- Third-party tool dependencies are declared once in
mcp_requirements.txtand installed by both CT paths.
The server name determines the execution mode and log prefix, while the actual MCP runtime and tools remain shared.
TEST Result and Reporting
| Output | Producer | Consumer |
|---|---|---|
| MCP server log | runtime.py |
artifact and TEST report |
| Per-tool log | runtime.py |
artifact and TEST report |
| TEST result JSON | run_test_request.py |
make_test_result.py and artifact storage |
| Markdown report | make_test_result.py |
GitHub Issue comment |
| GitHub Issue comment | GitHub Actions or Jenkins | User and AI Agent |
The reporting path is deliberately separated from TEST execution:
TEST request
-> Python Bridge
-> MCP Server
-> actual TEST tool
-> JSON + logs
-> Python Bridge
-> Markdown report
-> GitHub Issue comment
Source Alignment Notes
github_pages.yamlis the current GitHub CI/CD workflow and is separate from Issue-based CT. Its current job usesubuntu-latest, not thelocal-devself-hosted runner.test_request_local.yamlis the GitHub Actions CT workflow and explicitly uses thelocal-devself-hosted runner.- The current
Jenkinsfilepasseslocal-directtomake_test_result.py, while the script accepts onlygithub-actionsorjenkins. The Jenkins argument must be changed tojenkinsfor the direct result-rendering step to complete. - Several handlers in
toolsets.pyare currently stubs; the ping handlers execute subprocess-based smoke tests, while flash and log handlers return placeholder results.
Related
- System Design
- MCP Gateway
- MCP Server-Local
- MCP Server-GitHub
- GitHub Templates
- GitHub Self-hosted Runner