@omnisocials/mcp-server 1.51.0 → 1.51.1
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/build/client.d.ts +2 -0
- package/build/client.js +31 -1
- package/build/index.js +10 -2
- package/build/tools/hashtag-sets.js +2 -1
- package/build/tools/inbox.js +3 -3
- package/package.json +1 -1
package/build/client.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export declare function formatBytes(bytes: number): string;
|
|
|
8
8
|
export declare function formatDate(iso: string | null): string;
|
|
9
9
|
export declare function formatDateTime(iso: string | null): string;
|
|
10
10
|
export declare function truncate(value: unknown, len: number): string;
|
|
11
|
+
export declare function cutText(value: unknown, max: number): string;
|
|
12
|
+
export declare function wellFormed<T>(value: T): T;
|
|
11
13
|
export declare function capitalize(str: string): string;
|
|
12
14
|
/** Rates, averages and lengths: shown per platform, never added up across
|
|
13
15
|
* platforms (two 60% hold rates are not 120%). Mirrors
|
package/build/client.js
CHANGED
|
@@ -84,7 +84,37 @@ export function truncate(value, len) {
|
|
|
84
84
|
if (!str)
|
|
85
85
|
return "";
|
|
86
86
|
const clean = str.replace(/\n/g, " ");
|
|
87
|
-
|
|
87
|
+
// Count and cut on code points: a UTF-16 slice can split an emoji.
|
|
88
|
+
const chars = Array.from(clean);
|
|
89
|
+
return chars.length > len ? chars.slice(0, len - 1).join("") + "…" : clean;
|
|
90
|
+
}
|
|
91
|
+
// Text this server sends must be well-formed UTF-16. Half an emoji (a lone
|
|
92
|
+
// surrogate) is legal in a JS string and JSON.stringify writes it as
|
|
93
|
+
// "\ud83c", but strict JSON readers (Rust serde_json, Python clients that
|
|
94
|
+
// validate with pydantic) refuse it and drop the connection: "Transport
|
|
95
|
+
// closed" instead of an answer (2026-11-03, a drafts list cut a preview
|
|
96
|
+
// through an emoji). cutText cuts on code points; wellFormed turns any lone
|
|
97
|
+
// surrogate left in a tool result into U+FFFD (a regex: Node 18 has no
|
|
98
|
+
// String.prototype.toWellFormed).
|
|
99
|
+
const LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
100
|
+
export function cutText(value, max) {
|
|
101
|
+
if (typeof value !== "string")
|
|
102
|
+
return "";
|
|
103
|
+
const chars = Array.from(value);
|
|
104
|
+
return chars.length > max ? chars.slice(0, max).join("") : value;
|
|
105
|
+
}
|
|
106
|
+
export function wellFormed(value) {
|
|
107
|
+
if (typeof value === "string")
|
|
108
|
+
return value.replace(LONE_SURROGATE, "\uFFFD");
|
|
109
|
+
if (Array.isArray(value))
|
|
110
|
+
return value.map(wellFormed);
|
|
111
|
+
if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
|
|
112
|
+
const out = {};
|
|
113
|
+
for (const [key, item] of Object.entries(value))
|
|
114
|
+
out[key] = wellFormed(item);
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
88
118
|
}
|
|
89
119
|
export function capitalize(str) {
|
|
90
120
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
package/build/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { OmniSocialsClient } from "./client.js";
|
|
5
|
+
import { OmniSocialsClient, wellFormed } from "./client.js";
|
|
6
6
|
import { registerPostTools } from "./tools/posts.js";
|
|
7
7
|
import { registerMediaTools } from "./tools/media.js";
|
|
8
8
|
import { registerAccountTools } from "./tools/accounts.js";
|
|
@@ -31,8 +31,16 @@ const sessionState = { activeIndex: 0 };
|
|
|
31
31
|
const getActiveClient = () => workspaceClients[sessionState.activeIndex].client;
|
|
32
32
|
const server = new McpServer({
|
|
33
33
|
name: "OmniSocials",
|
|
34
|
-
version: "1.51.
|
|
34
|
+
version: "1.51.1",
|
|
35
35
|
});
|
|
36
|
+
const rawTool = server.tool.bind(server);
|
|
37
|
+
server.tool = (...args) => {
|
|
38
|
+
const cb = args[args.length - 1];
|
|
39
|
+
if (typeof cb === "function") {
|
|
40
|
+
args[args.length - 1] = async (...a) => wellFormed(await cb(...a));
|
|
41
|
+
}
|
|
42
|
+
return rawTool(...args);
|
|
43
|
+
};
|
|
36
44
|
// Register all tools - pass getter function so tools always use the active workspace's client
|
|
37
45
|
registerPostTools(server, getActiveClient);
|
|
38
46
|
registerMediaTools(server, getActiveClient);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { cutText } from "../client.js";
|
|
2
3
|
export function registerHashtagSetTools(server, getClient) {
|
|
3
4
|
server.tool("list_hashtag_sets", "List the saved hashtag sets in this workspace. Apply one to a new post by passing its name via create_post (hashtag_set) — the tags are appended to the captions or, with hashtag_placement='first_comment', posted as the auto first comment.", {}, { title: "List Hashtag Sets", readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async () => {
|
|
4
5
|
const result = await getClient().listHashtagSets();
|
|
@@ -17,7 +18,7 @@ export function registerHashtagSetTools(server, getClient) {
|
|
|
17
18
|
md += `| Set ID | Name | Tags | Preview |\n`;
|
|
18
19
|
md += `|--------|------|------|---------|\n`;
|
|
19
20
|
for (const s of sets) {
|
|
20
|
-
const preview = (s.preview || "").length > 80 ? `${s.preview
|
|
21
|
+
const preview = Array.from(s.preview || "").length > 80 ? `${cutText(s.preview, 77)}…` : s.preview || "";
|
|
21
22
|
md += `| \`${s.id}\` | ${s.name} | ${s.hashtag_count} | ${preview} |\n`;
|
|
22
23
|
}
|
|
23
24
|
md += `\nApply a set with create_post (hashtag_set="<name>"). Edit with update_hashtag_set.`;
|
package/build/tools/inbox.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { formatDateTime } from "../client.js";
|
|
2
|
+
import { cutText, formatDateTime } from "../client.js";
|
|
3
3
|
const PLATFORM_EMOJI = {
|
|
4
4
|
instagram: "📸",
|
|
5
5
|
facebook: "📘",
|
|
@@ -41,7 +41,7 @@ function renderInboxPost(post) {
|
|
|
41
41
|
}
|
|
42
42
|
md += `\n`;
|
|
43
43
|
if (post.caption) {
|
|
44
|
-
md += `> ${post.caption.replace(/\s*\n+\s*/g, " ")
|
|
44
|
+
md += `> ${cutText(post.caption.replace(/\s*\n+\s*/g, " "), 600)}\n`;
|
|
45
45
|
}
|
|
46
46
|
if (post.url)
|
|
47
47
|
md += `🔗 ${post.url}\n`;
|
|
@@ -148,7 +148,7 @@ export function registerInboxTools(server, getClient) {
|
|
|
148
148
|
md += `|----------|------|------|--------|----------------|----------------|\n`;
|
|
149
149
|
for (const c of convos) {
|
|
150
150
|
const who = c.participant?.name || c.participant?.username || "Unknown";
|
|
151
|
-
const text = (c.last_message?.text || "").replace(/\n/g, " ")
|
|
151
|
+
const text = cutText((c.last_message?.text || "").replace(/\n/g, " "), 40);
|
|
152
152
|
md += `| ${PLATFORM_EMOJI[c.platform] || ""} ${c.platform} | ${c.type} | ${who} | ${c.unread_count || 0} | ${text} | \`${c.conversation_id}\` |\n`;
|
|
153
153
|
}
|
|
154
154
|
if (result.pagination?.next_cursor) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnisocials/mcp-server",
|
|
3
|
-
"version": "1.51.
|
|
3
|
+
"version": "1.51.1",
|
|
4
4
|
"mcpName": "io.github.omnisocials/mcp-server",
|
|
5
5
|
"description": "MCP server for OmniSocials API - manage social media posts, media, accounts, analytics, and webhooks",
|
|
6
6
|
"type": "module",
|