Async Python SDK for connecting Discord bots and automation to Minecraft servers through a CraftCord plugin API.
Project description
CraftCord
CraftCord is an async Python SDK for talking to Minecraft Paper servers through CraftCordPlugin.
It provides a clean API for requests and live events over HTTP or WebSocket, so your app can focus on behavior instead of protocol plumbing.
Note:
- CraftCord requires CraftCordPlugin on your Paper server.
- Plugin repository: https://github.com/rytisltu09/CraftcordPlugin
What Changed
CraftCord no longer ships a built-in Discord adapter layer.
Use CraftCord as your Minecraft transport/event SDK, and wire Discord behavior directly in your own bot runtime (for example, discord.py).
This keeps the SDK simpler and avoids framework-specific abstractions.
Features
- Async-first API
- HTTP and WebSocket transports
- Typed Minecraft models
- Event dispatcher with typed events + GenericEvent fallback
- Built-in command registry/invocation
- Python-side plugin manager
- Framework-agnostic integration pattern for Discord bots and other Python apps
Installation
pip install craftcord
If your application uses discord.py, install it in your app environment:
pip install discord.py
Quick Start
Environment Variables
export CRAFTCORD_HOST="127.0.0.1"
export CRAFTCORD_PORT="8080"
export CRAFTCORD_TOKEN="your-api-token"
export CRAFTCORD_TRANSPORT="ws"
Minimal Client
import asyncio
from craftcord import Client
async def main() -> None:
client = Client(host="127.0.0.1", port=8080, token="secret")
@client.command("online")
async def online() -> list[str]:
players = await client.minecraft.players()
return [p.username for p in players]
await client.start()
asyncio.run(main())
Discord Integration (Direct)
CraftCord emits typed events you can handle directly and forward to Discord with your own bot.
Example: send a Discord embed when Minecraft emits server_start.
import discord
from discord.ext import commands
from craftcord import Client
from craftcord.minecraft.events import ServerStartEvent
bot = commands.Bot(command_prefix="!", intents=discord.Intents.default())
craft = Client(host="127.0.0.1", port=8080, token="secret")
DEFAULT_CHANNEL_ID = 123456789012345678
@craft.event("server_start")
async def on_server_start(event: ServerStartEvent) -> None:
channel = bot.get_channel(DEFAULT_CHANNEL_ID)
if channel is None:
return
embed = discord.Embed(
title="Minecraft Server Started",
description="The server is now online.",
color=discord.Color.green(),
timestamp=event.timestamp,
)
embed.add_field(name="Version", value=event.version, inline=True)
await channel.send(embed=embed)
For a full working example, see examples/basic_bot.py.
Core API
Common Minecraft operations:
await client.minecraft.players()
await client.minecraft.server_info()
await client.minecraft.send_message("Hello from CraftCord")
await client.minecraft.execute("time set day")
await client.minecraft.kick("Steve", reason="Rule violation")
await client.minecraft.ban("Steve", reason="Griefing")
Register event handlers:
@client.on("player_join")
async def on_join(event) -> None:
print(event.player.username)
Built-in typed event names:
- player_join
- player_leave
- player_chat
- player_death
- server_start
- server_stop
Unknown events are delivered as GenericEvent.
Transport Choice
WebSocket transport (default):
- Best for bots, dashboards, and real-time event streams.
export CRAFTCORD_TRANSPORT="ws"
HTTP transport:
- Best for scripts and one-off request/response workflows.
export CRAFTCORD_TRANSPORT="http"
Network Binding and Reachability
CraftCordPlugin bind behavior is configured on the Java plugin side:
- bindMode=local binds to 127.0.0.1
- bindMode=global binds to 0.0.0.0
- host= overrides bindMode
Your Python SDK host must be a reachable destination from the SDK process.
Do not use 0.0.0.0 as CRAFTCORD_HOST.
Example targets:
- Same machine: http://127.0.0.1:8080/api/v1
- LAN client: http://:8080/api/v1
- Public/proxy: https://craftcord.example.com/api/v1
Troubleshooting
Connection refused or timeout checklist:
- Ensure CraftCordPlugin is running.
- Confirm token and port match plugin config.
- Confirm CRAFTCORD_HOST points to a reachable address.
- Do not use 0.0.0.0 as client host.
- Check firewalls, routing, and reverse proxy forwarding.
WebSocket reconnect loop checklist:
- Verify host, port, and token.
- Verify plugin is reachable from the client machine.
- If you only need request/response, switch to HTTP transport.
discord.py integration checklist:
- Enable Message Content Intent when needed.
- Ensure bot permissions include reading and sending messages.
- Verify channel ID and command prefix.
Plugin System
Load reusable Python plugins (extensions):
class GreetingPlugin:
async def setup(self, client) -> None:
@client.on("player_join")
async def greet(event) -> None:
await client.minecraft.send_message(f"Welcome {event.player.username}!")
await client.plugins.load(GreetingPlugin)
Protocol
CraftCord uses authenticated JSON-RPC style messages over HTTP and WebSocket.
Authentication model:
- Bearer token
- HTTP validation endpoint
- WebSocket authentication handshake
Endpoint paths:
- /api/v1/auth/validate
- /api/v1/rpc
- /ws
Sample request payload:
{
"type": "request",
"id": "uuid",
"action": "minecraft.get_players",
"payload": {}
}
Development
pytest
ruff check .
Repository Structure
craftcord/
├── craftcord/
├── docs/
├── examples/
└── tests/
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file craftcord-1.0.0.tar.gz.
File metadata
- Download URL: craftcord-1.0.0.tar.gz
- Upload date:
- Size: 16.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61225f2109e265a18aa8c8c42112f46094dd1cc73d61f73b42dbd0b658a6f2b8
|
|
| MD5 |
d19c9d0d8eda9bead76e55b574cfe54b
|
|
| BLAKE2b-256 |
541aae8faec591f948cf94e129405850f8119adc293d1b4340da9ad1a24319b5
|
Provenance
The following attestation bundles were made for craftcord-1.0.0.tar.gz:
Publisher:
ci.yml on rytisltu09/Craftcord
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
craftcord-1.0.0.tar.gz -
Subject digest:
61225f2109e265a18aa8c8c42112f46094dd1cc73d61f73b42dbd0b658a6f2b8 - Sigstore transparency entry: 2162746443
- Sigstore integration time:
-
Permalink:
rytisltu09/Craftcord@91000d016f840c55dbc2337dda84d053bd2a3358 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/rytisltu09
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@91000d016f840c55dbc2337dda84d053bd2a3358 -
Trigger Event:
push
-
Statement type:
File details
Details for the file craftcord-1.0.0-py3-none-any.whl.
File metadata
- Download URL: craftcord-1.0.0-py3-none-any.whl
- Upload date:
- Size: 14.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
390984403d6d07c716304248e8ac5e2429ac4aa5f5f79c60618f23f961e3dc42
|
|
| MD5 |
acb648130990c2fa1be21c39b48d579f
|
|
| BLAKE2b-256 |
3962f52dfe2fcab52e2e0cb6f66808483405e04cace9e5836b251e7b047a02fa
|
Provenance
The following attestation bundles were made for craftcord-1.0.0-py3-none-any.whl:
Publisher:
ci.yml on rytisltu09/Craftcord
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
craftcord-1.0.0-py3-none-any.whl -
Subject digest:
390984403d6d07c716304248e8ac5e2429ac4aa5f5f79c60618f23f961e3dc42 - Sigstore transparency entry: 2162746536
- Sigstore integration time:
-
Permalink:
rytisltu09/Craftcord@91000d016f840c55dbc2337dda84d053bd2a3358 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/rytisltu09
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@91000d016f840c55dbc2337dda84d053bd2a3358 -
Trigger Event:
push
-
Statement type: