@omnisocials/mcp-server 1.0.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 +139 -0
- package/build/client.d.ts +87 -0
- package/build/client.js +108 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +36 -0
- package/build/tools/accounts.d.ts +3 -0
- package/build/tools/accounts.js +17 -0
- package/build/tools/analytics.d.ts +3 -0
- package/build/tools/analytics.js +30 -0
- package/build/tools/media.d.ts +3 -0
- package/build/tools/media.js +29 -0
- package/build/tools/posts.d.ts +3 -0
- package/build/tools/posts.js +137 -0
- package/build/tools/webhooks.d.ts +3 -0
- package/build/tools/webhooks.js +53 -0
- package/build/types.d.ts +56 -0
- package/build/types.js +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# @omnisocials/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for the [OmniSocials](https://omnisocials.com) API. Lets AI assistants manage your social media — create posts, upload media, view analytics, and more.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js 18+
|
|
8
|
+
- An OmniSocials API key (get one from **Settings > API** in the app)
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
### Claude Code
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
claude mcp add omnisocials -- npx -y @omnisocials/mcp-server
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then set your API key:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
export OMNISOCIALS_API_KEY=omsk_live_your_key_here
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Claude Desktop
|
|
25
|
+
|
|
26
|
+
Add to your `claude_desktop_config.json`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"omnisocials": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "@omnisocials/mcp-server"],
|
|
34
|
+
"env": {
|
|
35
|
+
"OMNISOCIALS_API_KEY": "omsk_live_your_key_here"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Cursor
|
|
43
|
+
|
|
44
|
+
Add to your `.cursor/mcp.json`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"omnisocials": {
|
|
50
|
+
"command": "npx",
|
|
51
|
+
"args": ["-y", "@omnisocials/mcp-server"],
|
|
52
|
+
"env": {
|
|
53
|
+
"OMNISOCIALS_API_KEY": "omsk_live_your_key_here"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Windsurf
|
|
61
|
+
|
|
62
|
+
Add to your `~/.codeium/windsurf/mcp_config.json`:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"omnisocials": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["-y", "@omnisocials/mcp-server"],
|
|
70
|
+
"env": {
|
|
71
|
+
"OMNISOCIALS_API_KEY": "omsk_live_your_key_here"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Available Tools
|
|
79
|
+
|
|
80
|
+
### Posts (7 tools)
|
|
81
|
+
|
|
82
|
+
| Tool | Description |
|
|
83
|
+
|------|-------------|
|
|
84
|
+
| `list_posts` | List all posts, optionally filter by status |
|
|
85
|
+
| `get_post` | Get details of a specific post |
|
|
86
|
+
| `create_post` | Create a new post, story, or reel |
|
|
87
|
+
| `create_and_publish_post` | Create and publish immediately |
|
|
88
|
+
| `update_post` | Update a draft or scheduled post |
|
|
89
|
+
| `delete_post` | Delete a post |
|
|
90
|
+
| `publish_post` | Publish a draft or scheduled post now |
|
|
91
|
+
|
|
92
|
+
### Media (3 tools)
|
|
93
|
+
|
|
94
|
+
| Tool | Description |
|
|
95
|
+
|------|-------------|
|
|
96
|
+
| `list_media` | List all media files |
|
|
97
|
+
| `upload_media` | Upload media from a URL (max 50MB) |
|
|
98
|
+
| `delete_media` | Delete a media file |
|
|
99
|
+
|
|
100
|
+
### Accounts (2 tools)
|
|
101
|
+
|
|
102
|
+
| Tool | Description |
|
|
103
|
+
|------|-------------|
|
|
104
|
+
| `list_accounts` | List connected social media accounts |
|
|
105
|
+
| `get_account` | Get account details |
|
|
106
|
+
|
|
107
|
+
### Analytics (3 tools)
|
|
108
|
+
|
|
109
|
+
| Tool | Description |
|
|
110
|
+
|------|-------------|
|
|
111
|
+
| `get_post_analytics` | Get stats for a published post |
|
|
112
|
+
| `get_analytics_overview` | Overview analytics for a time period |
|
|
113
|
+
| `get_account_analytics` | Account-level analytics (followers, etc.) |
|
|
114
|
+
|
|
115
|
+
### Webhooks (5 tools)
|
|
116
|
+
|
|
117
|
+
| Tool | Description |
|
|
118
|
+
|------|-------------|
|
|
119
|
+
| `list_webhooks` | List all webhooks |
|
|
120
|
+
| `create_webhook` | Create a webhook for event notifications |
|
|
121
|
+
| `get_webhook` | Get webhook details |
|
|
122
|
+
| `update_webhook` | Update a webhook |
|
|
123
|
+
| `delete_webhook` | Delete a webhook |
|
|
124
|
+
| `rotate_webhook_secret` | Rotate a webhook's signing secret |
|
|
125
|
+
|
|
126
|
+
## Environment Variables
|
|
127
|
+
|
|
128
|
+
| Variable | Required | Description |
|
|
129
|
+
|----------|----------|-------------|
|
|
130
|
+
| `OMNISOCIALS_API_KEY` | Yes | Your API key (`omsk_live_*` or `omsk_test_*`) |
|
|
131
|
+
| `OMNISOCIALS_BASE_URL` | No | Custom API base URL (defaults to production) |
|
|
132
|
+
|
|
133
|
+
## API Documentation
|
|
134
|
+
|
|
135
|
+
Full API docs: [docs.omnisocials.com](https://docs.omnisocials.com)
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ApiResponse } from "./types.js";
|
|
2
|
+
export declare class OmniSocialsClient {
|
|
3
|
+
private baseUrl;
|
|
4
|
+
private apiKey;
|
|
5
|
+
constructor(apiKey: string, baseUrl?: string);
|
|
6
|
+
request<T = unknown>(method: string, path: string, body?: unknown, queryParams?: Record<string, string>): Promise<ApiResponse<T>>;
|
|
7
|
+
listPosts(params?: {
|
|
8
|
+
status?: string;
|
|
9
|
+
limit?: string;
|
|
10
|
+
offset?: string;
|
|
11
|
+
}): Promise<ApiResponse<unknown>>;
|
|
12
|
+
getPost(id: string): Promise<ApiResponse<unknown>>;
|
|
13
|
+
createPost(data: {
|
|
14
|
+
content: string;
|
|
15
|
+
channels?: string[];
|
|
16
|
+
scheduled_at?: string;
|
|
17
|
+
media_ids?: string[] | Record<string, string[]>;
|
|
18
|
+
media_urls?: string[] | Record<string, string[]>;
|
|
19
|
+
type?: string;
|
|
20
|
+
pinterest?: Record<string, unknown>;
|
|
21
|
+
youtube?: Record<string, unknown>;
|
|
22
|
+
instagram?: Record<string, unknown>;
|
|
23
|
+
tiktok?: Record<string, unknown>;
|
|
24
|
+
x?: Record<string, unknown>;
|
|
25
|
+
}): Promise<ApiResponse<unknown>>;
|
|
26
|
+
createAndPublishPost(data: {
|
|
27
|
+
content: string;
|
|
28
|
+
channels?: string[];
|
|
29
|
+
media_ids?: string[] | Record<string, string[]>;
|
|
30
|
+
media_urls?: string[] | Record<string, string[]>;
|
|
31
|
+
type?: string;
|
|
32
|
+
pinterest?: Record<string, unknown>;
|
|
33
|
+
youtube?: Record<string, unknown>;
|
|
34
|
+
instagram?: Record<string, unknown>;
|
|
35
|
+
tiktok?: Record<string, unknown>;
|
|
36
|
+
x?: Record<string, unknown>;
|
|
37
|
+
}): Promise<ApiResponse<unknown>>;
|
|
38
|
+
updatePost(id: string, data: {
|
|
39
|
+
content?: string;
|
|
40
|
+
scheduled_at?: string;
|
|
41
|
+
channels?: string[];
|
|
42
|
+
media_ids?: string[] | Record<string, string[]>;
|
|
43
|
+
media_urls?: string[] | Record<string, string[]>;
|
|
44
|
+
type?: string;
|
|
45
|
+
pinterest?: Record<string, unknown>;
|
|
46
|
+
youtube?: Record<string, unknown>;
|
|
47
|
+
instagram?: Record<string, unknown>;
|
|
48
|
+
tiktok?: Record<string, unknown>;
|
|
49
|
+
x?: Record<string, unknown>;
|
|
50
|
+
}): Promise<ApiResponse<unknown>>;
|
|
51
|
+
deletePost(id: string): Promise<ApiResponse<unknown>>;
|
|
52
|
+
publishPost(id: string): Promise<ApiResponse<unknown>>;
|
|
53
|
+
listMedia(params?: {
|
|
54
|
+
limit?: string;
|
|
55
|
+
offset?: string;
|
|
56
|
+
}): Promise<ApiResponse<unknown>>;
|
|
57
|
+
uploadMedia(data: {
|
|
58
|
+
url: string;
|
|
59
|
+
filename?: string;
|
|
60
|
+
}): Promise<ApiResponse<unknown>>;
|
|
61
|
+
deleteMedia(id: string): Promise<ApiResponse<unknown>>;
|
|
62
|
+
listAccounts(): Promise<ApiResponse<unknown>>;
|
|
63
|
+
getAccount(id: string): Promise<ApiResponse<unknown>>;
|
|
64
|
+
getPostAnalytics(postId: string): Promise<ApiResponse<unknown>>;
|
|
65
|
+
getAnalyticsOverview(params?: {
|
|
66
|
+
period?: string;
|
|
67
|
+
start_date?: string;
|
|
68
|
+
end_date?: string;
|
|
69
|
+
}): Promise<ApiResponse<unknown>>;
|
|
70
|
+
getAccountAnalytics(params?: {
|
|
71
|
+
platform?: string;
|
|
72
|
+
date?: string;
|
|
73
|
+
}): Promise<ApiResponse<unknown>>;
|
|
74
|
+
listWebhooks(): Promise<ApiResponse<unknown>>;
|
|
75
|
+
createWebhook(data: {
|
|
76
|
+
url: string;
|
|
77
|
+
events: string[];
|
|
78
|
+
}): Promise<ApiResponse<unknown>>;
|
|
79
|
+
deleteWebhook(id: string): Promise<ApiResponse<unknown>>;
|
|
80
|
+
getWebhook(id: string): Promise<ApiResponse<unknown>>;
|
|
81
|
+
updateWebhook(id: string, data: {
|
|
82
|
+
url?: string;
|
|
83
|
+
events?: string[];
|
|
84
|
+
is_active?: boolean;
|
|
85
|
+
}): Promise<ApiResponse<unknown>>;
|
|
86
|
+
rotateWebhookSecret(id: string): Promise<ApiResponse<unknown>>;
|
|
87
|
+
}
|
package/build/client.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export class OmniSocialsClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
apiKey;
|
|
4
|
+
constructor(apiKey, baseUrl) {
|
|
5
|
+
this.apiKey = apiKey;
|
|
6
|
+
this.baseUrl =
|
|
7
|
+
baseUrl || "https://app.omnisocials.com/api/v1";
|
|
8
|
+
}
|
|
9
|
+
async request(method, path, body, queryParams) {
|
|
10
|
+
let url = `${this.baseUrl}${path}`;
|
|
11
|
+
if (queryParams) {
|
|
12
|
+
const params = new URLSearchParams(Object.entries(queryParams).filter(([, v]) => v !== undefined));
|
|
13
|
+
const qs = params.toString();
|
|
14
|
+
if (qs)
|
|
15
|
+
url += `?${qs}`;
|
|
16
|
+
}
|
|
17
|
+
const headers = {
|
|
18
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
19
|
+
"Content-Type": "application/json",
|
|
20
|
+
};
|
|
21
|
+
const options = { method, headers };
|
|
22
|
+
if (body && (method === "POST" || method === "PATCH" || method === "PUT")) {
|
|
23
|
+
options.body = JSON.stringify(body);
|
|
24
|
+
}
|
|
25
|
+
const response = await fetch(url, options);
|
|
26
|
+
if (response.status === 204) {
|
|
27
|
+
return { data: undefined };
|
|
28
|
+
}
|
|
29
|
+
const json = await response.json();
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
return {
|
|
32
|
+
error: json.error || {
|
|
33
|
+
code: "api_error",
|
|
34
|
+
message: `Request failed with status ${response.status}`,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return json;
|
|
39
|
+
}
|
|
40
|
+
// Posts
|
|
41
|
+
async listPosts(params) {
|
|
42
|
+
return this.request("GET", "/posts", undefined, params);
|
|
43
|
+
}
|
|
44
|
+
async getPost(id) {
|
|
45
|
+
return this.request("GET", `/posts/${id}`);
|
|
46
|
+
}
|
|
47
|
+
async createPost(data) {
|
|
48
|
+
return this.request("POST", "/posts/create", data);
|
|
49
|
+
}
|
|
50
|
+
async createAndPublishPost(data) {
|
|
51
|
+
return this.request("POST", "/posts/create-and-publish", data);
|
|
52
|
+
}
|
|
53
|
+
async updatePost(id, data) {
|
|
54
|
+
return this.request("PATCH", `/posts/${id}`, data);
|
|
55
|
+
}
|
|
56
|
+
async deletePost(id) {
|
|
57
|
+
return this.request("DELETE", `/posts/${id}`);
|
|
58
|
+
}
|
|
59
|
+
async publishPost(id) {
|
|
60
|
+
return this.request("POST", `/posts/${id}/publish`);
|
|
61
|
+
}
|
|
62
|
+
// Media
|
|
63
|
+
async listMedia(params) {
|
|
64
|
+
return this.request("GET", "/media", undefined, params);
|
|
65
|
+
}
|
|
66
|
+
async uploadMedia(data) {
|
|
67
|
+
return this.request("POST", "/media/upload-from-url", data);
|
|
68
|
+
}
|
|
69
|
+
async deleteMedia(id) {
|
|
70
|
+
return this.request("DELETE", `/media/${id}`);
|
|
71
|
+
}
|
|
72
|
+
// Accounts
|
|
73
|
+
async listAccounts() {
|
|
74
|
+
return this.request("GET", "/accounts");
|
|
75
|
+
}
|
|
76
|
+
async getAccount(id) {
|
|
77
|
+
return this.request("GET", `/accounts/${id}`);
|
|
78
|
+
}
|
|
79
|
+
// Analytics
|
|
80
|
+
async getPostAnalytics(postId) {
|
|
81
|
+
return this.request("GET", `/analytics/posts/${postId}`);
|
|
82
|
+
}
|
|
83
|
+
async getAnalyticsOverview(params) {
|
|
84
|
+
return this.request("GET", "/analytics/overview", undefined, params);
|
|
85
|
+
}
|
|
86
|
+
async getAccountAnalytics(params) {
|
|
87
|
+
return this.request("GET", "/analytics/accounts", undefined, params);
|
|
88
|
+
}
|
|
89
|
+
// Webhooks
|
|
90
|
+
async listWebhooks() {
|
|
91
|
+
return this.request("GET", "/webhooks");
|
|
92
|
+
}
|
|
93
|
+
async createWebhook(data) {
|
|
94
|
+
return this.request("POST", "/webhooks", data);
|
|
95
|
+
}
|
|
96
|
+
async deleteWebhook(id) {
|
|
97
|
+
return this.request("DELETE", `/webhooks/${id}`);
|
|
98
|
+
}
|
|
99
|
+
async getWebhook(id) {
|
|
100
|
+
return this.request("GET", `/webhooks/${id}`);
|
|
101
|
+
}
|
|
102
|
+
async updateWebhook(id, data) {
|
|
103
|
+
return this.request("PATCH", `/webhooks/${id}`, data);
|
|
104
|
+
}
|
|
105
|
+
async rotateWebhookSecret(id) {
|
|
106
|
+
return this.request("POST", `/webhooks/${id}/rotate-secret`);
|
|
107
|
+
}
|
|
108
|
+
}
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { OmniSocialsClient } from "./client.js";
|
|
5
|
+
import { registerPostTools } from "./tools/posts.js";
|
|
6
|
+
import { registerMediaTools } from "./tools/media.js";
|
|
7
|
+
import { registerAccountTools } from "./tools/accounts.js";
|
|
8
|
+
import { registerAnalyticsTools } from "./tools/analytics.js";
|
|
9
|
+
import { registerWebhookTools } from "./tools/webhooks.js";
|
|
10
|
+
const apiKey = process.env.OMNISOCIALS_API_KEY;
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
console.error("Error: OMNISOCIALS_API_KEY environment variable is required.");
|
|
13
|
+
console.error("Get your API key from OmniSocials Settings > API.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const baseUrl = process.env.OMNISOCIALS_BASE_URL;
|
|
17
|
+
const client = new OmniSocialsClient(apiKey, baseUrl);
|
|
18
|
+
const server = new McpServer({
|
|
19
|
+
name: "OmniSocials",
|
|
20
|
+
version: "1.0.0",
|
|
21
|
+
});
|
|
22
|
+
// Register all tools
|
|
23
|
+
registerPostTools(server, client);
|
|
24
|
+
registerMediaTools(server, client);
|
|
25
|
+
registerAccountTools(server, client);
|
|
26
|
+
registerAnalyticsTools(server, client);
|
|
27
|
+
registerWebhookTools(server, client);
|
|
28
|
+
// Start the server
|
|
29
|
+
async function main() {
|
|
30
|
+
const transport = new StdioServerTransport();
|
|
31
|
+
await server.connect(transport);
|
|
32
|
+
}
|
|
33
|
+
main().catch((error) => {
|
|
34
|
+
console.error("Failed to start MCP server:", error);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerAccountTools(server, client) {
|
|
3
|
+
server.tool("list_accounts", "List all connected social media accounts in the workspace.", {}, async () => {
|
|
4
|
+
const result = await client.listAccounts();
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool("get_account", "Get details of a specific connected social media account.", {
|
|
10
|
+
id: z.string().describe("The account ID"),
|
|
11
|
+
}, async ({ id }) => {
|
|
12
|
+
const result = await client.getAccount(id);
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerAnalyticsTools(server, client) {
|
|
3
|
+
server.tool("get_post_analytics", "Get analytics/statistics for a specific published post (impressions, engagements, likes, etc.).", {
|
|
4
|
+
post_id: z.string().describe("The post ID to get analytics for"),
|
|
5
|
+
}, async ({ post_id }) => {
|
|
6
|
+
const result = await client.getPostAnalytics(post_id);
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
server.tool("get_analytics_overview", "Get an overview of analytics across all posts and accounts for a time period.", {
|
|
12
|
+
period: z.string().optional().describe("Time period: 7d, 30d, 90d (default: 30d)"),
|
|
13
|
+
start_date: z.string().optional().describe("Custom start date (ISO 8601)"),
|
|
14
|
+
end_date: z.string().optional().describe("Custom end date (ISO 8601)"),
|
|
15
|
+
}, async (params) => {
|
|
16
|
+
const result = await client.getAnalyticsOverview(params);
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
server.tool("get_account_analytics", "Get account-level analytics (followers, subscribers, etc.) for connected social accounts.", {
|
|
22
|
+
platform: z.string().optional().describe("Filter by platform (e.g., instagram, youtube)"),
|
|
23
|
+
date: z.string().optional().describe("Date to get analytics for (YYYY-MM-DD, defaults to today)"),
|
|
24
|
+
}, async (params) => {
|
|
25
|
+
const result = await client.getAccountAnalytics(params);
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerMediaTools(server, client) {
|
|
3
|
+
server.tool("list_media", "List all media files in the workspace.", {
|
|
4
|
+
limit: z.string().optional().describe("Max results to return"),
|
|
5
|
+
offset: z.string().optional().describe("Offset for pagination"),
|
|
6
|
+
}, async (params) => {
|
|
7
|
+
const result = await client.listMedia(params);
|
|
8
|
+
return {
|
|
9
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
server.tool("upload_media", "Upload media from a URL. The file will be downloaded and stored. Max 50MB.", {
|
|
13
|
+
url: z.string().describe("Public URL of the media file to upload"),
|
|
14
|
+
filename: z.string().optional().describe("Optional filename for the uploaded media"),
|
|
15
|
+
}, async (params) => {
|
|
16
|
+
const result = await client.uploadMedia(params);
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
server.tool("delete_media", "Delete a media file by ID.", {
|
|
22
|
+
id: z.string().describe("The media ID to delete"),
|
|
23
|
+
}, async ({ id }) => {
|
|
24
|
+
const result = await client.deleteMedia(id);
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: result.error ? JSON.stringify(result.error) : "Media deleted successfully." }],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerPostTools(server, client) {
|
|
3
|
+
server.tool("list_posts", "List all posts in the workspace. Optionally filter by status.", {
|
|
4
|
+
status: z.string().optional().describe("Filter by status: draft, scheduled, published, failed"),
|
|
5
|
+
limit: z.string().optional().describe("Max results to return (default: 20)"),
|
|
6
|
+
offset: z.string().optional().describe("Offset for pagination"),
|
|
7
|
+
}, async (params) => {
|
|
8
|
+
const result = await client.listPosts(params);
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
server.tool("get_post", "Get details of a specific post by ID.", {
|
|
14
|
+
id: z.string().describe("The post ID"),
|
|
15
|
+
}, async ({ id }) => {
|
|
16
|
+
const result = await client.getPost(id);
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
server.tool("create_post", "Create a new social media post, story, or reel. Specify content, target channels, type, and optional platform-specific options.", {
|
|
22
|
+
content: z.string().describe("The post content/caption text"),
|
|
23
|
+
channels: z.array(z.string()).optional().describe("Array of channel IDs to post to"),
|
|
24
|
+
scheduled_at: z.string().optional().describe("ISO 8601 date for scheduled publishing"),
|
|
25
|
+
media_ids: z.union([
|
|
26
|
+
z.array(z.string()),
|
|
27
|
+
z.record(z.string(), z.array(z.string())),
|
|
28
|
+
]).optional().describe("Media IDs from upload — flat array (same for all platforms) or object with platform keys: { default: [...], instagram: [...] }"),
|
|
29
|
+
media_urls: z.union([
|
|
30
|
+
z.array(z.string()),
|
|
31
|
+
z.record(z.string(), z.array(z.string())),
|
|
32
|
+
]).optional().describe("External image/video URLs — flat array (same for all platforms) or object with platform keys: { default: [...], instagram: [...], pinterest: [...] }. Max 10 total."),
|
|
33
|
+
type: z.enum(["post", "story", "reel"]).optional().describe("Content type: 'post' (default), 'story' (Instagram/Facebook/Snapchat), 'reel' (Instagram/Facebook/YouTube/TikTok)"),
|
|
34
|
+
pinterest: z.object({
|
|
35
|
+
board_id: z.string().optional(),
|
|
36
|
+
title: z.string().optional(),
|
|
37
|
+
link: z.string().optional(),
|
|
38
|
+
}).optional().describe("Pinterest-specific options"),
|
|
39
|
+
youtube: z.object({
|
|
40
|
+
title: z.string().optional(),
|
|
41
|
+
tags: z.array(z.string()).optional(),
|
|
42
|
+
privacy_status: z.enum(["public", "private", "unlisted"]).optional(),
|
|
43
|
+
category_id: z.string().optional(),
|
|
44
|
+
made_for_kids: z.boolean().optional(),
|
|
45
|
+
notify_subscribers: z.boolean().optional(),
|
|
46
|
+
contains_synthetic_media: z.boolean().optional(),
|
|
47
|
+
}).optional().describe("YouTube Shorts options"),
|
|
48
|
+
instagram: z.object({
|
|
49
|
+
share_to_feed: z.boolean().optional(),
|
|
50
|
+
thumbnail_type: z.enum(["from-video", "from-library"]).optional(),
|
|
51
|
+
thumb_offset: z.number().optional(),
|
|
52
|
+
cover_url: z.string().optional(),
|
|
53
|
+
}).optional().describe("Instagram Reel options"),
|
|
54
|
+
tiktok: z.object({
|
|
55
|
+
privacy_level: z.enum(["PUBLIC_TO_EVERYONE", "MUTUAL_FOLLOW_FRIENDS", "FOLLOWER_OF_CREATOR", "SELF_ONLY"]).optional(),
|
|
56
|
+
disable_comment: z.boolean().optional(),
|
|
57
|
+
disable_duet: z.boolean().optional(),
|
|
58
|
+
disable_stitch: z.boolean().optional(),
|
|
59
|
+
is_aigc: z.boolean().optional(),
|
|
60
|
+
brand_content_toggle: z.boolean().optional(),
|
|
61
|
+
}).optional().describe("TikTok options"),
|
|
62
|
+
x: z.object({
|
|
63
|
+
reply_settings: z.enum(["", "following", "mentionedUsers"]).optional(),
|
|
64
|
+
}).optional().describe("X (Twitter) options"),
|
|
65
|
+
}, async (params) => {
|
|
66
|
+
const result = await client.createPost(params);
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
server.tool("create_and_publish_post", "Create a new post and publish it immediately to all selected platforms. No scheduling needed.", {
|
|
72
|
+
content: z.string().describe("The post content/caption text"),
|
|
73
|
+
channels: z.array(z.string()).optional().describe("Array of channel IDs to post to"),
|
|
74
|
+
media_ids: z.union([
|
|
75
|
+
z.array(z.string()),
|
|
76
|
+
z.record(z.string(), z.array(z.string())),
|
|
77
|
+
]).optional().describe("Media IDs from upload — flat array or per-platform object"),
|
|
78
|
+
media_urls: z.union([
|
|
79
|
+
z.array(z.string()),
|
|
80
|
+
z.record(z.string(), z.array(z.string())),
|
|
81
|
+
]).optional().describe("External image/video URLs — flat array or per-platform object. Max 10 total."),
|
|
82
|
+
type: z.enum(["post", "story", "reel"]).optional().describe("Content type: 'post' (default), 'story', 'reel'"),
|
|
83
|
+
pinterest: z.object({
|
|
84
|
+
board_id: z.string().optional(),
|
|
85
|
+
title: z.string().optional(),
|
|
86
|
+
link: z.string().optional(),
|
|
87
|
+
}).optional().describe("Pinterest-specific options"),
|
|
88
|
+
youtube: z.object({
|
|
89
|
+
title: z.string().optional(),
|
|
90
|
+
tags: z.array(z.string()).optional(),
|
|
91
|
+
privacy_status: z.enum(["public", "private", "unlisted"]).optional(),
|
|
92
|
+
}).optional().describe("YouTube Shorts options"),
|
|
93
|
+
tiktok: z.object({
|
|
94
|
+
privacy_level: z.enum(["PUBLIC_TO_EVERYONE", "MUTUAL_FOLLOW_FRIENDS", "FOLLOWER_OF_CREATOR", "SELF_ONLY"]).optional(),
|
|
95
|
+
}).optional().describe("TikTok options"),
|
|
96
|
+
}, async (params) => {
|
|
97
|
+
const result = await client.createAndPublishPost(params);
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
server.tool("update_post", "Update an existing post. Only draft and scheduled posts can be updated.", {
|
|
103
|
+
id: z.string().describe("The post ID to update"),
|
|
104
|
+
content: z.string().optional().describe("Updated post content"),
|
|
105
|
+
scheduled_at: z.string().optional().describe("Updated scheduled date (ISO 8601)"),
|
|
106
|
+
channels: z.array(z.string()).optional().describe("Updated channel IDs"),
|
|
107
|
+
media_ids: z.union([
|
|
108
|
+
z.array(z.string()),
|
|
109
|
+
z.record(z.string(), z.array(z.string())),
|
|
110
|
+
]).optional().describe("Media IDs — flat array or per-platform object"),
|
|
111
|
+
media_urls: z.union([
|
|
112
|
+
z.array(z.string()),
|
|
113
|
+
z.record(z.string(), z.array(z.string())),
|
|
114
|
+
]).optional().describe("External URLs — flat array or per-platform object. Max 10 total."),
|
|
115
|
+
}, async ({ id, ...data }) => {
|
|
116
|
+
const result = await client.updatePost(id, data);
|
|
117
|
+
return {
|
|
118
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
server.tool("delete_post", "Delete a post by ID. This action cannot be undone.", {
|
|
122
|
+
id: z.string().describe("The post ID to delete"),
|
|
123
|
+
}, async ({ id }) => {
|
|
124
|
+
const result = await client.deletePost(id);
|
|
125
|
+
return {
|
|
126
|
+
content: [{ type: "text", text: result.error ? JSON.stringify(result.error) : "Post deleted successfully." }],
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
server.tool("publish_post", "Publish a draft or scheduled post immediately. The post will be queued for immediate publishing.", {
|
|
130
|
+
id: z.string().describe("The post ID to publish"),
|
|
131
|
+
}, async ({ id }) => {
|
|
132
|
+
const result = await client.publishPost(id);
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerWebhookTools(server, client) {
|
|
3
|
+
server.tool("list_webhooks", "List all configured webhooks.", {}, async () => {
|
|
4
|
+
const result = await client.listWebhooks();
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool("create_webhook", "Create a new webhook to receive event notifications. Available events: post.scheduled, post.published, post.failed", {
|
|
10
|
+
url: z.string().describe("The HTTPS URL to send webhook events to"),
|
|
11
|
+
events: z.array(z.string()).describe("Events to subscribe to: post.scheduled, post.published, post.failed"),
|
|
12
|
+
}, async (params) => {
|
|
13
|
+
const result = await client.createWebhook(params);
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
server.tool("get_webhook", "Get details of a specific webhook by ID.", {
|
|
19
|
+
id: z.string().describe("The webhook ID"),
|
|
20
|
+
}, async ({ id }) => {
|
|
21
|
+
const result = await client.getWebhook(id);
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
server.tool("update_webhook", "Update a webhook's URL, events, or active status.", {
|
|
27
|
+
id: z.string().describe("The webhook ID to update"),
|
|
28
|
+
url: z.string().optional().describe("Updated HTTPS URL"),
|
|
29
|
+
events: z.array(z.string()).optional().describe("Updated event list"),
|
|
30
|
+
is_active: z.boolean().optional().describe("Enable or disable the webhook"),
|
|
31
|
+
}, async ({ id, ...data }) => {
|
|
32
|
+
const result = await client.updateWebhook(id, data);
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
server.tool("delete_webhook", "Delete a webhook by ID. You will stop receiving notifications at this URL.", {
|
|
38
|
+
id: z.string().describe("The webhook ID to delete"),
|
|
39
|
+
}, async ({ id }) => {
|
|
40
|
+
const result = await client.deleteWebhook(id);
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: "text", text: result.error ? JSON.stringify(result.error) : "Webhook deleted successfully." }],
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
server.tool("rotate_webhook_secret", "Rotate the signing secret for a webhook. The new secret will only be shown once.", {
|
|
46
|
+
id: z.string().describe("The webhook ID"),
|
|
47
|
+
}, async ({ id }) => {
|
|
48
|
+
const result = await client.rotateWebhookSecret(id);
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface ApiResponse<T = unknown> {
|
|
2
|
+
data?: T;
|
|
3
|
+
error?: {
|
|
4
|
+
code: string;
|
|
5
|
+
message: string;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export interface Post {
|
|
9
|
+
id: string;
|
|
10
|
+
content: string;
|
|
11
|
+
status: string;
|
|
12
|
+
scheduled_at: string | null;
|
|
13
|
+
published_at: string | null;
|
|
14
|
+
channels: string[];
|
|
15
|
+
media: string[];
|
|
16
|
+
created_at: string;
|
|
17
|
+
}
|
|
18
|
+
export interface MediaItem {
|
|
19
|
+
id: string;
|
|
20
|
+
url: string;
|
|
21
|
+
type: string;
|
|
22
|
+
filename: string;
|
|
23
|
+
size: number;
|
|
24
|
+
created_at: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Account {
|
|
27
|
+
id: string;
|
|
28
|
+
platform: string;
|
|
29
|
+
username: string;
|
|
30
|
+
profile_picture: string | null;
|
|
31
|
+
is_connected: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface Webhook {
|
|
34
|
+
id: string;
|
|
35
|
+
url: string;
|
|
36
|
+
events: string[];
|
|
37
|
+
is_active: boolean;
|
|
38
|
+
last_triggered_at: string | null;
|
|
39
|
+
failure_count: number;
|
|
40
|
+
created_at: string;
|
|
41
|
+
}
|
|
42
|
+
export interface AnalyticsOverview {
|
|
43
|
+
total_posts: number;
|
|
44
|
+
total_impressions: number;
|
|
45
|
+
total_engagements: number;
|
|
46
|
+
period: string;
|
|
47
|
+
}
|
|
48
|
+
export interface PostAnalytics {
|
|
49
|
+
post_id: string;
|
|
50
|
+
impressions: number;
|
|
51
|
+
engagements: number;
|
|
52
|
+
likes: number;
|
|
53
|
+
comments: number;
|
|
54
|
+
shares: number;
|
|
55
|
+
platform_stats: Record<string, unknown>;
|
|
56
|
+
}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@omnisocials/mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for OmniSocials API - manage social media posts, media, accounts, analytics, and webhooks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"omnisocials-mcp": "build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build/"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"dev": "tsc --watch",
|
|
16
|
+
"start": "node build/index.js",
|
|
17
|
+
"prepare": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"omnisocials",
|
|
22
|
+
"social-media",
|
|
23
|
+
"claude",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"ai"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/omnisocials/mcp-server"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://docs.omnisocials.com",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^25.3.3",
|
|
41
|
+
"typescript": "^5.8.2"
|
|
42
|
+
}
|
|
43
|
+
}
|