#
tokens: 7533/50000 13/13 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .dockerignore
├── .github
│   └── workflows
│       └── docker-build.yml
├── .gitignore
├── cs2-rcon-mcp.gif
├── Dockerfile
├── LICENSE
├── pyproject.toml
├── README.md
├── requirements.txt
├── src
│   └── rcon_mcp
│       ├── __init__.py
│       ├── __main__.py
│       ├── commands.py
│       ├── config.py
│       ├── server.py
│       └── utils.py
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------

```
 1 | # 🔐 Sensitive files
 2 | .env
 3 | .env.*
 4 | 
 5 | # 🐍 Python cache
 6 | __pycache__/
 7 | *.py[cod]
 8 | *.pyo
 9 | 
10 | # 📦 Virtual environments
11 | venv/
12 | env/
13 | .venv/
14 | ENV/
15 | 
16 | # 💾 Package files
17 | *.egg
18 | *.egg-info/
19 | dist/
20 | build/
21 | .eggs/
22 | 
23 | # 📁 OS / IDE / Editor files
24 | .DS_Store
25 | *.log
26 | *.swp
27 | *.swo
28 | .vscode/
29 | .idea/
30 | 
31 | # 🔧 Test files & coverage
32 | .coverage
33 | .tox/
34 | .pytest_cache/
35 | htmlcov/
36 | 
37 | # 🔄 Git and version control
38 | .git/
39 | .gitignore
40 | 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Python
 2 | __pycache__/
 3 | *.py[cod]
 4 | *$py.class
 5 | *.so
 6 | .Python
 7 | build/
 8 | develop-eggs/
 9 | dist/
10 | downloads/
11 | eggs/
12 | .eggs/
13 | lib/
14 | lib64/
15 | parts/
16 | sdist/
17 | var/
18 | wheels/
19 | *.egg-info/
20 | .installed.cfg
21 | *.egg
22 | 
23 | # Virtual Environment
24 | .env
25 | .venv
26 | env/
27 | venv/
28 | ENV/
29 | env.bak/
30 | venv.bak/
31 | 
32 | # IDE
33 | .idea/
34 | .vscode/
35 | *.swp
36 | *.swo
37 | .DS_Store
38 | 
39 | # Testing
40 | .coverage
41 | htmlcov/
42 | .pytest_cache/
43 | .tox/
44 | .nox/
45 | 
46 | # Logs
47 | *.log
48 | logs/
49 | 
50 | # Local development
51 | *.env
52 | .env.local
53 | .env.development
54 | .env.test
55 | .env.production
56 | 
57 | # Docker
58 | .docker/
59 | docker-compose.override.yml
60 | 
61 | # Misc
62 | *.bak
63 | *.tmp
64 | *.temp
65 | .cache/
66 | .pytest_cache/
67 | .mypy_cache/
68 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # CS2 RCON MCP
  2 | 
  3 | [![Python](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/downloads/)
  4 | [![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-green.svg)](https://cursor.sh)
  5 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
  6 | 
  7 | A Model Context Protocol server for CS2 RCON management.
  8 | 
  9 | ## Description
 10 | 
 11 | This project provides a Model Context Protocol (MCP) server interface for managing CS2 game servers via RCON. It allows remote control and monitoring of CS2 servers through a standardized protocol.
 12 | 
 13 | ![CS2 RCON MCP Demo](cs2-rcon-mcp.gif)
 14 | 
 15 | ## Features
 16 | 
 17 | - Manage your CS2 server in natural language
 18 | - RCON command execution
 19 | - Manage workshop maps (host, list, change) - [Explore Workshop Maps](https://steamcommunity.com/app/730/workshop/)
 20 | - SSE-based communication
 21 | - Docker support
 22 | 
 23 | ## Available Tools
 24 | 
 25 | | Tool | Short Description |
 26 | |------|-------------------|
 27 | | `rcon` | Execute any RCON command |
 28 | | `status` | Get current server status |
 29 | | `list_workshop_maps` | List all workshop maps on the server |
 30 | | `host_workshop_map` | Host a workshop map by its ID |
 31 | | `workshop_changelevel` | Change the map to a given workshop map |
 32 | 
 33 | ## Installation
 34 | 
 35 | ### Environment Variables
 36 | 
 37 | - `HOST`: CS2 server IP
 38 | - `SERVER_PORT`: CS2 server port
 39 | - `RCON_PASSWORD`: RCON password
 40 | 
 41 | ### Docker (recommended)
 42 | 
 43 | Pull the Docker image from GitHub Container Registry:
 44 | 
 45 | ```bash
 46 | docker pull ghcr.io/v9rt3x/cs2-rcon-mcp:latest
 47 | ```
 48 | 
 49 | ### Docker Environment Variables
 50 | 
 51 | When running with Docker, you can set the environment variables in two ways:
 52 | 
 53 | 1. **Directly in the command**:
 54 |    ```bash
 55 |    docker run -p 8080:8080 \
 56 |      -e HOST=your_server_ip \
 57 |      -e SERVER_PORT=your_server_port \
 58 |      -e RCON_PASSWORD=your_password \
 59 |      ghcr.io/v9rt3x/cs2-rcon-mcp:latest
 60 |    ```
 61 | 
 62 | 2. **Using a `.server-env` file**:
 63 |    Create a file named `.server-env` with the following content:
 64 |    ```
 65 |    HOST=your_server_ip
 66 |    SERVER_PORT=your_server_port
 67 |    RCON_PASSWORD=your_password
 68 |    ```
 69 | 
 70 |    Then run the container like this:
 71 |    ```bash
 72 |    docker run -p 8080:8080 --env-file .server-env ghcr.io/v9rt3x/cs2-rcon-mcp:latest
 73 |    ```
 74 | 
 75 | This provides users with an alternative method to set environment variables, making it easier to manage sensitive information like passwords.
 76 | 
 77 | ### Connecting from Visual Studio Code (GitHub Copilot)
 78 | 
 79 | To configure Visual Studio Code to work with the MCP server, follow these steps:
 80 | 
 81 | 1. **Start the MCP Server**: Ensure that your MCP server is running before attempting to connect from VS Code.
 82 | 
 83 | 2. **Open Visual Studio Code**: Launch VS Code and ensure that you have the GitHub Copilot extension installed and configured.
 84 | 
 85 | 3. **Configure GitHub Copilot**:
 86 |    - Change the mode from "Ask" to "Agent" mode.
 87 | 
 88 | 4. **Add MCP Server Configuration**:
 89 |    - Click on the toolbox icon in the upper left corner of the Copilot prompt.
 90 |    - Select "Add MCP Server" and choose the option for **HTTP - server-sent events**.
 91 | 
 92 | 5. **Enter the Server URL**:
 93 |    - For the URL, input: `http://localhost:8080/cs2server/sse`. This is the endpoint for the MCP server's SSE connection.
 94 | 
 95 | ### Alternative: Connecting from Cursor (or any other MCP-Client)
 96 | 
 97 | 1. Start the MCP server
 98 | 2. Configure Cursor's MCP settings by creating or updating `~/.cursor/mcp.json`:
 99 |    ```json
100 |    {
101 |      "mcpServers": {
102 |        "cs2server": {
103 |          "url": "http://localhost:8080/cs2server/sse"
104 |        }
105 |      }
106 |    }
107 |    ```
108 | 3. In Cursor, open the MCP panel (usually in the sidebar)
109 | 4. The server should automatically connect using the configured URL
110 | 
111 | Once connected, you can manage your server in natural language.
112 | 
113 | Example prompts:
114 | 
115 | 1. "Add 5 bots to the server and start a competitive match on de_dust2"
116 | 2. "What's the current server status? How many players are connected and what map are we on?"
117 | 
118 | Happy fragging! 😊
119 | 
```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
1 | rcon
2 | mcp==1.3.0
3 | python-dotenv==1.0.1
4 | sse-starlette==2.2.1
5 | starlette==0.46.0
6 | uvicorn==0.34.0
7 | 
```

