postiz-mcp
Summary: postiz-mcp is a typed MCP server/client for Postiz that lets an agent manage social channels, posts, uploads, analytics, and video with reads always on and writes/deletes safely gated.
List and verify connected social integrations; find the next available posting slot.
Read posts in a date range, recover missing platform content, and list Postiz UI notifications.
Fetch per-channel and per-post analytics, AI video voices, and provider-specific settings schemas.
Create, schedule, or publish posts (including multi-post threads with media/delays) when
POSTIZ_ENABLE_WRITE=true.Connect new channels via generated OAuth URLs and invoke per-platform integration tools.
Update post status (DRAFT ↔ QUEUE) and reattach release IDs.
Upload media from local files/base64 or server-side public URLs.
Generate AI videos through configured Postiz video integrations.
Delete posts, post groups, or integrations when write + delete are enabled and
confirm: trueis passed.Enforce a local hourly rate-limit guard and support Cloudflare Access service tokens.
Ship as a stdio MCP server, OpenClaw native plugin, and HTTP mode with bearer auth.
Click on "Deploy 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., "@postiz-mcp list my connected social channels"
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.
Canonical Postiz client for any MCP-compatible client. Full coverage of the Postiz public API (integrations, posts, uploads, analytics, video) with env-gated writes, confirm-required deletes, and a built-in rate-limit guard.
Ships as a stdio MCP server and a first-class OpenClaw native plugin from the same package.
Point it at your Postiz and your agent gets 22 typed, schema-validated tools. Reads are always on; writes stay off until you set POSTIZ_ENABLE_WRITE=true. The fatal line above is the server refusing to start without config, not a crash.
Why
If you self-host Postiz and want Claude / Codex / OpenClaw / Hermes / any MCP client to interact with it, this gives you a typed, tested, single-purpose tool surface instead of hand-rolled HTTP calls in every workflow.
Related MCP server: Postoria MCP Server
See also
gitroomhq/postiz-agent is the official Postiz CLI from Nevo David. It's the right pick if you're a Postiz Cloud subscriber wanting OAuth-flow auth, or if you only need a Bash-callable surface in Claude Code.
This package (postiz-mcp) is the right pick if you:
Self-host Postiz and want to skip running an OAuth broker
Use an MCP-native client (Claude Desktop, OpenClaw, Hermes, Codex CLI) and want typed tool schemas instead of bash-shelling
Want defense-in-depth gating (writes off by default, deletes require
enableDelete+confirm: true)Want a local rate-limit guard that refuses to send when your hourly budget is exhausted
Need Cloudflare Access service-token support
Warnings before you wire this up
Postiz writes are public side effects. A successful
postiz_create_postwithtype: "now"(or a near-term schedule) lands on real social accounts. Once published, posts can be deleted from Postiz but the platform-side post stays live - Postiz cannot recall it.The Postiz public API is rate-limited at 30 requests/hour by default. This server tracks the limit locally and refuses to send when the budget is exhausted. Override with
POSTIZ_RATE_LIMIT_PER_HOURif your Postiz instance is configured higher.Writes and deletes are gated off by default. Reads always work. To enable writes you must explicitly set
POSTIZ_ENABLE_WRITE=true. To enable deletes you must additionally setPOSTIZ_ENABLE_DELETE=trueAND passconfirm: truein the tool call.
Tools
Reads (always on)
postiz_list_integrations- list connected channelspostiz_check_integration- verify API keypostiz_find_next_slot- next free posting slot for a channelpostiz_list_posts- posts in a date windowpostiz_get_missing_content- recover platform content for a Postiz post with a missingreleaseIdpostiz_get_integration_settings- live runtime config for ONE connected integration: rules, maxLength (verified-aware), settings DTO, available platform-specific tools. Use before postiz_create_post when content length matters.postiz_list_notifications- Postiz UI notificationspostiz_get_platform_analytics- followers / impressions / engagementpostiz_get_post_analytics- likes / comments / sharespostiz_list_voices- AI video voice catalogpostiz_get_provider_settings_schema- per-providersettingsschema (X, LinkedIn, Reddit, etc.) bundled at build time
Writes (require POSTIZ_ENABLE_WRITE=true)
postiz_create_post- schedule / publish-now / draftpostiz_connect_integration- generate OAuth URL for a new channelpostiz_invoke_integration_tool- call a per-platform tool method on an integration (e.g. Reddit subreddit search, YouTube playlist lookup) via POST /api/public/v1/integration-trigger/{id}. Discover validmethodNamevalues viapostiz_get_integration_settings(id).toolsfirst.postiz_update_post_status- toggle DRAFT ↔ QUEUEpostiz_update_post_release_id- reattach a Postiz post to its platform-side releasepostiz_upload_file- multipart upload from local file or base64postiz_upload_from_url- server-side fetchpostiz_generate_video- AI video generation
Deletes (require POSTIZ_ENABLE_WRITE=true + POSTIZ_ENABLE_DELETE=true + confirm: true)
postiz_delete_post- cascades to whole grouppostiz_delete_post_group- delete every post in a cross-post grouppostiz_delete_integration- disconnect channel + all its scheduled posts
Install
npm install -g postiz-mcpOr from source:
git clone https://github.com/solomonneas/postiz-mcp.git
cd postiz-mcp
npm install
npm run buildConfiguration
Set these environment variables in your MCP client config:
Variable | Required | Default | Description |
| yes | - | Base URL, e.g. |
| yes | - | API key from Postiz Settings → Public API |
| no |
| Set |
| no |
| Set |
| no |
| HTTP timeout (ms) |
| no |
| Local guard ceiling. The server still trusts response headers when present. |
| no | - | Cloudflare Access service token client id (only needed if Postiz is behind CF Access) |
| no | - | Cloudflare Access service token secret |
Getting an API key
Log into Postiz as an admin
Settings → Public API → Generate API Key
Copy the value (starts with
pos_or is a raw UUID depending on your Postiz version)
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"postiz": {
"command": "postiz-mcp",
"env": {
"POSTIZ_URL": "http://localhost:5000",
"POSTIZ_API_KEY": "your-api-key-here",
"POSTIZ_ENABLE_WRITE": "true",
"POSTIZ_ENABLE_DELETE": "false"
}
}
}
}Claude Code
claude mcp add postiz \
--env POSTIZ_URL=http://localhost:5000 \
--env POSTIZ_API_KEY=your-api-key-here \
--env POSTIZ_ENABLE_WRITE=true \
-- postiz-mcpAdd --scope user to make it available from any directory instead of only the current project.
OpenClaw
postiz-mcp is also an OpenClaw native plugin. From a source checkout:
openclaw plugin add /absolute/path/to/postiz-mcp \
--config '{
"baseUrl": "http://localhost:5000",
"apiKeyEnv": "POSTIZ_API_KEY",
"enableWrite": true,
"enableDelete": false
}'Then export the API key and restart the gateway:
export POSTIZ_API_KEY=your-api-key-here
systemctl --user restart openclaw-gateway
openclaw plugin list # confirm "postiz" is enabledYou can also run it as a regular MCP server under OpenClaw:
openclaw mcp set postiz '{
"command": "postiz-mcp",
"env": {
"POSTIZ_URL": "http://localhost:5000",
"POSTIZ_API_KEY": "your-api-key-here",
"POSTIZ_ENABLE_WRITE": "true"
}
}'Hermes Agent
Hermes Agent reads MCP config from ~/.hermes/config.yaml under mcp_servers. Add an entry:
mcp_servers:
postiz:
command: "postiz-mcp"
env:
POSTIZ_URL: "http://localhost:5000"
POSTIZ_API_KEY: "your-api-key-here"
POSTIZ_ENABLE_WRITE: "true"Or from a source checkout:
mcp_servers:
postiz:
command: "node"
args: ["/absolute/path/to/postiz-mcp/dist/mcp-server.js"]
env:
POSTIZ_URL: "http://localhost:5000"
POSTIZ_API_KEY: "your-api-key-here"
POSTIZ_ENABLE_WRITE: "true"Then reload MCP from inside a Hermes session:
/reload-mcpCodex CLI
Codex CLI registers MCP servers via codex mcp add:
codex mcp add postiz \
--env POSTIZ_URL=http://localhost:5000 \
--env POSTIZ_API_KEY=your-api-key-here \
--env POSTIZ_ENABLE_WRITE=true \
-- postiz-mcpOr from a source checkout:
codex mcp add postiz \
--env POSTIZ_URL=http://localhost:5000 \
--env POSTIZ_API_KEY=your-api-key-here \
--env POSTIZ_ENABLE_WRITE=true \
-- node /absolute/path/to/postiz-mcp/dist/mcp-server.jsCodex writes the entry to ~/.codex/config.toml under [mcp_servers.postiz]. Verify with:
codex mcp listPostiz behind Cloudflare Access
If your Postiz is exposed via Cloudflare Tunnel + Access (e.g. https://postiz.example.com), generate a service token in the Cloudflare Zero Trust dashboard and add the env vars:
export POSTIZ_CF_ACCESS_CLIENT_ID=your-cf-id.access
export POSTIZ_CF_ACCESS_CLIENT_SECRET=your-cf-secretThe MCP server forwards them as CF-Access-Client-Id / CF-Access-Client-Secret on every request. If you forget them, you'll get a clear PostizCfAccessChallengeError instead of a confusing HTML response.
Example prompts
"List the integrations on my Postiz."
"Schedule a Bluesky post for tomorrow 9am: 'Just shipped postiz-mcp.'"
"What's the next available LinkedIn slot? Schedule this 4-tweet thread for that time on X with replies set to verified-only."
"What posted last week and how did the X post on Tuesday do?"
"Show me the X provider settings schema so I can construct a thread payload."
Thread mode (multi-post threads with per-post media + delay)
postiz_create_post's posts[].value[] array is a sequence - every entry posts to the same integration in order, with optional per-entry image[] and delay (minutes between posts). Use this for X threads, LinkedIn carousel-style follow-ups, etc.
{
"type": "schedule",
"date": "2026-05-15T09:00:00.000Z",
"posts": [
{
"integrationId": "integration-uuid-here",
"value": [
{
"content": "Launching our new feature today.",
"image": [{ "id": "abc", "path": "<path returned by postiz_upload_file>" }]
},
{
"content": "Here's what's new under the hood:",
"delay": 5
},
{
"content": "Try it and let us know what breaks.",
"delay": 5
}
]
}
]
}Each value[] after the first uses delay (minutes) to space posts out. image[] is optional per entry and uses paths returned by postiz_upload_file / postiz_upload_from_url - raw filesystem paths and external URLs are rejected.
Provider settings schemas
postiz_get_provider_settings_schema returns the bundled per-provider settings reference (parsed from docs.postiz.com/public-api/providers/{slug}.md). Use it before postiz_create_post when you need provider-specific fields like X's who_can_reply_post or LinkedIn's audience.
The schemas are refreshed monthly by a GitHub Actions workflow that opens a PR if Postiz updated any provider doc. To refresh manually:
npm run refresh-schemasDevelopment
npm install
npm run typecheck
npm test
npm run buildHTTP mode
Start the built entry point with node dist/mcp-server.js --http. Without
--http, the existing stdio transport is used. Keep the existing upstream
configuration (POSTIZ_URL, API key, optional Cloudflare Access credentials).
HTTP mode also accepts:
Variable | Default | Purpose |
| required | Separate bearer secret of at least 32 characters, trimmed. Blank, short and upstream-credential values are rejected. |
| loopback | Listening interface. |
|
| Listening port. |
|
| Set exactly |
/mcp requires bearer authentication. GET /healthz returns only
{"status":"ok"} without authentication. Host and Origin checks run before
authentication. Requests are capped at 1 MiB, including base64 uploads. Sessions
are capped at 128 and expire after 30 idle minutes. Request and header timeouts
are 30 and 10 seconds. SIGTERM and SIGINT close sessions and the listener.
Every connection gets its own MCP server. All connections use the same Postiz
account and share its rate budget. Write and delete flags are operator settings,
and confirm: true is required on each delete call. There is no stored pending
confirmation, draft, or publish ticket. Postiz stores drafts and schedules.
HTTP local file uploads require both the opt-in above and POSTIZ_UPLOAD_ROOTS
(comma- or colon-separated directories). Real paths and the opened file are
checked against those roots. Symlink escapes are rejected. File metadata and
contents are read through one handle, with the existing upload-size cap. Use
POSTIZ_MCP_HTTP_LOCAL_FILES=true and POSTIZ_UPLOAD_ROOTS for large media:
base64 input must fit inside the 1 MiB request limit, including JSON overhead.
Base64
uploads do not need filesystem access. Stdio and plugin uploads keep their
existing opt-in through upload roots.
URL uploads are fetched by Postiz, rather than by this MCP process. Recognized literal loopback, private IPv4, and private IPv6 ranges are rejected. IPv4-compatible, NAT64, and 6to4 IPv6 forms are not fully classified. This check does not resolve DNS or inspect redirects: a hostname resolving to a private address or a public URL redirecting there can still reach the Postiz host's network. Restrict that host's outbound network access before enabling writes for clients you do not trust.
Claude Code configuration:
{
"mcpServers": {
"postiz": {
"type": "http",
"url": "http://localhost:18815/mcp",
"headersHelper": "/path/to/helper POSTIZ_MCP_HTTP_TOKEN"
}
}
}The helper reads the named environment variable and prints a JSON object such
as {"Authorization":"Bearer ..."} to stdout. Keep the secret out of the
configuration file.
Codex streamable HTTP configuration:
[mcp_servers.postiz]
url = "http://localhost:18815/mcp"
bearer_token_env_var = "POSTIZ_MCP_HTTP_TOKEN"An example user service is in
docs/systemd/postiz-mcp-http.service.
Set its working directory and executable paths for your installation. Create
its EnvironmentFile with mode 0600, containing upstream configuration and
a separate HTTP token. The example is not installed or started automatically.
License
MIT
Available Tools
20 toolspostiz_check_integrationA
Verify the configured Postiz API key is valid and reaches the configured baseUrl. Useful as a first call before any other tool — if this returns ok, every other tool can authenticate against the same instance.
Inputs: no named parameters.
postiz_connect_integrationA
Generate the OAuth authorization URL for connecting a new social channel. Returns a url the user must open in a browser to finish the flow — Postiz redirects back to its own callback. This tool does NOT run a callback server. Requires enableWrite.
Inputs: provider (required), refresh.
postiz_create_postA
Create, schedule, or immediately publish one or more posts via POST /api/posts. PUBLIC SIDE EFFECT: with type='now' or a near-term schedule, this lands on real social accounts. Use postiz_get_provider_settings_schema first to construct valid settings blocks. Requires enableWrite.
Inputs: type (required), date (required), posts (required), shortLink, +1 more.
postiz_delete_integrationA
Disconnect a connected social channel. Cascades — Postiz also deletes every scheduled post for that integration. Requires enableWrite + enableDelete + confirm=true. Returns ok:false / not_found on 404 (already disconnected).
Inputs: integrationId (required), confirm (required).
postiz_delete_postA
Delete a Postiz post by id. CASCADES — every post in the same group is removed. Already-published platform posts remain live. Requires enableWrite + enableDelete + confirm=true.
Inputs: postId (required), confirm (required).
postiz_delete_post_groupA
Delete every post in a group (cross-post unit) via DELETE /api/posts/group/{group}. Use when you want to retract a whole cross-post in one call. Requires enableWrite + enableDelete + confirm=true.
Inputs: group (required), confirm (required).
postiz_find_next_slotA
Return the next available posting time for a given integration. The slot respects the org's configured posting schedule, so this is the right answer to use as date in postiz_create_post when you don't have a specific time in mind.
Inputs: integrationId (required).
postiz_generate_videoA
Generate an AI video via POST /api/video/generate. COST IMPLICATION: video generation may bill against the configured Postiz video integration's credit pool. Requires enableWrite. Body shape is provider-specific — see Postiz video docs.
Inputs: body (required).
postiz_get_missing_contentA
Fetch recent platform-side content for a post whose Postiz releaseId is marked missing. Pair with postiz_update_post_release_id to reattach.
Inputs: postId (required).
postiz_get_platform_analyticsA
Get follower / impression / engagement analytics for a connected channel via GET /api/analytics/platform. Available metrics depend on what the platform exposes to Postiz.
Inputs: integrationId (required), date.
postiz_get_post_analyticsA
Get per-post engagement metrics (likes, comments, shares) via GET /api/analytics/post. Returns whatever the source platform exposes — different shape per provider.
Inputs: postId (required).
postiz_get_provider_settings_schemaA
Look up the settings block schema for a Postiz provider (X, LinkedIn, Reddit, etc.) — bundled at build time from docs.postiz.com. Returns a default-settings template, the provider's __type value, and (by default) the full markdown reference. Call this before postiz_create_post when you need provider-specific fields.
Inputs: provider (required), includeMarkdown.
postiz_list_integrationsA
List every connected social-media channel for the org behind the configured Postiz API key. Returns id, name, providerIdentifier (the value used as __type in post settings), profile, and disabled state. Use this BEFORE postiz_create_post to get the integration id you need to target.
Inputs: no named parameters.
postiz_list_notificationsA
List notifications, sorted most-recent first. Useful for surfacing posting failures, OAuth re-auth prompts, and new-feature notices Postiz shows in its UI.
Inputs: page.
postiz_list_postsA
List posts in a date range via GET /api/posts. Returns scheduled, queued, and published posts with their integration, content, state, and any platform release URL.
Inputs: startDate, endDate, display, customer.
postiz_list_voicesA
List available AI voices for video generation via GET /api/video/function?functionName=voices. Required input for postiz_generate_video — pick a voice id from the returned catalog.
Inputs: integrationId.
postiz_update_post_release_idA
Update the releaseId (and optionally releaseURL) of a Postiz post via PATCH /api/posts/{id}/release-id. Use to reconcile a Postiz post with the actual platform-side release after a missing-content event. Requires enableWrite.
Inputs: postId (required), releaseId (required), releaseURL.
postiz_update_post_statusA
Transition a Postiz post between DRAFT and QUEUE via PATCH /api/posts/{id}/status. Moving DRAFT→QUEUE re-enters the schedule using the post's existing publishDate. Requires enableWrite.
Inputs: postId (required), state (required).
postiz_upload_fileA
Upload a media file (image, video) to Postiz storage via POST /api/uploads/file. Returns { id, path } that you can pass into postiz_create_post value[].image[]. Requires enableWrite.
Inputs: filePath, base64, fileName, mimeType.
postiz_upload_from_urlA
Upload a media file from a public URL via POST /api/uploads/url. Postiz fetches the URL server-side, so this works for sources the MCP host can't reach. Returns { id, path } usable in postiz_create_post value[].image[]. Requires enableWrite.
Inputs: url (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Each tool targets a unique action and resource type. For example, postiz_create_post, postiz_delete_post, and postiz_list_posts are clearly distinct. Even overlapping actions like postiz_delete_post and postiz_delete_post_group are differentiated by scope (single vs. group). Descriptions clarify boundaries effectively.
All tools follow a consistent 'postiz_verb_noun' pattern with underscore separation. Verbs like check, connect, create, delete, find, generate, get, list, update, and upload are used uniformly. There is no mixing of camelCase or other conventions.
With 20 tools, the set is slightly above the typical 'well-scoped' range (3-15) but still reasonable given the breadth of Postiz's functionality (post management, analytics, AI video, integrations, file uploads). Each tool serves a distinct purpose.
The tools cover the main lifecycle: integration management, post CRUD, analytics, file uploads, and AI video generation. Minor gaps include no direct 'get post by ID' (though list_posts can retrieve it) and no interaction management (comments, etc.), but core workflows are well-supported.
Maintenance
Related MCP Connectors
Create, schedule, and publish social posts, manage accounts, and read analytics as MCP tools.
Create, schedule, and publish social posts through the hosted SocialSpool MCP connector.
Publish, schedule, and manage social media posts across major platforms via the Postproxy API.
Manage social publishing workflows through OpenPost
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with the Postiz social media management platform through MCP tools. Supports creating and managing posts, retrieving integrations, and accessing account information through multiple transport protocols.2-

Postoria MCP Serverofficial
AlicenseAqualityCmaintenanceEnables MCP-compatible clients to create, schedule, queue, inspect, and delete Postoria posts through the Postoria Public API.1417 npm1MIT- AlicenseNot gradedqualityFmaintenanceMCP server for managing social media posts across multiple platforms using the Postiz API. Supports creating, updating, deleting posts, and generating videos.38 npm3MIT

@fopost/mcpofficial
AlicenseAqualityBmaintenanceEnables managing social media posts, accounts, and AI-powered content features from any MCP client, including scheduling, publishing, analysis, and AI caption generation.1423 npmMIT