CXA MCP Server
# CXA MCP Server
> **Model Context Protocol server for CX Assurance** – exposes an AI-accessible performance tool that lets any MCP-compatible agent (GitHub Copilot, Claude, Cursor, etc.) run real browser-based performance scans and receive a rich dashboard report.
---
## Table of Contents
1. [Overview](#overview)
2. [Architecture](#architecture)
3. [Project Structure](#project-structure)
4. [Available Tools](#available-tools)
5. [Getting Started](#getting-started)
6. [Configuration](#configuration)
7. [Running the Server](#running-the-server)
8. [Testing](#testing)
9. [Adding New Tool Categories](#adding-new-tool-categories)
10. [MCP Client Configuration](#mcp-client-configuration)
11. [Logging](#logging)
12. [Sample Performance Payload](#sample-performance-payload)
---
## Overview
The CXA MCP Server is a **self-contained performance scanning engine** powered by Puppeteer.
An agent can ask _"Run a performance scan on https://example.com"_ and receive a rich Markdown dashboard covering:
- **Core Web Vitals** – Load time, Speed Index (fixed – never negative), TTFB, FCP, DOM Content Loaded, Transfer Size
- **Performance grades** – A+ through F per Web Vitals thresholds
- **Visual load bars** – ASCII progress bars for quick visual comparison
- **Omni-channel results** – Real load times across 6 browser/device profiles with per-profile grades
- **Mobile vs Desktop comparison** – Average load time delta and % slower
- **Actionable recommendations** – Targeted suggestions based on actual metric values
> **Scope:** Performance only. Accessibility, SEO, and security data are intentionally excluded from this tool. No external API is called – all scanning is done locally with a real Chromium browser.
---
## Architecture
```
Agent (Copilot / Claude / Cursor …)
│
│ JSON-RPC 2.0 (stdio)
▼
┌─────────────────────────────┐
│ MCP Server (stdio) │
│ src/server.js │
│ │
│ ┌──────────────────────┐ │
│ │ Tool Registry │ │ ← src/tools/index.js
│ │ performanceTool.js │ │ ← src/tools/performanceTool.js
│ └──────────┬───────────┘ │
│ │ │
│ ┌──────────▼───────────┐ │
│ │ Service Layer │ │ ← src/services/performanceService.js
│ └──────────┬───────────┘ │
│ │ orchestrates │
│ ┌──────────▼───────────┐ │
│ │ Scanners │ │ ← loadTimeScanner + performanceScanner only
│ └──────────┬───────────┘ │
│ │ │
│ ┌──────────▼───────────┐ │
│ │ Browser Runner │ │ ← Puppeteer / Chromium
│ └──────────────────────┘ │
└─────────────────────────────┘
│ headless Chromium
▼
Target Web Page
```
**Key design decisions:**
| Concern | Decision |
|---------|----------|
| Transport | `stdio` – required by the MCP spec for local server ↔ agent communication |
| Logging | Always `stderr` – stdout is reserved for the JSON-RPC transport |
| Tool isolation | Each domain (performance, accessibility …) lives in its own file |
| No external HTTP library | Node ≥ 18 native `fetch` – keeps the dependency list minimal |
| Error handling | All tool handlers return structured error text instead of throwing, so the agent always receives a readable response |
| Scope | Performance-only – accessibility, SEO, security scanners exist but are not wired into `cxa_scan_performance` |
---
## Project Structure
```
mcp-cxa/
├── .env.example # Environment variable template
├── .gitignore
├── package.json
├── README.md # ← you are here
│
├── performance-samples/ # Reference data & API docs
│ ├── performance_result.json
│ └── performance-details.md
│
├── src/
│ ├── server.js # Entry point – bootstraps MCP server
│ ├── config/
│ │ └── index.js # Centralised config (env-driven)
│ ├── tools/
│ │ ├── index.js # Central tool registry
│ │ └── performanceTool.js # Performance MCP tool definitions
│ ├── services/
│ │ └── performanceService.js # Business logic / API calls
│ └── utils/
│ ├── logger.js # Structured stderr logger
│ ├── httpClient.js # fetch wrapper with timeout & error handling
│ └── formatters.js # Raw payload → Markdown report
│
└── tests/
├── config/
│ └── index.test.js
├── services/
│ └── performanceService.test.js
└── utils/
├── formatters.test.js
└── logger.test.js
```
---
## Available Tools
### `cxa_scan_performance`
Runs a **real browser-based performance scan** for any URL and returns a rich Markdown dashboard.
| Parameter | Type | Required | Default | Description |
|-----------|--------|----------|----------|-------------|
| `url` | string | ✅ | – | Fully-qualified URL to scan |
| `region` | string | ❌ | `Local` | Label stamped on the report |
**Returns:** Rich Markdown performance dashboard including:
- Score card with grades (A+–F) for load time, TTFB, FCP
- ASCII visual load bars
- Omni-channel table (6 profiles: Chrome, Edge, Firefox, Safari, Android Chrome, iOS Safari)
- Mobile vs Desktop comparison
- Actionable recommendations
> **Note:** Accessibility, SEO, and security are **not** included in this tool's output.
---
## Getting Started
### Prerequisites
- Node.js **≥ 18.0.0** (for native `fetch` and `--test` runner)
- Chromium / Puppeteer (installed automatically via `npm install`)
### Install
```bash
cd mcp-cxa
npm install
```
### Configure
```bash
cp .env.example .env
# Edit .env if needed – no API key required
```
---
## Configuration
All configuration is read from environment variables (see `.env.example`):
| Variable | Default | Description |
|-----------------------|-----------|-------------|
| `CXA_SCAN_TIMEOUT_MS` | `30000` | Page load timeout per profile (ms) |
| `CXA_HEADLESS` | `true` | Set `false` to watch Chromium during dev |
| `CXA_DEFAULT_REGION` | `Local` | Region label stamped on results |
| `CXA_LOG_LEVEL` | `info` | `debug` / `info` / `warn` / `error` |
> No `CXA_API_BASE_URL` or `CXA_API_TOKEN` are needed – all scanning is self-contained.
---
## Running the Server
```bash
# Production
npm start
# Development (auto-restart on file change – Node ≥ 18.11)
npm run dev
```
> **Note:** The server communicates over **stdio**. You should not see any output on stdout; all log lines appear on stderr as newline-delimited JSON.
---
## Testing
Tests use Node's built-in test runner (`node:test`) – no additional test framework required.
```bash
# Run all tests once
npm test
# Run tests in watch mode
npm run test:watch
```
### Test coverage by module
| Module | Test file |
|--------|-----------|
| `src/config/index.js` | `tests/config/index.test.js` |
| `src/utils/logger.js` | `tests/utils/logger.test.js` |
| `src/utils/formatters.js` | `tests/utils/formatters.test.js` |
| `src/services/performanceService.js` | `tests/services/performanceService.test.js` |
The HTTP client and MCP tool wiring are tested indirectly through the service tests (the HTTP client is stubbed so no real network calls are made).
---
## Adding New Tool Categories
The server is designed to grow. To add, say, an **Accessibility** tool:
1. **Create the service**
```
src/services/accessibilityService.js
```
Export `getAccessibilitySummary(projectId)` and any other methods.
2. **Create the tool file**
```
src/tools/accessibilityTool.js
```
Export `registerAccessibilityTools(server)` following the same pattern as `performanceTool.js`.
3. **Register it in the central registry**
```js
// src/tools/index.js
const { registerAccessibilityTools } = require('./accessibilityTool');
// ...
function registerAllTools(server) {
registerPerformanceTools(server);
registerAccessibilityTools(server); // ← add this line
}
```
4. **Add a formatter** (optional) in `src/utils/formatters.js`.
5. **Write tests** under `tests/services/` and `tests/utils/`.
---
## MCP Client Configuration
### VS Code (GitHub Copilot)
Add the following to your VS Code `settings.json` or `.vscode/mcp.json`:
```json
{
"servers": {
"cxa-mcp": {
"type": "stdio",
"command": "node",
"args": ["${workspaceFolder}/mcp-cxa/src/server.js"],
"env": {
"CXA_LOG_LEVEL": "info"
}
}
}
}
```
### Claude Desktop (`claude_desktop_config.json`)
```json
{
"mcpServers": {
"cxa-mcp": {
"command": "node",
"args": ["/absolute/path/to/mcp-cxa/src/server.js"],
"env": {
"CXA_LOG_LEVEL": "info"
}
}
}
}
```
---
## Logging
All log entries are written to **stderr** as newline-delimited JSON:
```json
{"timestamp":"2026-03-13T06:27:31.123Z","level":"INFO","message":"CXA MCP Server is running – listening on stdio"}
{"timestamp":"2026-03-13T06:27:32.456Z","level":"INFO","message":"Tool invoked: cxa_scan_performance","meta":{"url":"https://example.com","region":"Local"}}
```
Set `CXA_LOG_LEVEL=debug` to see every browser navigation event.
---
## Sample Performance Payload
The backend returns a JSON object of the following shape (see `performance-samples/performance_result.json`):
```json
{
"url": "https://www.sammonsfinancialgroup.com/",
"executionId": "464a1bd3-45c8-4390-a31a-5ef779e81ca1",
"timestamp": "2026-03-13T06:27:31.820822Z",
"browser": "Chrome",
"region": "Virginia",
"speedIndex": "0.02 s",
"uiux": "",
"sustainabilityScore": "",
"accessibility": "",
"seoScore": "",
"security": "",
"omniChannel": [
{ "Browser": "Windows 11 - Chrome", "loadTime": 1229, "version": "125" },
{ "Browser": "Android 14 - Chrome", "loadTime": 2058, "version": "14" }
]
}
```
The formatter converts this into a structured Markdown table report that agents can render or summarise for end users.
---
## API Endpoint Reference
| Method | Path | Description |
|--------|------|-------------|
| GET | `/test/reports/getSummaryDetails?projectId=<id>` | Fetch latest scan summary |
| POST | `/test/scan/trigger` | Trigger a new scan _(extend when live)_ |
TDQS
Scored across 1 tool
There is only one tool, so there is no risk of selecting the wrong tool or confusing it with another operation. Its purpose is clearly stated as a performance-only scan.
The single tool name cxa_scan_performance uses a clear snake_case verb_noun pattern consistent with MCP naming conventions. With no other tools, there is no inconsistency to assess.
A single tool feels thin for a server surface, even though the scope is narrowly defined as performance scanning. It borders on under-scoped but is defensible for a very specific, single-purpose scanner.
The tool covers performance measurement across multiple browser/device profiles and returns a rich dashboard, matching the stated performance-only scope. Minor gaps exist around configuration, historical comparison, or export options, but core performance scanning is complete.