--------------------------------------------------------------------------------
/src/rcon_mcp/__init__.py:
--------------------------------------------------------------------------------

```python
1 | """CS2 RCON MCP - A Model Context Protocol server for CS2 RCON management."""
2 | 
3 | __version__ = "0.1.0" 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | FROM python:3.13.2-slim
 2 | 
 3 | WORKDIR /app
 4 | 
 5 | # Copy only the requirements first to leverage Docker cache
 6 | COPY pyproject.toml README.md /app/
 7 | 
 8 | # Install build dependencies
 9 | RUN pip install --no-cache-dir --upgrade pip && \
10 |     pip install --no-cache-dir hatchling
11 | 
12 | # Copy the source code
13 | COPY src/ /app/src/
14 | 
15 | # Install the package in development mode
16 | RUN pip install --no-cache-dir -e .
17 | 
18 | EXPOSE 8080
19 | 
20 | # Run the application using the module path
21 | CMD ["python", "-m", "rcon_mcp"]
22 | 
```

--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [build-system]
 2 | requires = ["hatchling"]
 3 | build-backend = "hatchling.build"
 4 | 
 5 | [project]
 6 | name = "rcon-mcp"
 7 | version = "0.1.0"
 8 | description = "A Model Context Protocol server for CS2 RCON management"
 9 | readme = "README.md"
