Search

Search the docs…

Connect your AI

MCP server

Postika speaks the Model Context Protocol. Any MCP client can read your calendar and create, edit, approve or delete posts with photos and videos, with the same rules as the app. Most people only need this: no API keys.

Server URL

https://postika.app/api/mcp
Transport
Streamable HTTP, stateless, JSON responses. POST, GET and DELETE on the same URL.
Authentication
OAuth 2.1 (automatic) or a project API key in Authorization: Bearer ptk_…
Projects
OAuth connections reach every project of the user; key connections reach only the key's project.

How the client connects

You only paste the URL. Clients that support MCP authorization do the rest:

  1. 1
    The client calls the server without a token and gets 401 with this header:
    WWW-Authenticate: Bearer resource_metadata="https://postika.app/.well-known/oauth-protected-resource"
  2. 2
    It reads the resource metadata, then the authorization server metadata at /.well-known/oauth-authorization-server.
  3. 3
    It registers itself at /api/oauth/register (dynamic client registration) and opens /oauth/authorize with PKCE.
  4. 4
    The user signs in and clicks Allow (Permitir). The client exchanges the code for a ptat_ access token and a ptrt_ refresh token.

The details of every step are in Authentication. Users can disconnect any AI from Connect AI → Connected AIs (Conectar IA → IAs conectadas) in the app.

Tools

Ten tools, enough to run the whole calendar from the chat without the REST API. Dates are always in the project's local time, YYYY-MM-DD HH:MM. With a single project, project_id can be left out. Every tool carries MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) so clients know which ones only read and which ones need confirmation.

ToolWhat it doesKind
list_projectsProjects of the connection with role, time zone, current local time and whether the subscription is active (with the reason if not).read
get_account_statusPlan, trial end, renewal, channels used vs. the plan limit, role and permissions, pending approvals and warnings with links. Works even when the subscription is inactive.read
list_channelsConnected channels: ID, network, handle, character limit, whether it needs a photo or video, video only, max photos.read
list_postsPosts in a range of days, or by status regardless of date (drafts, failed…), with per-channel status, errors and URLs.read
get_postOne post with text, time, media IDs, per-channel status, errors and published URLs.read
create_postNew post in approval, schedule, draft or now mode, with photos and videos from media_urls.write
update_postChange text, time, channels, mode or media of a post that hasn't been published yet. Omitted fields stay as they are.write
list_pending_approvalsPosts waiting for approval and whether this connection can approve them.read
approve_postApprove a pending post (owners and admins only). Same checks as the button in the app.write
delete_postDelete a post from Postika. A post already live stays on the network. Marked destructive.destructive

create_post

project_idstring
Project ID. Not needed with a single project.
contentstringrequired
Post text, 1 to 5000 characters. Each network also applies its own limit.
channel_idsstring[]required
One or more channel IDs from list_channels.
modeenumrequired
approval (pending in the app, preferred) · schedule · draft · now (publish immediately).
whenstring
Local time YYYY-MM-DD HH:MM. Required for schedule and approval; optional for draft; ignored for now.
media_urlsstring[]
Up to 10 public https:// links straight to the files: JPG, PNG, WebP, GIF (15 MB) or MP4, MOV (100 MB). Required for Instagram, TikTok and Pinterest; YouTube needs a video.
notestring
Optional note for whoever approves it. Not published.

If the connection belongs to an editor, schedule and now are saved as pending approval and the result includes a notice saying so.

update_post

post_idstringrequired
Post ID.
content · channel_ids · when · mode
Same as create_post, all optional.
media_urlsstring[]
Photos or videos to add.
keep_media_idsstring[]
Media IDs from get_post to keep, in order. Omit to keep all; [] removes them.

How media_urls are fetched

Postika downloads the files from its own servers, so the fetcher is locked down against SSRF:

  • Only https:// on port 443, no user:password@.
  • The host is resolved and every address checked before connecting, and the connection goes to exactly those addresses (no DNS rebinding). Loopback, private, link-local (cloud metadata), CGNAT, multicast and reserved ranges are refused, also in IPv6 and IPv4-mapped form.
  • At most 3 redirects, each one checked again. 45 seconds and the size limits above, enforced while downloading.
  • The file type comes from its first bytes, not from the Content-Type; web pages are rejected.

Errors and subscription

Only two things are HTTP errors on the MCP endpoint, because clients handle them by themselves: 401 with WWW-Authenticate (no token or expired: the client starts OAuth or refreshes) and 429 with Retry-After. Everything else is a normal tool result with isError: true and an English message that says what to do, with a link, so the AI can tell the user. initialize and tools/list always work, so the connector never shows up as broken.

CodeWhenThe AI is told to
subscription_inactiveThe owner of that project has no active subscription or trial.Send the user to /billing (or ask the owner).
no_channelsThe project has no connected channels.Connect one in Channels (link).
channel_disconnectedA channel needs reconnecting.Reconnect it (link) or leave it out.
approval_forbiddenAn editor tried to approve.Ask an owner or admin (link).
needs_media · needs_video…A network rule isn't met.Add media_urls or change the channels.
media_fetch_failedA media URL was refused or couldn't be downloaded.Use a public https link to the file.
project_required · project_not_foundSeveral projects and no project_id, or an unknown one.Call list_projects.
The subscription is checked per project and on every call: when it's activated again the connection works right away, without reconnecting. The REST API returns the same messages with HTTP status codes (402 for subscription_inactive).

Security

  • Bearer tokens only (never cookies), so the endpoint doesn't filter by Origin: Claude.ai and ChatGPT call it from their servers, and a web page or DNS rebinding can't do anything without a token.
  • Request bodies up to 1 MB. 120 requests per minute per token or key, 60 per minute per IP without a valid credential.
  • Each tool call is logged with tool name, project and result code, never the content, and kept 90 days.

Example prompts

  • “Draft three LinkedIn posts about our launch and leave them for my approval on Monday, Wednesday and Friday at 9:00.”
  • “What is scheduled for next week? Move nothing, just give me a summary.”
  • “Turn this blog post into an X thread opener and a Threads post, and schedule both for tomorrow at 18:30.”
  • “Delete the drafts I created yesterday in the Acme project.”
  • “Post this photo to Instagram and TikTok tomorrow at 19:00: https://example.com/launch.jpg”
  • “What is waiting for my approval? Approve the LinkedIn one.”

Claude.ai and Claude Desktop

  1. 1
    Open Settings → Connectors and click Add custom connector.
  2. 2
    Name it Postika and paste https://postika.app/api/mcp.
  3. 3
    Click Connect, sign in to Postika and click Allow (Permitir).

Connectors added on claude.ai also appear in Claude Desktop and the mobile apps with the same account.

ChatGPT

  1. 1
    Open Settings → Apps & Connectors → Advanced settings and turn on Developer mode.
  2. 2
    Back in Apps & Connectors, click Create. Paste https://postika.app/api/mcp and choose OAuth authentication.
  3. 3
    Click Create, then Allow (Permitir) in the Postika window. Enable the connector from the composer when you chat.

Claude Code

claude mcp add --transport http postika https://postika.app/api/mcp

Then type /mcp inside Claude Code, pick postika and authenticate in the browser. Add --scope user to make it available in every project on your machine.

Cursor

Use Add in one click (Añadir en un clic) on the Connect AI (Conectar IA) page of the app, or add the server to ~/.cursor/mcp.json. Cursor opens the Postika permission window the first time.

~/.cursor/mcp.json
{
  "mcpServers": {
    "postika": {
      "url": "https://postika.app/api/mcp"
    }
  }
}

VS Code

Run MCP: Add Server → HTTP from the command palette and paste the URL, or commit it to your workspace:

.vscode/mcp.json
{
  "servers": {
    "postika": {
      "type": "http",
      "url": "https://postika.app/api/mcp"
    }
  }
}

Gemini CLI

~/.gemini/settings.json
{
  "mcpServers": {
    "postika": {
      "httpUrl": "https://postika.app/api/mcp"
    }
  }
}

Then run /mcp auth postika inside Gemini CLI.

Other clients (API key)

Hermes, OpenClaw and other agents that don't support OAuth connect with a project API key. Create one in Connect AI → Project keys (Conectar IA → Claves de proyecto): right after creating it, the app offers Copy MCP configuration (Copiar configuración MCP) with the key already in it.

mcp.json
{
  "mcpServers": {
    "postika": {
      "type": "http",
      "url": "https://postika.app/api/mcp",
      "headers": {
        "Authorization": "Bearer ptk_…"
      }
    }
  }
}

To check the connection by hand, list the tools with curl:

curl https://postika.app/api/mcp \
  -H "Authorization: Bearer $POSTIKA_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'