REST API
Reference for the FastAPI endpoints exposed by test_server.py on port 8083.
All endpoints accept and return JSON unless noted.
|
Auth model. In the multi-stand deployment every request enters through the
gateway ( |
Gateway
These endpoints are served by the gateway itself (gateway_service/app.py),
not proxied to a worker. They handle login, central account / stand / env-profile
management, and run dispatch onto a worker pool. Cross-ref: Environments & the Gateway
and Accounts, Roles & Audit.
Auth
| Method | Path | Purpose |
|---|---|---|
POST |
|
Authenticate. Body |
POST |
|
Invalidate the caller’s session token. Allowlisted. |
GET |
|
Current session identity |
Users (admin)
| Method | Path | Purpose |
|---|---|---|
GET |
|
List all accounts. |
POST |
|
Create an account. Body |
POST |
|
Set a new password. Body |
DELETE |
|
Delete an account. |
Audit (admin)
| Method | Path | Purpose |
|---|---|---|
GET |
|
Central activity / audit log. Query: |
Env Profiles
Profiles are named bundles of worker settings (emulator_url, ACS URL, …)
that the gateway materialises onto a worker at dispatch time.
| Method | Path | Purpose |
|---|---|---|
GET |
|
List env profiles (any authenticated user). |
POST |
|
Create / replace a profile. Body |
GET |
|
Full profile settings (admin). |
DELETE |
|
Delete a profile. |
Stands / Workers (admin)
| Method | Path | Purpose |
|---|---|---|
GET |
|
List worker stands. |
POST |
|
Register / upsert a stand. Body |
PATCH |
|
Update a stand (e.g. |
DELETE |
|
Deregister a stand. |
POST |
|
Auto-provision a new worker stack via Portainer. Body |
Run Dispatch
| Method | Path | Purpose |
|---|---|---|
POST |
|
Materialise |
POST |
|
Same, for a batch. Body |
GET |
|
Name of the worker running the caller’s own active run (so "Live Browser" connects to the right noVNC). Returns `{stand: name |
| The gateway proxies the worker endpoints in the sections below per-caller and owner-scopes them (see Runs). Batch-status, per-run reads, WebSocket and stop are fanned out across the worker pool so they reach the caller’s run on whichever worker it landed. |
Test Cases
| Method | Path | Purpose |
|---|---|---|
GET |
|
List all YAML cases. Returns |
GET |
|
Parsed JSON view of a single case. |
GET |
|
Raw YAML text of a case. |
POST |
|
Create a new case from a JSON body. |
PUT |
|
Replace an existing case. |
POST |
|
Regenerate |
POST |
|
Upload a hand-edited YAML file. |
DELETE |
|
Delete a case. |
DELETE |
|
Delete all cases (reset volume). |
GET |
|
Distinct values of |
Case Organization
Projects and per-case org fields (project, references, priority, type) used to group and filter cases in the editor. See Organizing Cases: Projects & Sections for the user-facing workflow.
| Method | Path | Purpose |
|---|---|---|
GET |
|
List projects, each with a |
POST |
|
Create a project. Body |
PATCH |
|
Rename ( |
DELETE |
|
Delete a project; its cases are orphaned to Unassigned ( |
POST |
|
Bulk-assign cases to a project. Body |
GET |
|
Read-only, non-secret UI config (currently |
POST |
|
Backfill org fields (project, references, priority, type) from TestRail into local YAMLs — no conversion / Stage 2 / cache bump. Body |
Trees
XML tree files live under /opt/mcp-shared/ on the test-runner host and are
referenced from each YAML’s emulator_setup.tree_file. The editor’s Tree
File dropdown is populated from these endpoints.
| Method | Path | Purpose |
|---|---|---|
GET |
|
List |
POST |
|
Upload an |
DELETE |
|
Delete an |
# List
curl -s http://ai.friendly-tech.com:8083/api/trees | python -m json.tool
# Upload (or replace)
curl -F "file=@./181.xml" http://ai.friendly-tech.com:8083/api/trees/upload
Uploads are accepted only for .xml. Path traversal attempts (../, \\,
/) and dot-aliases (., ..) are rejected with HTTP 400.
|
Runs
| Method | Path | Purpose |
|---|---|---|
POST |
|
Start a single run. Query parameters: |
POST |
|
Force-stop the caller’s own run (owner-scoped, no body). Not "all runs" — through the gateway it fans out to every worker so it reaches the caller’s run wherever it landed. |
POST |
|
Start a batch. Body: |
GET |
|
Current batch status. Returns |
GET |
|
Latest in-memory batch report JSON. |
GET |
|
List archived batch reports as |
GET |
|
Full archived batch report (summary + per-test results). |
DELETE |
|
Wipe archived reports on disk. |
GET |
|
Last 100 run summaries (in-memory). |
GET |
|
List of run-ids currently in |
GET |
|
Full report for one run. |
DELETE |
|
Clear in-memory run registry. |
|
Owner isolation. Run reads, batch reports, WebSocket attach and stop are
owner-scoped — a run is visible only to the account that started it
( |
POST /api/run uses query parameters, not a JSON body. Curl example:
|
curl -X POST "http://ai.friendly-tech.com:8083/api/run?test_file=C7677.yaml&model=opus"
GET /api/runs/{run_id} is the canonical poll endpoint — returns:
{
"run_id":"...",
"test_id":"C7677",
"title":"...",
"status":"passed|failed|error|running",
"elapsed_ms":42031,
"phase":"loading|pages|executing|parsing|done",
"steps":[{"step":1,"status":"pass","description":"..."}],
"report":{"status":"passed", "steps":[...]},
"output":"...",
"mcpLog":[...]
}
WebSocket
WS /ws/run/{run_id} — streams live updates for a run (steps, output append,
MCP log). Same payload shape as GET /api/runs/{run_id} but pushed.
TestRail Integration
| Method | Path | Purpose |
|---|---|---|
GET |
|
Connection check. |
GET |
|
List projects. |
GET |
|
Query: |
GET |
|
Query: |
POST |
|
Preview converter output without writing. |
POST |
|
Batch import. Body: |
POST |
|
Single reimport. Body: |
POST |
|
Trigger the auto-sync loop programmatically. Periodic refresh is driven by the |
XML Import (API only — no UI)
The XML paste / batch modals were removed from the Editor; the converter is still callable over HTTP for air-gapped or read-only TestRail accounts. See Importing Tests → XML Import API.
| Method | Path | Purpose |
|---|---|---|
POST |
|
Convert a single |
POST |
|
Convert and persist a full XML export. Body: |
POST |
|
Convert + run a |
Tools
| Method | Path | Purpose |
|---|---|---|
POST |
|
NL → TR-181 tree via |
POST |
|
Run |
GET |
|
Probe each MCP server. Returns |
GET |
|
Detailed MCP diagnostic dump (per-server URLs, last error, last successful tool list). |
Settings
| Method | Path | Purpose |
|---|---|---|
GET |
|
Current persisted settings. |
PUT |
|
Replace settings. Body: full settings JSON. |
DELETE |
|
Wipe UI overrides; effective values fall back to docker-compose env vars and then to hardcoded defaults. |
Admin / Ops
Ops endpoints used by the test-runner UI and by the host-side credential
refresh script. They lean on Portainer (PORTAINER_URL /
PORTAINER_USERNAME / PORTAINER_PASSWORD env vars) and return 503 when
that wiring is missing.
| Method | Path | Purpose |
|---|---|---|
POST |
|
Restart the sibling |
GET |
|
Lightweight probe so the UI can hide the Restart button when Portainer env is unset. Returns |
GET |
|
Inspect on-disk Claude CLI credentials. Returns |
POST |
|
Push fresh |
POST |
|
Push the current |
QA Validation Notes
Source-of-truth YAMLs at /data/qa-notes/<id>.yaml on the qa-notes
volume. Each save fires a webhook to knowledge-mcp/admin/refresh-notes
that re-pulls and re-embeds. See QA Validation Notes for the user-facing
workflow.
| Method | Path | Purpose |
|---|---|---|
GET |
|
List notes with filters. Query params: |
GET |
|
One full note (body untruncated, all auto-fields populated). |
POST |
|
Create. Body shape mirrors the YAML schema: |
PUT |
|
Full replace. Same body as POST plus an optional |
DELETE |
|
Soft-deprecate by default (file stays on disk with |
POST |
|
Manual webhook trigger. Returns |
GET |
|
All notes (incl. deprecated) in the on-disk YAML shape. Used by |
GET |
|
Allowlists for UI dropdowns: |
scope.global is serialised as the YAML key global (a Python
keyword). The Pydantic model exposes it as is_global internally but
the REST contract uses the plain global alias both inbound and
outbound. The same shape is what /api/notes/raw returns to
knowledge-mcp.
|
# Create a note targeting one case
curl -X POST http://ai.friendly-tech.com:8083/api/notes \
-H 'Content-Type: application/json' \
-d '{
"title":"Monitoring Health flap 70/80",
"body":"ft-device-network DeviceParameterStorageService is incremental-only...",
"scope":{"test_ids":["C7626"],"widgets":["Monitoring"],"kpi_types":["monitoring"],"topologies":[],"global":false},
"severity":"warning",
"status":"active",
"tags":["flap","clickhouse"]
}'
# Search via knowledge-mcp (scope-filtered)
curl -X POST http://ai.friendly-tech.com:7030/search/qa_notes \
-H 'Content-Type: application/json' \
-d '{"query":"Health flap","test_id":"C7626","limit":3}'
# Manual reindex
curl -X POST http://ai.friendly-tech.com:8083/api/notes/reindex