10 | requires-python = ">=3.8"
11 | dependencies = [
12 |     "rcon",
13 |     "mcp==1.3.0",
14 |     "python-dotenv==1.0.1",
15 |     "sse-starlette==2.2.1",
16 |     "starlette==0.46.0",
17 |     "uvicorn==0.34.0"
18 | ]
19 | 
20 | [project.scripts]
21 | rcon-mcp = "rcon_mcp.__main__:main"
22 | 
23 | [tool.hatch.build.targets.wheel]
24 | packages = ["src/rcon_mcp"]
25 | 
```

--------------------------------------------------------------------------------
/src/rcon_mcp/__main__.py:
--------------------------------------------------------------------------------

```python
 1 | from .config import AppConfig
 2 | from .server import MCPServer
 3 | from .utils import setup_logging, parse_args
 4 | from .commands import mcp_server
 5 | import logging
 6 | 
 7 | logger = logging.getLogger(__name__)
 8 | 
 9 | def main() -> None:
10 |     """Main entry point for the RCON Model Context Protocol application."""
11 |     # Setup logging
12 |     setup_logging()
13 |     
14 |     try:
15 |         # Load configurations
16 |         app_config = AppConfig.from_args(parse_args())
17 |         
18 |         # Create and run the server
19 |         server = MCPServer(mcp_server, app_config)
20 |         server.run()
21 |         
22 |     except Exception as e:
23 |         logger.error(f"Application error: {e}")
24 |         raise
25 | 
26 | if __name__ == "__main__":
27 |     main() 
```

--------------------------------------------------------------------------------
/src/rcon_mcp/utils.py:
--------------------------------------------------------------------------------

```python
 1 | import logging
 2 | import argparse
 3 | from typing import Dict, Any
 4 | 
 5 | def setup_logging() -> None:
 6 |     """Configure logging for the application."""
 7 |     logging.basicConfig(
 8 |         level=logging.INFO,
 9 |         format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
10 |     )
11 | 
12 | def parse_args() -> Dict[str, Any]:
13 |     """Parse command line arguments.
14 |     
15 |     Returns:
16 |         Dict[str, Any]: Dictionary of parsed arguments.
17 |     """
18 |     parser = argparse.ArgumentParser(description='Run MCP SSE-based server')
19 |     parser.add_argument('--host', default='0.0.0.0', help='Host to bind to')
20 |     parser.add_argument('--port', type=int, default=8080, help='Port to listen on')
21 |     parser.add_argument('--debug', action='store_true', help='Enable debug mode')
22 |     return vars(parser.parse_args()) 
```

--------------------------------------------------------------------------------
/.github/workflows/docker-build.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Docker Build and Push
 2 | 
 3 | on:
 4 |   push:
 5 |     tags:
 6 |       - 'v*'
 7 | 
 8 | env:
 9 |   REGISTRY: ghcr.io
10 |   IMAGE_NAME: ${{ github.repository }}
11 | 
12 | jobs:
13 |   build-and-push:
14 |     runs-on: ubuntu-latest
15 |     permissions:
16 |       contents: read
17 |       packages: write
18 | 
19 |     steps:
20 |       - name: Checkout repository
21 |         uses: actions/checkout@v4
22 | 
23 |       - name: Log in to the Container registry
24 |         uses: docker/login-action@v3
25 |         with:
26 |           registry: ${{ env.REGISTRY }}
27 |           username: ${{ github.actor }}
28 |           password: ${{ secrets.GITHUB_TOKEN }}
29 | 
30 |       - name: Log in to Docker Hub
31 |         uses: docker/login-action@v3
32 |         with:
33 |           username: ${{ secrets.DOCKER_HUB_USERNAME }}
34 |           password: ${{ secrets.DOCKERHUB_TOKEN }}
35 | 
36 |       - name: Extract metadata (tags, labels) for Docker
37 |         id: meta
38 |         uses: docker/metadata-action@v5
39 |         with:
40 |           images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
41 | 
42 |       - name: Build and push Docker image
43 |         uses: docker/build-push-action@v6
44 |         with:
45 |           context:
46 |           push: true
47 |           tags: v9r73x/cs2-rcon-mcp:latest
48 | 
```

