MCP server for interacting with Prusa Connect via OAuth2 (Authorization Code + PKCE) against Prusa Account — using the same public OAuth client id that the PrusaSlicer desktop app ships with.
- OAuth2 Authentication: One-time interactive login via an embedded native webview; refresh tokens are persisted and rotated automatically
- Printer Management: List all printers and get detailed status information
- Job Tracking: View recent print jobs for specific printers
- File & Storage Management: Browse printer files and storage devices
- Printer Commands: Send commands directly to printers (pause, resume, temperature, etc.) — see the full command reference
- Event Monitoring: Fetch recent printer events
Install dependencies with uv:
uv syncThat's it on macOS and Windows. On Linux, pywebview additionally needs the system WebKit2GTK libraries for the login window — on Debian/Ubuntu that's apt install gir1.2-webkit2-4.1 libgirepository1.0-dev. (The MCP server itself never opens a window, so this is only needed on the host where you run prusa-mcp login.)
This server targets MCP Python SDK v2 (mcp>=2.0.0), which speaks the current protocol revision. If you are upgrading from an older checkout, re-run uv sync — v2 replaces httpx with httpx2 and drops the mcp.server.fastmcp module, so a stale environment will fail to import.
Run this once, on a machine with a display:
uv run prusa-mcp loginThis opens a small native window showing the Prusa Account login page. You sign in with your Prusa credentials (SSO, 2FA, passkeys — whatever you use on the website); the moment Prusa Account finishes authorizing the client, the window closes automatically and access + refresh tokens are written to ~/.config/prusa-mcp/tokens.json (override with PRUSA_TOKEN_FILE) with mode 0600.
Under the hood: Prusa Account completes the flow by redirecting to prusaslicer://login?code=... — the custom URL scheme that the real PrusaSlicer desktop app registers with the OS. The embedded webview intercepts that navigation before the OS gets a chance to hand it off, so you never see PrusaSlicer pop up (even if you have it installed) and no paste-back is needed.
From then on the MCP server refreshes access tokens silently. You only need to re-run prusa-mcp login if the refresh token is ever revoked.
Running inside Docker? Run prusa-mcp login on the host, point PRUSA_TOKEN_FILE at a file on a volume mounted into the container, and the server will read and refresh tokens from there.
All environment variables are optional:
| Variable | Default | Description |
|---|---|---|
PRUSA_CONNECT_URL |
https://connect.prusa3d.com |
Base URL for Prusa Connect |
PRUSA_ACCOUNT_URL |
https://account.prusa3d.com |
Base URL for Prusa Account (OAuth) |
PRUSA_TOKEN_FILE |
~/.config/prusa-mcp/tokens.json |
Path to the OAuth token file |
PRUSA_OAUTH_CLIENT_ID |
(PrusaSlicer client) | Override the public OAuth client id |
Set these in your shell environment before running the server (e.g. export PRUSA_CONNECT_URL=...).
Add to your claude_desktop_config.json:
{
"mcpServers": {
"prusa-mcp": {
"command": "uv",
"args": [
"--directory",
"/path/to/prusa-mcp",
"run",
"prusa-mcp"
]
}
}
}# Run the MCP server directly
uv run prusa-mcp
# Or via python module
python -m prusa_mcpReport the current Prusa Connect authentication status. Authentication itself happens out-of-band via the prusa-mcp login CLI subcommand (OAuth2 PKCE). This tool only checks that stored tokens are valid and refreshable. The legacy email/password parameters are accepted for backwards compatibility but ignored.
| Parameter | Type | Required | Description |
|---|---|---|---|
email |
string | No | Ignored — kept for backwards compatibility |
password |
string | No | Ignored — kept for backwards compatibility |
Get a list of all your Prusa printers.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
int | No | Max printers to return (default: 10) |
Get detailed status of a specific printer.
| Parameter | Type | Required | Description |
|---|---|---|---|
printer_uuid |
string | Yes | UUID or name of the printer |
Get recent jobs for a specific printer.
| Parameter | Type | Required | Description |
|---|---|---|---|
printer_uuid |
string | Yes | UUID of the printer |
limit |
int | No | Max jobs to return (default: 5) |
Get list of files on a printer.
| Parameter | Type | Required | Description |
|---|---|---|---|
printer_uuid |
string | Yes | UUID of the printer |
limit |
int | No | Max files to return (default: 100) |
Get storage devices for a printer.
| Parameter | Type | Required | Description |
|---|---|---|---|
printer_uuid |
string | Yes | UUID of the printer |
Send a command to a specific printer (e.g., pause, resume, set temperature).
| Parameter | Type | Required | Description |
|---|---|---|---|
printer_uuid |
string | Yes | UUID of the printer |
command |
string | Yes | Command name (see command reference) |
args |
object | No | Command arguments |
Fetch recent events for a printer.
| Parameter | Type | Required | Description |
|---|---|---|---|
printer_uuid |
string | Yes | UUID of the printer |
limit |
int | No | Max events to return (default: 100) |
- Token File: The refresh and access tokens are stored in
PRUSA_TOKEN_FILE(default~/.config/prusa-mcp/tokens.json), written with0600permissions. Treat this file like a password — anyone with a copy can act as you against Prusa Connect until the refresh token is revoked. - No Credentials on Disk: Your Prusa Account email and password are never stored by this server; they are only ever entered on
account.prusa3d.comitself during the one-time webview login. - Public Client + PKCE: Authentication uses the public PrusaSlicer OAuth client with PKCE — there is no client secret to leak. The authorization code is bound to a per-login verifier, so intercepting the code alone is not enough to mint a token.
- Dedicated Account: Consider using a dedicated service account for automated access rather than your personal one.
- Revoking Access: To revoke this server's access, sign in to
account.prusa3d.com, remove the authorized application, and delete the local token file.
- First Login: Run
prusa-mcp login. The CLI generates a PKCE pair and opensaccount.prusa3d.com/o/authorize/inside an embedded native webview (viapywebview). After you sign in, Prusa Account redirects the webview toprusaslicer://login?code=...&state=.... A background watcher thread polls the webview's current URL, captures the callback before the OS tries to dispatch the custom scheme, and destroys the window. - Token Exchange: The CLI posts the code + PKCE verifier to
account.prusa3d.com/o/token/and receives an access token and a refresh token, which it writes to the token file. - API Requests: The MCP tools call
get_access_token()before every request. If the cached access token is still valid (JWTexpcheck with a 60-second leeway), it's reused; otherwise the refresh token is exchanged for a new pair, which is written back to disk. - Bearer Auth: All Prusa Connect API calls attach
Authorization: Bearer <jwt>— the same mechanism PrusaSlicer uses. This makes write endpoints likesend_printer_commandwork, which cookie-based auth alone does not.
Not authenticatedfrom the tools: Runuv run prusa-mcp loginto generate or refresh the token file.- Refresh token rejected: The refresh token may have been revoked (e.g. you changed your password or removed the authorized app in the Prusa Account dashboard). Delete the token file and run
prusa-mcp loginagain. - Headless machines (no display):
prusa-mcp loginneeds a windowed session to show the webview. Run the login on a desktop host (macOS, Windows, or Linux with X11/Wayland) and ship the resultingtokens.jsonto the headless machine via a mounted volume orscp. - Linux:
ImportErroraboutgi/webkit2: Install the system WebKit2GTK bindings:apt install gir1.2-webkit2-4.1 libgirepository1.0-dev(Debian/Ubuntu) or the equivalent for your distribution. - Docker: Run
prusa-mcp loginon the host, not inside the container. PointPRUSA_TOKEN_FILEat a path inside a volume mounted into both host and container. - TLS / certificate errors behind a proxy:
httpx2validates against the OS trust store (viatruststore) instead of the bundledcertifiroots. Import your proxy's CA into the system trust store, or pointSSL_CERT_FILE/SSL_CERT_DIRat it.