codivupload-mcp 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 +93 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +219 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# codivupload-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [CodivUpload](https://codivupload.com) — publish, schedule, and manage social media posts across 9 platforms using AI agents.
|
|
4
|
+
|
|
5
|
+
Works with Claude Desktop, Claude Code, Cursor, and any MCP-compatible client.
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
### Claude Desktop
|
|
10
|
+
|
|
11
|
+
Add to your `claude_desktop_config.json`:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"codivupload": {
|
|
17
|
+
"command": "npx",
|
|
18
|
+
"args": ["-y", "codivupload-mcp"],
|
|
19
|
+
"env": {
|
|
20
|
+
"CODIVUPLOAD_API_KEY": "cdv_live_your_api_key"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Claude Code (CLI)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
claude mcp add codivupload \
|
|
31
|
+
--command "npx -y codivupload-mcp" \
|
|
32
|
+
--env CODIVUPLOAD_API_KEY=cdv_live_your_api_key
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Cursor
|
|
36
|
+
|
|
37
|
+
Add to your MCP settings in Cursor → Settings → MCP Servers.
|
|
38
|
+
|
|
39
|
+
## Get Your API Key
|
|
40
|
+
|
|
41
|
+
1. Sign up at [app.codivupload.com](https://app.codivupload.com)
|
|
42
|
+
2. Go to **Dashboard → Settings → API Keys**
|
|
43
|
+
3. Create a new key — it starts with `cdv_live_`
|
|
44
|
+
|
|
45
|
+
Free plan includes 10 posts/month. Upgrade for unlimited.
|
|
46
|
+
|
|
47
|
+
## Available Tools
|
|
48
|
+
|
|
49
|
+
| Tool | Description |
|
|
50
|
+
|------|-------------|
|
|
51
|
+
| `publish_post` | Publish to 1-9 platforms in one call |
|
|
52
|
+
| `schedule_post` | Queue for future delivery (UTC ISO 8601) |
|
|
53
|
+
| `get_posts` | List recent posts with status |
|
|
54
|
+
| `get_post_status` | Check delivery status for a specific post |
|
|
55
|
+
| `list_profiles` | Show connected social profiles |
|
|
56
|
+
| `create_profile` | Create a new profile |
|
|
57
|
+
| `upload_media` | Upload media to CDN |
|
|
58
|
+
| `list_media` | List uploaded media assets |
|
|
59
|
+
| `list_broadcasts` | List YouTube live streams |
|
|
60
|
+
| `create_broadcast` | Start a 24/7 live stream |
|
|
61
|
+
|
|
62
|
+
## Supported Platforms
|
|
63
|
+
|
|
64
|
+
TikTok, Instagram, YouTube, Facebook, LinkedIn, X (Twitter), Threads, Pinterest, Bluesky
|
|
65
|
+
|
|
66
|
+
## Example
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
You: Schedule my product video to TikTok and Instagram for tomorrow 9am
|
|
70
|
+
|
|
71
|
+
Claude: I'll schedule that for you.
|
|
72
|
+
|
|
73
|
+
Using tool: schedule_post
|
|
74
|
+
→ Scheduled to TikTok and Instagram for 2026-04-03T14:00:00Z
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Environment Variables
|
|
78
|
+
|
|
79
|
+
| Variable | Required | Description |
|
|
80
|
+
|----------|----------|-------------|
|
|
81
|
+
| `CODIVUPLOAD_API_KEY` | Yes | Your CodivUpload API key (`cdv_live_...`) |
|
|
82
|
+
| `CODIVUPLOAD_API_BASE_URL` | No | API base URL (default: `https://api.codivupload.com`) |
|
|
83
|
+
|
|
84
|
+
## Links
|
|
85
|
+
|
|
86
|
+
- [CodivUpload](https://codivupload.com)
|
|
87
|
+
- [API Documentation](https://docs.codivupload.com)
|
|
88
|
+
- [API Reference](https://api.codivupload.com)
|
|
89
|
+
- [MCP Guide](https://codivupload.com/use-case/mcp-agents)
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT — Codivion LLC
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var API_BASE = process.env.CODIVUPLOAD_API_BASE_URL || "https://api.codivupload.com";
|
|
8
|
+
var API_KEY = process.env.CODIVUPLOAD_API_KEY;
|
|
9
|
+
if (!API_KEY) {
|
|
10
|
+
console.error("Error: CODIVUPLOAD_API_KEY environment variable is required.");
|
|
11
|
+
console.error("Get your API key at https://app.codivupload.com/en/dashboard/settings");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
var headers = {
|
|
15
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
16
|
+
"Content-Type": "application/json"
|
|
17
|
+
};
|
|
18
|
+
async function apiCall(method, path, body) {
|
|
19
|
+
const url = `${API_BASE}/v1${path}`;
|
|
20
|
+
const res = await fetch(url, {
|
|
21
|
+
method,
|
|
22
|
+
headers,
|
|
23
|
+
...body ? { body: JSON.stringify(body) } : {}
|
|
24
|
+
});
|
|
25
|
+
const data = await res.json();
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
return { error: true, status: res.status, ...data };
|
|
28
|
+
}
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
var server = new McpServer({
|
|
32
|
+
name: "codivupload",
|
|
33
|
+
version: "1.0.0"
|
|
34
|
+
});
|
|
35
|
+
server.tool(
|
|
36
|
+
"list_profiles",
|
|
37
|
+
"List all social media profiles in your workspace with their connected platform accounts.",
|
|
38
|
+
{},
|
|
39
|
+
async () => {
|
|
40
|
+
const data = await apiCall("GET", "/agency/profiles");
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
server.tool(
|
|
47
|
+
"create_profile",
|
|
48
|
+
"Create a new social media profile in your workspace.",
|
|
49
|
+
{
|
|
50
|
+
username: z.string().describe("Unique username for the profile (min 3 chars)"),
|
|
51
|
+
profile_name: z.string().describe("Display name for the profile")
|
|
52
|
+
},
|
|
53
|
+
async ({ username, profile_name }) => {
|
|
54
|
+
const data = await apiCall("POST", "/agency/profiles", { username, profile_name });
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
server.tool(
|
|
61
|
+
"publish_post",
|
|
62
|
+
"Publish content to one or more social media platforms. Supports TikTok, Instagram, YouTube, Facebook, LinkedIn, X, Threads, Pinterest, Bluesky.",
|
|
63
|
+
{
|
|
64
|
+
platforms: z.array(z.string()).describe("Platform slugs: tiktok, instagram, youtube, facebook, linkedin, twitter, threads, pinterest, bluesky"),
|
|
65
|
+
post_type: z.enum(["post", "reel", "story", "short"]).describe("Content type"),
|
|
66
|
+
description: z.string().describe("Post caption / body text"),
|
|
67
|
+
media_urls: z.array(z.string()).optional().describe("CDN URLs for images or video files"),
|
|
68
|
+
profile_name: z.string().optional().describe("Target profile username (for multi-profile workspaces)"),
|
|
69
|
+
// Platform-specific overrides
|
|
70
|
+
tiktok_privacy_level: z.number().optional().describe("TikTok privacy: 0=public, 1=friends, 2=private"),
|
|
71
|
+
tiktok_disable_duet: z.boolean().optional().describe("Disable TikTok duet"),
|
|
72
|
+
tiktok_disable_comment: z.boolean().optional().describe("Disable TikTok comments"),
|
|
73
|
+
tiktok_disable_stitch: z.boolean().optional().describe("Disable TikTok stitch"),
|
|
74
|
+
tiktok_brand_content_toggle: z.boolean().optional().describe("Enable TikTok branded content"),
|
|
75
|
+
instagram_media_type: z.string().optional().describe("REELS, STORIES, or IMAGE"),
|
|
76
|
+
instagram_location_id: z.string().optional().describe("Instagram location ID"),
|
|
77
|
+
youtube_type: z.string().optional().describe("video, short, or live"),
|
|
78
|
+
youtube_privacy: z.string().optional().describe("public, unlisted, or private"),
|
|
79
|
+
youtube_category_id: z.string().optional().describe("YouTube category ID"),
|
|
80
|
+
youtube_tags: z.array(z.string()).optional().describe("YouTube video tags"),
|
|
81
|
+
youtube_title: z.string().optional().describe("YouTube video title"),
|
|
82
|
+
youtube_thumbnail_url: z.string().optional().describe("YouTube thumbnail image URL"),
|
|
83
|
+
facebook_type: z.string().optional().describe("video, image, text, link, reel"),
|
|
84
|
+
linkedin_type: z.string().optional().describe("post or article"),
|
|
85
|
+
pinterest_board_id: z.string().optional().describe("Pinterest board ID"),
|
|
86
|
+
pinterest_link: z.string().optional().describe("Pinterest destination link")
|
|
87
|
+
},
|
|
88
|
+
async (params) => {
|
|
89
|
+
const data = await apiCall("POST", "/posts", params);
|
|
90
|
+
return {
|
|
91
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
server.tool(
|
|
96
|
+
"schedule_post",
|
|
97
|
+
"Schedule content for future publishing. Same parameters as publish_post plus a scheduled date.",
|
|
98
|
+
{
|
|
99
|
+
platforms: z.array(z.string()).describe("Platform slugs"),
|
|
100
|
+
post_type: z.enum(["post", "reel", "story", "short"]).describe("Content type"),
|
|
101
|
+
description: z.string().describe("Post caption / body text"),
|
|
102
|
+
scheduled_date: z.string().describe("UTC ISO 8601 datetime for delivery, e.g. 2026-04-05T14:00:00Z"),
|
|
103
|
+
media_urls: z.array(z.string()).optional().describe("CDN URLs for media files"),
|
|
104
|
+
profile_name: z.string().optional().describe("Target profile username"),
|
|
105
|
+
// All platform-specific overrides
|
|
106
|
+
tiktok_privacy_level: z.number().optional().describe("TikTok privacy: 0=public, 1=friends, 2=private"),
|
|
107
|
+
instagram_media_type: z.string().optional().describe("REELS, STORIES, or IMAGE"),
|
|
108
|
+
youtube_type: z.string().optional().describe("video, short, or live"),
|
|
109
|
+
youtube_privacy: z.string().optional().describe("public, unlisted, or private"),
|
|
110
|
+
youtube_category_id: z.string().optional().describe("YouTube category ID"),
|
|
111
|
+
youtube_tags: z.array(z.string()).optional().describe("YouTube video tags"),
|
|
112
|
+
youtube_title: z.string().optional().describe("YouTube video title")
|
|
113
|
+
},
|
|
114
|
+
async (params) => {
|
|
115
|
+
const data = await apiCall("POST", "/posts", params);
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
server.tool(
|
|
122
|
+
"get_posts",
|
|
123
|
+
"List recent posts with delivery status and platform breakdown. Filter by status or date.",
|
|
124
|
+
{
|
|
125
|
+
limit: z.number().optional().describe("Number of posts to return (default 20, max 100)"),
|
|
126
|
+
status: z.string().optional().describe("Filter by status: scheduled, publishing, published, failed"),
|
|
127
|
+
profile_name: z.string().optional().describe("Filter by profile username")
|
|
128
|
+
},
|
|
129
|
+
async ({ limit, status, profile_name }) => {
|
|
130
|
+
const params = new URLSearchParams();
|
|
131
|
+
if (limit) params.set("limit", String(limit));
|
|
132
|
+
if (status) params.set("status", status);
|
|
133
|
+
if (profile_name) params.set("profile_name", profile_name);
|
|
134
|
+
const query = params.toString() ? `?${params.toString()}` : "";
|
|
135
|
+
const data = await apiCall("GET", `/posts${query}`);
|
|
136
|
+
return {
|
|
137
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
server.tool(
|
|
142
|
+
"get_post_status",
|
|
143
|
+
"Check delivery status for a specific post by its ID.",
|
|
144
|
+
{
|
|
145
|
+
post_id: z.string().describe("The post ID to check status for")
|
|
146
|
+
},
|
|
147
|
+
async ({ post_id }) => {
|
|
148
|
+
const data = await apiCall("GET", `/posts/${post_id}`);
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
server.tool(
|
|
155
|
+
"upload_media",
|
|
156
|
+
"Upload a media file to CodivUpload CDN. Returns a URL that can be used in publish_post or schedule_post.",
|
|
157
|
+
{
|
|
158
|
+
file_url: z.string().describe("Public URL of the file to upload to CDN"),
|
|
159
|
+
profile_name: z.string().optional().describe("Profile to associate the media with")
|
|
160
|
+
},
|
|
161
|
+
async ({ file_url, profile_name }) => {
|
|
162
|
+
const data = await apiCall("POST", "/upload-media", {
|
|
163
|
+
media_url: file_url,
|
|
164
|
+
...profile_name ? { profile_name } : {}
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
server.tool(
|
|
172
|
+
"list_media",
|
|
173
|
+
"List media assets uploaded to your workspace CDN.",
|
|
174
|
+
{
|
|
175
|
+
limit: z.number().optional().describe("Number of items to return")
|
|
176
|
+
},
|
|
177
|
+
async ({ limit }) => {
|
|
178
|
+
const params = limit ? `?limit=${limit}` : "";
|
|
179
|
+
const data = await apiCall("GET", `/agency/media${params}`);
|
|
180
|
+
return {
|
|
181
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
server.tool(
|
|
186
|
+
"list_broadcasts",
|
|
187
|
+
"List active and past YouTube live stream broadcasts.",
|
|
188
|
+
{},
|
|
189
|
+
async () => {
|
|
190
|
+
const data = await apiCall("GET", "/broadcasts");
|
|
191
|
+
return {
|
|
192
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
server.tool(
|
|
197
|
+
"create_broadcast",
|
|
198
|
+
"Start a new 24/7 YouTube live stream broadcast.",
|
|
199
|
+
{
|
|
200
|
+
profile_name: z.string().describe("Profile with YouTube connected"),
|
|
201
|
+
title: z.string().describe("Stream title"),
|
|
202
|
+
media_url: z.string().describe("Video file URL to loop"),
|
|
203
|
+
loop: z.boolean().optional().describe("Loop the video continuously (default true)")
|
|
204
|
+
},
|
|
205
|
+
async (params) => {
|
|
206
|
+
const data = await apiCall("POST", "/broadcasts", params);
|
|
207
|
+
return {
|
|
208
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
async function main() {
|
|
213
|
+
const transport = new StdioServerTransport();
|
|
214
|
+
await server.connect(transport);
|
|
215
|
+
}
|
|
216
|
+
main().catch((err) => {
|
|
217
|
+
console.error("Fatal error:", err);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codivupload-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for CodivUpload — publish, schedule, and manage social media posts across 9 platforms via AI agents (Claude, Cursor, etc.)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"codivupload",
|
|
8
|
+
"social-media",
|
|
9
|
+
"claude",
|
|
10
|
+
"ai-agent",
|
|
11
|
+
"scheduling",
|
|
12
|
+
"api"
|
|
13
|
+
],
|
|
14
|
+
"author": "Codivion LLC <support@codivupload.com>",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/Codivion/codivupload-mcp"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://codivupload.com/use-case/mcp-agents",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Codivion/codivupload-mcp/issues"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.js",
|
|
26
|
+
"bin": {
|
|
27
|
+
"codivupload-mcp": "dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
34
|
+
"dev": "tsx src/index.ts",
|
|
35
|
+
"prepublishOnly": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
39
|
+
"zod": "^4.3.6"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^22.0.0",
|
|
43
|
+
"tsup": "^8.0.0",
|
|
44
|
+
"tsx": "^4.0.0",
|
|
45
|
+
"typescript": "^5.5.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|