--------------------------------------------------------------------------------
/src/rcon_mcp/config.py:
--------------------------------------------------------------------------------

```python
 1 | import os
 2 | from dataclasses import dataclass
 3 | import logging
 4 | from typing import Optional
 5 | 
 6 | logger = logging.getLogger(__name__)
 7 | 
 8 | @dataclass
 9 | class ServerConfig:
10 |     """Configuration for the CS2 server connection."""
11 |     host: str
12 |     port: int
13 |     password: str
14 | 
15 |     @classmethod
16 |     def from_env(cls) -> 'ServerConfig':
17 |         """Create a ServerConfig instance from environment variables.
18 |         
19 |         Returns:
20 |             ServerConfig: The configured server settings.
21 |             
22 |         Raises:
23 |             ValueError: If required environment variables are missing or invalid.
24 |         """
25 |         host = os.getenv("HOST")
26 |         port = os.getenv("SERVER_PORT")
27 |         password = os.getenv("RCON_PASSWORD")
28 | 
29 |         if not all([host, port, password]):
30 |             raise ValueError(
31 |                 "Missing required environment variables: HOST, SERVER_PORT, RCON_PASSWORD"
32 |             )
33 | 
34 |         try:
35 |             port_int = int(port)
36 |         except ValueError:
37 |             raise ValueError(f"Invalid SERVER_PORT value: {port}")
38 | 
39 |         return cls(host=host, port=port_int, password=password)
40 | 
41 | @dataclass
42 | class AppConfig:
43 |     """Configuration for the MCP application."""
44 |     debug: bool = False
45 |     host: str = "0.0.0.0"
46 |     port: int = 8080
47 | 
48 |     @classmethod
49 |     def from_args(cls, args: Optional[dict] = None) -> 'AppConfig':
50 |         """Create an AppConfig instance from command line arguments.
51 |         
52 |         Args:
53 |             args: Optional dictionary of command line arguments.
54 |             
55 |         Returns:
56 |             AppConfig: The configured application settings.
57 |         """
58 |         if args is None:
59 |             return cls()
60 |         return cls(
61 |             debug=args.get("debug", False),
62 |             host=args.get("host", "0.0.0.0"),
63 |             port=args.get("port", 8080)
64 |         ) 
```

--------------------------------------------------------------------------------
/src/rcon_mcp/server.py:
--------------------------------------------------------------------------------

