A full-stack Pokémon battle simulation server built with FastAPI and React. It's designed to adhere to the Model Context Protocol (MCP) and leverages the power of the PokéAPI to fetch live data and run exciting battles.
I built this project to explore the Model Context Protocol and create a fun, interactive Pokémon battle experience. Key aspects include:
- Seamlessly fetching detailed Pokémon data from the official PokéAPI.
- Running realistic turn-based battles with core Pokémon mechanics.
- Providing structured, MCP-compliant responses for easy integration.
- A simple React frontend to visually demonstrate the API's capabilities.
- Backend: Python (FastAPI, httpx, Pydantic)
- Frontend: React (with Tailwind CSS for styling)
- API: PokéAPI
- Architecture: Model Context Protocol (MCP)
This project allows you to:
- Retrieve comprehensive data for any Pokémon, including their base stats, types, abilities, and a list of their level-up moves with details like power and effect.
- Simulate a battle between any two Pokémon. The simulation considers speed for turn order, calculates damage using a formula incorporating stats, move power, type effectiveness, STAB, critical hits, and a touch of randomness.
- Experience core status effects like Paralysis (with turn skipping and speed reduction), Burn (reducing Attack and causing turn-end damage), and Poison (causing turn-end damage).
- Get a clear battle outcome showing the winner, a detailed log of every action taken each turn, and the final state of both Pokémon (HP and status).
- Interact with the API directly or through a simple, responsive web interface.
Here's a quick look at how the battle simulation works:
- Turn Order: Determined by the Speed stat. If speeds are equal, the order is random each turn.
- Damage Formula:
(((2 * Level / 5 + 2) * Attacking_Stat / Defending_Stat * Move_Power) / 50 + 2) × STAB × Type_Effectiveness × Critical_Hit × Random_Factor- Attacking_Stat: Uses Attack for Physical moves, Special Attack for Special moves.
- Defending_Stat: Uses Defense for Physical moves, Special Defense for Special moves.
- STAB (Same Type Attack Bonus): A 1.5× multiplier if the move's type matches one of the attacking Pokémon's types.
- Type Effectiveness: Damage is multiplied based on the defending Pokémon's type(s) versus the attacking move's type.
- Critical Hit: A 6.25% chance to multiply damage by 1.5×.
- Random Factor: A multiplier between 0.85 and 1.0 applied to the final damage.
- Paralysis: The affected Pokémon has a 25% chance to be unable to move that turn, and its Speed stat is quartered.
- Burn: The affected Pokémon's Attack stat is halved, and it loses 1/16 of its maximum HP at the end of each turn.
- Poison: The affected Pokémon loses 1/8 of its maximum HP at the end of each turn.
Retrieve detailed information about a specific Pokémon.
GET /api/resource/pokemon/{name}
- Path Parameter:
{name}(string) - The name of the Pokémon (case-insensitive).
Example Query (using curl):
curl http://localhost:8000/api/resource/pokemon/pikachuExpected Output Structure (MCPToolResponse):
{
"content": {
"id": 25,
"name": "pikachu",
"height": 4,
"weight": 60,
"stats": [ { "name": "hp", "base_value": 35 }, ... ],
"types": [ { "name": "electric" } ],
"abilities": [ { "name": "static", "is_hidden": false }, ... ],
"moves": [ { "name": "thunder-shock", "level": 1, "type": "electric", "power": 40, ... }, ... ],
"evolution_chain": [ { "name": "pichu", "method": null, "condition": null }, ... ]
},
"metadata": {
"timestamp": "...",
"status": "success"
}
}Initiate a battle simulation between two Pokémon.
POST /api/tool/battle
- Request Body (MCPToolRequest):
{
"content": {
"pokemon1": "pikachu",
"pokemon2": "charmander"
}
}- Content Fields:
pokemon1(string): The name of the first Pokémon.pokemon2(string): The name of the second Pokémon.
Example Query (using curl):
escaped_json_body='{"content":{"pokemon1":"pikachu","pokemon2":"charmander"}}'
curl -X POST \
-H "Content-Type: application/json" \
-d "$escaped_json_body" \
http://localhost:8000/api/tool/battleExpected Output Structure (MCPToolResponse):
{
"content": {
"winner": "pikachu",
"battle_log": [ { "turn": 1, "event_type": "attack", "description": "Pikachu used Thunderbolt!", ... }, ... ],
"final_state": {
"pikachu": { "name": "pikachu", "current_hp": 30, "max_hp": 100, "status": null },
"charmander": { "name": "charmander", "current_hp": 0, "max_hp": 80, "status": "burned" }
},
"turns": 10
},
"metadata": {
"timestamp": "...",
"status": "success"
}
}project/
├── app/ # Backend FastAPI application
│ ├── api/ # API routes and schemas
│ │ ├── routes.py
│ │ └── mcp/ # Model Context Protocol schemas
│ │ └── schemas.py
│ ├── services/ # Business logic for data fetching and battles
│ │ ├── pokemon_service.py
│ │ └── battle_service.py
│ ├── core/ # Configuration and settings
│ │ └── config.py
│ └── main.py # FastAPI app entry point
├── frontend/ # Optional React frontend application
│ └── src/
│ └── App.tsx # Main React component
├── requirements.txt # Python dependencies
├── .env.example # Example environment variables
└── README.md # Project documentation
Follow these steps to get the project running locally:
-
Clone the repository:
git clone <repository_url> cd <repository_directory>
-
Set up the Backend:
# Navigate to the backend app directory cd project # (Optional but recommended) Create and activate a Python virtual environment # python -m venv .venv # .venv\Scripts\activate # On Windows # source .venv/bin/activate # On macOS/Linux # Install Python dependencies pip install -r requirements.txt # Create your .env file (copy the example) cp .env.example .env # You might need to adjust settings in .env if not using the default PokéAPI URL # Start the FastAPI server # The server will run on http://localhost:8000 uvicorn app.main:app --reload
Leave the backend terminal running.
-
Set up the Frontend (Optional):
# Make sure you are in the project root directory cd project # Navigate to the frontend directory cd frontend # Install Node.js dependencies npm install # Start the React development server # The frontend will typically run on http://localhost:5173 npm run dev
Now you can access the frontend in your browser at http://localhost:5173 or interact directly with the backend API at http://localhost:8000/docs (Swagger UI).
- The battle simulation is a simplified model for demonstration purposes.
- An active internet connection is required to fetch data from PokéAPI.
- The default level for all Pokémon in battles is 50.
Feel free to fork this repository and contribute! Whether it's adding more complex battle mechanics, improving the frontend UI, or enhancing API documentation, all contributions are welcome.

