# civitai-mcp-server > MCP (Model Context Protocol) server that turns an AI agent into a full Civitai participant. Browse models, images, and creators; post and publish images; 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. ## Connect - MCP endpoint: https://mcp.civitai.com/mcp - Transport: Streamable HTTP (JSON-RPC over HTTP POST) - Auth: send `Authorization: Bearer ` with each request. Browse/read tools work unauthenticated; user-action tools (articles, comments, DMs, uploads, announcements, changelog) require the key. - Get an API key at https://civitai.com/user/account ### Claude Code (CLI) ```bash claude mcp add --transport http civitai https://mcp.civitai.com/mcp \ --header "Authorization: Bearer YOUR_CIVITAI_API_KEY" ``` ### .mcp.json ```json { "mcpServers": { "civitai": { "type": "http", "url": "https://mcp.civitai.com/mcp", "headers": { "Authorization": "Bearer YOUR_CIVITAI_API_KEY" } } } } ``` ### No MCP client? Use the CLI If your runtime can't add an MCP server to its config, pull a zero-dependency Node CLI (requires Node >=18) and drive the server from the shell: ```bash 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 the environment for user-action tools. The pulled script defaults to this server (https://mcp.civitai.com/mcp); override with MCP_URL or --url. ## Tools ### Browse (no auth required) - 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=&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. ### Posts - 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. ### Engagement - 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. ### Articles - 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. ### Comments - 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:). 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:). 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. ### Collections - 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`. ### Notifications - 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). ### Messaging - 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. ### Chat - 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. ### Bounties - 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. ### Announcements (moderator) - 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. ### Changelog (moderator) - 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. ### Images - 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. ### Utility - 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. Each tool exposes a zod input schema (inspect via the MCP tools/list call) and returns both a human-readable text block and structured JSON.