```python
 1 | import logging
 2 | from typing import Optional
 3 | from starlette.applications import Starlette
 4 | from starlette.requests import Request
 5 | from starlette.routing import Mount, Route
 6 | from mcp.server import Server
 7 | from mcp.server.sse import SseServerTransport
 8 | from .config import AppConfig
 9 | 
10 | logger = logging.getLogger(__name__)
11 | 
12 | class MCPServer:
13 |     """Model Context Protocol server implementation for CS2 server management."""
14 |     
15 |     def __init__(self, mcp_server: Server, config: AppConfig):
16 |         """Initialize the MCP server.
17 |         
18 |         Args:
19 |             mcp_server: The MCP server instance to handle requests.
20 |             config: Application configuration settings.
21 |         """
22 |         self.mcp_server = mcp_server
23 |         self.config = config
24 |         self.sse = SseServerTransport("/cs2server/messages/")
25 |         self.app = self._create_starlette_app()
26 | 
27 |     def _create_starlette_app(self) -> Starlette:
28 |         """Create the Starlette application with SSE support.
29 |         
30 |         Returns:
31 |             Starlette: The configured Starlette application.
32 |         """
33 |         async def handle_sse(request: Request) -> None:
34 |             """Handle SSE connections for the MCP server.
35 |             
36 |             Args:
37 |                 request: The incoming HTTP request.
38 |                 
39 |             Raises:
40 |                 Exception: If there's an error handling the SSE connection.
41 |             """
42 |             logger.info("Handling new SSE connection")
43 |             try:
44 |                 async with self.sse.connect_sse(
45 |                     request.scope,
46 |                     request.receive,
47 |                     request._send,
48 |                 ) as (read_stream, write_stream):
49 |                     await self.mcp_server.run(
50 |                         read_stream,
51 |                         write_stream,
52 |                         self.mcp_server.create_initialization_options(),
53 |                     )
54 |             except Exception as e:
55 |                 logger.error(f"Error handling SSE connection: {e}")
56 |                 raise
57 | 
58 |         return Starlette(
59 |             debug=self.config.debug,
60 |             routes=[
61 |                 Route("/cs2server/sse", endpoint=handle_sse),
62 |                 Mount("/cs2server/messages/", app=self.sse.handle_post_message),
63 |             ],
64 |         )
65 | 
66 |     def run(self) -> None:
67 |         """Run the MCP server."""
68 |         import uvicorn
69 |         logger.info(f"Starting server on {self.config.host}:{self.config.port}")
70 |         uvicorn.run(self.app, host=self.config.host, port=self.config.port) 
```

--------------------------------------------------------------------------------
/src/rcon_mcp/commands.py:
--------------------------------------------------------------------------------

