Alexa+ Add-on Local Inspector
The Local Inspector is a command-line tool that lets you connect to your MCP server, call its tools, and instantly see how the resulting UI widgets render inside Alexa device frames, before you submit anything for review.
Instead of discovering rendering problems during the review process, you catch them in your own development loop: inspect, fix, re-inspect, as many times as you need.
The inspector runs as a local proxy between your AI coding agent and your MCP server. Your agent drives the MCP calls; the inspector captures the traffic, renders the widget, and produces a readiness report automatically.
What it does
The Local Inspector supports two analysis modes. You can run either or both in a single session:
| Mode | What it checks |
|---|---|
| Visual rendering | Renders your widget inside Alexa device frames, screenshots every device surface, and evaluates visual, accessibility, and UI quality rules |
| MCP data-layer | Inspects tool definitions, request/response payloads, errors, and latency for correctness and quality (no UI required) |
At the end of a run, the inspector writes two output files:
inspection-summary.json: a full record of what was tested, with per-tool results and screenshotscertification-verdict.json: a structured pass/fail verdict against the production-readiness checklist
Prerequisites
| Requirement | Notes |
|---|---|
| Node.js 24+ | Required to run the CLI |
@alexa-ai/addon-local-inspector CLI |
Install instructions below |
Playwright CLI (@playwright/cli) |
Required for visual analysis only; not needed for data-layer analysis |
| A running MCP server | Must be reachable at an http:// or https:// endpoint |
ui:// resource (_meta.ui.resourceUri) for the widget rendering path to work. Tools that return data only (no ui:// resource) can still be assessed using the data-layer analysis mode.Installation
Log in to the Developer Console and follow the steps in the Getting Started guide. The Getting Started guide walks you through installing the CLI, downloading the agent skills, and loading the inspector skill into your coding agent.
Quick start
Step 1: Start the CLI, pointing it at your MCP server:
addon-local-inspector https://your-mcp-server.example.com/mcp
The Inspector UI opens in your browser automatically. Leave it open.
Step 2: Load the inspector skill into your coding agent. The Getting Started guide covers exactly how to do this for your agent. Once loaded, your agent knows the full inspection workflow.
Step 3: Ask your agent to run an inspection. For example: "Inspect my MCP server and check its readiness." Your agent takes it from there: it calls your tools, renders the widget in the UI, takes screenshots, and produces the readiness report. You watch the browser UI as it works and confirm tool parameters when prompted.
Custom ports (if the defaults conflict with other local services):
addon-local-inspector https://your-mcp-server.example.com/mcp --server-port 8080 --client-port 8081
CLI reference
addon-local-inspector <url> [options]
Arguments
| Argument | Description |
|---|---|
<url> |
Your MCP server endpoint (http:// or https://) |
Options
| Flag | Default | Description |
|---|---|---|
--server-port <port> |
6277 |
Port for the MCP proxy |
--client-port <port> |
6274 |
Port for the Inspector UI |
--verbose |
off | Enable verbose proxy logging |
-h, --help |
- |
Show help |
localhost. Both the proxy and the UI bind to 127.0.0.1 and reject requests from any other origin, protecting you from DNS-rebinding attacks while developing locally. Remote http:// (non-TLS) upstreams are rejected; only loopback http:// addresses are allowed for local dev servers. Remote servers must use https://.How the three pieces fit together
The Local Inspector has three components that work together. Understanding the role of each one will help you get set up and interpret what's happening during an inspection.
1. The inspector skill
The inspector skill is an instruction document that you load into your AI coding agent (Claude, Kiro, Cursor, or any compatible agent). It tells your agent exactly how to run an inspection: which MCP protocol calls to make, in what order, how to capture screenshots, and how to generate the readiness report. You don't write any of this logic yourself.
2. Your coding agent
Once it has the skill loaded, your coding agent drives the entire inspection automatically. It initializes the MCP session, discovers your tools, loads the widget HTML, calls tools, captures screenshots across device surfaces, and writes the output files. Your only manual step is confirming tool parameters before each call; your agent will prompt you.
3. The inspector CLI and UI
The CLI (addon-local-inspector) starts two things locally: a proxy that sits between your agent and your MCP server, and a browser UI that renders your widgets live inside Alexa device frames. Your browser opens automatically when you start the CLI. Leave it open; it updates in real time as your agent works.
Your role vs. your agent's role:
| You do | Your coding agent does |
|---|---|
Start the CLI (addon-local-inspector <url>) |
Initialize the MCP session |
| Load the inspector skill into your coding agent | Discover and call your tools |
| Watch the Inspector UI in your browser | Load widget HTML and trigger rendering |
| Confirm tool parameters when your agent asks | Capture screenshots across device surfaces |
| Review the readiness report | Write certification-verdict.json and inspection-summary.json |
Proxy endpoints
These endpoints are available on the proxy port (default 6277):
| Endpoint | Description |
|---|---|
POST /mcp |
Forward a JSON-RPC request to your MCP server |
GET /mcp |
Server-to-client SSE stream for server-initiated messages |
DELETE /mcp |
Terminate the MCP session |
GET /events |
SSE stream for the Inspector UI (tool discovery, widget updates, errors) |
GET /health |
Returns {"status":"ok"} after initialize, {"status":"not-ready"} before |
GET /state |
Full state snapshot (useful for scripting and data-layer analysis) |
Simplified JSON responses
By default, MCP servers return SSE-framed responses. The proxy unwraps them for you when you send Accept: application/json:
# Clean JSON — no SSE parsing needed
curl -s http://localhost:6277/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
# → {"result":{...},"jsonrpc":"2.0","id":1}
What your agent does: step by step
Step 1: Start the proxy and open the UI
You run this command to start the inspector:
addon-local-inspector https://your-mcp-server.example.com/mcp
The Inspector UI opens in your browser. Your agent reads these values from the CLI startup output:
MCP proxy listening at http://localhost:<port>: the proxy portInspector UI available at http://localhost:<port>: the UI portDevice surface buttons: [...]: the list of device surfaces to screenshot (visual mode)
Step 2: Initialize the MCP session
curl -s -D /tmp/inspector-live/init-headers.txt \
-X POST http://localhost:6277/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <your-token>' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"addon-local-inspector","version":"1.0.0"}}}'
Extract the session ID from the response headers — include it on every subsequent request:
grep -i 'mcp-session-id' /tmp/inspector-live/init-headers.txt
Then send notifications/initialized:
curl -s -X POST http://localhost:6277/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <your-token>' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
Step 3: Discover tools
curl -s -X POST http://localhost:6277/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <your-token>' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
> /tmp/inspector-live/tools.json
Tools that include a ui:// resource URI in their metadata (_meta.ui.resourceUri) support visual rendering. Tools without it can still be assessed via data-layer analysis.
Step 4: Load the widget HTML (visual mode only)
This must happen before any tools/call. It loads the widget into the device frame so it's ready to receive tool results:
curl -s -X POST http://localhost:6277/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <your-token>' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"<ui-resource-uri>"}}'
You only need to do this once per session. After the widget is loaded, each subsequent tool call updates it in place.
Step 5: Call a tool
curl -s -X POST http://localhost:6277/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <your-token>' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"<tool-name>","arguments":{...}}}' \
> /tmp/inspector-live/tool-result.json
The widget in your browser updates automatically. Switch between device surfaces using the buttons in the UI to see how your widget adapts.
Step 6: Screenshot device surfaces (visual mode only)
Use the Playwright CLI to capture screenshots of every device surface listed in the CLI startup output. Screenshots are taken in a separate headless session; your browser window is never disturbed.
# Open a headless analysis session at the device panel popout
npx @playwright/cli -s="analysis-session" open "http://localhost:6274/?popout=1&panel=device"
npx @playwright/cli -s="analysis-session" resize 3840 2160
# Click a device surface button and screenshot
npx @playwright/cli -s="analysis-session" click "getByRole('button', { name: '<surface-label>' })"
sleep 2
npx @playwright/cli -s="analysis-session" screenshot \
--filename="/tmp/inspector-live/screenshots/<tool-name>-<surface-key>-<timestamp>.png"
# Close when done
npx @playwright/cli -s="analysis-session" close
Repeat the click-and-screenshot block for every surface listed in Device surface buttons from the startup output.
Step 7: Review the verdict
The inspector produces two JSON files in your working directory:
certification-verdict.json — structured pass/fail per rule:
{
"verdict": "CERTIFIED | CONDITIONAL | NOT_CERTIFIED",
"passCount": 0,
"failCount": 0,
"warnCount": 0,
"rules": [
{
"id": "VR-01",
"category": "visual",
"status": "PASS | FAIL | WARN",
"surfaces": { "<surface-key>": "PASS | FAIL | WARN" },
"notes": "..."
}
],
"screenshotPaths": ["..."]
}
inspection-summary.json — full record of the session:
{
"serverUrl": "https://your-mcp-server.example.com/mcp",
"analysisScope": ["visual", "mcp-data"],
"tools": [{ "name": "...", "hasUi": true, "uiResourceUri": "ui://..." }],
"calls": [{ "tool": "...", "arguments": {}, "succeeded": true }],
"screenshots": ["..."],
"certification": { "...copy of certification-verdict.json..." }
}
Verdict meanings:
| Verdict | Meaning |
|---|---|
CERTIFIED |
All evaluated rules pass across all device surfaces |
CONDITIONAL |
Warnings exist but no hard failures |
NOT_CERTIFIED |
One or more rules fail; review the blocking issues in rules[] |
Device surfaces
The inspector evaluates your widget against two Alexa screen breakpoints:
| Surface | Screen size |
|---|---|
| Small | 10" and below |
| Large | 11" and above |
Your widget must render correctly on both surfaces to meet the visual requirements for certification.
Output files
All files are written to a fixed working directory:
- macOS / Linux:
/tmp/alexaplus-addon-local-inspector-live/ - Windows:
%TEMP%\alexaplus-addon-local-inspector-live\
| File | Written by | Description |
|---|---|---|
tools.json |
Step 3 | Full tools/list response |
tool-result.json |
Step 5 | Latest tools/call response (overwritten each call) |
screenshots/ |
Step 6 | One PNG per tool × device surface (accumulate across runs) |
state.json |
Data-layer analysis | Full proxy state snapshot |
certification-verdict.json |
Readiness analysis | Structured verdict against the checklist |
inspection-summary.json |
Final report | Complete session summary |
Platform compatibility
Commands in this guide use Bash/Zsh syntax (macOS/Linux). On Windows, use these equivalents:
| Unix | Windows (cmd) | Windows (PowerShell) |
|---|---|---|
/tmp/ |
%TEMP%\ |
$env:TEMP\ |
lsof -ti :<port> -sTCP:LISTEN |
netstat -ano \| findstr "LISTENING" \| findstr :<port> |
same |
kill <pid> |
taskkill /PID <pid> /F |
same |
sleep <n> |
— | Start-Sleep -Seconds <n> |
mkdir -p |
— | New-Item -ItemType Directory -Force |
grep |
— | Select-String |
python3 |
python |
same |
2>/dev/null |
2>NUL |
2>$null |
Troubleshooting
Widget is blank after a tool call
You must run resources/read (Step 4) before the first tools/call. The widget HTML must be loaded into the frame before it can receive and render tool results.
{"status":"not-ready"} on /health
The initialize request has not been sent yet, or it failed. Check proxy logs by restarting with --verbose.
Response is SSE-framed (event: message\ndata: ...) instead of JSON
Add Accept: application/json to your request. Without it, the proxy passes through the raw SSE format from the upstream server.
Session errors on requests after initialize
The Mcp-Session-Id header is missing or incorrect. Re-run initialize with -D <path>/init-headers.txt and extract the session ID from that file.
Inspector UI unreachable at localhost:6274
Check whether the port is already in use:
lsof -i :6274 # macOS/Linux
Kill only the listening server process, then restart:
kill $(lsof -ti :6274 -sTCP:LISTEN) 2>/dev/null
Playwright CLI not found
Install it and a browser:
npm install -g @playwright/cli
playwright-cli install-browser
Playwright is only required for visual analysis. If you are running data-layer analysis only, you can skip this.
certification-verdict.json is missing rule results
The verdict only includes rules for the analysis scope you selected. Visual rules only appear when visual analysis runs; MCP data rules only appear when data-layer analysis runs. This is by design: absence means "not evaluated," not "passed."
State looks stale after a page reload
Verify the proxy state directly:
curl -s http://localhost:6277/state | python3 -m json.tool
The UI fetches this same endpoint on every load. If the proxy is still running, state is preserved.
SSE events reference
The proxy broadcasts these named events on GET /events:
| Event | Triggered when | Payload |
|---|---|---|
connected |
initialize response received |
{ address, serverInfo } |
tools-discovered |
tools/list response received |
{ tools } |
resource-fetched |
resources/read response received |
{ uri, mimeType, contentLength } |
widget-html |
HTML resource read | { uri, html } |
tool-called |
tools/call request/response cycle |
{ toolName, request, response, eventId, ts, durationMs } |
error |
Upstream failure or JSON-RPC error | { method, description } |
Last updated: Jul 16, 2026

