@publishq/mcp 1.0.0 → 1.0.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/dist/index.js +95 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37,6 +37,67 @@ import {
|
|
|
37
37
|
zUpdatePostPath
|
|
38
38
|
} from "@publishq/sdk";
|
|
39
39
|
import { toJSONSchema } from "zod/v4-mini";
|
|
40
|
+
|
|
41
|
+
// package.json
|
|
42
|
+
var package_default = {
|
|
43
|
+
name: "@publishq/mcp",
|
|
44
|
+
version: "1.0.1",
|
|
45
|
+
mcpName: "com.publishq/publishq",
|
|
46
|
+
private: false,
|
|
47
|
+
description: "Model Context Protocol (MCP) server for PublishQ. Let AI agents schedule and publish across your social platforms.",
|
|
48
|
+
license: "Apache-2.0",
|
|
49
|
+
author: "PublishQ",
|
|
50
|
+
repository: {
|
|
51
|
+
type: "git",
|
|
52
|
+
url: "git+https://github.com/alexand-ro/2-publishq.git",
|
|
53
|
+
directory: "packages/mcp"
|
|
54
|
+
},
|
|
55
|
+
homepage: "https://publishq.com",
|
|
56
|
+
keywords: [
|
|
57
|
+
"publishq",
|
|
58
|
+
"mcp",
|
|
59
|
+
"model-context-protocol",
|
|
60
|
+
"ai-agent",
|
|
61
|
+
"claude",
|
|
62
|
+
"social-media"
|
|
63
|
+
],
|
|
64
|
+
type: "module",
|
|
65
|
+
bin: {
|
|
66
|
+
"publishq-mcp": "./dist/index.js"
|
|
67
|
+
},
|
|
68
|
+
files: [
|
|
69
|
+
"dist",
|
|
70
|
+
"README.md",
|
|
71
|
+
"LICENSE"
|
|
72
|
+
],
|
|
73
|
+
scripts: {
|
|
74
|
+
build: "tsup",
|
|
75
|
+
dev: "tsup --watch",
|
|
76
|
+
typecheck: "tsc --noEmit",
|
|
77
|
+
lint: "eslint src tests --max-warnings 0",
|
|
78
|
+
test: "pnpm build && vitest run",
|
|
79
|
+
prepublishOnly: "npm run build"
|
|
80
|
+
},
|
|
81
|
+
dependencies: {
|
|
82
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
83
|
+
"@publishq/sdk": "workspace:^",
|
|
84
|
+
zod: "4.4.3"
|
|
85
|
+
},
|
|
86
|
+
devDependencies: {
|
|
87
|
+
"@types/node": "^20",
|
|
88
|
+
tsup: "^8.5.1",
|
|
89
|
+
typescript: "^5",
|
|
90
|
+
vitest: "3.2.4"
|
|
91
|
+
},
|
|
92
|
+
engines: {
|
|
93
|
+
node: ">=20"
|
|
94
|
+
},
|
|
95
|
+
publishConfig: {
|
|
96
|
+
access: "public"
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/tools.ts
|
|
40
101
|
function describeError(error) {
|
|
41
102
|
const cause = error.cause;
|
|
42
103
|
if (cause instanceof Error) {
|
|
@@ -134,7 +195,7 @@ function publishqTools(publishq2) {
|
|
|
134
195
|
title: "List posts",
|
|
135
196
|
description: "List the posts on the authenticated PublishQ account. Paginated. Each post includes its connected accounts and status (DRAFT, SCHEDULED, PUBLISHING, PUBLISHED, FAILED).",
|
|
136
197
|
inputSchema: advertisedSchema(zListPostsQuery),
|
|
137
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
198
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
138
199
|
},
|
|
139
200
|
(args) => run(publishq2.posts.list(args))
|
|
140
201
|
);
|
|
@@ -144,7 +205,7 @@ function publishqTools(publishq2) {
|
|
|
144
205
|
title: "Get a post",
|
|
145
206
|
description: "Get one post by its PublishQ post ID.",
|
|
146
207
|
inputSchema: advertisedSchema(zGetPostPath),
|
|
147
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
208
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
148
209
|
},
|
|
149
210
|
(args) => run(publishq2.posts.get(args.id))
|
|
150
211
|
);
|
|
@@ -154,7 +215,7 @@ function publishqTools(publishq2) {
|
|
|
154
215
|
title: "Create a post",
|
|
155
216
|
description: "Create a post for one or more connected accounts. Get account IDs from publishq_list_accounts. Each account accepts postOverrides and platformSpecificSettings. Before posting to TikTok, call publishq_get_tiktok_creator_info and include all required TikTok settings. Omit both scheduledAt and publishNow to save as a draft; set publishNow to publish immediately, or scheduledAt (ISO 8601) to schedule for later.",
|
|
156
217
|
inputSchema: advertisedSchema(zCreatePostBody),
|
|
157
|
-
annotations: { readOnlyHint: false, openWorldHint: true }
|
|
218
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }
|
|
158
219
|
},
|
|
159
220
|
(args) => run(publishq2.posts.create(args))
|
|
160
221
|
);
|
|
@@ -164,7 +225,12 @@ function publishqTools(publishq2) {
|
|
|
164
225
|
title: "Update a post",
|
|
165
226
|
description: "Update a draft or scheduled post. Supports content, scheduledAt, complete media replacement/removal through mediaIds, thumbnailTimestamp, and accounts (each with postOverrides and platformSpecificSettings, for example a YouTube thumbnailMediaId). Only the fields you send change; send a field as null to remove it. Published and publishing posts cannot be updated.",
|
|
166
227
|
inputSchema: mergedAdvertisedSchema(zUpdatePostPath, zUpdatePostBody),
|
|
167
|
-
annotations: {
|
|
228
|
+
annotations: {
|
|
229
|
+
readOnlyHint: false,
|
|
230
|
+
destructiveHint: false,
|
|
231
|
+
idempotentHint: true,
|
|
232
|
+
openWorldHint: true
|
|
233
|
+
}
|
|
168
234
|
},
|
|
169
235
|
(args) => {
|
|
170
236
|
const { id, ...body } = args;
|
|
@@ -204,7 +270,7 @@ function publishqTools(publishq2) {
|
|
|
204
270
|
title: "List connected accounts",
|
|
205
271
|
description: "List the social accounts connected to the authenticated PublishQ account. Optionally filter by workspace and platform. Use the returned account IDs when creating posts.",
|
|
206
272
|
inputSchema: advertisedSchema(zListAccountsQuery),
|
|
207
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
273
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
208
274
|
},
|
|
209
275
|
(args) => run(publishq2.accounts.list(args))
|
|
210
276
|
);
|
|
@@ -214,7 +280,7 @@ function publishqTools(publishq2) {
|
|
|
214
280
|
title: "Get TikTok creator info",
|
|
215
281
|
description: "Get a TikTok account's current privacy options, interaction settings, and max video duration. Call this before creating a TikTok post. The privacyLevel you set must be one of the returned privacyLevelOptions.",
|
|
216
282
|
inputSchema: advertisedSchema(zGetTikTokCreatorInfoPath),
|
|
217
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
283
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
218
284
|
},
|
|
219
285
|
(args) => run(publishq2.accounts.getTikTokCreatorInfo(args.id))
|
|
220
286
|
);
|
|
@@ -224,7 +290,7 @@ function publishqTools(publishq2) {
|
|
|
224
290
|
title: "List workspaces",
|
|
225
291
|
description: "List your workspaces, including their names, colors, and account counts.",
|
|
226
292
|
inputSchema: { type: "object", properties: {} },
|
|
227
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
293
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
228
294
|
},
|
|
229
295
|
() => run(publishq2.workspaces.list())
|
|
230
296
|
);
|
|
@@ -234,7 +300,7 @@ function publishqTools(publishq2) {
|
|
|
234
300
|
title: "Get a workspace",
|
|
235
301
|
description: "Get one workspace by its ID.",
|
|
236
302
|
inputSchema: advertisedSchema(zGetWorkspacePath),
|
|
237
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
303
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
238
304
|
},
|
|
239
305
|
(args) => run(publishq2.workspaces.get(args.id))
|
|
240
306
|
);
|
|
@@ -244,7 +310,7 @@ function publishqTools(publishq2) {
|
|
|
244
310
|
title: "Create a workspace",
|
|
245
311
|
description: "Create a workspace to organize your connected accounts.",
|
|
246
312
|
inputSchema: advertisedSchema(zCreateWorkspaceBody),
|
|
247
|
-
annotations: { readOnlyHint: false, openWorldHint: true }
|
|
313
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }
|
|
248
314
|
},
|
|
249
315
|
(args) => run(publishq2.workspaces.create(args))
|
|
250
316
|
);
|
|
@@ -254,7 +320,7 @@ function publishqTools(publishq2) {
|
|
|
254
320
|
title: "List media",
|
|
255
321
|
description: "List your uploaded and generated media files. Optionally filter by media ID, type, and source.",
|
|
256
322
|
inputSchema: advertisedSchema(zListMediaQuery),
|
|
257
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
323
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
258
324
|
},
|
|
259
325
|
(args) => run(publishq2.media.list(args))
|
|
260
326
|
);
|
|
@@ -264,7 +330,7 @@ function publishqTools(publishq2) {
|
|
|
264
330
|
title: "Get a media file",
|
|
265
331
|
description: "Get one media file by its ID, including its URL and usage.",
|
|
266
332
|
inputSchema: advertisedSchema(zGetMediaPath),
|
|
267
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
333
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
268
334
|
},
|
|
269
335
|
(args) => run(publishq2.media.get(args.id))
|
|
270
336
|
);
|
|
@@ -274,7 +340,7 @@ function publishqTools(publishq2) {
|
|
|
274
340
|
title: "Start a media upload",
|
|
275
341
|
description: 'Get a signed upload URL for a file of up to 4 GB on the machine you run commands on, and the media ID it becomes. Send the file with a PUT to uploadUrl, with the same Content-Type and no Authorization header, for example `curl -X PUT -H "Content-Type: image/jpeg" --upload-file ./photo.jpg "<uploadUrl>"`. Then attach the media ID to a post through mediaIds. The URL expires after an hour.',
|
|
276
342
|
inputSchema: advertisedSchema(zCreateMediaUploadBody),
|
|
277
|
-
annotations: { readOnlyHint: false, openWorldHint: true }
|
|
343
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }
|
|
278
344
|
},
|
|
279
345
|
(args) => run(publishq2.media.createUpload(args))
|
|
280
346
|
);
|
|
@@ -294,7 +360,7 @@ function publishqTools(publishq2) {
|
|
|
294
360
|
title: "List media folders",
|
|
295
361
|
description: 'List every folder in the media library, parents before subfolders, with the number of files in each folder and its subfolders. Folder paths look like "Channel A/Shorts". Use a path as folderPath in publishq_list_media, publishq_upload_media or publishq_move_media.',
|
|
296
362
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
297
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
363
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
298
364
|
},
|
|
299
365
|
() => run(publishq2.media.listFolders())
|
|
300
366
|
);
|
|
@@ -304,7 +370,12 @@ function publishqTools(publishq2) {
|
|
|
304
370
|
title: "Move media to a folder",
|
|
305
371
|
description: 'Move up to 100 media files to a folder by path, for example "Channel A/Shorts", or to the top level with folderPath null. A folder that does not exist yet is created by moving files into it. Posts keep working: they use media IDs, not folders.',
|
|
306
372
|
inputSchema: advertisedSchema(zMoveMediaBody),
|
|
307
|
-
annotations: {
|
|
373
|
+
annotations: {
|
|
374
|
+
readOnlyHint: false,
|
|
375
|
+
destructiveHint: false,
|
|
376
|
+
idempotentHint: true,
|
|
377
|
+
openWorldHint: true
|
|
378
|
+
}
|
|
308
379
|
},
|
|
309
380
|
(args) => run(publishq2.media.move(args))
|
|
310
381
|
);
|
|
@@ -314,7 +385,7 @@ function publishqTools(publishq2) {
|
|
|
314
385
|
title: "Rename a media folder",
|
|
315
386
|
description: "Rename a media folder. Only the last part of the path changes, and its files and subfolders follow. Answers 404 when no folder has that path (check publishq_list_media_folders), and is refused when a folder with the new name already exists at the same level.",
|
|
316
387
|
inputSchema: advertisedSchema(zRenameMediaFolderBody),
|
|
317
|
-
annotations: { readOnlyHint: false, openWorldHint: true }
|
|
388
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }
|
|
318
389
|
},
|
|
319
390
|
(args) => run(publishq2.media.renameFolder(args))
|
|
320
391
|
);
|
|
@@ -324,7 +395,7 @@ function publishqTools(publishq2) {
|
|
|
324
395
|
title: "Preview deleting a media folder",
|
|
325
396
|
description: "Count what deleting a media folder would remove: files and subfolders at every level, and files kept because a draft or scheduled post uses them. Call this first, show the numbers to the user and get their confirmation before publishq_delete_media_folder.",
|
|
326
397
|
inputSchema: advertisedSchema(zPreviewMediaFolderDeletionQuery),
|
|
327
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
398
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
|
|
328
399
|
},
|
|
329
400
|
(args) => run(publishq2.media.previewFolderDeletion(args.path))
|
|
330
401
|
);
|
|
@@ -340,10 +411,17 @@ function publishqTools(publishq2) {
|
|
|
340
411
|
);
|
|
341
412
|
return tools;
|
|
342
413
|
}
|
|
414
|
+
var PUBLISHQ_SERVER_DESCRIPTION = "Schedule and publish social media posts, organize media, and keep each brand in its own workspace.";
|
|
343
415
|
function createPublishQServer(tools) {
|
|
344
416
|
const byName = new Map(tools.map((tool) => [tool.definition.name, tool]));
|
|
345
417
|
const server2 = new McpServer(
|
|
346
|
-
{
|
|
418
|
+
{
|
|
419
|
+
name: "publishq",
|
|
420
|
+
title: "PublishQ",
|
|
421
|
+
version: package_default.version,
|
|
422
|
+
description: PUBLISHQ_SERVER_DESCRIPTION,
|
|
423
|
+
websiteUrl: "https://publishq.com"
|
|
424
|
+
},
|
|
347
425
|
{ capabilities: { tools: {} } }
|
|
348
426
|
);
|
|
349
427
|
server2.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
package/package.json
CHANGED