Socifyr MCP tools reference
The Socifyr MCP server exposes 20 tools. Each one calls the TypeScript SDK, which calls the REST API with your API key. The remote server and the local stdio server register the same tool definitions, so they behave the same.
This page lists every tool with its input schema, a sample call and a sample result. For connecting a client, see MCP setup. For failures and their fixes, see MCP errors.
Which MCP tools does Socifyr have?
| Group | Tools |
|---|---|
| Accounts | list_connections, refresh_connection, reconnect_connection |
| Posting | post_text, post_image, post_video |
| Scheduling | schedule_post, schedule_posts |
| Managing posts | list_posts, check_post_status, update_post, retry_post, publish_draft |
| Media | list_media, delete_media |
| Analytics | get_post_analytics, get_follower_growth, compare_accounts |
| Plan | get_usage |
| AI | generate_caption |
How does an MCP client call these tools?
A client sends a tools/call request with the tool name and an arguments object. The samples below show the name and arguments. Every tool returns a content array with one text item. When something goes wrong the result has isError: true and the text begins with Error: followed by the API message, so the model can read it and correct itself.
{
"name": "post_text",
"arguments": {
"connections": ["linkedin-myhandle", "x-myhandle"],
"caption": "Just shipped our new docs"
}
}Which tools can an API key with guardrails use?
An API key with a daily post limit, an X spend cap or requireApproval is deny-by-default. It can only call API routes on an allowlist. From the routes behind each tool:
| Allowed for guarded keys | Not allowed for guarded keys |
|---|---|
list_connections, post_text, post_image, post_video, schedule_post, schedule_posts, list_posts, check_post_status, update_post, retry_post, list_media, get_post_analytics, get_follower_growth, compare_accounts, get_usage, generate_caption | refresh_connection, reconnect_connection, delete_media |
publish_draft is allowed for a key with a post limit or spend cap, but a key with requireApproval gets a 403: This API key requires approval and cannot publish drafts directly — submit the post for approval and a teammate will review it. A guarded key calling a blocked tool gets This API key has guardrails and cannot call this endpoint — use a dashboard session or an unrestricted key. See API keys.
list_connections
Lists connected accounts with their slugs and health. Call it first: every posting tool needs slugs from here.
Input: none.
Sample call
{ "name": "list_connections", "arguments": {} }Sample result
Connected accounts (3):
• instagram-mybrand — instagram / mybrand (expires 11/18/2026) ⚠ expiring — call refresh_connection
• x-myhandle — x / myhandle ⚠ NEEDS RECONNECT — call reconnect_connection
• linkedin-myhandle — linkedin / Madhav Poudel
Use these slugs in the "connections" field when posting.Flags in the result come from the connection status: needs_reconnect shows NEEDS RECONNECT — call reconnect_connection. expiring shows expiring — call refresh_connection when the account can refresh, and expiring soon — call reconnect_connection when it cannot. active shows no flag. Disconnected accounts are left out. With no accounts the tool says so and points to the dashboard. See Connections and slugs.
refresh_connection
Renews an account's access token with its stored refresh token. No owner action is needed. Use it when list_connections shows expiring or a post failed with an expired or invalid token.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection | string | yes | Connection slug, for example instagram-mybrand |
{ "name": "refresh_connection", "arguments": { "connection": "instagram-mybrand" } }Refreshed instagram-mybrand (instagram). Status: active. New expiry: 1/12/2027, 10:00:00 AM.If the platform cannot refresh, the result is an error: Could not refresh "instagram-mybrand": <API message> followed by If it cannot be refreshed, call reconnect_connection to get a re-authorization link.
reconnect_connection
Returns a single-use link the account owner opens to re-authorize an account whose status is needs_reconnect, or whose post failed with reconnect_required.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection | string | yes | Connection slug, for example x-myhandle |
{ "name": "reconnect_connection", "arguments": { "connection": "x-myhandle" } }Reconnect link for x-myhandle (x):
https://api.socifyr.com/api/oauth/x/connect-popup?code=...
Ask the account owner to open it and approve access with the SAME account (a different account creates a new connection instead). It works once and expires in 10 minutes. Afterwards, retry the failed post (retry_post) or run list_connections to confirm the status is active.The slug and scheduled posts are kept when the same account is approved. Only the workspace owner can create the link; anyone else gets Only the workspace owner can connect accounts. An unknown slug gives Connection not found. The full flow is in Connections and slugs.
post_text
Publishes a text post to one or more accounts now.
| Parameter | Type | Required | Description |
|---|---|---|---|
caption | string | yes | The text to post |
connections | string[] (at least 1) | yes | Connection slugs |
firstComment | string | no | A first comment added after posting, for example hashtags |
{
"name": "post_text",
"arguments": {
"connections": ["linkedin-myhandle", "x-myhandle"],
"caption": "Just shipped our new docs",
"firstComment": "#buildinpublic"
}
}Post submitted successfully!
ID: 6a05033584584482ace13d72
Request ID: 9f2c7a1e-3d44-4b2a-8e1f-0a5c2d7e9f10
Check results with: check_post_status tool using ID "6a05033584584482ace13d72"The tool returns as soon as the post is accepted. Publishing continues in the background, so follow with check_post_status. With an approval-required key the post waits in pending_approval even though the message says it was submitted.
post_image
Publishes one or more images, now or scheduled.
| Parameter | Type | Required | Description |
|---|---|---|---|
connections | string[] (at least 1) | yes | Connection slugs |
images | string[] (1 to 10) | yes | Public image URLs or media library IDs (24-character hex) |
text | string | no | Caption |
scheduledAt | string | no | ISO 8601 time. Omit to post now |
firstComment | string | no | First comment |
contentFormat | photo_single | photo_carousel | story | no | Format override |
{
"name": "post_image",
"arguments": {
"connections": ["instagram-mybrand"],
"images": ["6a04f715d3d7d93575e65d13", "https://cdn.example.com/banner.png"],
"text": "New product banner",
"contentFormat": "photo_carousel"
}
}Submitted
ID: 6a05033584584482ace13d72
Images: 2
Connections: instagram-mybrandWith scheduledAt the first line reads Scheduled for <date and time>. The tool takes URLs and library IDs only; it cannot upload a file from your disk. Upload through the SDK, CLI or REST API first, then pass the ID.
post_video
Publishes one video, now or scheduled.
| Parameter | Type | Required | Description |
|---|---|---|---|
connections | string[] (at least 1) | yes | Connection slugs |
video | string | yes | Public video URL or media library ID |
text | string | no | Caption |
scheduledAt | string | no | ISO 8601 time. Omit to post now |
firstComment | string | no | First comment |
contentFormat | short_video | story | feed_video | no | Format override |
{
"name": "post_video",
"arguments": {
"connections": ["tiktok-mybrand", "instagram-mybrand"],
"video": "6a04f715d3d7d93575e65d13",
"text": "Behind the scenes",
"contentFormat": "short_video"
}
}Submitted
ID: 6a05033584584482ace13d72
Connections: tiktok-mybrand, instagram-mybrandschedule_post
Schedules a text post for a future time.
| Parameter | Type | Required | Description |
|---|---|---|---|
caption | string | yes | The text to post |
connections | string[] (at least 1) | yes | Connection slugs |
scheduledAt | string | yes | ISO 8601 time, for example 2026-12-01T09:00:00Z |
firstComment | string | no | First comment |
{
"name": "schedule_post",
"arguments": {
"connections": ["linkedin-myhandle"],
"caption": "Tomorrow at 9",
"scheduledAt": "2026-12-01T09:00:00Z"
}
}Post scheduled for 12/1/2026, 9:00:00 AM
ID: 6a05033584584482ace13d73
Connections: linkedin-myhandleThe displayed time uses the server's locale and timezone. For scheduled media use post_image or post_video with scheduledAt. The free plan does not include scheduling.
schedule_posts
Schedules many text posts in one call. Use it instead of repeating schedule_post.
| Parameter | Type | Required | Description |
|---|---|---|---|
posts | object[] (1 to 500) | yes | The posts to schedule |
posts[].text | string | yes | Post text |
posts[].connections | string[] (at least 1) | yes | Connection slugs |
posts[].scheduledAt | string | yes | ISO 8601 future time |
posts[].title | string | no | Optional title |
{
"name": "schedule_posts",
"arguments": {
"posts": [
{ "text": "Monday tip", "connections": ["x-myhandle"], "scheduledAt": "2026-12-07T09:00:00Z" },
{ "text": "Friday recap", "connections": ["x-myhandle", "linkedin-myhandle"], "scheduledAt": "2026-12-11T16:00:00Z", "title": "Weekly recap" }
]
}
}Scheduled 1 of 2 posts.
1 failed:
• Row 1: scheduledAt must be in the futureRows are numbered from 1 in the order you sent them. A failed row does not stop the others. Same behavior as the CLI schedule command.
list_posts
Lists posts with their IDs, so you can find one to edit, publish or check.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
status | draft | scheduled | queued | publishing | completed | partial_failure | failed | no | all | Filter by status. scheduled is an alias the tool maps to the stored pending status |
limit | integer 1 to 50 | no | 20 | Maximum results |
{ "name": "list_posts", "arguments": { "status": "scheduled", "limit": 10 } }Posts (2 total):
• 6a05033584584482ace13d73 — [pending] text "Tomorrow at 9" | scheduled 12/1/2026, 9:00:00 AM
→ linkedin/Madhav Poudel
• 6a05032a84584482ace13d5f — [pending] photo "New product banner" | scheduled 12/3/2026, 5:30:00 PM
→ instagram/mybrand, x/myhandle
Use a post ID with update_post, publish_draft, check_post_status, or get_post_analytics.Each entry shows the ID, status, type, a preview of up to 60 characters of the title or text, the schedule time and the target accounts. The tool has no filter for pending-approval posts.
check_post_status
Returns the status and per-platform result of a post.
| Parameter | Type | Required | Description |
|---|---|---|---|
postId | string | yes | The ID from a posting tool, or a request ID |
{ "name": "check_post_status", "arguments": { "postId": "6a05032a84584482ace13d5f" } }Post 6a05032a84584482ace13d5f
Status: partial_failure
✓ linkedin → https://linkedin.com/feed/update/...
✗ x (rate limit exceeded)A · marks a channel that has not finished. With no channel results yet the text says No channel results yet. Statuses are explained in post lifecycle.
update_post
Edits a draft or a scheduled post that has not published.
| Parameter | Type | Required | Description |
|---|---|---|---|
postId | string | yes | Draft or scheduled post ID, from list_posts |
connections | string[] (at least 1) | no | The full set of slugs. Replaces the current accounts, it is not a delta |
text | string | no | New caption or body |
title | string | no | New title |
description | string | no | New description |
firstComment | string | no | First comment text |
mediaIds | string[] | no | Media library IDs. Replaces the current media |
scheduledAt | string | no | New ISO 8601 time. For a scheduled post it must be in the future |
contentFormat | string | no | Content format override |
{
"name": "update_post",
"arguments": {
"postId": "6a05032a84584482ace13d5f",
"connections": ["instagram-mybrand", "x-mybrand", "linkedin-mybrand"],
"scheduledAt": "2026-12-01T09:00:00Z"
}
}Post 6a05032a84584482ace13d5f updated.
Connections now: instagram-mybrand, x-mybrand, linkedin-mybrand
Scheduled for: 12/1/2026, 9:00:00 AM
Check it with: check_post_status tool using ID "6a05032a84584482ace13d5f"Passing only postId returns an error: Nothing to update — provide at least one field (connections, text, scheduledAt, …).
retry_post
Re-queues the failed channels of a partial_failure or failed post. Channels that published are skipped.
| Parameter | Type | Required | Description |
|---|---|---|---|
postId | string | yes | The post ID |
{ "name": "retry_post", "arguments": { "postId": "6a05032a84584482ace13d5f" } }Retry queued
ID: 6a05032a84584482ace13d5f
Retried channels: 1
Check results with: check_post_status tool using ID "6a05032a84584482ace13d5f"If a channel failed because the account needs reconnecting, run reconnect_connection first.
publish_draft
Publishes a saved draft now.
| Parameter | Type | Required | Description |
|---|---|---|---|
postId | string | yes | The draft ID |
{ "name": "publish_draft", "arguments": { "postId": "6a05032a84584482ace13d5f" } }Draft published
ID: 6a05032a84584482ace13d5f
Request ID: 9f2c7a1e-3d44-4b2a-8e1f-0a5c2d7e9f10
Check results with: check_post_status tool using ID "6a05032a84584482ace13d5f"The MCP server cannot create a draft or submit one for approval. Create drafts with the dashboard, CLI --draft, or the SDK, and submit for approval via the SDK or REST. See feature parity.
list_media
Lists media library items. The IDs work in post_image and post_video without re-uploading.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
type | image | video | document | no | all | Filter by type |
search | string | no | none | Search by filename |
limit | integer 1 to 100 | no | 20 | Maximum results |
{ "name": "list_media", "arguments": { "type": "video", "limit": 10 } }Media library (2 total):
• 6a93a4bfaa1135c3d8dd3df5 — launch-teaser.mp4 (video, 8.4MB)
• 6a93b7c2d1e0f3a4b5c6d7e8 — demo-full.mp4 (video, 156.2MB)
Use these IDs in post_image or post_video "images"/"video" fields.delete_media
Deletes one or more media items.
| Parameter | Type | Required | Description |
|---|---|---|---|
ids | string[] (at least 1) | yes | Media IDs |
{ "name": "delete_media", "arguments": { "ids": ["6a93a4bfaa1135c3d8dd3df5"] } }Deleted 1 media item: 6a93a4bfaa1135c3d8dd3df5Not available to API keys with guardrails.
get_post_analytics
Per-platform results and engagement for one post.
| Parameter | Type | Required | Description |
|---|---|---|---|
postId | string | yes | Post ID or request ID |
{ "name": "get_post_analytics", "arguments": { "postId": "6a05032a84584482ace13d5f" } }Post analytics: 6a05032a84584482ace13d5f
Status: completed
✓ youtube → https://youtube.com/shorts/6zaztTmk3Ck | likes: 12, comments: 3, impressions: 480get_follower_growth
Follower or subscriber growth per connected account. Counts are captured once a day. LinkedIn and TikTok cannot report followers.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
period | last_day | last_week | last_month | last_3months | last_year | no | last 30 days | Time window |
connection | string | no | all | Only this account, by slug |
platform | string | no | all | Only accounts on this platform |
{ "name": "get_follower_growth", "arguments": { "period": "last_3months" } }Follower growth 2026-08-14 → 2026-11-13
Total: 5340 followers, +212
· x-mybrand: 4200 followers, +180 (+4.48%)
· bluesky-mybrand: 1140 followers, +32 (+2.89%)
· linkedin-me: follower count not available on linkedinA new account shows first daily snapshot pending until its first snapshot.
compare_accounts
Compares accounts for a window: followers and change, posts, total engagement, engagement per post, engagement rate and per-follower rate. Sorted by engagement. Inputs are the same as get_follower_growth.
{ "name": "compare_accounts", "arguments": { "period": "last_month" } }Account comparison 2026-10-14 → 2026-11-13
· x-mybrand [x]: 4200 followers (+180), 12 posts, 424 engagement (35.33/post), 2.02% rate, 0.84% per follower
· bluesky-mybrand [bluesky]: 1140 followers (+32), 9 posts, 150 engagement (16.67/post), 0% rate, 1.46% per followerEngagement is likes plus comments plus shares plus saves; rate is engagement divided by impressions.
get_usage
Shows usage against plan limits: posts this month, X posts, connected accounts and storage. Check it before connecting accounts or posting in bulk.
Input: none.
{ "name": "get_usage", "arguments": {} }Usage (free plan):
Posts this month: 12 / 30 (18 left)
X posts this month: 2 / 5 (3 left) (~$0.00 X spend)
Connected accounts: 2 / 3 (1 left)
Storage: 120MB / 1.0GB (904MB left)An unlimited dimension reads <used> / unlimited.
generate_caption
Generates captions with AI from a description, a URL or a brief.
| Parameter | Type | Required | Description |
|---|---|---|---|
description | string | yes | What to post about, or the raw content to work from |
platforms | string[] (at least 1) | yes | Platform types for tone, for example ["linkedin", "x"]. These are platform names, not connection slugs |
tone | professional | casual | humorous | inspirational | informative | no | Writing tone |
{
"name": "generate_caption",
"arguments": {
"description": "Launch of our new analytics dashboard",
"platforms": ["linkedin", "x"],
"tone": "professional"
}
}Generated captions:
[linkedin]
<caption text>
---
[x]
<caption text>The workspace needs its own AI provider key. Without one the result is Error: No AI provider key set for this workspace. Add your own key in Settings → AI to use AI features. AI endpoints allow 10 requests per minute. See AI composer and BYOK. The tool generates text only; hashtag suggestions exist in the REST API but not as an MCP tool.
FAQ
Can the MCP server upload a file from my computer?
No. post_image and post_video take public URLs or media library IDs. Upload first with the SDK, CLI or REST API, or reuse an ID from list_media.
Why does the tool say "submitted" but nothing is live yet?
Posting tools return when the post is accepted. Publishing runs in the background. Call check_post_status with the returned ID. A key with requireApproval leaves the post in pending_approval until a teammate approves it.
Which tools change data?
post_text, post_image, post_video, schedule_post, schedule_posts, update_post, retry_post, publish_draft, delete_media, refresh_connection and reconnect_connection change state. The rest only read, or generate text.