{"openapi":"3.1.0","info":{"title":"Go Fish Play API","version":"0.1.0","description":"A real, stateless, playable 2-4 player Go Fish engine with AI-controlled fill-in seats: real matching, go-fish draws, automatic book detection, and a genuine probability-informed AI. Every tool call takes the full game state and returns the new state; nothing is stored server-side.\n\nEvery operation is read-only or compute-only. The same tools are available over MCP (streamable HTTP) at https://gofishplay.connectorbay.com/mcp.","contact":{"name":"Unify Dynamics LLC","email":"hr@unifydynamics.com","url":"https://connectorbay.com/gofishplay/docs"},"termsOfService":"https://connectorbay.com/gofishplay/terms"},"servers":[{"url":"https://gofishplay.connectorbay.com"}],"externalDocs":{"url":"https://connectorbay.com/gofishplay/docs"},"security":[{},{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Optional. A Pro API key raises rate limits; no credentials are required."}},"schemas":{"Error":{"type":"object","properties":{"ok":{"const":false},"error":{"type":"object"}}}}},"paths":{"/v1/tools/new_game":{"post":{"operationId":"new_game","summary":"Shuffles a 52-card deck and deals hands (7 cards each for 2-3 players, 5 for 4). Use for","description":"Shuffles a 52-card deck and deals hands (7 cards each for 2-3 players, 5 for 4). Use for\n    \"let's play Go Fish\", \"deal me in with two AI opponents\".","tags":["tools"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"players":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"default":null,"description":"2-4 seats as [{\"name\": str, \"is_ai\": bool}, ...]. Defaults to one human ('You') vs one AI.","examples":[[{"is_ai":false,"name":"You"},{"is_ai":true,"name":"AI"}]],"title":"Players"}},"title":"new_gameArguments","type":"object"}}}},"responses":{"200":{"description":"Tool result. `ok: true` on success; `ok: false` with a structured `error` (provider_unavailable, upstream_error, bad_input) when the tool could not answer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Arguments failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-read-only":true}},"/v1/tools/get_valid_moves":{"post":{"operationId":"get_valid_moves","summary":"Lists every legal (target_player, rank) ask for whoever's turn it currently is -- only","description":"Lists every legal (target_player, rank) ask for whoever's turn it currently is -- only\n    ranks they hold, only opponents who still have cards. Empty once the game is over. Use for\n    \"what can I ask for\", \"who can I ask\".","tags":["tools"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"state":{"additionalProperties":true,"description":"The current game state, exactly as returned by new_game/ask/ai_move.","examples":[{"current_player":0,"deck":["2S"],"last_action":null,"players":[{"books":[],"hand":["3S","7H"],"is_ai":false,"name":"You"},{"books":[],"hand":["9D"],"is_ai":true,"name":"AI"}],"status":"in_progress","winner":null}],"title":"State","type":"object"}},"required":["state"],"title":"get_valid_movesArguments","type":"object"}}}},"responses":{"200":{"description":"Tool result. `ok: true` on success; `ok: false` with a structured `error` (provider_unavailable, upstream_error, bad_input) when the tool could not answer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Arguments failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-read-only":true}},"/v1/tools/ask":{"post":{"operationId":"ask","summary":"The current player asks one opponent for a rank. status is invalid_move, transfer (got","description":"The current player asks one opponent for a rank. status is invalid_move, transfer (got\n    cards -- goes again), go_fish (drew a non-matching card -- turn passes), go_fish_match (drew a\n    match -- goes again), go_fish_empty_deck, or win (the game just ended -- see state.winner).\n    Books complete automatically. Use for \"ask [name] for sevens\", \"do you have any kings\".","tags":["tools"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"state":{"additionalProperties":true,"description":"The current game state, exactly as returned by new_game/ask/ai_move.","examples":[{"current_player":0,"deck":["2S"],"last_action":null,"players":[{"books":[],"hand":["3S","7H"],"is_ai":false,"name":"You"},{"books":[],"hand":["9D"],"is_ai":true,"name":"AI"}],"status":"in_progress","winner":null}],"title":"State","type":"object"},"target_player":{"description":"Seat index of the opponent being asked.","maximum":3,"minimum":0,"title":"Target Player","type":"integer"},"rank":{"description":"The rank to ask for, e.g. '7', '10', 'K'. Must be a rank the asker already holds.","title":"Rank","type":"string"}},"required":["state","target_player","rank"],"title":"askArguments","type":"object"}}}},"responses":{"200":{"description":"Tool result. `ok: true` on success; `ok: false` with a structured `error` (provider_unavailable, upstream_error, bad_input) when the tool could not answer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Arguments failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-read-only":true}},"/v1/tools/ai_move":{"post":{"operationId":"ai_move","summary":"For an AI-controlled current player: decides AND applies a real ask in one call (asks for","description":"For an AI-controlled current player: decides AND applies a real ask in one call (asks for\n    its strongest rank, targets the opponent with the most cards) -- includes `decision` explaining\n    the reasoning. Invalid if the current seat is human-controlled. Use for \"let the AI take its\n    turn\", \"computer's move\".","tags":["tools"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"state":{"additionalProperties":true,"description":"The current game state, exactly as returned by new_game/ask/ai_move.","examples":[{"current_player":0,"deck":["2S"],"last_action":null,"players":[{"books":[],"hand":["3S","7H"],"is_ai":false,"name":"You"},{"books":[],"hand":["9D"],"is_ai":true,"name":"AI"}],"status":"in_progress","winner":null}],"title":"State","type":"object"}},"required":["state"],"title":"ai_moveArguments","type":"object"}}}},"responses":{"200":{"description":"Tool result. `ok: true` on success; `ok: false` with a structured `error` (provider_unavailable, upstream_error, bad_input) when the tool could not answer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Arguments failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-read-only":true}},"/v1/tools/render":{"post":{"operationId":"render","summary":"A human-readable table: each seat's hand (or hidden card count for non-viewers), books, the","description":"A human-readable table: each seat's hand (or hidden card count for non-viewers), books, the\n    deck size, whose turn it is, and the last action. Use for \"show me my hand\", \"what's the\n    board look like\".","tags":["tools"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"state":{"additionalProperties":true,"description":"The current game state, exactly as returned by new_game/ask/ai_move.","examples":[{"current_player":0,"deck":["2S"],"last_action":null,"players":[{"books":[],"hand":["3S","7H"],"is_ai":false,"name":"You"},{"books":[],"hand":["9D"],"is_ai":true,"name":"AI"}],"status":"in_progress","winner":null}],"title":"State","type":"object"},"viewer":{"anyOf":[{"maximum":3,"minimum":0,"type":"integer"},{"type":"null"}],"default":null,"description":"Seat index of the player viewing the board; other seats' hands are hidden (card counts only). Omit to show everything (useful for a fully-AI spectated game).","title":"Viewer"}},"required":["state"],"title":"renderArguments","type":"object"}}}},"responses":{"200":{"description":"Tool result. `ok: true` on success; `ok: false` with a structured `error` (provider_unavailable, upstream_error, bad_input) when the tool could not answer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Arguments failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-read-only":true}},"/v1/tools/rules":{"post":{"operationId":"rules","summary":"Plain-language rules: how an ask/go-fish/book/turn-passing works, end-of-game, and the AI's","description":"Plain-language rules: how an ask/go-fish/book/turn-passing works, end-of-game, and the AI's\n    real strategy. Use for \"how do you play Go Fish\", \"how does the AI decide\".","tags":["tools"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"state":{"anyOf":[{"additionalProperties":true,"description":"The current game state, exactly as returned by new_game/ask/ai_move.","examples":[{"current_player":0,"deck":["2S"],"last_action":null,"players":[{"books":[],"hand":["3S","7H"],"is_ai":false,"name":"You"},{"books":[],"hand":["9D"],"is_ai":true,"name":"AI"}],"status":"in_progress","winner":null}],"type":"object"},{"type":"null"}],"default":null,"title":"State"}},"title":"rulesArguments","type":"object"}}}},"responses":{"200":{"description":"Tool result. `ok: true` on success; `ok: false` with a structured `error` (provider_unavailable, upstream_error, bad_input) when the tool could not answer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Arguments failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-read-only":true}}}}