Examples
The last green end-to-end run (2026-09-08T01:26:41+00:00) — 52 cases, verdict GREEN.
{
"ran_at": "2026-09-08T01:26:41+00:00",
"started": "2026-09-08T01:26:02+00:00",
"verdict": "GREEN",
"surface": "claude+chatgpt+full",
"surfaces": [
"claude",
"chatgpt",
"full"
],
"hosts": {
"mcp": "mcp.sportscall.ai [public]",
"auth": "auth.sportscall.ai [local \u00b7 no DNS (gaierror)]",
"developers": "developers.sportscall.ai [local \u00b7 no DNS (gaierror)]"
},
"fixture": {
"line": "a0000000-0000-4000-8000-0000000000a1",
"did": "+15550001001",
"contact": "+15550001002",
"players": [
"Bijan Robinson",
"James Cook"
],
"demo_code": "<from /opt/aria/.env SPORTSCALL_OAUTH_DEMO_CODE>"
},
"counts": {
"cases": 52,
"pos": 34,
"neg": 17,
"pass": 52,
"fail": 0
},
"known_gaps": [
"E_DEMO_NOOP has NO producer in the server (only the error-table entry exists); the plan expects the fixture to answer E_DEMO_NOOP on call tools"
],
"cleanup": {
"full_bearers_deleted": 1,
"oauth_tokens_revoked": 0,
"watches_cancelled": 0,
"idempotency_rows_deleted": 2,
"callback_rows_left": "1 (acgw has no DELETE grant on sportscall_callback_requests; refused-call audit rows on the synthetic line)",
"queue_rows_deleted": 0,
"fixture_restored": true
},
"render_chars": 60111
}✅ fixture dressed: the five-player QA roster resolves on the fixture (saved config restored at close) [pos · -]
{
"name": "fixture dressed: the five-player QA roster resolves on the fixture (saved config restored at close)",
"kind": "pos",
"surface": "-",
"request": {
"players": [
"Josh Allen",
"Bijan Robinson",
"\u2026 +3 more"
]
},
"response": {
"resolved": [
"Josh Allen",
"Bijan Robinson",
"\u2026 +3 more"
]
},
"pass": true
}✅ no bearer \u2192 401 + WWW-Authenticate resource_metadata (public: mcp.sportscall.ai [public]) [neg · -]
{
"name": "no bearer \u2192 401 + WWW-Authenticate resource_metadata (public: mcp.sportscall.ai [public])",
"kind": "neg",
"surface": "-",
"request": {
"rpc": "tools/list",
"auth": "none",
"url": "https://mcp.sportscall.ai"
},
"response": {
"status": 401,
"ms": 22,
"www-authenticate": "Bearer <redacted>\"https://mcp.sportscall.ai/.well-known/oauth-protected-resource\"",
"error": {
"code": -32001,
"message": "bearer token missing, revoked, or unknown"
}
},
"pass": true
}✅ no bearer \u2192 401 + WWW-Authenticate resource_metadata (loopback: mcp.sportscall.ai [local \u00b7 forced loopback]) [neg · -]
{
"name": "no bearer \u2192 401 + WWW-Authenticate resource_metadata (loopback: mcp.sportscall.ai [local \u00b7 forced loopback])",
"kind": "neg",
"surface": "-",
"request": {
"rpc": "tools/list",
"auth": "none",
"url": "http://127.0.0.1:9001/v1/mcp/sportscall"
},
"response": {
"status": 401,
"ms": 3,
"www-authenticate": "Bearer <redacted>\"https://mcp.sportscall.ai/.well-known/oauth-protected-resource\"",
"error": {
"code": -32001,
"message": "bearer token missing, revoked, or unknown"
}
},
"pass": true
}✅ initialize without a bearer (loopback) \u2192 200, serverInfo.version 1.0 (initialize is unauthenticated by design) [pos · -]
{
"name": "initialize without a bearer (loopback) \u2192 200, serverInfo.version 1.0 (initialize is unauthenticated by design)",
"kind": "pos",
"surface": "-",
"request": {
"rpc": "initialize",
"auth": "none",
"params": {
"protocolVersion": "2025-06-18",
"clientInfo": {
"name": "sportscall-e2e",
"version": "1.0"
}
}
},
"response": {
"status": 200,
"ms": 2,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {
"listChanged": false
},
"resources": {
"listChanged": false
}
},
"serverInfo": {
"name": "sportscall",
"version": "1.0",
"title": "SportsCall \u2014 Fantasy Co-Manager"
},
"instructions": "One bearer = one SportsCall phone line. Start with get_my_fantasy_context when a question depends on the user's team. Decision tools return \u2026 (+14 chars)"
}
},
"pass": true
}✅ AS metadata \u2192 issuer auth.sportscall.ai \u00b7 S256 only \u00b7 registration + revocation endpoints [pos · -]
{
"name": "AS metadata \u2192 issuer auth.sportscall.ai \u00b7 S256 only \u00b7 registration + revocation endpoints",
"kind": "pos",
"surface": "-",
"request": {
"method": "GET",
"url": "http://127.0.0.1:9001/v1/oauth/sportscall/.well-known/oauth-authorization-server"
},
"response": {
"status": 200,
"ms": 2,
"body": {
"issuer": "https://auth.sportscall.ai",
"authorization_endpoint": "https://auth.sportscall.ai/authorize",
"token_endpoint": "https://auth.sportscall.ai/token",
"registration_endpoint": "https://auth.sportscall.ai/register",
"revocation_endpoint": "https://auth.sportscall.ai/revoke",
"code_challenge_methods_supported": [
"S256"
],
"scopes_supported": [
"league.read",
"roster.read",
"\u2026 +5 more"
]
}
},
"pass": true
}✅ connect \u00b7 DCR client reused (claude) [pos · claude]
{
"name": "connect \u00b7 DCR client reused (claude)",
"kind": "pos",
"surface": "claude",
"request": {
"client_id": "scoa_xVyCiQaSrRQ1Q8lxy-",
"redirect_uri": "https://claude.ai/api/mcp/auth_callback"
},
"response": {
"status": 200,
"note": "authorize page rendered for the persisted client"
},
"pass": true
}✅ connect \u00b7 DCR client reused (chatgpt) [pos · chatgpt]
{
"name": "connect \u00b7 DCR client reused (chatgpt)",
"kind": "pos",
"surface": "chatgpt",
"request": {
"client_id": "scoa_g9KJbpWYF11O77ur4m",
"redirect_uri": "https://chatgpt.com/connector_platform_oauth_redirect"
},
"response": {
"status": 200,
"note": "authorize page rendered for the persisted client"
},
"pass": true
}✅ chatgpt client asks roster.write \u2192 302 error=invalid_scope (roster moves never on a directory client \u2014 Ian's ruling 3) [neg · chatgpt]
{
"name": "chatgpt client asks roster.write \u2192 302 error=invalid_scope (roster moves never on a directory client \u2014 Ian's ruling 3)",
"kind": "neg",
"surface": "chatgpt",
"request": {
"method": "GET",
"url": "http://127.0.0.1:9001/v1/oauth/sportscall/authorize",
"headers": {
"Host": "auth.sportscall.ai"
},
"params": {
"client_id": "scoa_g9KJbpWYF11O77ur4m",
"redirect_uri": "https://chatgpt.com/connector_platform_oauth_redirect",
"response_type": "code",
"state": "e2e-rw",
"code_challenge": "IFNqKzmjo62HPwwKp7bZ5ipDrRElOHsmeoz6j7DfYXY",
"code_challenge_method": "S256",
"scope": "league.read roster.read analysis.read alerts.write messages.write calls.write roster.write"
}
},
"response": {
"status": 302,
"ms": 3,
"headers": {
"cache-control": "no-store",
"location": "https://chatgpt.com/connector_platform_oauth_redirect?error=invalid_scope&error_description=a+requested+scope+is+unknown+or+not+available+to\u2026 (+28 chars)"
},
"body": ""
},
"pass": true
}✅ connect \u00b7 PKCE S256 walk on the demo fixture (claude \u00b7 all five directory scopes) [pos · claude]
{
"name": "connect \u00b7 PKCE S256 walk on the demo fixture (claude \u00b7 all five directory scopes)",
"kind": "pos",
"surface": "claude",
"request": {
"client_id": "scoa_xVyCiQaSrRQ1Q8lxy-",
"redirect_uri": "https://claude.ai/api/mcp/auth_callback",
"phone": "+15550001001",
"code": "<SPORTSCALL_OAUTH_DEMO_CODE>",
"pkce": "S256"
},
"response": {
"steps": [
{
"step": "GET /authorize \u2192 200 page + rid + sc_authz cookie",
"ok": true,
"status": 200,
"detail": {
"rid": true,
"cookie": "<redacted>"
}
},
{
"step": "phone step (fixture DID; the text is 555-faked)",
"ok": true,
"status": 200,
"detail": "We texted a code to +1\u2022\u2022\u2022\u2022\u2022\u20221002 from your SportsCall line."
},
{
"step": "code step (SPORTSCALL_OAUTH_DEMO_CODE, fixture only) \u2192 consent lists the requested scopes",
"ok": true,
"status": 200,
"detail": {
"consent_scopes": [
"league.read",
"roster.read",
"analysis.read",
"alerts.write",
"messages.write"
]
}
},
{
"step": "consent allow (ticked ['league.read', 'roster.read', 'analysis.read', 'alerts.write', 'messages.write']) \u2192 302 redirect_uri?code&state",
"ok": true,
"status": 302,
"detail": {
"location_host": "claude.ai",
"state_matches": true
}
},
{
"step": "POST /token (authorization_code + code_verifier) \u2192 Bearer, 24 h, no-store",
"ok": true,
"status": 200,
"detail": {
"token_type": "Bearer",
"expires_in": 86400,
"scope": "league.read roster.read analysis.read alerts.write messages.write",
"refresh_token_present": true
}
}
],
"granted_scope": "league.read roster.read analysis.read alerts.write messages.write"
},
"pass": true
}✅ connect \u00b7 PKCE S256 walk on the demo fixture (chatgpt \u00b7 five + calls.write) [pos · chatgpt]
{
"name": "connect \u00b7 PKCE S256 walk on the demo fixture (chatgpt \u00b7 five + calls.write)",
"kind": "pos",
"surface": "chatgpt",
"request": {
"client_id": "scoa_g9KJbpWYF11O77ur4m",
"redirect_uri": "https://chatgpt.com/connector_platform_oauth_redirect",
"phone": "+15550001001",
"code": "<SPORTSCALL_OAUTH_DEMO_CODE>",
"pkce": "S256"
},
"response": {
"steps": [
{
"step": "GET /authorize \u2192 200 page + rid + sc_authz cookie",
"ok": true,
"status": 200,
"detail": {
"rid": true,
"cookie": "<redacted>"
}
},
{
"step": "phone step (fixture DID; the text is 555-faked)",
"ok": true,
"status": 200,
"detail": "We texted a code to +1\u2022\u2022\u2022\u2022\u2022\u20221002 from your SportsCall line."
},
{
"step": "code step (SPORTSCALL_OAUTH_DEMO_CODE, fixture only) \u2192 consent lists the requested scopes",
"ok": true,
"status": 200,
"detail": {
"consent_scopes": [
"league.read",
"roster.read",
"analysis.read",
"alerts.write",
"messages.write",
"calls.write"
]
}
},
{
"step": "consent allow (ticked ['league.read', 'roster.read', 'analysis.read', 'alerts.write', 'messages.write', 'calls.write']) \u2192 302 redirect_uri?code&state",
"ok": true,
"status": 302,
"detail": {
"location_host": "chatgpt.com",
"state_matches": true
}
},
{
"step": "POST /token (authorization_code + code_verifier) \u2192 Bearer, 24 h, no-store",
"ok": true,
"status": 200,
"detail": {
"token_type": "Bearer",
"expires_in": 86400,
"scope": "league.read roster.read analysis.read alerts.write messages.write calls.write",
"refresh_token_present": true
}
}
],
"granted_scope": "league.read roster.read analysis.read alerts.write messages.write calls.write"
},
"pass": true
}✅ connect \u00b7 PKCE S256 walk on the demo fixture (chatgpt \u00b7 consent WITHOUT messages.write / calls.write) [pos · chatgpt]
{
"name": "connect \u00b7 PKCE S256 walk on the demo fixture (chatgpt \u00b7 consent WITHOUT messages.write / calls.write)",
"kind": "pos",
"surface": "chatgpt",
"request": {
"client_id": "scoa_g9KJbpWYF11O77ur4m",
"redirect_uri": "https://chatgpt.com/connector_platform_oauth_redirect",
"phone": "+15550001001",
"code": "<SPORTSCALL_OAUTH_DEMO_CODE>",
"pkce": "S256"
},
"response": {
"steps": [
{
"step": "GET /authorize \u2192 200 page + rid + sc_authz cookie",
"ok": true,
"status": 200,
"detail": {
"rid": true,
"cookie": "<redacted>"
}
},
{
"step": "phone step (fixture DID; the text is 555-faked)",
"ok": true,
"status": 200,
"detail": "We texted a code to +1\u2022\u2022\u2022\u2022\u2022\u20221002 from your SportsCall line."
},
{
"step": "code step (SPORTSCALL_OAUTH_DEMO_CODE, fixture only) \u2192 consent lists the requested scopes",
"ok": true,
"status": 200,
"detail": {
"consent_scopes": [
"league.read",
"roster.read",
"analysis.read",
"alerts.write",
"messages.write",
"calls.write"
]
}
},
{
"step": "consent allow (ticked ['league.read', 'roster.read', 'analysis.read', 'alerts.write']) \u2192 302 redirect_uri?code&state",
"ok": true,
"status": 302,
"detail": {
"location_host": "chatgpt.com",
"state_matches": true
}
},
{
"step": "POST /token (authorization_code + code_verifier) \u2192 Bearer, 24 h, no-store",
"ok": true,
"status": 200,
"detail": {
"token_type": "Bearer",
"expires_in": 86400,
"scope": "league.read roster.read analysis.read alerts.write",
"refresh_token_present": true
}
}
],
"granted_scope": "league.read roster.read analysis.read alerts.write"
},
"pass": true
}✅ initialize \u2192 protocolVersion 2025-06-18 \u00b7 serverInfo.version 1.0 [pos · claude]
{
"name": "initialize \u2192 protocolVersion 2025-06-18 \u00b7 serverInfo.version 1.0",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "initialize",
"auth": "bearer",
"params": {
"protocolVersion": "2025-06-18",
"clientInfo": {
"name": "sportscall-e2e-claude",
"version": "1.0"
}
}
},
"response": {
"status": 200,
"ms": 22,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {
"listChanged": false
},
"resources": {
"listChanged": false
}
},
"serverInfo": {
"name": "sportscall",
"version": "1.0",
"title": "SportsCall \u2014 Fantasy Co-Manager"
},
"instructions": "One bearer = one SportsCall phone line. Start with get_my_fantasy_context when a question depends on the user's team. Decision tools return \u2026 (+14 chars)"
}
},
"pass": true
}✅ tools/list (claude) \u2192 no voice tool, no roster move, channel enum = [sms], every description starts 'Use this' [pos · claude]
{
"name": "tools/list (claude) \u2192 no voice tool, no roster move, channel enum = [sms], every description starts 'Use this'",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/list",
"auth": "bearer"
},
"response": {
"status": 200,
"tools": [
"get_my_leagues",
"get_my_fantasy_context",
"\u2026 +10 more"
],
"watch_roster.channel.enum": [
"sms"
]
},
"pass": true
}✅ claude surface listing has NO schedule_sportscall / call_me_now / send_me_weekly_brief [neg · claude]
{
"name": "claude surface listing has NO schedule_sportscall / call_me_now / send_me_weekly_brief",
"kind": "neg",
"surface": "claude",
"request": {
"method": "tools/list"
},
"response": {
"tools": [
"get_my_leagues",
"get_my_fantasy_context",
"\u2026 +10 more"
],
"voice_tools_present": []
},
"pass": true
}✅ get_my_leagues \u2192 ok:true, the fixture's league listed, isError:false [pos · claude]
{
"name": "get_my_leagues \u2192 ok:true, the fixture's league listed, isError:false",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_my_leagues",
"arguments": {}
},
"response": {
"status": 200,
"ms": 22,
"isError": false,
"text": "1 league linked: QA League on MyFantasyLeague (QA Team) \u2014 primary.",
"structuredContent": {
"ok": true,
"leagues": [
{
"platform": "mfl",
"platform_label": "MyFantasyLeague",
"league_id": "qa",
"name": "QA League",
"team": "QA Team",
"record": "",
"scoring": null,
"team_count": null,
"week": null,
"matchup": {},
"primary": true,
"waiver_position": null
}
],
"primary_platform": "mfl"
}
},
"pass": true
}✅ get_my_fantasy_context \u2192 ok:true with league rules, week, roster [pos · claude]
{
"name": "get_my_fantasy_context \u2192 ok:true with league rules, week, roster",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_my_fantasy_context",
"arguments": {}
},
"response": {
"status": 200,
"ms": 81,
"isError": false,
"text": "QA League on MyFantasyLeague \u2014 10-team \u00b7 Week 1. No matchup posted yet. Starters: QB Josh Allen (QB, BUF), RB Bijan Robinson (RB, ATL), RB2 \u2026 (+83 chars)",
"structuredContent": {
"ok": true,
"league": {
"platform": "MyFantasyLeague",
"name": "QA League",
"teams": 10,
"scoring": "",
"week": 1,
"format_line": "10-team \u00b7 Week 1"
},
"leagues": [
{
"platform": "mfl",
"platform_label": "MyFantasyLeague",
"league_id": "qa",
"name": "QA League",
"team": "QA Team",
"record": "",
"scoring": null,
"team_count": null,
"week": null,
"matchup": {},
"primary": true,
"waiver_position": null
}
],
"rules": {
"sport": "football",
"team_count": 10,
"starting_slots": [
"QB",
"RB",
"\u2026 +1 more"
],
"bench_size": 1
},
"record": "",
"week": 1,
"matchup": {},
"roster": {
"starters": [
{
"slot": "QB",
"name": "Josh Allen",
"pos": "QB",
"team": "BUF"
},
{
"slot": "RB",
"name": "Bijan Robinson",
"pos": "RB",
"team": "ATL"
},
"\u2026 +1 more"
],
"bench": [
{
"slot": "BN",
"name": "Tyler Allgeier",
"pos": "RB",
"team": "ATL"
}
]
},
"roster_source": "mfl:qa"
}
},
"pass": true
}✅ get_roster_status \u2192 ok:true, every rostered player with a status line [pos · claude]
{
"name": "get_roster_status \u2192 ok:true, every rostered player with a status line",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_roster_status",
"arguments": {}
},
"response": {
"status": 200,
"ms": 129,
"isError": false,
"text": "5 on file (4 starters). No starter is out or on bye. Next kickoff Sun 1 PM.",
"structuredContent": {
"ok": true,
"platform": "mfl",
"week": 1,
"players": [
{
"name": "Josh Allen",
"slot": "QB",
"pos": "QB",
"team": "BUF",
"starter": true,
"status": "",
"detail": "",
"return": "",
"bye": false,
"next_kickoff": "2026-09-13T17:00:00+00:00",
"event_id": "401872660",
"status_as_of": "2026-09-08T01:25:38.500901+00:00"
},
{
"name": "Bijan Robinson",
"slot": "RB",
"pos": "RB",
"team": "ATL",
"starter": true,
"status": "",
"detail": "",
"return": "",
"bye": false,
"next_kickoff": "2026-09-13T17:00:00+00:00",
"event_id": "401872658",
"status_as_of": "2026-09-08T01:25:38.500901+00:00"
},
"\u2026 +1 more"
],
"flagged": [],
"injury_feed_ok": true,
"status_as_of": "2026-09-08T01:25:38.500901+00:00",
"sources": [
{
"label": "RotoWire",
"as_of": "2026-09-08T01:25:38.500901+00:00"
},
{
"label": "our own ledger",
"as_of": ""
}
]
}
},
"pass": true
}✅ analyze_start_sit [Bijan Robinson vs James Cook] \u2192 THE CALL: every required field \u00b7 confidence 50\u201395 \u00b7 3 factors \u00b7 decision_id \u00b7 no odds words [pos · claude]
{
"name": "analyze_start_sit [Bijan Robinson vs James Cook] \u2192 THE CALL: every required field \u00b7 confidence 50\u201395 \u00b7 3 factors \u00b7 decision_id \u00b7 no odds words",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "analyze_start_sit",
"arguments": {
"players": [
"Bijan Robinson",
"James Cook"
]
}
},
"response": {
"status": 200,
"ms": 102,
"isError": false,
"text": "THE CALL \u00b7 START Bijan Robinson over James Cook \u00b7 70% \u00b7 10-team \u00b7 Week 1 \u00b7 Updated 9:26 PM ET \u00b7 Volume \u2192 \u00b7 Matchup \u2193 \u00b7 Injury risk \u2193 \u00b7 Why: Bijan Robinson projects 21.5 to James Cook's 17.1 and team expected to chase \u2014 fewer carries late. \u00b7 Risk: Game flow could flip it \u2014 team expected to chase \u2014 fewer carries late is the read on file today. \u00b7 Watch this call: watch_decision(decision_id=d_079b7a38dc8d)",
"structuredContent": {
"ok": true,
"decision": {
"schema_version": "1.0",
"decision_id": "d_079b7a38dc8d",
"kind": "start_sit",
"verdict": "START",
"headline": "START Bijan Robinson over James Cook",
"subject": [
{
"name": "Bijan Robinson",
"pos": "RB",
"team": "ATL",
"role": "pick",
"status": "",
"projection": 21.53
},
{
"name": "James Cook",
"pos": "RB",
"team": "BUF",
"role": "other",
"status": "",
"projection": 17.11
}
],
"confidence": 70,
"confidence_method": "det-v1",
"confidence_breakdown": {
"method": "det-v1",
"base": 50,
"edge": 19.9,
"freshness": 0,
"injury": 0,
"confidence": 70
},
"league": {
"platform": "MyFantasyLeague",
"name": "QA League",
"teams": 10,
"scoring": "",
"week": 1,
"format_line": "10-team \u00b7 Week 1"
},
"updated_at": "2026-09-08T01:26:39+00:00",
"updated_display": "Updated 9:26 PM ET",
"factors": [
{
"name": "Volume",
"direction": "\u2192",
"note": "No usage on file yet this season"
},
{
"name": "Matchup",
"direction": "\u2193",
"note": "Team expected to chase \u2014 fewer carries late"
},
"\u2026 +1 more"
],
"reasoning": "Bijan Robinson projects 21.5 to James Cook's 17.1 and team expected to chase \u2014 fewer carries late.",
"risk": "Game flow could flip it \u2014 team expected to chase \u2014 fewer carries late is the read on file today.",
"sources": [
{
"label": "RotoWire",
"as_of": "fetched Sep 8, 12:40 AM UTC"
},
{
"label": "RotoWire",
"as_of": "2026-09-08T01:25:38.500901+00:00"
}
],
"watchable": true,
"lock_at": "2026-09-13T17:00:00+00:00"
},
"players": [
{
"player": "Bijan Robinson",
"pos": "RB",
"team": "ATL",
"on_roster": true,
"slot": "RB",
"status": "",
"detail": "",
"status_as_of": "2026-09-08T01:25:38.500901+00:00",
"bye": false,
"bye_week": null,
"projection": {
"points": 21.53,
"source": "RotoWire NFL weekly projections feed (week 1)",
"as_of": "fetched Sep 8, 12:40 AM UTC",
"label": "week 1"
},
"game_env": {
"script": "behind",
"scoring": "neutral",
"known": true
},
"why": [
"projected 21.5",
"team expected to chase \u2014 fewer carries late"
]
},
{
"player": "James Cook",
"pos": "RB",
"team": "BUF",
"on_roster": true,
"slot": "RB2",
"status": "",
"detail": "",
"status_as_of": "2026-09-08T01:25:38.500901+00:00",
"bye": false,
"bye_week": null,
"projection": {
"points": 17.11,
"source": "RotoWire NFL weekly projections feed (week 1)",
"as_of": "fetched Sep 8, 12:40 AM UTC",
"label": "week 1"
},
"game_env": {
"script": "even",
"scoring": "neutral",
"known": true
},
"why": [
"projected 17.1",
"game expected to stay close"
]
}
]
},
"_meta": {
"openai/outputTemplate": "ui://sportscall/decision-card.html",
"sportscall/version": "1.0"
}
},
"pass": true
}✅ watch_decision(d_079b7a38dc8d) \u2192 ok:true, watch_id, ends at lock [pos · claude]
{
"name": "watch_decision(d_079b7a38dc8d) \u2192 ok:true, watch_id, ends at lock",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "watch_decision",
"arguments": {
"decision_id": "d_079b7a38dc8d"
}
},
"response": {
"status": 200,
"ms": 119,
"isError": false,
"text": "Got it \u2014 I'm watching the call on Robinson over Cook until Sun 1 PM. If it flips or the confidence moves a band, SportsCall texts you.",
"structuredContent": {
"ok": true,
"watch_id": 104,
"decision_id": "d_079b7a38dc8d",
"kind": "start_sit",
"verdict": "START",
"channel": "sms",
"until_at": "2026-09-13T17:00:00+00:00",
"existing": false,
"baseline": {
"verdict": "START",
"winner": "Bijan Robinson",
"band": "solid",
"statuses": {
"Bijan Robinson": "",
"James Cook": ""
},
"risk_realized": false
}
}
},
"pass": true
}✅ list_watches \u2192 shows the decision watch [pos · claude]
{
"name": "list_watches \u2192 shows the decision watch",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "list_watches",
"arguments": {}
},
"response": {
"status": 200,
"ms": 24,
"isError": false,
"text": "1 active watch: #104 decision START Robinson over Cook by sms until Sun 1 PM.",
"structuredContent": {
"ok": true,
"watches": [
{
"id": 104,
"kind": "decision",
"subject": {
"a": "Bijan Robinson",
"b": "James Cook",
"kind": "start_sit",
"label": "START Robinson over Cook",
"players": [
"Bijan Robinson",
"James Cook"
],
"verdict": "START",
"platform": "mfl",
"decision_id": "d_079b7a38dc8d"
},
"channel": "sms",
"until_at": "2026-09-13T17:00:00+00:00",
"alerts_sent": 0,
"last_alert_at": null,
"created_at": "2026-09-08T01:26:40.067275+00:00",
"last_skip_reason": null
}
]
}
},
"pass": true
}✅ cancel_watch(#104) \u2192 ok:true [pos · claude]
{
"name": "cancel_watch(#104) \u2192 ok:true",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "cancel_watch",
"arguments": {
"id": 104
}
},
"response": {
"status": 200,
"ms": 22,
"isError": false,
"text": "Watch #104 cancelled.",
"structuredContent": {
"ok": true,
"watch_id": 104
}
},
"pass": true
}✅ watch_roster \u00d72 with one Idempotency-Key \u2192 second answer replayed:true, same watch_id [pos · claude]
{
"name": "watch_roster \u00d72 with one Idempotency-Key \u2192 second answer replayed:true, same watch_id",
"kind": "pos",
"surface": "claude",
"request": {
"first": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "watch_roster",
"arguments": {
"channel": "sms"
},
"Idempotency-Key": "e2e-claude-eee5b8b4a9"
},
"second": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "watch_roster",
"arguments": {
"channel": "sms"
},
"Idempotency-Key": "e2e-claude-eee5b8b4a9"
}
},
"response": {
"first": {
"status": 200,
"ms": 122,
"isError": false,
"text": "Got it. I'm watching your whole roster on MyFantasyLeague. If something material changes before Sun 1 PM lock, SportsCall will text you.",
"structuredContent": {
"ok": true,
"watch_id": 105,
"channel": "sms",
"until_at": "2026-09-13T17:00:00+00:00"
}
},
"second": {
"status": 200,
"ms": 22,
"isError": false,
"text": "Got it. I'm watching your whole roster on MyFantasyLeague. If something material changes before Sun 1 PM lock, SportsCall will text you.",
"structuredContent": {
"ok": true,
"watch_id": 105,
"replayed": true,
"keys": [
"channel",
"ok",
"\u2026 +3 more"
]
}
}
},
"pass": true
}✅ get_weekly_brief \u2192 ok:true, one read, sends nothing (no sid, no sends) [pos · claude]
{
"name": "get_weekly_brief \u2192 ok:true, one read, sends nothing (no sid, no sends)",
"kind": "pos",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_weekly_brief",
"arguments": {}
},
"response": {
"status": 200,
"ms": 192,
"isError": false,
"text": "SportsCall brief \u2014 10-team \u00b7 Week 1. Last week: W 149.4-109.1 vs Zero Eifert. No starter is out or on bye. In action this week: Josh Allen, \u2026 (+139 chars)",
"structuredContent": {
"ok": true,
"sends": false,
"week": 1,
"keys": [
"brief_text",
"candidates",
"\u2026 +15 more"
]
}
},
"pass": true
}✅ get_weekly_brief with `deliver` \u2192 E_BAD_ARGS (the brief never sends \u2014 Ian's ruling 2) [neg · claude]
{
"name": "get_weekly_brief with `deliver` \u2192 E_BAD_ARGS (the brief never sends \u2014 Ian's ruling 2)",
"kind": "neg",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_weekly_brief",
"arguments": {
"deliver": "sms"
}
},
"response": {
"status": 200,
"ms": 22,
"isError": true,
"text": "The brief is read-only here \u2014 ask me to text you a specific note if you want one.",
"structuredContent": {
"ok": false,
"code": "E_BAD_ARGS",
"sends": false,
"retryable": false
}
},
"pass": true
}✅ analyze_trade with empty `get` \u2192 E_BAD_ARGS [neg · claude]
{
"name": "analyze_trade with empty `get` \u2192 E_BAD_ARGS",
"kind": "neg",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "analyze_trade",
"arguments": {
"give": [
"Josh Allen"
],
"get": []
}
},
"response": {
"status": 200,
"ms": 21,
"isError": true,
"text": "Tell me what you'd give and what you'd get.",
"structuredContent": {
"ok": false,
"decision": null,
"players": [],
"code": "E_BAD_ARGS",
"retryable": false
},
"_meta": {
"openai/outputTemplate": "ui://sportscall/decision-card.html",
"sportscall/version": "1.0"
}
},
"pass": true
}✅ unknown tool get_odds \u2192 JSON-RPC \u221232601 [neg · claude]
{
"name": "unknown tool get_odds \u2192 JSON-RPC \u221232601",
"kind": "neg",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_odds",
"arguments": {}
},
"response": {
"status": 200,
"ms": 20,
"error": {
"code": -32601,
"message": "unknown tool: get_odds"
}
},
"pass": true
}✅ schedule_sportscall on the claude surface \u2192 \u221232601 (off this surface) [neg · claude]
{
"name": "schedule_sportscall on the claude surface \u2192 \u221232601 (off this surface)",
"kind": "neg",
"surface": "claude",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "schedule_sportscall",
"arguments": {
"at_iso": "2026-09-07T20:26",
"topic": "e2e past"
}
},
"response": {
"status": 200,
"ms": 20,
"error": {
"code": -32601,
"message": "unknown tool: schedule_sportscall"
}
},
"pass": true
}✅ initialize \u2192 protocolVersion 2025-06-18 \u00b7 serverInfo.version 1.0 [pos · chatgpt]
{
"name": "initialize \u2192 protocolVersion 2025-06-18 \u00b7 serverInfo.version 1.0",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "initialize",
"auth": "bearer",
"params": {
"protocolVersion": "2025-06-18",
"clientInfo": {
"name": "sportscall-e2e-chatgpt",
"version": "1.0"
}
}
},
"response": {
"status": 200,
"ms": 19,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {
"listChanged": false
},
"resources": {
"listChanged": false
}
},
"serverInfo": {
"name": "sportscall",
"version": "1.0",
"title": "SportsCall \u2014 Fantasy Co-Manager"
},
"instructions": "One bearer = one SportsCall phone line. Start with get_my_fantasy_context when a question depends on the user's team. Decision tools return \u2026 (+14 chars)"
}
},
"pass": true
}✅ tools/list (chatgpt) \u2192 schedule_sportscall listed \u00b7 no roster move \u00b7 channel enum [sms, call] \u00b7 every description starts 'Use this' [pos · chatgpt]
{
"name": "tools/list (chatgpt) \u2192 schedule_sportscall listed \u00b7 no roster move \u00b7 channel enum [sms, call] \u00b7 every description starts 'Use this'",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/list",
"auth": "bearer"
},
"response": {
"status": 200,
"tools": [
"get_my_leagues",
"get_my_fantasy_context",
"\u2026 +11 more"
],
"watch_roster.channel.enum": [
"sms",
"call"
]
},
"pass": true
}✅ get_my_leagues \u2192 ok:true, the fixture's league listed, isError:false [pos · chatgpt]
{
"name": "get_my_leagues \u2192 ok:true, the fixture's league listed, isError:false",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_my_leagues",
"arguments": {}
},
"response": {
"status": 200,
"ms": 21,
"isError": false,
"text": "1 league linked: QA League on MyFantasyLeague (QA Team) \u2014 primary.",
"structuredContent": {
"ok": true,
"leagues_n": 1,
"keys": [
"leagues",
"ok",
"\u2026 +1 more"
]
}
},
"pass": true
}✅ get_my_fantasy_context \u2192 ok:true with league rules, week, roster [pos · chatgpt]
{
"name": "get_my_fantasy_context \u2192 ok:true with league rules, week, roster",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_my_fantasy_context",
"arguments": {}
},
"response": {
"status": 200,
"ms": 68,
"isError": false,
"text": "QA League on MyFantasyLeague \u2014 10-team \u00b7 Week 1. No matchup posted yet. Starters: QB Josh Allen (QB, BUF), RB Bijan Robinson (RB, ATL), RB2 \u2026 (+83 chars)",
"structuredContent": {
"ok": true,
"week": 1,
"roster_source": "mfl:qa",
"leagues_n": 1,
"keys": [
"league",
"leagues",
"\u2026 +7 more"
]
}
},
"pass": true
}✅ get_roster_status \u2192 ok:true, every rostered player with a status line [pos · chatgpt]
{
"name": "get_roster_status \u2192 ok:true, every rostered player with a status line",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_roster_status",
"arguments": {}
},
"response": {
"status": 200,
"ms": 107,
"isError": false,
"text": "5 on file (4 starters). No starter is out or on bye. Next kickoff Sun 1 PM.",
"structuredContent": {
"ok": true,
"week": 1,
"players_n": 5,
"flagged_n": 0,
"keys": [
"flagged",
"injury_feed_ok",
"\u2026 +6 more"
]
}
},
"pass": true
}✅ analyze_start_sit [Bijan Robinson vs James Cook] \u2192 THE CALL: every required field \u00b7 confidence 50\u201395 \u00b7 3 factors \u00b7 decision_id \u00b7 no odds words [pos · chatgpt]
{
"name": "analyze_start_sit [Bijan Robinson vs James Cook] \u2192 THE CALL: every required field \u00b7 confidence 50\u201395 \u00b7 3 factors \u00b7 decision_id \u00b7 no odds words",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "analyze_start_sit",
"arguments": {
"players": [
"Bijan Robinson",
"James Cook"
]
}
},
"response": {
"status": 200,
"ms": 116,
"isError": false,
"text": "THE CALL \u00b7 START Bijan Robinson over James Cook \u00b7 70% \u00b7 10-team \u00b7 Week 1 \u00b7 Updated 9:26 PM ET \u00b7 Volume \u2192 \u00b7 Matchup \u2193 \u00b7 Injury risk \u2193 \u00b7 Why: \u2026 (+265 chars)",
"structuredContent": {
"ok": true,
"decision": {
"schema_version": "1.0",
"decision_id": "d_079b7a38dc8d",
"kind": "start_sit",
"verdict": "START",
"headline": "START Bijan Robinson over James Cook",
"subject": [
{
"name": "Bijan Robinson",
"pos": "RB",
"team": "ATL",
"role": "pick",
"status": "",
"projection": 21.53
},
{
"name": "James Cook",
"pos": "RB",
"team": "BUF",
"role": "other",
"status": "",
"projection": 17.11
}
],
"confidence": 70,
"confidence_method": "det-v1",
"confidence_breakdown": {
"method": "det-v1",
"base": 50,
"edge": 19.9,
"freshness": 0,
"injury": 0,
"confidence": 70
},
"league": {
"platform": "MyFantasyLeague",
"name": "QA League",
"teams": 10,
"scoring": "",
"week": 1,
"format_line": "10-team \u00b7 Week 1"
},
"updated_at": "2026-09-08T01:26:40+00:00",
"updated_display": "Updated 9:26 PM ET",
"factors": [
{
"name": "Volume",
"direction": "\u2192",
"note": "No usage on file yet this season"
},
{
"name": "Matchup",
"direction": "\u2193",
"note": "Team expected to chase \u2014 fewer carries late"
},
"\u2026 +1 more"
],
"reasoning": "Bijan Robinson projects 21.5 to James Cook's 17.1 and team expected to chase \u2014 fewer carries late.",
"risk": "Game flow could flip it \u2014 team expected to chase \u2014 fewer carries late is the read on file today.",
"sources": [
{
"label": "RotoWire",
"as_of": "fetched Sep 8, 12:40 AM UTC"
},
{
"label": "RotoWire",
"as_of": "2026-09-08T01:25:38.500901+00:00"
}
],
"watchable": true,
"lock_at": "2026-09-13T17:00:00+00:00"
},
"players": [
{
"player": "Bijan Robinson",
"pos": "RB",
"team": "ATL",
"on_roster": true,
"slot": "RB",
"status": "",
"detail": "",
"status_as_of": "2026-09-08T01:25:38.500901+00:00",
"bye": false,
"bye_week": null,
"projection": {
"points": 21.53,
"source": "RotoWire NFL weekly projections feed (week 1)",
"as_of": "fetched Sep 8, 12:40 AM UTC",
"label": "week 1"
},
"game_env": {
"script": "behind",
"scoring": "neutral",
"known": true
},
"why": [
"projected 21.5",
"team expected to chase \u2014 fewer carries late"
]
},
{
"player": "James Cook",
"pos": "RB",
"team": "BUF",
"on_roster": true,
"slot": "RB2",
"status": "",
"detail": "",
"status_as_of": "2026-09-08T01:25:38.500901+00:00",
"bye": false,
"bye_week": null,
"projection": {
"points": 17.11,
"source": "RotoWire NFL weekly projections feed (week 1)",
"as_of": "fetched Sep 8, 12:40 AM UTC",
"label": "week 1"
},
"game_env": {
"script": "even",
"scoring": "neutral",
"known": true
},
"why": [
"projected 17.1",
"game expected to stay close"
]
}
]
},
"_meta": {
"openai/outputTemplate": "ui://sportscall/decision-card.html",
"sportscall/version": "1.0"
}
},
"pass": true
}✅ watch_decision(d_079b7a38dc8d) \u2192 ok:true, watch_id, ends at lock [pos · chatgpt]
{
"name": "watch_decision(d_079b7a38dc8d) \u2192 ok:true, watch_id, ends at lock",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "watch_decision",
"arguments": {
"decision_id": "d_079b7a38dc8d"
}
},
"response": {
"status": 200,
"ms": 121,
"isError": false,
"text": "Got it \u2014 I'm watching the call on Robinson over Cook until Sun 1 PM. If it flips or the confidence moves a band, SportsCall texts you.",
"structuredContent": {
"ok": true,
"watch_id": 106,
"decision_id": "d_079b7a38dc8d",
"existing": false,
"keys": [
"baseline",
"channel",
"\u2026 +7 more"
]
}
},
"pass": true
}✅ list_watches \u2192 shows the decision watch [pos · chatgpt]
{
"name": "list_watches \u2192 shows the decision watch",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "list_watches",
"arguments": {}
},
"response": {
"status": 200,
"ms": 23,
"isError": false,
"text": "1 active watch: #106 decision START Robinson over Cook by sms until Sun 1 PM.",
"structuredContent": {
"ok": true,
"watches_n": 1,
"keys": [
"ok",
"watches"
]
}
},
"pass": true
}✅ cancel_watch(#106) \u2192 ok:true [pos · chatgpt]
{
"name": "cancel_watch(#106) \u2192 ok:true",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "cancel_watch",
"arguments": {
"id": 106
}
},
"response": {
"status": 200,
"ms": 26,
"isError": false,
"text": "Watch #106 cancelled.",
"structuredContent": {
"ok": true,
"watch_id": 106
}
},
"pass": true
}✅ watch_roster \u00d72 with one Idempotency-Key \u2192 second answer replayed:true, same watch_id [pos · chatgpt]
{
"name": "watch_roster \u00d72 with one Idempotency-Key \u2192 second answer replayed:true, same watch_id",
"kind": "pos",
"surface": "chatgpt",
"request": {
"first": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "watch_roster",
"arguments": {
"channel": "sms"
},
"Idempotency-Key": "e2e-chatgpt-9eeca74886"
},
"second": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "watch_roster",
"arguments": {
"channel": "sms"
},
"Idempotency-Key": "e2e-chatgpt-9eeca74886"
}
},
"response": {
"first": {
"status": 200,
"ms": 108,
"isError": false,
"text": "Got it. I'm watching your whole roster on MyFantasyLeague. If something material changes before Sun 1 PM lock, SportsCall will text you.",
"structuredContent": {
"ok": true,
"watch_id": 107,
"keys": [
"channel",
"ok",
"\u2026 +2 more"
]
}
},
"second": {
"status": 200,
"ms": 23,
"isError": false,
"text": "Got it. I'm watching your whole roster on MyFantasyLeague. If something material changes before Sun 1 PM lock, SportsCall will text you.",
"structuredContent": {
"ok": true,
"watch_id": 107,
"replayed": true,
"keys": [
"channel",
"ok",
"\u2026 +3 more"
]
}
}
},
"pass": true
}✅ get_weekly_brief \u2192 ok:true, one read, sends nothing (no sid, no sends) [pos · chatgpt]
{
"name": "get_weekly_brief \u2192 ok:true, one read, sends nothing (no sid, no sends)",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_weekly_brief",
"arguments": {}
},
"response": {
"status": 200,
"ms": 185,
"isError": false,
"text": "SportsCall brief \u2014 10-team \u00b7 Week 1. Last week: W 149.4-109.1 vs Zero Eifert. No starter is out or on bye. In action this week: Josh Allen, \u2026 (+139 chars)",
"structuredContent": {
"ok": true,
"sends": false,
"week": 1,
"keys": [
"brief_text",
"candidates",
"\u2026 +15 more"
]
}
},
"pass": true
}✅ get_weekly_brief with `deliver` \u2192 E_BAD_ARGS (the brief never sends \u2014 Ian's ruling 2) [neg · chatgpt]
{
"name": "get_weekly_brief with `deliver` \u2192 E_BAD_ARGS (the brief never sends \u2014 Ian's ruling 2)",
"kind": "neg",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_weekly_brief",
"arguments": {
"deliver": "sms"
}
},
"response": {
"status": 200,
"ms": 23,
"isError": true,
"text": "The brief is read-only here \u2014 ask me to text you a specific note if you want one.",
"structuredContent": {
"ok": false,
"code": "E_BAD_ARGS",
"sends": false,
"retryable": false
}
},
"pass": true
}✅ analyze_trade with empty `get` \u2192 E_BAD_ARGS [neg · chatgpt]
{
"name": "analyze_trade with empty `get` \u2192 E_BAD_ARGS",
"kind": "neg",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "analyze_trade",
"arguments": {
"give": [
"Josh Allen"
],
"get": []
}
},
"response": {
"status": 200,
"ms": 24,
"isError": true,
"text": "Tell me what you'd give and what you'd get.",
"structuredContent": {
"ok": false,
"decision": null,
"players": [],
"code": "E_BAD_ARGS",
"retryable": false
},
"_meta": {
"openai/outputTemplate": "ui://sportscall/decision-card.html",
"sportscall/version": "1.0"
}
},
"pass": true
}✅ unknown tool get_odds \u2192 JSON-RPC \u221232601 [neg · chatgpt]
{
"name": "unknown tool get_odds \u2192 JSON-RPC \u221232601",
"kind": "neg",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "get_odds",
"arguments": {}
},
"response": {
"status": 200,
"ms": 20,
"error": {
"code": -32601,
"message": "unknown tool: get_odds"
}
},
"pass": true
}✅ schedule_sportscall in the past \u2192 E_PAST [neg · chatgpt]
{
"name": "schedule_sportscall in the past \u2192 E_PAST",
"kind": "neg",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "schedule_sportscall",
"arguments": {
"at_iso": "2026-09-07T20:26",
"topic": "e2e past"
}
},
"response": {
"status": 200,
"ms": 20,
"isError": true,
"text": "That time has passed \u2014 pick a later one, or say call me now.",
"structuredContent": {
"ok": false,
"reason": "in_the_past",
"code": "E_PAST",
"retryable": false
}
},
"pass": true
}✅ schedule_sportscall 2 days out (fixture) \u2192 no call may leave: E_DEMO_NOOP \u00b7 or a pending queue row (deleted) \u00b7 or a closed gate [pos · chatgpt]
{
"name": "schedule_sportscall 2 days out (fixture) \u2192 no call may leave: E_DEMO_NOOP \u00b7 or a pending queue row (deleted) \u00b7 or a closed gate",
"kind": "pos",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "schedule_sportscall",
"arguments": {
"at_iso": "2026-09-09T12:00",
"topic": "e2e demo"
}
},
"response": {
"status": 200,
"ms": 23,
"isError": true,
"text": "I can't schedule that: this line is out of minutes \u2014 top up and ask again.",
"structuredContent": {
"ok": false,
"reason": "refused_zero_balance",
"code": "E_ZERO_BALANCE",
"retryable": false
}
},
"pass": true,
"note": "gate refused (E_ZERO_BALANCE) \u2014 nothing queued; the fixture has no minutes, so the zero-balance gate answers before any call could queue",
"known_defect": "E_DEMO_NOOP has NO producer in the server (only the error-table entry exists); the plan expects the fixture to answer E_DEMO_NOOP on call tools"
}✅ scope-stripped token (no messages.write / calls.write) + watch_roster channel=call \u2192 HTTP 403 \u00b7 \u221232002 \u00b7 data.code E_SCOPE \u00b7 WWW-Authenticate insufficient_scope [neg · chatgpt]
{
"name": "scope-stripped token (no messages.write / calls.write) + watch_roster channel=call \u2192 HTTP 403 \u00b7 \u221232002 \u00b7 data.code E_SCOPE \u00b7 WWW-Authenticate insufficient_scope",
"kind": "neg",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "watch_roster",
"arguments": {
"channel": "call"
}
},
"response": {
"status": 403,
"ms": 22,
"www-authenticate": "Bearer <redacted>\"insufficient_scope\", scope=\"alerts.write calls.write\"",
"error": {
"code": -32002,
"message": "This connection wasn't allowed to do that (calls.write). Reconnect SportsCall and tick \u201cCall your phone from your SportsCall line when you a\u2026 (+16 chars)",
"data": {
"code": "E_SCOPE",
"missing": [
"calls.write"
]
}
}
},
"pass": true
}✅ scope-stripped token + send_fantasy_alert \u2192 \u221232002 E_SCOPE (missing messages.write) \u2014 no text leaves [neg · chatgpt]
{
"name": "scope-stripped token + send_fantasy_alert \u2192 \u221232002 E_SCOPE (missing messages.write) \u2014 no text leaves",
"kind": "neg",
"surface": "chatgpt",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "send_fantasy_alert",
"arguments": {
"message": "e2e must be refused"
}
},
"response": {
"status": 403,
"ms": 20,
"www-authenticate": "Bearer <redacted>\"insufficient_scope\", scope=\"messages.write\"",
"error": {
"code": -32002,
"message": "This connection wasn't allowed to do that (messages.write). Reconnect SportsCall and tick \u201cText your phone from your SportsCall line when yo\u2026 (+19 chars)",
"data": {
"code": "E_SCOPE",
"missing": [
"messages.write"
]
}
}
},
"pass": true
}✅ replayed authorization code \u2192 400 invalid_grant, and the token it minted is burned (tools/list \u2192 401) [neg · chatgpt]
{
"name": "replayed authorization code \u2192 400 invalid_grant, and the token it minted is burned (tools/list \u2192 401)",
"kind": "neg",
"surface": "chatgpt",
"request": {
"grant_type": "authorization_code",
"code": "<the code from the stripped walk, replayed>"
},
"response": {
"token": {
"status": 400,
"ms": 7,
"headers": {
"cache-control": "no-store",
"content-type": "application/json"
},
"body": {
"error": "invalid_grant",
"error_description": "code already used"
}
},
"then_tools_list": {
"status": 401,
"ms": 20,
"www-authenticate": "Bearer <redacted>\"https://mcp.sportscall.ai/.well-known/oauth-protected-resource\"",
"error": {
"code": -32001,
"message": "bearer token missing, revoked, or unknown"
}
}
},
"pass": true
}✅ tools/list (full \u00b7 the line's own bearer) \u2192 send_lineup_alert, call_me_now, fantasy_* present [pos · full]
{
"name": "tools/list (full \u00b7 the line's own bearer) \u2192 send_lineup_alert, call_me_now, fantasy_* present",
"kind": "pos",
"surface": "full",
"request": {
"rpc": "tools/list",
"auth": "bearer"
},
"response": {
"status": 200,
"tools": [
"get_my_leagues",
"get_my_fantasy_context",
"\u2026 +24 more"
]
},
"pass": true
}✅ send_lineup_alert on:true \u2192 ok:true, lineup_alert:true, a standing watch_id [pos · full]
{
"name": "send_lineup_alert on:true \u2192 ok:true, lineup_alert:true, a standing watch_id",
"kind": "pos",
"surface": "full",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "send_lineup_alert",
"arguments": {
"on": true
}
},
"response": {
"status": 200,
"ms": 121,
"isError": false,
"text": "Lineup alerts are on. Before every kickoff I check your starters \u2014 if one is out, doubtful, on bye or inactive, SportsCall texts you a swap.",
"structuredContent": {
"ok": true,
"lineup_alert": true,
"watch_id": 108
}
},
"pass": true
}✅ send_lineup_alert on:false \u2192 ok:true, lineup_alert:false (cleanup) [pos · full]
{
"name": "send_lineup_alert on:false \u2192 ok:true, lineup_alert:false (cleanup)",
"kind": "pos",
"surface": "full",
"request": {
"rpc": "tools/call",
"auth": "bearer",
"tool": "send_lineup_alert",
"arguments": {
"on": false
}
},
"response": {
"status": 200,
"ms": 23,
"isError": false,
"text": "Lineup alerts are off for this line. Ask again any time to turn them back on.",
"structuredContent": {
"ok": true,
"lineup_alert": false
}
},
"pass": true
}✅ POST /revoke (claude) \u2192 200 \u00b7 then tools/list with the revoked token \u2192 401 [neg · claude]
{
"name": "POST /revoke (claude) \u2192 200 \u00b7 then tools/list with the revoked token \u2192 401",
"kind": "neg",
"surface": "claude",
"request": {
"method": "POST",
"url": "http://127.0.0.1:9001/v1/oauth/sportscall/revoke",
"form": {
"token": "<redacted>"
}
},
"response": {
"revoke": {
"status": 200,
"ms": 4,
"headers": {
"cache-control": "no-store",
"content-type": "application/json"
},
"body": {}
},
"then_tools_list": {
"status": 401,
"ms": 19,
"www-authenticate": "Bearer <redacted>\"https://mcp.sportscall.ai/.well-known/oauth-protected-resource\"",
"error": {
"code": -32001,
"message": "bearer token missing, revoked, or unknown"
}
}
},
"pass": true
}✅ POST /revoke (chatgpt) \u2192 200 \u00b7 then tools/list with the revoked token \u2192 401 [neg · chatgpt]
{
"name": "POST /revoke (chatgpt) \u2192 200 \u00b7 then tools/list with the revoked token \u2192 401",
"kind": "neg",
"surface": "chatgpt",
"request": {
"method": "POST",
"url": "http://127.0.0.1:9001/v1/oauth/sportscall/revoke",
"form": {
"token": "<redacted>"
}
},
"response": {
"revoke": {
"status": 200,
"ms": 4,
"headers": {
"cache-control": "no-store",
"content-type": "application/json"
},
"body": {}
},
"then_tools_list": {
"status": 401,
"ms": 19,
"www-authenticate": "Bearer <redacted>\"https://mcp.sportscall.ai/.well-known/oauth-protected-resource\"",
"error": {
"code": -32001,
"message": "bearer token missing, revoked, or unknown"
}
}
},
"pass": true
}✅ developers /examples renders this transcript (every case name on the page) [pos · -]
{
"name": "developers /examples renders this transcript (every case name on the page)",
"kind": "pos",
"surface": "-",
"request": {
"method": "GET",
"url": "http://127.0.0.1:9001/v1/developers/sportscall/examples"
},
"response": {
"status": 200,
"bytes": 83158,
"missing_case_names": []
},
"pass": true
}Fantasy-sports research and league-management assistance. Not for wagering or sportsbook transactions. · server 1.0 · status · generated 2026-09-08 06:16Z