Civitai MCP Server
OfficialCivitai MCP Server
Turn your AI agent into a full Civitai participant.
A Model Context Protocol server that gives AI agents first-class access to Civitai: browse models, images, and creators; post and publish work; react, review, follow, and collect; write articles and comments; send and reply to direct messages; create and enter bounties; and (for moderators) manage site announcements and the changelog. 53 tools, exposed over Streamable HTTP or stdio.
There are two ways to use it:
Hosted (recommended) — point your MCP client at
https://mcp.civitai.com/mcp. Zero install.Self-host — run it yourself with pnpm, Docker, or in Kubernetes.
Quick start — hosted (recommended)
The easiest path: add the hosted endpoint to your MCP client and supply your own Civitai API key. Nothing to install or run.
MCP endpoint:
https://mcp.civitai.com/mcpTransport: Streamable HTTP
Auth: send
Authorization: Bearer <YOUR_CIVITAI_API_KEY>with each request
Browse / read tools (search models, images, creators, etc.) work without a key. Everything that writes (posting, reacting, commenting, DMs, bounties, ...) needs one. Grab a key at civitai.com/user/account.
Claude Code (CLI)
claude mcp add --transport http civitai https://mcp.civitai.com/mcp \
--header "Authorization: Bearer YOUR_CIVITAI_API_KEY"Claude Desktop / claude.ai (custom connector)
Note: the claude.ai / Claude Desktop custom-connector UI is OAuth-only — it has no field for a static API key or custom header (anthropics/claude-ai-mcp#112). Because this server currently runs in token-only mode (
OAUTH_ENABLED=false), the custom-connector flow won't work yet. Use Claude Code, Cursor, or any client that supports a bearer header. One-click OAuth connect will work here once Civitai OAuth ships andOAUTH_ENABLED=true.
Cursor (~/.cursor/mcp.json)
{
"mcpServers": {
"civitai": {
"url": "https://mcp.civitai.com/mcp",
"headers": { "Authorization": "Bearer YOUR_CIVITAI_API_KEY" }
}
}
}Generic .mcp.json (any client)
{
"mcpServers": {
"civitai": {
"type": "http",
"url": "https://mcp.civitai.com/mcp",
"headers": { "Authorization": "Bearer YOUR_CIVITAI_API_KEY" }
}
}
}Tip: hand your agent
https://mcp.civitai.com/llms.txt(or justhttps://mcp.civitai.com/) and it can read everything it needs - endpoint, transport, auth, and the full tool catalog - to configure itself. See The/llms.txttrick.
CLI (no MCP client needed)
Some agent runtimes can load a skill but can't edit their MCP client config (no way to add an HTTP MCP server). For those, pull the zero-dependency Node CLI (Node >=18) and drive the server straight from the shell - no MCP client config:
curl -fsSL https://mcp.civitai.com/cli -o mcp-cli.mjs
node mcp-cli.mjs list
node mcp-cli.mjs call search_models '{"query":"anime","type":"Checkpoint"}'Set CIVITAI_API_KEY in your environment for user-action tools (browse/read
tools work without it). The pulled script defaults to the server it came from;
override with MCP_URL or --url. Add --json for the raw JSON-RPC result,
schema <tool> to inspect a tool's input schema, or --help for usage.
Self-host
Prefer to run your own instance (private deployment, in-cluster next to the
Civitai app, or local dev)? All three paths below work. The API destination is
fully overridable via CIVITAI_API_URL.
pnpm
pnpm install
cp .env.example .env # set CIVITAI_API_KEY for authenticated tools (optional)
pnpm build
pnpm start # HTTP mode on :3100, GET /healthz, POST /mcpFor local development with hot reload:
pnpm devDocker
Prebuilt images are published to GHCR:
docker run --rm -p 3100:3100 \
-e CIVITAI_API_KEY=YOUR_CIVITAI_API_KEY \
ghcr.io/civitai/civitai-mcp-server:latest
curl localhost:3100/healthzOr build locally:
docker build -t civitai-mcp-server .
docker run --rm -p 3100:3100 -e CIVITAI_API_KEY=YOUR_CIVITAI_API_KEY civitai-mcp-serverMulti-stage build on node:20-alpine, runs as the non-root node user, with a
HEALTHCHECK hitting /healthz.
Kubernetes
See k8s/deployment.example.yaml: Deployment +
Service, CIVITAI_API_KEY from a Secret, CIVITAI_API_URL pointed at the
in-cluster Civitai service, readiness/liveness probes on /healthz.
Local stdio (for agents that spawn a process)
{
"mcpServers": {
"civitai": {
"command": "node",
"args": ["/path/to/civitai-mcp-server/dist/index.js"],
"env": {
"MCP_TRANSPORT": "stdio",
"CIVITAI_API_KEY": "YOUR_CIVITAI_API_KEY"
}
}
}
}Environment variables
Var | Default | Purpose |
|
| Base URL for all API calls (REST + tRPC). In-cluster override, e.g. |
|
| Public website base for user-facing links in tool output (post/model/image/profile URLs). Distinct from |
| — | Bearer token for authenticated calls. Optional for browse tools (enhances results); required for user-action tools. In HTTP mode it is the fallback when a request omits an |
|
|
|
|
| HTTP listen port (http transport only). |
| — | Optional canonical public base URL (e.g. |
|
| Gates one-click OAuth (RFC 9728 protected-resource metadata + the 401 |
| — | Optional: skip the |
|
| Max bytes accepted for an image fetched/decoded by |
| — | CSV allowlist of hostnames permitted for URL-based image uploads. When set, only these hosts (and subdomains) may be fetched. Empty = block only internal/private/loopback/metadata targets (default SSRF guard). |
| — | CSV of |
Per-request auth (multi-tenant)
In HTTP mode, if an incoming MCP request carries Authorization: Bearer <key>,
that key is used for upstream calls instead of CIVITAI_API_KEY. The env key is
the fallback. This lets one deployment serve multiple users without a
per-deployment key (this is how the hosted instance works). In stdio mode only
the env key is used.
Tool catalog (53 tools)
Every tool returns both a compact human-readable text block and a
structuredContent JSON payload. Read-only tools are marked readOnlyHint: true;
destructive ones destructiveHint: true. Errors are normalized to
{ ok: false, error, details? } with isError: true (tools never throw raw;
tRPC zodError validation details are surfaced). The catalog below is the single
source of truth from the live tool registry - the landing page and llms.txt
render the same list.
Browse (no auth required)
Tool | Description |
| Search models. Includes AIR URNs + |
| Batch model details (concurrency 3): versions, files, AIR URNs. |
| Batch version details: files, trigger words, AIR. |
| Search images with full generation metadata ( |
| Batch image details: prompt, negative, sampler, steps, CFG, seed, resources. |
| Search creators/users. |
| List filter enum values (model types, sorts, base models, timeframes). |
Posts (auth - onboarded, non-muted)
Tool | Description |
| Flagship sharing flow via the composite |
| Fetch a post by ID. |
| Publish a draft via |
| Delete a post you own. |
Engagement (auth)
Tool | Description |
| Toggle Like/Dislike/Laugh/Cry/Heart on image/post/article/comment/resourceReview/etc. |
| Star rating (1-5) + recommend + Markdown details. |
| Read your existing review for a model version. |
| Follow/unfollow (resolves username to id). |
| Favorite/bookmark a model (explicit |
| Toggle new-version notifications. |
| Bookmark/un-bookmark an article. |
| Complete TOS/RedTOS/Profile/BrowsingLevels/Buzz. Prerequisite for any verified/guarded write. |
Articles (auth)
Tool | Description |
| Create/update. Markdown to HTML. Cover by UUID or URL (auto-uploaded). |
| getById to rebuild to upsert with the |
| Dedicated |
| Fetch by ID. |
Comments (auth)
Tool | Description |
| Recursive thread fetch with per-comment reaction aggregation. |
| Single comment, uncapped body. |
| Post or reply (reply via |
| Edit, delete, toggle reaction. |
| Moderator-gated upstream. |
Collections (auth - flag-gated collections)
Tool | Description |
| Create/update a collection. |
| Save one item (article/image/post/model) into one or more collections. |
| Follow/unfollow a collection. |
Notifications (auth)
Tool | Description |
| List notifications (unread/category filters). |
| Mark one ( |
| Quick unread count. |
Messaging (auth)
Tool | Description |
| Lookup to |
Chat (auth) - read & reply to existing threads
Tool | Description |
| List your conversations + participants. |
| Read a chat's messages (paginated, |
| Send into an existing chat ( |
| Mark ONE chat read via |
| Blanket clear of every conversation via |
Bounties (auth - flag-gated bounties)
Tool | Description |
| Create via |
| Update a bounty you own. |
| Submit an entry via the composite |
| Award a bounty to an entry. |
Announcements (auth, moderator)
Tool | Description |
| Create/update with field merge. Image by UUID or URL. |
| Delete by ID. |
|
|
Changelog (auth, moderator + changelogEdit flag)
Tool | Description |
| Create/update. Markdown to HTML; |
Images (auth)
Tool | Description |
| URL or base64 to presign to PUT to UUID (+ probed dimensions). |
Utility
Tool | Description |
| Resolve the current user (id, username) and authoritative status via |
Auth & scopes
API key: create one at civitai.com/user/account and send it as
Authorization: Bearer <key>. In HTTP mode the per-request header overrides anyCIVITAI_API_KEYenv fallback.Browse without a key: all
search_*/get_*browse tools work unauthenticated (a key just enriches results).Onboarded, non-muted account: most write actions are
verified(requires onboarding) orguarded(also blocks muted users). A fresh agent account must finish onboarding first - usecomplete_onboarding_step.whoamireports the current onboarding/muted/moderator state.Scoped tokens: if you use a scoped token (rather than a Full key), it must carry the write scope a tool needs (e.g.
MediaWrite,SocialWrite,BountiesWrite,CollectionsWrite). A Full key passes everything.API-key-blocked actions: a few site actions are intentionally unavailable to API keys (e.g. tipping buzz) and are not shipped as tools.
OAuth one-click connect (opt-in, off by default)
Off by default. Set
OAUTH_ENABLED=trueto turn this on. It is gated because it only works once the Civitai app's OAuth dynamic-client-registration (DCR) is live - with it off the server runs in token-only mode (supply an API key viaAuthorization: Bearer; an unauthenticated auth-required call returns the normal "setCIVITAI_API_KEY" error). WithOAUTH_ENABLEDunset or false, the metadata endpoint 404s and no 401 challenge is emitted.
The server is an OAuth 2.0 resource server (RFC 9728 / RFC 6750). When
OAUTH_ENABLED=true and the Civitai app's DCR is live, MCP clients can connect
with no manually pasted API key - they discover the authorization server and run
the standard authorization-code flow on first use:
The client
POSTs atools/callfor an auth-required tool without anAuthorizationheader.The server replies HTTP 401 with
WWW-Authenticate: Bearer resource_metadata="<base>/.well-known/oauth-protected-resource".The client fetches
GET /.well-known/oauth-protected-resource, learns the authorization server (https://civitai.com) and supported scopes, registers itself (DCR), runs the OAuth flow, and retries with a bearer token.
Two behaviors back this:
GET /.well-known/oauth-protected-resource- Protected Resource Metadata: the advertisedresource(the/mcpendpoint),authorization_servers(CIVITAI_API_URL),scopes_supported(canonical scope names), andbearer_methods_supported: ["header"].401 challenge - a
tools/callfor an auth-requiredtool with noAuthorization: Beareris short-circuited at the HTTP layer with a 401 + challenge (instead of a deeper JSON-RPC200 + isErrorthe client can't act on). Browse/read tools stay anonymous;initialize,tools/list,notifications/*, andpingare never challenged. In a batch, if any call needs auth and no bearer is present, the whole request is challenged. The token is not validated here (presence is enough); a bad token surfaces as a tool error upstream.
Prod note: set
PUBLIC_BASE_URL=https://mcp.civitai.comso the advertisedresourceexactly matches the URL clients call - OAuth resource matching is strict, and a Host-derived mismatch would break token audience validation.
The /llms.txt trick
The server exposes an llms.txt-style self-setup guide. Hand your agent the URL and it can configure itself - it reads the MCP endpoint, transport, auth instructions, and the full tool catalog with no human in the loop:
https://mcp.civitai.com/llms.txthttps://mcp.civitai.com/ content-negotiates on User-Agent: a browser gets a
self-contained HTML landing page; anything else (curl, fetch, agents, missing UA)
gets the llms.txt text. The advertised endpoint is derived from the request
Host header (honoring X-Forwarded-Proto/-Host), or pinned via
PUBLIC_BASE_URL, so it is always correct for the deployment serving it.
Transports
Streamable HTTP (default):
POST /mcp. Stateless - a fresh server and transport are created per request (sessionIdGenerator: undefined,enableJsonResponse: true), so it scales horizontally.GET /healthzis a plain 200 with no upstream calls (used by readiness/liveness probes).stdio: set
MCP_TRANSPORT=stdio. stdout is reserved for the protocol; logs go to stderr.
HTTP endpoints
Method & path | Purpose |
| MCP Streamable HTTP endpoint (JSON-RPC). |
| Plain 200 liveness/readiness probe (no upstream calls). |
| Dual-audience index: browser UA gets HTML; everything else gets |
| The agent self-setup guide as |
| The pullable zero-dependency Node CLI ( |
Security
SSRF guard:
upload_imagefetches user-supplied URLs through a guard that blocks internal/private/loopback/metadata targets by default, with an optionalCIVITAI_UPLOAD_ALLOWED_HOSTSallowlist.Size cap: fetched/decoded images are capped at
CIVITAI_UPLOAD_MAX_BYTES(10 MB default) to prevent memory exhaustion.DNS-rebinding protection: enable
MCP_ALLOWED_HOSTSto validate the incomingHostheader against an allowlist.Request body cap: the HTTP layer caps request bodies (25 MB) and returns JSON-RPC parse errors for malformed input.
Container hardening: non-root user, read-only root filesystem, dropped capabilities in the example k8s manifest.
Local dev with the MCP Inspector
pnpm inspector # runs: npx @modelcontextprotocol/inspector tsx src/index.tsThis launches the Inspector against the stdio transport. Set CIVITAI_API_KEY
in your environment first if you want to exercise the authenticated tools.
Development
pnpm typecheck # strict tsc, no emit
pnpm test # vitest (no network - fetch is mocked)
pnpm build # tsc to distSee CONTRIBUTING.md for the contribution flow.
Non-goals
No generation tools (generation lives elsewhere).
No moderation actions.
No model file downloads.
License
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/civitai/civitai-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server