@omnisocials/mcp-server 1.17.0 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/build/client.d.ts +1 -0
- package/build/client.js +5 -0
- package/build/index.js +1 -1
- package/build/tools/posts.js +49 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -218,6 +218,12 @@ Full API docs: [docs.omnisocials.com](https://docs.omnisocials.com)
|
|
|
218
218
|
|
|
219
219
|
## Changelog
|
|
220
220
|
|
|
221
|
+
### 1.18.0
|
|
222
|
+
|
|
223
|
+
- **`retry_post`:** retry the failed platforms of a `failed` or partially failed (`warning`) post on the same post — only failed platforms are re-published, succeeded ones never post twice. Async via the publishing queue; poll `get_post` for the outcome. Max 3 retries per platform. Backed by `POST /api/v1/posts/{id}/retry`.
|
|
224
|
+
- **Retry linkage:** posts expose `retry_of` / `retries`, and `get_post` renders them — a `published` post with empty `published_urls` and `retries` set is a resolved failure, not a second publish.
|
|
225
|
+
- **`get_post` now renders per-platform publish errors** (previously dropped) with a pointer to `retry_post`.
|
|
226
|
+
|
|
221
227
|
### 1.17.0
|
|
222
228
|
|
|
223
229
|
- **Per-media alt text (accessibility descriptions):** `media_urls` / `media_ids` entries now accept `{ url, alt }` / `{ id, alt }` objects everywhere, including thread parts. Delivered to Mastodon (media description), Bluesky (embed alt), X (photos/GIFs), and Pinterest (pin `alt_text` fallback). `get_post` reads alt text back.
|
package/build/client.d.ts
CHANGED
|
@@ -213,6 +213,7 @@ export declare class OmniSocialsClient {
|
|
|
213
213
|
}): Promise<ApiResponse<unknown>>;
|
|
214
214
|
deletePost(id: string): Promise<ApiResponse<unknown>>;
|
|
215
215
|
publishPost(id: string): Promise<ApiResponse<unknown>>;
|
|
216
|
+
retryPost(id: string): Promise<ApiResponse<unknown>>;
|
|
216
217
|
searchLocations(query: string): Promise<ApiResponse<unknown>>;
|
|
217
218
|
validateLocation(id: string): Promise<ApiResponse<unknown>>;
|
|
218
219
|
searchInstagramAudio(query?: string, type?: "music" | "original_sound"): Promise<ApiResponse<unknown>>;
|
package/build/client.js
CHANGED
|
@@ -219,6 +219,11 @@ export class OmniSocialsClient {
|
|
|
219
219
|
async publishPost(id) {
|
|
220
220
|
return this.request("POST", `/posts/${id}/publish`);
|
|
221
221
|
}
|
|
222
|
+
// Retry the failed platforms of a failed/warning post on the same post.
|
|
223
|
+
// Succeeded platforms are never re-published (server-side idempotency guard).
|
|
224
|
+
async retryPost(id) {
|
|
225
|
+
return this.request("POST", `/posts/${id}/retry`);
|
|
226
|
+
}
|
|
222
227
|
// Locations (Instagram place tagging)
|
|
223
228
|
async searchLocations(query) {
|
|
224
229
|
return this.request("GET", "/locations/search", undefined, { q: query });
|
package/build/index.js
CHANGED
|
@@ -29,7 +29,7 @@ const sessionState = { activeIndex: 0 };
|
|
|
29
29
|
const getActiveClient = () => workspaceClients[sessionState.activeIndex].client;
|
|
30
30
|
const server = new McpServer({
|
|
31
31
|
name: "OmniSocials",
|
|
32
|
-
version: "1.
|
|
32
|
+
version: "1.18.0",
|
|
33
33
|
});
|
|
34
34
|
// Register all tools - pass getter function so tools always use the active workspace's client
|
|
35
35
|
registerPostTools(server, getActiveClient);
|
package/build/tools/posts.js
CHANGED
|
@@ -193,6 +193,14 @@ export function registerPostTools(server, getClient) {
|
|
|
193
193
|
md += `| **Created** | ${formatDateTime(p.created_at)} |\n`;
|
|
194
194
|
if (appUrl)
|
|
195
195
|
md += `| **Open in OmniSocials** | ${appUrl} |\n`;
|
|
196
|
+
// Retry linkage: a "published" post with `retries` set and empty
|
|
197
|
+
// published_urls is a resolved failure — the live URLs are on the retry
|
|
198
|
+
// post, so don't count both as separate publishes.
|
|
199
|
+
if (p.retry_of)
|
|
200
|
+
md += `| **Retry of post** | \`${p.retry_of}\` (this post is a retry of that failed post) |\n`;
|
|
201
|
+
if (Array.isArray(p.retries) && p.retries.length) {
|
|
202
|
+
md += `| **Retried by** | ${p.retries.map((r) => `\`${r}\``).join(", ")} (live URLs are on the retry post) |\n`;
|
|
203
|
+
}
|
|
196
204
|
// Media can be a flat array (same set everywhere) or a per-platform
|
|
197
205
|
// object ({ default: [...], instagram: [...] }). The old `p.media.length`
|
|
198
206
|
// check silently dropped the object shape (`.length` is undefined).
|
|
@@ -300,6 +308,21 @@ export function registerPostTools(server, getClient) {
|
|
|
300
308
|
md += `- **${capitalize(platform.replace(/_/g, " "))}**: ${url}\n`;
|
|
301
309
|
}
|
|
302
310
|
}
|
|
311
|
+
// Per-platform publish errors (status failed/warning). Point at
|
|
312
|
+
// retry_post — only the failed platforms are re-published.
|
|
313
|
+
const postErrors = (p.errors && typeof p.errors === "object" && !Array.isArray(p.errors))
|
|
314
|
+
? p.errors
|
|
315
|
+
: {};
|
|
316
|
+
const errorEntries = Object.entries(postErrors);
|
|
317
|
+
if (errorEntries.length) {
|
|
318
|
+
md += `\n\n### Publish Errors\n\n`;
|
|
319
|
+
for (const [platform, message] of errorEntries) {
|
|
320
|
+
md += `- **${capitalize(platform.replace(/_/g, " "))}**: ${message}\n`;
|
|
321
|
+
}
|
|
322
|
+
if (p.status === "failed" || p.status === "warning") {
|
|
323
|
+
md += `\n_Retry the failed platform(s) with \`retry_post\` — platforms that already succeeded are never re-published._\n`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
303
326
|
// First comments: nested under each platform object by the API. Show the
|
|
304
327
|
// configured text plus, once published, the outcome (posted/failed/skipped).
|
|
305
328
|
const firstCommentPlatforms = ["instagram", "facebook", "linkedin", "linkedin_page", "youtube"];
|
|
@@ -854,7 +877,7 @@ Do NOT call without required media — it will fail.`, {
|
|
|
854
877
|
content: [{ type: "text", text: result.error ? `Error (${result.error.code}): ${result.error.message}` : "Post deleted successfully." }],
|
|
855
878
|
};
|
|
856
879
|
});
|
|
857
|
-
server.tool("publish_post", `Publish a draft or scheduled post immediately. The post will be queued for publishing.
|
|
880
|
+
server.tool("publish_post", `Publish a draft or scheduled post immediately. The post will be queued for publishing. Only draft and scheduled posts can be published — for a failed or partially failed (warning) post use \`retry_post\` instead, which re-publishes only the failed platforms.
|
|
858
881
|
|
|
859
882
|
IMPORTANT: Before publishing, verify the post has all required media. If publishing a story or reel, ensure media was attached when the post was created/updated. If it's missing, use update_post to add media first, or inform the user.`, {
|
|
860
883
|
id: z.string().describe("The post ID to publish"),
|
|
@@ -875,6 +898,31 @@ IMPORTANT: Before publishing, verify the post has all required media. If publish
|
|
|
875
898
|
content: [{ type: "text", text: md }],
|
|
876
899
|
};
|
|
877
900
|
});
|
|
901
|
+
server.tool("retry_post", `Retry the failed platforms of a failed or partially failed post — on the same post, no duplicate created. Use when a post has status \`failed\` (every platform failed) or \`warning\` (some failed, some published): only the FAILED platforms are re-published; platforms that already succeeded are never posted again.
|
|
902
|
+
|
|
903
|
+
The retry runs asynchronously (usually within a few minutes). Poll \`get_post\` afterwards: on success the status becomes \`published\` and \`published_urls\` gains the platform's live URL; on another failure the platform's entry reappears under errors. Each platform can be retried at most 3 times — after that, recreate the post. Note \`publish_post\` refuses failed posts; this is the tool for them.`, {
|
|
904
|
+
id: z.string().describe("The failed or partially failed post ID to retry"),
|
|
905
|
+
}, async ({ id }) => {
|
|
906
|
+
const result = await getClient().retryPost(id);
|
|
907
|
+
if (result.error) {
|
|
908
|
+
return {
|
|
909
|
+
content: [{ type: "text", text: `Error (${result.error.code}): ${result.error.message}` }],
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
const p = result.data;
|
|
913
|
+
let md = `## Retry Queued\n\n`;
|
|
914
|
+
md += `| Field | Value |\n`;
|
|
915
|
+
md += `|-------|-------|\n`;
|
|
916
|
+
md += `| **ID** | \`${p.id}\` |\n`;
|
|
917
|
+
md += `| **Status** | ${capitalize(p.status || "posting")} |\n`;
|
|
918
|
+
if (Array.isArray(p.platforms) && p.platforms.length) {
|
|
919
|
+
md += `| **Retrying** | ${p.platforms.map((x) => capitalize(x.replace(/_/g, " "))).join(", ")} |\n`;
|
|
920
|
+
}
|
|
921
|
+
md += `\n_Platforms that already succeeded are never re-published. Check \`get_post\` in a minute or two for the outcome._`;
|
|
922
|
+
return {
|
|
923
|
+
content: [{ type: "text", text: md }],
|
|
924
|
+
};
|
|
925
|
+
});
|
|
878
926
|
server.tool("search_locations", `Search for an Instagram location to tag on a post. Use this whenever the user wants to post WITH a place/location (e.g. "post this at my dealership", "tag the café"). It returns matching real venues with their addresses and a location ID.
|
|
879
927
|
|
|
880
928
|
Flow: call this with the place name → present the options to the user → once they pick, pass that result's \`id\` as \`location_id\` on create_post / create_and_publish_post / update_post. Only Instagram supports location tagging.
|
package/package.json
CHANGED