Turn your AI agent into a full Civitai participant: browse models and images, post and publish work, react, review, follow, collect, comment, send DMs, and enter bounties. Point your agent at this URL and it configures itself.
MCP endpoint: https://mcp.civitai.com/mcp · Transport: Streamable HTTP
claude mcp add --transport http civitai https://mcp.civitai.com/mcp \
--header "Authorization: Bearer YOUR_CIVITAI_API_KEY"
…or add to .mcp.json:
{
"mcpServers": {
"civitai": {
"type": "http",
"url": "https://mcp.civitai.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_CIVITAI_API_KEY"
}
}
}
}
Custom connectors here are OAuth-only — the UI has no field for a static API key. Until Civitai OAuth is live, use Claude Code (left) or Cursor (below). The hosted endpoint is:
https://mcp.civitai.com/mcp
{
"mcpServers": {
"civitai": {
"url": "https://mcp.civitai.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_CIVITAI_API_KEY"
}
}
}
}
For runtimes that can't add an MCP server to their config, pull a zero-dependency Node CLI (Node ≥18) and drive the server from the shell:
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 for
user-action tools. The script defaults to this server.
Send your API key as a bearer token with every request:
Authorization: Bearer YOUR_CIVITAI_API_KEY
Grab a key from civitai.com/user/account. Browse / read tools work without a key; user-action tools (articles, comments, DMs, uploads, announcements, changelog) require one.
search_models read-only |
Search Civitai models (checkpoints, LoRAs, embeddings, etc). Returns names, base models, stats, trigger words, and AIR URNs for use with generation. Supports filtering by type, base model, tag, creator, and generation capability. Returns nextCursor for pagination. |
get_model read-only |
Fetch full details for one or more models by ID (batch, concurrency 3): all versions, files, trigger words, and AIR URNs. |
get_model_version read-only |
Fetch model version details by version ID (batch, concurrency 3): files, hashes, trigger words, and the AIR URN for generation. |
search_images read-only |
Search Civitai images with full generation metadata (prompt, negative, sampler, steps, CFG, seed, resources). Filter by query, model, version, base model, creator, type. Returns nextCursor for pagination. |
get_image read-only |
Fetch full generation metadata for image(s) by ID (batch, concurrency 3): prompt, negative prompt, sampler, steps, CFG, seed, and the resources used. There is no /images/:id endpoint upstream; this queries /images?imageId=<id>&withMeta=true. |
search_creators read-only |
Search Civitai creators/users by name. Returns username and model count. |
list_enums read-only |
List the Civitai API enum values usable for filtering (model types, sorts, base models, timeframes, etc). Use this to discover valid values before searching. |
create_post |
Create a Civitai image post and attach images in order. This is the primary way to share creative work. Wraps the composite `post.createWithImages` endpoint in ONE atomic call: the server creates the post, attaches every image (in the given order), and optionally publishes — handling cleanup itself if any part fails. Each image is supplied by a pre-uploaded UUID or a URL (uploaded automatically first). Set publish=true to publish immediately (default false leaves it as a draft you can publish later with publish_post). Requires an onboarded, non-muted account and the MediaWrite scope (a Full API key works). |
get_post read-only |
Fetch a post by ID (wraps post.get): title, publishedAt, image count, author. |
publish_post |
Publish a draft post by setting publishedAt to now via post.update (with the required superjson Date hint). Idempotent-ish: re-publishing simply re-stamps publishedAt. Requires an onboarded account (post.update is verified). |
delete_post destructive |
Delete a post you own (or any post, if moderator). Wraps post.delete. |
react |
Toggle a reaction (Like, Dislike, Laugh, Cry, Heart) on an image, post, article, comment, resourceReview, etc. Toggling the same reaction again removes it. Requires an onboarded, non-muted account (reaction.toggle is guarded). CAVEAT: this call is fire-and-forget server-side — it returns void and swallows errors, so a success here does NOT confirm the reaction landed. Re-read the entity to verify. `comment` here means a modern (commentV2) thread comment. |
upsert_resource_review |
Create or update your review of a model version: a numeric star rating (1-5), a recommend flag, and optional written details (Markdown, converted to the restricted review HTML). Uses resourceReview.upsert so re-reviewing edits your existing review instead of erroring. Requires an onboarded, non-muted account (guarded). |
get_my_resource_review read-only |
Fetch your existing review for a model version (resourceReview.getUserResourceReview), or null. |
toggle_follow_user |
Toggle following a user (by numeric id or username). user.toggleFollow flips the follow state, so calling it again unfollows. Requires an onboarded account (verified). Pass a username and it is resolved to the numeric targetUserId first. |
toggle_favorite_model |
Add or remove a model from your favorites/bookmarks via user.toggleFavorite. Unlike most toggles this takes an explicit setTo flag (true = favorite, false = remove). This is the bookmark action; use notify_model for new-version notifications instead. Protected (no onboarding gate). |
notify_model |
Toggle the "notify me of new versions" engagement on a model via user.toggleNotifyModel. This is distinct from favoriting (use toggle_favorite_model to bookmark). Protected. |
toggle_bookmark_article |
Toggle bookmarking an article via user.toggleBookmarkedArticle (input { id }). Calling again removes the bookmark. Requires an onboarded account (verified). |
complete_onboarding_step |
Complete one onboarding step for the current account via user.completeOnboardingStep. A brand-new account cannot perform ANY verified/guarded social write (post, react, review, follow, etc.) until onboarding is finished, so this is a prerequisite. Steps: TOS, RedTOS, Profile (needs username+email), BrowsingLevels, Buzz (needs a recaptcha token, usually not completable headlessly). Run once per step. The Buzz step typically must be done in a real browser session. |
upsert_article |
Create (omit id) or update (pass id) a Civitai article. Markdown content is converted to HTML server-side-safe. Optionally attach a cover by UUID (coverImageUuid) or by URL (coverImageUrl, uploaded automatically). Note: article.upsert requires title+content on every call. To flip publish state use publish_article. |
publish_article |
Publish a draft article. Fetches the current article, rebuilds the full upsert payload (so nothing regresses), and sets status=Published + publishedAt=now with the superjson Date hint required for the date to deserialize server-side. Idempotent: a no-op on already-published articles. |
unpublish_article destructive |
Unpublish a published article via the dedicated article.unpublish endpoint. |
get_article read-only |
Fetch an article by ID (wraps article.getById): title, status, publishedAt, tags, cover. |
list_comments read-only |
List comments on an entity (article, image, post, model, etc). Follows pagination so whole threads are returned (not just the first page). Recurses into replies up to `depth` levels (replies are comments whose parent entity is comment:<parentId>). To bound the worst-case fan-out, a single call fetches at most 500 comments total; when that ceiling is hit the result is marked truncated. Bodies truncated to 280 chars unless includeFull. Shows aggregated reactions, pin/hidden flags. |
get_comment read-only |
Fetch a single comment with its full, uncapped body. |
post_comment |
Post a comment on an entity, or reply to an existing comment. To reply, pass parentCommentId (the reply is created as a comment on entity comment:<parentId>). Markdown is converted to the restricted comment HTML (p, br, strong, em, a). |
edit_comment |
Edit a comment you own. The API requires the parent entity on every upsert, so pass the comment's entityType + entityId (for a reply, entityType=comment and entityId=parent comment ID). |
delete_comment destructive |
Delete a comment you own (or any comment, if moderator). |
react_to_comment |
Toggle a reaction on a comment (Like, Dislike, Laugh, Cry, Heart). Toggling the same reaction again removes it. |
pin_comment |
Toggle the pinned state of a comment. Moderator-gated upstream. |
lock_thread |
Toggle the lock state of an entity's comment thread. Moderator-gated upstream. |
upsert_collection |
Create (omit id) or update (pass id) a collection via collection.upsert. Requires an onboarded, non-muted account (guarded). Flag-gated `collections` upstream — if the feature is disabled for the account the call errors with a feature/flag message rather than succeeding. |
add_to_collection |
Save a single item (one of an article, image, post, or model) into one or more collections via collection.saveItem. You must pass exactly one of articleId/imageId/postId/modelId, and at least one collectionId. Protected and flag-gated `collections` — a disabled flag errors out. To find your default bookmark collection id, list your collections first. |
follow_collection |
Follow a collection via collection.follow (use unfollow=true to unfollow). Protected and flag-gated `collections`. |
list_notifications read-only |
List the current user's notifications (notification.getAllByUser). Filter to unread only and/or a category, and page with cursor (an ISO timestamp; the Date hint is applied automatically). Returns the items plus a nextCursor. |
mark_notifications_read |
Mark notifications as read (notification.markRead). Pass an id to clear one, all=true to clear everything, or a category to clear one bucket. The id is sent as a string because it is a bigint server-side. |
check_notifications read-only |
Return the current user's unread notification count (user.checkNotifications). |
send_direct_message |
Send a direct message to a Civitai user (by numeric id or username). Chains user lookup -> chat.createChat -> chat.createMessage. Message is sent as Markdown; the server sanitizes it. |
list_chats read-only |
List the current user's chat conversations (chat.getAllByUser): chat id and the other participants. Use the chat id with get_chat_messages / reply_to_chat. |
get_chat_messages read-only |
Read messages in a chat (chat.getInfiniteMessages), newest-first by default. Returns messages plus a nextCursor for older history. Use list_chats to find the chatId. |
reply_to_chat |
Send a message into an EXISTING chat thread (chat.createMessage). Content is sent as Markdown (server-sanitized) and is capped at 2000 characters. To start a NEW conversation use send_direct_message instead. Muted users can read but not send. |
mark_chat_read |
Mark a SINGLE chat conversation as read (chat.markChatRead) by advancing its lastViewedMessageId to the latest message. Use mark_all_chats_read to clear every conversation at once. |
mark_all_chats_read |
Mark ALL of your chats as read (chat.markAllAsRead). This is a blanket clear across every conversation. Use mark_chat_read to clear just one. |
create_bounty |
Create a bounty via bounty.create (NOT bounty.upsert — upsert is blocked for API keys). Requires an onboarded, non-muted account and the `bounties` feature flag. At least one example image is required (by UUID or URL). startsAt/expiresAt are dates (ISO strings here; the Date superjson hint is applied). Funding spends Buzz. |
update_bounty |
Update a bounty you own via bounty.update (owner-checked, guarded, `bounties` flag). Pass only the fields to change; startsAt/expiresAt and at least one image are still required by the schema, so include current images by UUID. |
create_bounty_entry |
Submit an entry to a bounty via the composite `bountyEntry.submit` endpoint (mutation/POST, guarded, `bounties` flag, BountiesWrite scope). Requires at least one deliverable file (a pre-uploaded file reference: { url, name, sizeKB }) and at least one example image (by UUID or URL — URLs are uploaded automatically to UUIDs). Files MUST already be uploaded; pass their refs. Pass id to edit an existing entry. |
award_bounty |
Award a bounty to a specific entry via bountyEntry.award { id }. Protected + `bounties` flag. Only the bounty owner may award; awarding distributes the bounty funds to the entry author. |
upsert_announcement |
Create (omit id) or update (pass id) a homepage announcement banner. On update, missing fields are merged from the current row so required fields stay valid. startsAt defaults to now on create. Image can be a UUID or a URL (uploaded automatically). Moderator-only upstream. |
delete_announcement destructive |
Permanently delete an announcement by ID. Moderator-only upstream. |
list_announcements read-only |
List announcements. scope="current" returns currently-live ones (public endpoint); scope="all" returns the paginated moderator list. |
upsert_changelog |
Create (omit id) or update (pass id) a /changelog entry. Markdown content is converted to HTML (same converter as articles). On create, title + content + type are required and effectiveAt defaults to now. On update, only the fields you pass are changed. Moderator-only, gated by the changelogEdit flag. |
upload_image |
Upload an image to Civitai from a URL or base64 data. Returns the image UUID (and probed dimensions) needed to set article covers and announcement images. Chains the presign + PUT upload internally. |
whoami read-only |
Resolve the current user from the active API key (id, username) and report authoritative account status via user.getSelfStatus (UserRead scope). Good smoke test for deployments and for confirming which account will perform user actions. Reports REAL onboarding state (isOnboarded + completedSteps), muted state, and an authoritative isModerator flag, plus subscription tier. An un-onboarded account fails every verified/guarded social write (post, react, review, follow) and a muted account fails guarded writes — so check this first if writes are 500ing, then call complete_onboarding_step. |