Skip to content

Commit 4c19478

Browse files
committed
Add MCP test-code-review & reporting handlers and docs
1 parent 3488484 commit 4c19478

File tree

6 files changed

+362
-19
lines changed

6 files changed

+362
-19
lines changed

docs/MCP_SERVER_ARCHITECTURE.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
**MCP Server Architecture**
2+
3+
**Overview**
4+
5+
This document describes the architecture of the Model Control Plane (MCP) server implemented in this repository. The MCP provides a lightweight HTTP front-end that accepts prompts and workflow requests, orchestrates AI clients and local tools (Playwright bridge), and stores short-term context.
6+
7+
**Components**
8+
9+
- **MCP server (Java):** The entry point that binds HTTP endpoints and dispatches requests to handlers. See [src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java](src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java#L1).
10+
- **Handlers:** Small HttpHandler classes for each endpoint (health, completion, context, generate-page-object, generate-and-run-playwright-test, generate-and-run-selenium-test, correct-code, workflow). See [src/main/java/org/k11techlab/framework/ai/mcp/handlers](src/main/java/org/k11techlab/framework/ai/mcp/handlers/).
11+
- **AI Clients:** Pluggable clients used by handlers to call LLMs or RAG services (RAGEnhancedAIClient, OpenAIClient). These encapsulate prompt formatting, API calls and retry/timeout logic.
12+
- **Playwright bridge (PlaywrightMCPClient):** A process-based JSON-RPC client wrapper that runs `npx @playwright/mcp` and communicates over stdio to control Playwright for browser-driven test execution. See [src/main/java/org/k11techlab/framework/ai/mcp/util/PlaywrightMCPClient.java](src/main/java/org/k11techlab/framework/ai/mcp/util/PlaywrightMCPClient.java#L1).
13+
- **Workflows:** Higher-level orchestration (e.g., PlaywrightWorkflow) that generates a test, runs it, and archives logs/reports. See [src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java](src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java#L1).
14+
- **Context store (MongoContextStore):** Optional persistence for conversation/context objects using MongoDB. Configured via `config/mcp-config.properties`. See [src/main/java/org/k11techlab/framework/ai/mcp/store/MongoContextStore.java](src/main/java/org/k11techlab/framework/ai/mcp/store/MongoContextStore.java#L1).
15+
- **Prompts folder:** `mcp_prompts/` holds prompt files referenced by requests (e.g. `mcp_prompts/k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt`). The server can accept a `promptFile` reference to load prompts server-side.
16+
17+
**Endpoints (summary)**
18+
19+
- `GET /mcp/health` — simple liveness check handled by HealthHandler.
20+
- `POST /mcp/completion` — textual prompt completion using AI client.
21+
- `POST /mcp/generate-page-object` — accept `{ "promptFile":"<relpath>" }` or text and run the page-object generator.
22+
- `POST /mcp/generate-and-run-playwright-test` — generate Playwright code and run it via the Playwright bridge; archives logs to `mcp_testlog/` and `mcp_testreport/`.
23+
- `POST /mcp/generate-and-run-selenium-test` — generate Selenium (Java/TestNG) test and run via Maven/Surefire.
24+
- `POST /mcp/correct-code` — fix or transform submitted code.
25+
26+
See handlers directory for implementation details: [src/main/java/org/k11techlab/framework/ai/mcp/handlers](src/main/java/org/k11techlab/framework/ai/mcp/handlers/).
27+
28+
**Data & control flow (high-level)**
29+
30+
1. Client sends HTTP request to MCP server endpoint (e.g., generate-page-object).
31+
2. Handler validates input, loads prompt text (inline or from `mcp_prompts/`), and prepares LLM input.
32+
3. Handler invokes an AI client (RAG or direct LLM) to generate code (page object or test).
33+
4. For run requests, the handler either:
34+
- writes generated artifacts to disk and calls the Playwright bridge (PlaywrightMCPClient) which runs Playwright and streams test results; or
35+
- generates Java test code and invokes Maven to run the test (Selenium path).
36+
5. Workflow copies outputs to `mcp_testlog/` and `mcp_testreport/` and returns a response with run metadata.
37+
38+
**Configuration**
39+
40+
- `config/mcp-config.properties` controls port, prompt mappings, classNameBase, log.dir and Mongo connection settings. See [config/mcp-config.properties](config/mcp-config.properties#L1).
41+
- Default port observed in the repo is `8090` (property `mcp.port`).
42+
43+
**Runtime requirements**
44+
45+
- Java 17+ / JDK 21 recommended for running the server (project was prepared for Java 21 migration).
46+
- Node.js + Playwright CLI (`npx @playwright/mcp`) for Playwright runs.
47+
- MongoDB if you want persistent context storage (optional; in-memory alternatives may exist).
48+
49+
**Artifacts & logs**
50+
51+
- Generated tests and page objects: `src/test/java/org/k11techlab/framework_unittests/ai_generated/...` (example generated test: [GeneratedPlaywrightLoginTest.java](src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions/GeneratedPlaywrightLoginTest.java#L1)).
52+
- Test run logs: `mcp_testlog/`.
53+
- HTML reports: `mcp_testreport/` and `target/surefire-reports/` for Maven-run tests.
54+
55+
**Troubleshooting notes**
56+
57+
- If endpoints return connection errors, ensure the MCP server process is running and listening on the configured port (look for startup message: "MCP Server started on port <port>").
58+
- Playwright runs require `npx` available in PATH and appropriate browser binaries; run `npx playwright install` if required.
59+
- Check `mcp_testlog/` for Playwright bridge logs and `mcp_testreport/` for HTML test reports after a run.
60+
61+
**Where to look in the code**
62+
63+
- Server bootstrap: [src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java](src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java#L1)
64+
- Handlers: [src/main/java/org/k11techlab/framework/ai/mcp/handlers](src/main/java/org/k11techlab/framework/ai/mcp/handlers/)
65+
- Playwright bridge: [src/main/java/org/k11techlab/framework/ai/mcp/util/PlaywrightMCPClient.java](src/main/java/org/k11techlab/framework/ai/mcp/util/PlaywrightMCPClient.java#L1)
66+
- Playwright orchestration: [src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java](src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java#L1)
67+
- Prompts: `mcp_prompts/` folder (example: [mcp_prompts/k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt](mcp_prompts/k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt#L1)).
68+
69+
**Next steps / improvements (suggested)**
70+
71+
- Harden generated interactions with robust waits / fallback actions in generators (addresses flaky selectors like the "login menu not visible" case).
72+
- Add a small systemd/Windows service script or a Dockerfile to run MCP persistently for CI/demo scenarios.
73+
- Add a health-check and readiness probe endpoint that also verifies Playwright and Mongo availability.

mcp_prompts/k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt

Lines changed: 117 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,123 @@
1-
# Page Object Creation Prompt for HomePage and LoginPage
1+
# Page Object Creation Prompt — site pages and element id mappings
22

33
{
4-
"pageObjects": [
5-
{
6-
"className": "HomePage",
7-
"fields": {
8-
"isDashboardVisible": {"id": "Dashboard", "method": "isVisible"},
9-
"clickServiceLink": {"id": "service", "text": "Service", "method": "click"},
10-
"clickLoginMenu": {"id": "loginMenu", "text": "Login", "method": "click"},
11-
"clickRegisterMenu": {"id": "registerMenu", "text": "Register", "method": "click"}
12-
}
13-
},
14-
{
15-
"className": "LoginPage",
16-
"fields": {
17-
"enterUsername": {"id": "username", "name": "username", "text": "Username", "method": "fill"},
18-
"enterPassword": {"id": "password", "name": "password", "text": "Password", "method": "fill"},
19-
"clickLogin": {"id": "login", "name": "login", "text": "Login", "method": "click"}
20-
}
4+
"pages": {
5+
"frontend/app/home/page.js": {
6+
"container": { "id": "home-hero-section", "type": "section" },
7+
"hero_bg": { "id": "home-hero-bg", "type": "background" },
8+
"hero_content": { "id": "home-hero-content", "type": "container" },
9+
"hero_grid": { "id": "home-hero-grid", "type": "layout" },
10+
"hero_left": { "id": "home-hero-left", "type": "container" },
11+
"hero_announcement": { "id": "home-hero-announcement", "type": "text" },
12+
"hero_title": { "id": "home-hero-title", "type": "heading" },
13+
"hero_description": { "id": "home-hero-description", "type": "text" },
14+
"hero_actions": { "id": "home-hero-actions", "type": "container" },
15+
"explore_services_btn": { "id": "home-explore-services-btn", "type": "link" },
16+
"contact_btn": { "id": "home-contact-btn", "type": "link" },
17+
"hero_benefits": { "id": "home-hero-benefits", "type": "list" },
18+
"benefit_fast": { "id": "home-benefit-fast", "type": "badge" },
19+
"benefit_scalable": { "id": "home-benefit-scalable", "type": "badge" },
20+
"benefit_ai": { "id": "home-benefit-ai", "type": "badge" },
21+
"hero_image_container": { "id": "home-hero-image-container", "type": "container" },
22+
"hero_image": { "id": "home-hero-image", "type": "image" },
23+
"quick_actions_section": { "id": "home-quick-actions-section", "type": "section" },
24+
"quick_actions_container": { "id": "home-quick-actions-container", "type": "container" },
25+
"quick_actions_header": { "id": "home-quick-actions-header", "type": "container" },
26+
"quick_actions_header_content": { "id": "home-quick-actions-header-content", "type": "container" },
27+
"quick_actions_title": { "id": "home-quick-actions-title", "type": "heading" },
28+
"quick_actions_desc": { "id": "home-quick-actions-desc", "type": "text" },
29+
"quick_actions_grid": { "id": "home-quick-actions-grid", "type": "grid" },
30+
"dashboard_link": { "id": "home-dashboard-link", "type": "link" },
31+
"dashboard_card": { "id": "home-dashboard-card", "type": "card" },
32+
"dashboard_card_body": { "id": "home-dashboard-card-body", "type": "container" },
33+
"dashboard_icon": { "id": "home-dashboard-icon", "type": "icon" },
34+
"dashboard_content": { "id": "home-dashboard-content", "type": "container" },
35+
"dashboard_title_row": { "id": "home-dashboard-title-row", "type": "container" },
36+
"dashboard_title": { "id": "home-dashboard-title", "type": "heading" },
37+
"dashboard_arrow": { "id": "home-dashboard-arrow", "type": "icon" },
38+
"dashboard_desc": { "id": "home-dashboard-desc", "type": "text" },
39+
"services_link": { "id": "home-services-link", "type": "link" },
40+
"services_card": { "id": "home-services-card", "type": "card" },
41+
"services_card_body": { "id": "home-services-card-body", "type": "container" },
42+
"services_icon": { "id": "home-services-icon", "type": "icon" },
43+
"services_content": { "id": "home-services-content", "type": "container" },
44+
"services_title_row": { "id": "home-services-title-row", "type": "container" },
45+
"services_title": { "id": "home-services-title", "type": "heading" },
46+
"services_arrow": { "id": "home-services-arrow", "type": "icon" },
47+
"services_desc": { "id": "home-services-desc", "type": "text" }
48+
},
49+
"frontend/app/login/page.js": {
50+
"container": { "id": "login-container", "type": "form-container" },
51+
"title": { "id": "login-title", "type": "heading" },
52+
"error": { "id": "login-error", "type": "text" },
53+
"form": { "id": "login-form", "type": "form" },
54+
"username": { "id": "login-username", "type": "input" },
55+
"password": { "id": "login-password", "type": "input" },
56+
"forgot_password_link": { "id": "login-forgot-password-link", "type": "container" },
57+
"forgot_link": { "id": "login-forgot-link", "type": "link" },
58+
"submit": { "id": "login-submit", "type": "button" },
59+
"register_link": { "id": "login-register-link", "type": "text" },
60+
"register_here": { "id": "login-register-here", "type": "link" }
61+
},
62+
"frontend/app/forgot-password/page.js": {
63+
"container": { "id": "forgot-password-container", "type": "form-container" },
64+
"form": { "id": "forgot-password-form", "type": "form" },
65+
"email": { "id": "forgot-password-email", "type": "input" },
66+
"submit": { "id": "forgot-password-submit", "type": "button" },
67+
"message": { "id": "forgot-password-message", "type": "text" },
68+
"error": { "id": "forgot-password-error", "type": "text" }
69+
},
70+
"frontend/app/reset-password/page.js": {
71+
"container": { "id": "reset-password-container", "type": "form-container" },
72+
"title": { "id": "reset-password-title", "type": "heading" },
73+
"message": { "id": "reset-password-message", "type": "text" },
74+
"error": { "id": "reset-password-error", "type": "text" },
75+
"form": { "id": "reset-password-form", "type": "form" },
76+
"password": { "id": "reset-password-password", "type": "input" },
77+
"confirm": { "id": "reset-password-confirm", "type": "input" },
78+
"submit": { "id": "reset-password-submit", "type": "button" }
79+
},
80+
"frontend/app/register/page.js": {
81+
"container": { "id": "register-container", "type": "form-container" },
82+
"title": { "id": "register-title", "type": "heading" },
83+
"error": { "id": "register-error", "type": "text" },
84+
"success": { "id": "register-success", "type": "text" },
85+
"form": { "id": "register-form", "type": "form" },
86+
"username": { "id": "register-username", "type": "input" },
87+
"email": { "id": "register-email", "type": "input" },
88+
"password": { "id": "register-password", "type": "input" },
89+
"subscription": { "id": "register-subscription", "type": "select" },
90+
"submit": { "id": "register-submit", "type": "button" }
91+
},
92+
"frontend/app/contact/page.js": {
93+
"container": { "id": "contact-container", "type": "form-container" },
94+
"title": { "id": "contact-title", "type": "heading" },
95+
"form": { "id": "contact-form", "type": "form" },
96+
"name": { "id": "contact-name", "type": "input" },
97+
"email": { "id": "contact-email", "type": "input" },
98+
"message": { "id": "contact-message", "type": "textarea" },
99+
"submit": { "id": "contact-submit", "type": "button" },
100+
"sent": { "id": "contact-sent", "type": "text" }
101+
},
102+
"frontend/app/services/page.js": {
103+
"container": { "id": "services-container", "type": "container" },
104+
"title": { "id": "services-title", "type": "heading" }
105+
},
106+
"frontend/app/about/page.js": {
107+
"container": { "id": "about-container", "type": "container" },
108+
"title": { "id": "about-title", "type": "heading" }
109+
},
110+
"frontend/app/insights/page.js": {
111+
"container": { "id": "insights-container", "type": "container" }
112+
},
113+
"frontend/app/dashboard/page.js": {
114+
"container": { "id": "dashboard-container", "type": "container" },
115+
"title": { "id": "dashboard-title", "type": "heading" },
116+
"welcome": { "id": "dashboard-welcome", "type": "text" },
117+
"email": { "id": "dashboard-email", "type": "text" },
118+
"logout": { "id": "dashboard-logout", "type": "button" }
21119
}
22-
]
120+
}
23121
}
24122

25123
- Use id as the first preference, then name, then text for selectors.

scripts/test_mcp.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# Test MCP endpoints script
5+
# Usage: MCP_PORT=8090 MCP_HOST=http://localhost ./scripts/test_mcp.sh
6+
7+
HOST=${MCP_HOST:-http://localhost}
8+
PORT=${MCP_PORT:-8090}
9+
BASE="$HOST:$PORT/mcp"
10+
11+
echo "Using MCP at $BASE"
12+
13+
echo "\n=== /mcp/health ==="
14+
curl -sS "$BASE/health" || true
15+
16+
echo "\n=== /mcp/workflow ==="
17+
curl -sS -X POST "$BASE/workflow" -H "Content-Type: text/plain" -d "Run login workflow for test user" || true
18+
19+
# Sample broken Java for /mcp/correct-code
20+
BROKEN_JAVA='public class X { public static void main(String[] args) { System.out.println("hi") } }'
21+
22+
echo "\n=== /mcp/correct-code ==="
23+
curl -sS -X POST "$BASE/correct-code" -H "Content-Type: text/plain" -d "$BROKEN_JAVA" || true
24+
25+
# Read page object prompt file from repository and post it to MCP
26+
PROMPT_REL="k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt"
27+
PROMPT_FILE="mcp_prompts/$PROMPT_REL"
28+
29+
if [ -f "$PROMPT_FILE" ]; then
30+
echo "\n=== /mcp/generate-page-object (using promptFile reference) ==="
31+
# Instruct server to load the prompt file from its mcp-prompts folder
32+
curl -sS -X POST "$BASE/generate-page-object" -H "Content-Type: application/json" -d "{\"promptFile\":\"$PROMPT_REL\"}" || true
33+
34+
# Extract human-readable instruction lines (bulleted lines starting with '-') and send to completion endpoint
35+
INSTRUCTIONS=$(awk '/^- /{flag=1} flag{print}' "$PROMPT_FILE" | sed 's/^- //') || true
36+
if [ -n "$INSTRUCTIONS" ]; then
37+
echo "\n=== /mcp/completion (text prompt from file instructions) ==="
38+
curl -sS -X POST "$BASE/completion" -H "Content-Type: text/plain" -d "$INSTRUCTIONS" || true
39+
fi
40+
else
41+
echo "\nPrompt file not found: $PROMPT_FILE — skipping generate-page-object requests"
42+
fi
43+
44+
# Generate and run tests (playwright + selenium)
45+
echo "\n=== /mcp/generate-and-run-playwright-test ==="
46+
curl -sS -X POST "$BASE/generate-and-run-playwright-test?engine=playwright&packageName=org.k11techlab.framework_unittests.ai_generated.k11softwaresolutions" -H "Content-Type: text/plain" -d "Open login page and sign in" || true
47+
48+
echo "\n=== /mcp/generate-and-run-selenium-test ==="
49+
curl -sS -X POST "$BASE/generate-and-run-selenium-test?engine=selenium&packageName=org.k11techlab.framework_unittests.ai_generated.k11softwaresolutions" -H "Content-Type: text/plain" -d "Open login page and sign in" || true
50+
51+
# Done
52+
53+
echo "\nAll MCP endpoint checks completed."

src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public void start(int port) throws IOException {
3030
server.createContext("/mcp/generate-and-run-selenium-test", new GenerateAndRunTestHandler());
3131
server.createContext("/mcp/generate-and-run-playwright-test", new GenerateAndRunTestHandler());
3232
server.createContext("/mcp/generate-page-object", new GeneratePageObjectHandler());
33+
server.createContext("/mcp/test-code-review", new TestCodeReviewHandler(aiClient));
34+
server.createContext("/mcp/report", new ReportingHandler());
3335

3436
server.setExecutor(null);
3537
server.start();

0 commit comments

Comments
 (0)