pretix-agent-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pretix-agent-mcpClone this year's conference for 2027, June 12–14, same tickets, early-bird until March."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
pretix-agent-mcp
Run a self-hosted pretix instance from an AI agent — without the pretix API token ever reaching the agent, and without giving it arbitrary REST access.
Codex / AI agent untrusted: may be manipulated via prompt injection
│
│ MCP over streamable HTTP + bearer token (or stdio for same-machine dev)
▼
pretix-agent-mcp trusted: holds the credential, enforces capabilities,
│ masks personal data, gates irreversible writes
│ restricted pretix team token
▼
pretix REST API64 purpose-built tools cover routine event administration: create and configure events, clone last year's edition, manage series dates, products, quotas, prices, vouchers, orders and check-in. The web UI is left for one-time organizer setup — notably payment provider onboarding, which involves credentials an agent must never touch.
"Clone this year's conference for 2027, June 12–14, same tickets, early-bird until March." → the agent clones the event, adjusts dates and presale windows, and hands back a preview link. The event exists in draft. Zero UI visits.
"Take the 2027 conference live." → the agent stages it; you run
pretix-agent-mcp approve 3f9a1con the server. That's the whole ceremony.
What makes it safe
Threat | Mitigation |
Prompt-injected agent exfiltrating personal data |
|
Prompt-injected agent issuing destructive writes | Irreversible operations return a preview and a handle. A human approves them out of band on the server. A |
Agent reaching beyond its remit | Capability allowlist; disabled tools are not advertised at all. The organizer slug is pinned in config. Every path segment is validated. There is no generic HTTP/API tool. |
Unauthorized network client | Bearer token required, constant-time compared. Binds |
Credential theft | The pretix token lives only in the server's environment — never in results, errors, logs, audit records or tool parameters. |
Defaults are closed: localhost, read-only, personal data masked, no writes. Each relaxation is an explicit config change. See SECURITY.md.
Related MCP server: @vorionsys/mcp-server
Install
git clone https://github.com/bitcoinaustria/pretix-agent-mcp
cd pretix-agent-mcp
uv pip install -e . # or: pip install -e .
cp .env.example .env # then edit itRun it:
set -a && . ./.env && set +a
pretix-agent-mcp serveOr with Docker:
docker build -t pretix-agent-mcp .
docker run --rm -p 127.0.0.1:8765:8765 --env-file .env \
-v "$PWD/state:/state" -e STATE_DB=/state/pending-actions.sqlite3 -e AUDIT_LOG=/state/audit.jsonl \
-e MCP_HOST=0.0.0.0 pretix-agent-mcpCheck what a configuration exposes before pointing an agent at it:
pretix-agent-mcp toolsConnecting a client
Endpoint: https://pretix-mcp.example.org/mcp (streamable HTTP), with your
MCP_BEARER_TOKEN. No bridge or proxy is needed — Codex and Claude Code both speak
streamable HTTP with a bearer token directly.
Codex CLI (~/.codex/config.toml):
[mcp_servers.pretix]
url = "https://pretix-mcp.example.org/mcp"
bearer_token_env_var = "PRETIX_MCP_TOKEN" # Codex stores the variable NAME, reads it at connect time
tool_timeout_sec = 60 # sales_summary can be slow on large eventsThen export PRETIX_MCP_TOKEN=... in the shell that launches Codex, or use the CLI:
codex mcp add pretix --url https://pretix-mcp.example.org/mcp --bearer-token-env-var PRETIX_MCP_TOKENGotchas: the key is url (there is no http_url and no type = "http" — transport is
inferred); bearer_token is rejected at load in favour of bearer_token_env_var; static
headers go in http_headers = { ... } and cannot be set from codex mcp add.
Claude Code:
claude mcp add --transport http pretix https://pretix-mcp.example.org/mcp --header "Authorization: Bearer $PRETIX_MCP_TOKEN"Same-machine development uses stdio, where the parent process is the peer and no bearer token applies:
pretix-agent-mcp serve --transport stdiopretix Hosted (pretix.eu) or self-hosted
Both work — it is the same documented REST API. For pretix Hosted set:
PRETIX_BASE_URL=https://pretix.euTwo hosted-specific things to know:
Rate limits. pretix Hosted allows 360 requests per minute per organizer for token authentication and answers a 429 with
Retry-After; self-hosted instances do not rate-limit by default. The client honoursRetry-Afterand retries up to three times, so a burst degrades into a slower call rather than an error.sales_summaryis the tool most likely to hit the limit on a big event (one request per 100 orders scanned) — lowerSALES_SCAN_CAP, or ask pretix support for a higher limit, if you run into it.Plugins.
set_event_pluginscan only enable what the instance actually ships; hosted and self-hosted offer different plugin sets. Read the current list withget_eventfirst.
Nothing else differs: team tokens, the event and order APIs, and the settings API behave the same, and the shop URLs the tools hand back are correct for either.
The pretix token
Create a team in pretix (Organizer → Teams) with only the permissions your enabled capabilities need, then add a token to that team. Never use a team that can change teams and permissions.
You enable | pretix team permissions needed |
| Can view orders, Can view vouchers, plus access to the relevant events |
| + Can create events, Can change event settings, Can change product settings |
| + Can change vouchers |
| + Can change orders |
| + Can change orders / Can change event settings |
Restrict the team to specific events where you can, and set PRETIX_EVENT_ALLOWLIST as a
second, server-side limit.
Capabilities
Every tool belongs to exactly one class. MCP_CAPABILITIES decides which classes exist;
unlisted tools are never advertised to the client.
Class | Behaviour |
| Executes directly. |
| Executes directly when enabled. |
| Records a pending action and returns a preview. Mutates nothing until a human approves. |
The live-event guard. A write that targets a live event and can affect price,
availability, product structure or existing orders is escalated to write:high-risk at
call time. The same operation on a draft or test-mode event executes directly. So agents
build and reconfigure drafts without friction, while anything touching a selling event or
a customer's money goes through approval.
publish_event is always high-risk — it is the boundary crossing itself. It sets
live=true and leaves test mode, because test mode, not the live flag, is what keeps
orders from being real. No other tool can leave test mode, so an agent cannot start real
sales without an approval.
An operator who accepts the risk can reclassify individual high-risk tools to plain
write with MCP_AUTO_APPROVE (e.g. auto-approve publish_event, keep the gate on
refunds). That is an explicit, audited, per-tool decision.
The approval ceremony
$ pretix-agent-mcp pending
3f9a1c publish_event (expires in 812s)
Take event 'conf27' (Conf 27) LIVE — the public shop opens.
starts: 2027-06-12T09:00:00+02:00
presale: 2027-01-15T00:00:00+01:00 → 2027-06-01T00:00:00+02:00
test mode: True
approve with: pretix-agent-mcp approve <id> (1 pending)
$ pretix-agent-mcp approve 3f9a1c
approved 3f9a1c (publish_event)
the agent can now call execute_pending_action with this idapprove --run executes it immediately instead of waiting for the agent. reject <id>
throws it away. Nothing here is reachable from the agent: the approval lives on the
server on purpose, because a chat-based confirmation is forgeable by a prompt-injected
agent and a shell command on the server is not.
Tools
Domain | read | write | write:high-risk |
Events |
|
|
|
Series dates |
|
|
|
Catalog |
|
|
|
Orders |
|
|
|
Vouchers |
|
|
|
Check-in & waiting list |
|
|
|
Approval |
|
| — |
¹ subject to the live-event guard. A single voucher is an ordinary write; a bulk batch is
guarded, because 500 free or quota-blocking vouchers against a selling event is a price and
availability change in all but name (a documented tightening of the PRD, which classed all
voucher tools as plain write).
Notes:
sales_summaryis computed server-side by paginating orders (pretix has no aggregate endpoint). It returns totals and counts only, in either PII mode, and reports its scan window — large events are slow and the window is capped (SALES_SCAN_CAP).All list tools paginate, cap results server-side (≤ 50 per page by default) and mark a truncated answer as such.
create_subeventsis a batch: "every first Thursday until December, 40 seats each" is one call. The agent computes the dates; the server creates them.
Configuration
Environment variables, or a JSON config file passed with --config (env wins). Full list
with comments in .env.example.
Variable | Default | Meaning |
| — | Base URL of your pretix instance |
| — | Restricted team token. Server-side only |
| — | Organizer slug, pinned; agents cannot change it |
| all events | Comma-separated event slugs |
| — | Client credential (≥ 24 chars). Required for HTTP |
|
|
|
| — | Expose exactly these tools |
| — | High-risk tools reclassified to |
|
|
|
|
| Bind address |
|
| Append-only audit log |
|
| Pending approvals |
|
| How long a proposal stays approvable |
|
|
|
Deployment
Put TLS in front of it. Nginx:
location /mcp {
proxy_pass http://127.0.0.1:8765/mcp;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off; # streamable HTTP may hold the response open
proxy_read_timeout 300s;
}Keep the bind on 127.0.0.1 and let the proxy be the only route in. If you must bind an
external interface, the server refuses to start without MCP_BEARER_TOKEN.
Alongside a self-hosted pretix container
docker-compose.example.yml runs this as its own container
next to pretix/standalone, reaching pretix over the internal network
(PRETIX_BASE_URL=http://pretix:80).
Do not extend the pretix image to run both in one container, even though pip install pretix-agent-mcp into a derived image would work. The pretix container holds the database
credentials, the Django secret key and the ticket data; this one holds an API token limited
to a restricted team. Separating them is what keeps a compromise of the agent-facing
service — the component deliberately exposed to an untrusted agent — from becoming a
compromise of the whole instance, which is the difference between "the attacker can do what
that token allows" and "the attacker reads your database". It also keeps docker pull an
upgrade instead of an image rebuild, and keeps pretix's own supervisor config untouched.
Two things to keep in mind for that setup:
Mount a volume for
/state. Without it, an approved-but-not-executed action and the whole audit trail vanish on restart.docker execinto the MCP container is enough to approve a pending action, so access to the Docker socket is equivalent to approval rights. That is the same trust level as shell access on the host, which is what the out-of-band approval assumes.
Run the server on a different machine from the agent when you can — that is what makes "the credential is not on the agent's machine" a structural property rather than a habit.
Protocol
MCP revision 2026-07-28 via the official Python SDK, which keeps backward
compatibility with the initialization-based revisions (2025-06-18 / 2025-11-25). The
2026-07-28 protocol is stateless: no initialize handshake, no session id, protocol
version per request. server/discover and the tools/list freshness hints
(ttlMs/cacheScope) come from the SDK; cross-call state — pending-action ids — is a
server-minted handle passed as an ordinary tool argument.
Authorization deviates from the spec's OAuth 2.1 framework (which is optional): a static bearer token, constant-time compared, appropriate for a single-operator deployment where the operator controls both ends. The spec's token rules still hold — header only, never the query string; missing or invalid token gets 401. Multi-user access would mean implementing RFC 9728 metadata and an external authorization server; that is not built.
Deprecated MCP features are deliberately absent: Roots, Sampling, Logging, HTTP+SSE. Diagnostics go to stderr; writes go to the audit log.
Audit log
One JSONL record per write and per high-risk lifecycle event (proposed / approved / executed / failed), with the tool, PII-redacted arguments, outcome and pending-action id. Reads are not logged. Neither token ever appears.
{"ts":"2027-01-15T10:22:31Z","event":"executed","tool":"publish_event","outcome":"ok","pending_action_id":"3f9a1c","args":{"event":"conf27"}}Known limits
These are pretix API limits, not workarounds waiting to happen:
Payment provider onboarding (Stripe/PayPal credentials, OAuth connects) is organizer-level, partly outside the REST API, and involves credentials agents must not handle. One-time UI task.
Event settings expose the subset the pretix settings API exposes. Where the UI has more, the tools have less.
Mail routing settings (
mail_bcc,mail_from,mail_reply_to,smtp_*) are refused byupdate_event_settingson purpose: an agent that can BCC every customer mail to an address of its choosing exfiltrates personal data that redaction never sees, because it never passes through the agent's context. Change those in the UI.Question options are not editable via PATCH on a question; recreate the question, or edit choices in the UI.
Checking someone in is deliberately not a tool: scanning tickets is a physical-presence operation.
Organizer-level team and token management is out of scope by design — agents must not manage their own permissions.
Development
make setup
make ci # ruff check + format check + pytest, the same thing CI runsAGENTS.md — the working rules (and what Claude, Codex and friends load)
ARCHITECTURE.md — where the seams are and why
TESTING.md — the fake-pretix harness and what a change owes in tests
CONTRIBUTING.md — how to open a PR
PRD.md — the product spec this was built from
MIT licensed. Contributions welcome — changes to validation, redaction, the approval gate or auth need tests.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityCmaintenanceAn MCP server that enforces runtime governance on AI agent actions — file access, command execution, delegation chains, and permission escalation.MIT

@vorionsys/mcp-serverofficial
AlicenseAqualityBmaintenanceMCP server for AI-agent governance using trust scoring, behavioral signals, and pre-flight action checks.10381Apache 2.0- Flicense-qualityBmaintenanceAn MCP server that enables AI agents to safely interact with a double-entry payments ledger, enforcing idempotency, policy-based access control, and human-in-the-loop approval for high-value actions.
- Alicense-qualityCmaintenanceGoverned MCP server for bank-grade agent tool access with RBAC, PII redaction, rate limiting, and audit logging.MIT
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
Hosted Google Calendar MCP server for AI agents. No self-hosting or Google Cloud setup.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/bitcoinaustria/pretix-agent-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server