MCP Server — E2E Test Plan
Key paths to validate on staging before each production deploy.
V1 — API Key Authentication
| # | Path | Expected | SLA |
|---|---|---|---|
| 1 | POST /mcp with valid V1 API key + { method: "initialize" } | HTTP 200, mcp-session-id header in response | < 2s |
| 2 | POST /mcp with invalid/missing key | HTTP 401 | < 1s |
| 3 | POST /mcp (session exists) + { method: "tools/list" } | JSON with expected tools array | < 2s |
| 4 | get_products call on merchant session | Returns business-scoped product data | < 3s |
| 5 | get_products called with wrong businessId (not in principal) | Tool handler returns error content | < 2s |
| 6 | void_transaction called without pos:write scope | ToolRegistry dispatch throws McpInsufficientScopesError | < 1s |
| 7 | DELETE /mcp with valid Authorization + session ID | Session closed, subsequent requests return 400 | < 1s |
V2 — OAuth Token Exchange
| # | Path | Expected | SLA |
|---|---|---|---|
| 8 | POST /mcp/token with valid Firebase ID token | HTTP 200, accessToken JWT returned with authorizedBusinessIds | < 3s |
| 9 | POST /mcp/token with expired/invalid Firebase token | HTTP 401 | < 2s |
| 10 | POST /mcp/token for user with no business memberships | HTTP 403 | < 2s |
| 11 | Session opened with V2 token → tools/list includes set_active_business (multi-business user) | Tool present in list | < 2s |
| 12 | set_active_business with valid businessId | activeBusinessId updated in session; next domain tool call returns data for the new business | < 2s |
| 13 | set_active_business with unauthorized businessId | Error content in response; session activeBusinessId unchanged | < 1s |
| 14 | V2 session: principal written to Redis on initialize | GET mcp:session:{sid} in Redis returns valid JSON principal with correct TTL | < 1s |
| 15 | set_active_tenant (platform_operator key) with valid businessId | Subsequent get_products call is scoped to the new tenant | < 2s |
PSA Tools
| # | Path | Expected | SLA |
|---|---|---|---|
| 16 | log_hours without userId field | Tool returns isError: true with "userId is required" message | < 1s |
| 17 | log_hours with all required fields (stepId, userId, hours) | Time entry created; response contains entry object | < 3s |
Intent Tools (pos:intents scope)
| # | Path | Expected | SLA |
|---|---|---|---|
| 18 | Merchant session with pos:intents → tools/list | All 4 intent tools present | < 2s |
| 19 | tenant_developer session → tools/list | Intent tools NOT present | < 2s |
| 20 | summarize_day call | Returns totalRevenue, orderCount, topProducts, lowStockAlertCount | < 5s |
| 21 | summarize_day for date with no transactions | Returns zeros without error | < 3s |
| 22 | get_client_health with valid implementation ID | Returns phase, completionPct, hoursBurned, hoursEstimated, openBlockers | < 5s |