```python
  1 | from typing import Dict, List
  2 | from rcon.source import Client
  3 | import logging
  4 | from mcp.server.fastmcp import FastMCP
  5 | from .config import ServerConfig
  6 | 
  7 | logger = logging.getLogger(__name__)
  8 | 
  9 | # Initialize FastMCP server to interact with CS2 servers
 10 | mcp = FastMCP("CS2 MCP-Server 🚀", dependencies=["rcon"])
 11 | 
 12 | class RCONCommands:
 13 |     """Handler for RCON commands to the CS2 server."""
 14 |     
 15 |     def __init__(self, config: ServerConfig):
 16 |         """Initialize the RCON commands handler.
 17 |         
 18 |         Args:
 19 |             config: Server configuration containing connection details.
 20 |         """
 21 |         self.config = config
 22 | 
 23 |     def execute(self, command: str) -> str:
 24 |         """Execute an RCON command on the CS2 server.
 25 |         
 26 |         Args:
 27 |             command: The RCON command to execute.
 28 |             
 29 |         Returns:
 30 |             str: The server's response to the command.
 31 |             
 32 |         Raises:
 33 |             ConnectionError: If unable to connect to the RCON server.
 34 |             ValueError: If the command execution fails.
 35 |         """
 36 |         try:
 37 |             with Client(self.config.host, self.config.port, passwd=self.config.password) as client:
 38 |                 response = client.run(command, '')
 39 |                 return response
 40 |         except Exception as e:
 41 |             logger.error(f"Failed to execute RCON command '{command}': {e}")
 42 |             raise ConnectionError(f"Failed to execute RCON command: {e}") from e
 43 | 
 44 |     def status(self) -> str:
 45 |         """Get the current status of the CS2 server.
 46 |         
 47 |         Returns:
 48 |             str: The server's status information.
 49 |             
 50 |         Raises:
 51 |             ConnectionError: If unable to connect to the RCON server.
 52 |         """
 53 |         return self.execute("status")
 54 |     
 55 |     def list_workshop_maps(self) -> str:
 56 |         """List all workshop maps on the CS2 server.
 57 |         
 58 |         Returns:
 59 |             str: A list of workshop maps.
 60 |         """
 61 |         return self.execute("ds_workshop_listmaps")
 62 |     
 63 |     def host_workshop_map(self, workshop_map_id: int) -> str:
 64 |         """Hosts a workshop map by its id on the CS2 server.
 65 |         
 66 |         Returns:
 67 |             str: The server's response to the host_workshop_map command.
 68 |         """
 69 |         command = f"host_workshop_map {workshop_map_id}"
 70 |         return self.execute(command)
 71 |     
 72 |     def workshop_changelevel(self, workshop_map_name: str) -> str:
 73 |         """Changes the map to a given CS2 workshop map on the CS2 server.
 74 |         
 75 |         Returns:
 76 |             str: The server's response to the ds_worskshop_changelevel command.
 77 |         """
 78 |         command = f"ds_workshop_changelevel {workshop_map_name}"
 79 |         return self.execute(command)
 80 | 
 81 |     @staticmethod
 82 |     def get_available_commands() -> Dict[str, str]:
 83 |         """Get a dictionary of available RCON commands and their descriptions.
 84 |         
 85 |         Returns:
 86 |             Dict[str, str]: Dictionary mapping command names to their descriptions.
 87 |         """
 88 |         return {
 89 |             "changelevel <map_name>": "Changes the current map.",
 90 |             "mp_warmup_end": "Ends the warmup phase.",
 91 |             "mp_restartgame 1": "Restarts the game after 1 second.",
 92 |             "bot_kick": "Kicks all bots from the server.",
 93 |             "bot_add_t": "Adds a bot to the Terrorist side.",
 94 |             "bot_add_ct": "Adds a bot to the Counter-Terrorist side.",
 95 |             "bot_quota <number>": "Sets the total number of bots.",
 96 |             "mp_freezetime 15": "Sets the freeze time before rounds start (15 sec).",
 97 |             "mp_roundtime 1.92": "Sets the round duration to 1:55 minutes.",
 98 |             "mp_maxrounds 24": "Sets the maximum number of rounds (MR24).",
 99 |             "mp_halftime 1": "Enables halftime after 12 rounds.",
100 |             "mp_buytime 20": "Sets how long players can buy weapons (20 sec).",
101 |             "mp_startmoney 800": "Sets the starting money for players.",
102 |             "mp_overtime_enable 1": "Enables overtime if the match is tied.",
103 |             "mp_overtime_maxrounds 6": "Sets max rounds in overtime (MR6).",
104 |             "mp_overtime_startmoney 12500": "Sets start money for overtime rounds.",
105 |             "mp_defuser_allocation 2": "Gives all CTs a defuse kit.",
106 |             "mp_limitteams 1": "Prevents unbalanced teams.",
107 |             "mp_autoteambalance 1": "Enables automatic team balancing.",
108 |             "mp_force_pick_time 5": "Time players have to pick a team.",
109 |             "mp_ignore_round_win_conditions 0": "Disables forced round end.",
110 |             "mp_death_drop_gun 1": "Allows players to drop their weapons on death.",
111 |             "mp_t_default_grenades \"weapon_molotov;weapon_smokegrenade\"": "Sets default grenades for Ts.",
112 |             "mp_ct_default_grenades \"weapon_incgrenade;weapon_smokegrenade\"": "Sets default grenades for CTs.",
113 |             "sv_cheats 0": "Disables cheats (must be 1 to enable commands like noclip).",
114 |             "rcon_password <password>": "Sets the RCON password for remote control.",
115 |             "rcon <command>": "Runs a remote command on the server.",
116 |             "exec <config_name>": "Executes a config file (e.g., exec server.cfg).",
117 |             "status": "Shows server status and player information.",
118 |             "kick <player_name or #userid>": "Kicks a player from the server.",
119 |             "banid <time> <steamID>": "Bans a player for a certain duration.",
120 |             "host_workshop_map <workshop_id>": "Loads a workshop map.",
121 |             "mp_endmatch": "Ends the current match.",
122 |             "mp_pause_match": "Pauses the match.",
123 |             "mp_unpause_match": "Unpauses the match.",
124 |             "sv_alltalk 0": "Disables voice chat between teams.",
125 |             "mp_spectators_max 4": "Limits the number of spectators.",
126 |             "mp_forcecamera 1": "Restricts dead players' view to only their team.",
127 |             "sv_voiceenable 1": "Enables voice communication.",
128 |             "mp_respawn_immunitytime 0": "Disables spawn protection.",
129 |             "mp_display_kill_assists 1": "Enables assist tracking in scoreboard.",
130 |             "mp_randomspawn 0": "Ensures standard spawn locations.",
131 |             "sv_infinite_ammo 0": "Disables infinite ammo (1 for unlimited bullets).",
132 |             "sv_grenade_trajectory 0": "Disables grenade trajectory lines.",
133 |             "sv_showimpacts 0": "Disables bullet impact visualization.",
134 |             "mp_warmuptime 60": "Sets warmup duration (60 sec).",
135 |             "mp_suicide_penalty 0": "Removes suicide penalty.",
136 |             "mp_teammates_are_enemies 0": "Disables friendly fire (1 = FFA mode).",
137 |             "mp_round_restart_delay 5": "Time before the next round starts (5 sec).",
138 |             "mp_weapon_allow_glock 1": "Enables/disables specific weapons.",
139 |             "mp_c4timer 40": "Sets bomb timer duration (40 sec standard).",
140 |             "mp_playercashawards 1": "Enables money rewards for player actions.",
141 |             "mp_teamcashawards 1": "Enables team-wide money rewards.",
142 |             "sv_matchpause_auto_5v5 1": "Enables auto-pause for 5v5 competitive.",
143 |             "mp_friendlyfire 1": "Enables friendly fire.",
144 |             "sv_competitive_minspec 1": "Forces minimum competitive settings."
145 |         }
146 | 
147 | # Create RCON commands instance
148 | rcon_commands = RCONCommands(ServerConfig.from_env())
149 | 
150 | @mcp.tool()
151 | def rcon(command: str) -> str:
152 |     """Execute an RCON command on the CS2 server.
153 |     
154 |     Args:
155 |         command: The RCON command to execute.
156 |         
157 |     Returns:
158 |         str: The server's response to the command.
159 |         
160 |     Raises:
161 |         ConnectionError: If unable to connect to the RCON server.
162 |         ValueError: If the command execution fails.
163 |     """
164 |     return rcon_commands.execute(command)
165 | 
166 | @mcp.tool()
167 | def status() -> str:
168 |     """Get the current status of the CS2 server.
169 |     
170 |     Returns:
171 |         str: The server's status information.
172 |         
173 |     Raises:
174 |         ConnectionError: If unable to connect to the RCON server.
175 |     """
176 |     return rcon_commands.status()
177 | 
178 | @mcp.tool()
179 | def list_workshop_maps() -> str:
180 |     """List all workshop maps on the CS2 server.
181 |         
182 |     Returns:
183 |         str: A list of workshop maps.
184 |         
185 |     Raises:
186 |         ConnectionError: If unable to connect to the server.
187 |     """
188 |     return rcon_commands.list_workshop_maps()
189 | 
190 | @mcp.tool()
191 | def host_workshop_map(workshop_map_id: int) -> str:
192 |     """Hosts a workshop map by its id on the CS2 server.
193 |     
194 |     Args:
195 |         command: The id of the workshop map that should be hosted.
196 |         
197 |     Returns:
198 |         str: The server's response to the command.
199 |         
200 |     Raises:
201 |         ConnectionError: If unable to connect to the server.
202 |         ValueError: If the command execution fails.
203 |     """
204 |     return rcon_commands.host_workshop_map(workshop_map_id)
205 | 
206 | @mcp.tool()
207 | def workshop_changelevel(workshop_map_name: str) -> str:
208 |     """Changes the map to a given CS2 workshop map on the CS2 server.
209 |     
210 |     Args:
211 |         command: The workshop map name the map should change to.
212 |         
213 |     Returns:
214 |         str: The server's response to the command.
215 |         
216 |     Raises:
217 |         ConnectionError: If unable to connect to the server.
218 |         ValueError: If the command execution fails.
219 |     """
220 |     return rcon_commands.workshop_changelevel(workshop_map_name)
221 | 
222 | # Export the MCP instance
223 | mcp_server = mcp._mcp_server
224 | 
```