@schedulala/mcp-server
An MCP server that lets AI tools (Claude Desktop, Claude Code, Cursor, and any MCP-compatible client) schedule and manage social media posts through Schedulala.
It is a thin wrapper over the Schedulala Developer REST API (/api/v1/*). All logic lives in the API; this server only translates MCP tool calls into authenticated HTTP requests.
Tools
29 tools. The "Annotations" column lists the MCP tool hints (readOnly, destructive, idempotent; all tools are openWorld since they hit a live external API).
Posts
create_post | Create/schedule a post across one or more platforms | destructive |
list_posts | List your API-created posts, with filters + pagination | readOnly |
get_post | Get one post by id (per-platform status, URLs, errors) | readOnly |
update_post | Edit a draft or scheduled post (content, media, schedule, platforms) | destructive |
cancel_post | Delete a draft or cancel a scheduled post | destructive, idempotent |
retry_post | Retry the failed platforms of a post | destructive |
bulk_create_posts | Create up to 25 posts in one request (consumes quota per post) | destructive |
validate_post | Check content against platform rules without posting | readOnly |
Media
upload_media | Host media on the Schedulala CDN for create_post: re-host a public image/video URL, or pass a small image (3MB max) inline as base64 data | — |
list_media | List recent uploads (dashboard Media library + API) so "post my latest upload" works without copying URLs — the path for posting videos from chat | readOnly, idempotent |
Limits: images up to 20 MB (jpeg, png, webp; gif 15 MB), videos up to 50 MB (mp4, mov, webm). Larger videos: pass their public URL directly in create_post mediaItems (fetched at publish time).
Threads
create_thread | Create a chain of sequential posts (twitter, threads, bluesky); consumes quota per entry | destructive |
Accounts and usage
list_accounts | List connected social accounts (ids used by other tools) | readOnly |
get_usage | Plan, post quota, social sets, billing period, rate limit | readOnly |
connect_account | Link to connect a new platform (OAuth/credentials happen on schedulala.com, never in chat) | readOnly |
get_upgrade_link | Subscribe or manage-billing link (payment happens on schedulala.com / Stripe) | readOnly |
Analytics
Analytics platforms: instagram, twitter, bluesky, threads, facebook, linkedin, pinterest, tiktok, youtube.
get_post_analytics | Per-post metrics + engagement rate for one account (cursor paginated) | readOnly |
get_follower_growth | Current followers, 7d/30d growth, daily history | readOnly |
get_best_posting_times | Top hours/days by historical engagement | readOnly |
get_video_transcript | Caption tracks + parsed transcript of a video on a connected channel | readOnly |
get_video_retention | Per-video audience retention curve (YouTube Analytics API, 7-day cache) | readOnly |
Feeds (social listening)
Search: bluesky, threads (threads keyword search has a Meta-enforced budget of 500 searches per rolling 7 days per user, shared with the dashboard). Profile lookup: bluesky.
search_feeds | Keyword search; every result carries reply targets for reply_to_comment | readOnly |
lookup_profile | Public profile + recent posts | readOnly |
list_feed_keywords | List saved feed keywords | readOnly |
update_feed_keywords | Add/remove saved feed keywords (max 20) | — |
Engagement
Comments + reply: facebook, instagram, youtube, linkedin, threads, bluesky. Hide: facebook, instagram, youtube, threads. Mentions: instagram, threads, bluesky. (tiktok, telegram, twitter, pinterest are not engagement platforms.)
list_comments | Recent comments, or comments on a specific post | readOnly |
list_mentions | Posts/comments where the account is mentioned/tagged/quoted | readOnly |
reply_to_comment | Publish a reply (target differs per platform — see below) | destructive |
hide_comment | Hide/unhide a comment | destructive, idempotent |
account ids and accountId parameters come from list_accounts. Reply targets per platform: commentId (instagram/youtube); commentId or postId (facebook/linkedin/threads); parentUri+parentCid+rootUri+rootCid for bluesky — these four come back on every bluesky comment/mention under platformData.replyRefs, so chain list_comments → reply_to_comment.
Supported posting platforms: twitter, instagram, linkedin, facebook, youtube, bluesky, tiktok, telegram, threads, pinterest.
Requirements
- Node.js >= 18
- A Schedulala API key. Get one at https://schedulala.com/developers.
sk_test_* keys run in sandbox mode (simulated post lifecycle, no real posting, no quota burn) — use these for testing.
sk_live_* keys post for real.
Configuration
The server reads two environment variables:
SCHEDULALA_API_KEY | yes | — | Server exits with an error if this is unset. |
SCHEDULALA_API_URL | no | https://schedulala.com | Override for local/dev (e.g. http://localhost:3000). |
Install
This package is published with a bin, so most clients can run it via npx without a manual install:
npx -y @schedulala/mcp-server
To build from source (in this repo):
cd packages/mcp-server
npm install
npm run build
Client setup
Hosted alternative: clients with built-in remote-connector support don't
need this package at all. claude.ai (Settings → Connectors) and ChatGPT
(developer-mode MCP connectors) connect directly to
https://schedulala.com/api/mcp — the same tools, with OAuth sign-in instead
of a manually managed API key. This stdio package is for clients that spawn
local MCP servers (Claude Desktop, Claude Code, Cursor, and similar).
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"schedulala": {
"command": "npx",
"args": ["-y", "@schedulala/mcp-server"],
"env": {
"SCHEDULALA_API_KEY": "sk_live_xxx"
}
}
}
}
Restart Claude Desktop after saving.
Claude Code
claude mcp add --transport stdio \
--env SCHEDULALA_API_KEY=sk_live_xxx \
schedulala -- npx -y @schedulala/mcp-server
Or point it at a local build instead of npx:
claude mcp add --transport stdio \
--env SCHEDULALA_API_KEY=sk_test_xxx \
schedulala -- node /absolute/path/to/packages/mcp-server/build/index.js
Cursor
Create .cursor/mcp.json in your project (or ~/.cursor/mcp.json for global):
{
"mcpServers": {
"schedulala": {
"command": "npx",
"args": ["-y", "@schedulala/mcp-server"],
"env": {
"SCHEDULALA_API_KEY": "sk_live_xxx"
}
}
}
}
Local development config
Point the server at a locally running Schedulala instance and use a sandbox key:
Claude Desktop / Cursor (local build + localhost API)
{
"mcpServers": {
"schedulala-local": {
"command": "node",
"args": ["/absolute/path/to/packages/mcp-server/build/index.js"],
"env": {
"SCHEDULALA_API_KEY": "sk_test_xxx",
"SCHEDULALA_API_URL": "http://localhost:3000"
}
}
}
}
Claude Code (local)
claude mcp add --transport stdio \
--env SCHEDULALA_API_KEY=sk_test_xxx \
--env SCHEDULALA_API_URL=http://localhost:3000 \
schedulala-local -- node /absolute/path/to/packages/mcp-server/build/index.js
Testing
MCP Inspector (interactive UI)
cd packages/mcp-server
npm run build
SCHEDULALA_API_KEY=sk_test_xxx npx @modelcontextprotocol/inspector node build/index.js
Smoke test over stdio
printf '%s\n%s\n%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| SCHEDULALA_API_KEY=sk_test_dummy node build/index.js
This should return a JSON-RPC response listing all 29 tools.
Embedding (./lib)
The package exposes a second, side-effect-free entry point for reuse by a sibling server (e.g. a remote/HTTP MCP server):
"exports": {
".": "./build/index.js",
"./lib": "./build/lib.js"
}
@schedulala/mcp-server/lib re-exports the SchedulalaApiClient, the ApiClientError type, every register*Tools function (registerPostTools, registerThreadTools, registerAnalyticsTools, registerEngagementTools, registerAccountTools, registerUsageTools, registerYouTubeTools, registerFeedTools, registerMediaTools, registerAccountSetupTools), all formatters, and all request/response types — with no shebang and no transport side effects. Import it to register the same tools against your own McpServer instance:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import {
SchedulalaApiClient,
registerPostTools,
registerAnalyticsTools,
registerEngagementTools,
} from "@schedulala/mcp-server/lib";
const client = new SchedulalaApiClient(apiKey, baseUrl);
const server = new McpServer({ name: "my-remote", version: "1.0.0" });
registerPostTools(server, client);
registerAnalyticsTools(server, client);
registerEngagementTools(server, client);
The stdio binary (. / the package bin) is unchanged.
Notes
- No brands endpoint. There is no
/api/v1/brands. Read brand / social-set ids from list_accounts (each account has a brandId) or get_usage.
- stdout is reserved for JSON-RPC. This server only logs to stderr.
License
MIT