@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.
Files changed (2) hide show
  1. package/dist/index.js +95 -17
  2. 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: { readOnlyHint: false, idempotentHint: true, openWorldHint: true }
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: { readOnlyHint: false, idempotentHint: true, openWorldHint: true }
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
- { name: "publishq", version: "0.1.0" },
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@publishq/mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "mcpName": "com.publishq/publishq",
5
5
  "private": false,
6
6
  "description": "Model Context Protocol (MCP) server for PublishQ. Let AI agents schedule and publish across your social platforms.",