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 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
@@ -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
+ }