posterly-mcp-server 0.48.5 → 0.49.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.
Files changed (49) hide show
  1. package/README.md +8 -2
  2. package/dist/lib/api-client.d.ts +80 -12
  3. package/dist/lib/api-client.js +40 -15
  4. package/dist/lib/format.d.ts +39 -2
  5. package/dist/lib/format.js +158 -0
  6. package/dist/lib/version.d.ts +1 -1
  7. package/dist/lib/version.js +1 -1
  8. package/dist/tools/audit-google-business-profile.d.ts +2 -2
  9. package/dist/tools/connect-account.d.ts +2 -2
  10. package/dist/tools/create-post.d.ts +12 -12
  11. package/dist/tools/create-posts-batch.d.ts +8 -8
  12. package/dist/tools/create-webhook.d.ts +2 -2
  13. package/dist/tools/disconnect-account.d.ts +2 -2
  14. package/dist/tools/find-slot.d.ts +2 -2
  15. package/dist/tools/get-updates.d.ts +4 -0
  16. package/dist/tools/get-updates.js +13 -1
  17. package/dist/tools/list-accounts.d.ts +2 -2
  18. package/dist/tools/list-activity.d.ts +4 -0
  19. package/dist/tools/list-activity.js +16 -3
  20. package/dist/tools/list-analytics.d.ts +2 -2
  21. package/dist/tools/list-comments.d.ts +2 -2
  22. package/dist/tools/list-conversations.d.ts +2 -2
  23. package/dist/tools/list-google-business-media.d.ts +2 -2
  24. package/dist/tools/list-google-business-reviews.d.ts +4 -4
  25. package/dist/tools/list-media.d.ts +4 -0
  26. package/dist/tools/list-media.js +22 -1
  27. package/dist/tools/list-platforms.d.ts +4 -4
  28. package/dist/tools/list-post-suggestions.d.ts +4 -0
  29. package/dist/tools/list-post-suggestions.js +16 -4
  30. package/dist/tools/list-posts.d.ts +35 -17
  31. package/dist/tools/list-posts.js +63 -33
  32. package/dist/tools/manage-comment.d.ts +2 -2
  33. package/dist/tools/manage-conversation.d.ts +4 -4
  34. package/dist/tools/manage-google-business-media.d.ts +8 -8
  35. package/dist/tools/manage-google-business-review.d.ts +10 -10
  36. package/dist/tools/manage-publishing-pause.d.ts +2 -2
  37. package/dist/tools/manage-webhook.d.ts +4 -4
  38. package/dist/tools/validate-post.d.ts +8 -8
  39. package/package.json +1 -1
  40. package/server.json +2 -2
  41. package/src/lib/api-client.ts +94 -17
  42. package/src/lib/format.ts +201 -1
  43. package/src/lib/version.ts +1 -1
  44. package/src/tools/get-updates.ts +15 -1
  45. package/src/tools/list-activity.ts +18 -3
  46. package/src/tools/list-media.ts +23 -2
  47. package/src/tools/list-post-suggestions.ts +17 -4
  48. package/src/tools/list-posts.ts +74 -45
  49. package/tool-registry.json +110 -5
@@ -1,10 +1,20 @@
1
1
  import { z } from 'zod';
2
- import { dashboardUrlForPostList, formatLocalDateTime, truncateText } from '../lib/format.js';
2
+ import { dashboardUrlForPostList, formatPostCounts, formatPostListPage } from '../lib/format.js';
3
+ import { validateArgs } from '../lib/tool-runtime.js';
3
4
  import { SUPPORTED_PLATFORM_INPUTS, SUPPORTED_PLATFORM_IDS } from '../generated/platform-manifest.js';
5
+ export const LIST_POSTS_DESCRIPTION = 'Posts in your workspaces, teammates\' too, per your role there (brand-locked seats only see their assigned brands). If workspace_id is omitted, this searches every workspace you belong to. ' +
6
+ 'view=list (default): posts filtered by status (scheduled, published, failed, draft), platform, account_id, workspace_id, brand_id, approval_status, approval_waiting_on, and a scheduled date range: scheduled_from (inclusive) and scheduled_to (a plain date includes that whole day), read in timezone (IANA, default UTC; also the zone times are shown in). Returns limit posts (default 20, max 200) starting at offset; with a date range the order defaults to oldest first (order=asc|desc). ' +
7
+ 'The output always says whether every matching post was shown. If it says more are available, call again with the offset it gives and keep paging until all are shown before drawing any conclusion about totals, gaps, or how busy a client is. ' +
8
+ 'view=counts (scheduled_from and scheduled_to required, up to 366 days): exact totals per day, status, account, and brand for the same filters (limit, offset, and order are ignored); use it for "how many" or "is this month full" questions. ' +
9
+ 'approval_waiting_on=client is the same queue as approval_status=pending_client. Each post includes approval.pending_client_approval.';
4
10
  export const listPostsTool = {
5
11
  name: 'list_posts',
6
- description: 'List upcoming or recent posts. Filter by status (scheduled, published, failed, draft), platform, account_id, workspace_id, approval_status, approval_waiting_on, or brand_id. approval_waiting_on=client is the same queue as approval_status=pending_client. Each post includes approval.pending_client_approval. Returns posts in your workspaces, teammates\' too, per your role there (brand-locked seats only see their assigned brands). If workspace_id is omitted, this searches every workspace you belong to.',
12
+ description: LIST_POSTS_DESCRIPTION,
7
13
  inputSchema: z.object({
14
+ view: z
15
+ .enum(['list', 'counts'])
16
+ .optional()
17
+ .describe('list (default): the posts themselves, one page at a time. counts: exact totals per day, status, account, and brand (needs scheduled_from and scheduled_to).'),
8
18
  status: z
9
19
  .string()
10
20
  .optional()
@@ -17,12 +27,34 @@ export const listPostsTool = {
17
27
  .string()
18
28
  .optional()
19
29
  .describe('Filter to a specific social account ID (from list_accounts).'),
30
+ scheduled_from: z
31
+ .string()
32
+ .optional()
33
+ .describe('Start of the scheduled range, inclusive: a date (2026-10-01) or an ISO date-time. Plain dates and times without an offset are read in timezone.'),
34
+ scheduled_to: z
35
+ .string()
36
+ .optional()
37
+ .describe('End of the scheduled range: a plain date (2026-10-31) includes that whole day; an ISO date-time is exclusive.'),
38
+ timezone: z
39
+ .string()
40
+ .optional()
41
+ .describe('IANA time zone such as Europe/London for reading plain dates and showing times. Default UTC.'),
42
+ order: z
43
+ .enum(['asc', 'desc'])
44
+ .optional()
45
+ .describe('asc (oldest first) or desc (newest first). Default asc with a date range, otherwise desc. Ignored by view=counts.'),
20
46
  limit: z
21
47
  .number()
22
48
  .min(1)
23
- .max(100)
49
+ .max(200)
24
50
  .optional()
25
- .describe('Number of posts to return (default 20, max 100)'),
51
+ .describe('Posts per page (default 20, max 200). Ignored by view=counts.'),
52
+ offset: z
53
+ .number()
54
+ .int()
55
+ .min(0)
56
+ .optional()
57
+ .describe('How many matching posts to skip. Use the offset the previous page gives to get the next page. Ignored by view=counts.'),
26
58
  workspace_id: z
27
59
  .string()
28
60
  .optional()
@@ -40,36 +72,34 @@ export const listPostsTool = {
40
72
  .optional()
41
73
  .describe('Filter to posts assigned to a specific brand/client (the id from list_brands).'),
42
74
  }),
43
- async execute(client, input) {
44
- const { posts, total } = await client.listPosts({
45
- ...input,
46
- limit: input.limit || 20,
47
- });
48
- if (posts.length === 0) {
49
- return 'No posts found matching your criteria.\n\nNext step for the AI agent: tell the user their posterly queue is clear for that filter, then ask what they want to schedule next.';
75
+ async execute(client, input, ctx) {
76
+ const { mode, args } = validateArgs(ctx, 'list_posts', input);
77
+ const filters = postFilters(args);
78
+ const timeZone = filters.timezone || 'UTC';
79
+ if (mode === 'counts') {
80
+ return formatPostCounts(await client.countPosts(filters));
50
81
  }
51
- const lines = posts.map((p) => {
52
- const date = formatLocalDateTime(p.scheduled_at);
53
- const caption = truncateText(p.content, 60);
54
- const approvalBits = [];
55
- if (p.approval && p.approval.status !== 'none') {
56
- approvalBits.push(`approval: ${p.approval.status}`);
57
- if (p.approval.waiting_on)
58
- approvalBits.push(`waiting on: ${p.approval.waiting_on}`);
59
- }
60
- if (p.brand_id)
61
- approvalBits.push(`brand: ${p.brand_id}`);
62
- if (p.content_plan_id)
63
- approvalBits.push(`plan: ${p.content_plan_id}`);
64
- const approvalSuffix = approvalBits.length > 0 ? ` [${approvalBits.join(', ')}]` : '';
65
- return `• [${p.status}] #${p.id}: ${caption} (${date})${approvalSuffix}`;
82
+ const hasRange = Boolean(filters.scheduled_from || filters.scheduled_to);
83
+ const page = await client.listPosts({
84
+ ...filters,
85
+ limit: args.limit || 20,
86
+ offset: args.offset,
87
+ order: args.order ?? (hasRange ? 'asc' : undefined),
66
88
  });
67
- return [
68
- `Posts (${posts.length} of ${total}):`,
69
- ...lines,
70
- '',
71
- `View in posterly: ${dashboardUrlForPostList(posts)}`,
72
- 'Next step for the AI agent: summarize the queue in plain language and use the dashboard link above if the user wants to inspect it in posterly.',
73
- ].join('\n');
89
+ return formatPostListPage(page, { timeZone, dashboardUrl: dashboardUrlForPostList(page.posts || []) });
74
90
  },
75
91
  };
92
+ function postFilters(input) {
93
+ return {
94
+ status: input.status,
95
+ platform: input.platform,
96
+ account_id: input.account_id,
97
+ workspace_id: input.workspace_id,
98
+ approval_status: input.approval_status,
99
+ approval_waiting_on: input.approval_waiting_on,
100
+ brand_id: input.brand_id,
101
+ scheduled_from: input.scheduled_from,
102
+ scheduled_to: input.scheduled_to,
103
+ timezone: input.timezone,
104
+ };
105
+ }
@@ -28,9 +28,9 @@ export declare const manageCommentTool: {
28
28
  }, "strip", z.ZodTypeAny, {
29
29
  action: "update" | "delete" | "reply";
30
30
  comment_id: string;
31
+ workspace_id?: string | undefined;
31
32
  confirm?: boolean | undefined;
32
33
  preview_id?: string | undefined;
33
- workspace_id?: string | undefined;
34
34
  type?: "public" | "private" | undefined;
35
35
  content?: string | undefined;
36
36
  is_hidden?: boolean | undefined;
@@ -38,9 +38,9 @@ export declare const manageCommentTool: {
38
38
  }, {
39
39
  action: "update" | "delete" | "reply";
40
40
  comment_id: string;
41
+ workspace_id?: string | undefined;
41
42
  confirm?: boolean | undefined;
42
43
  preview_id?: string | undefined;
43
- workspace_id?: string | undefined;
44
44
  type?: "public" | "private" | undefined;
45
45
  content?: string | undefined;
46
46
  is_hidden?: boolean | undefined;
@@ -25,19 +25,19 @@ export declare const manageConversationTool: {
25
25
  preview_id: z.ZodOptional<z.ZodString>;
26
26
  }, "strip", z.ZodTypeAny, {
27
27
  action: "send" | "sync";
28
+ account_id?: number | undefined;
29
+ workspace_id?: string | undefined;
28
30
  confirm?: boolean | undefined;
29
31
  preview_id?: string | undefined;
30
- workspace_id?: string | undefined;
31
- account_id?: number | undefined;
32
32
  content?: string | undefined;
33
33
  conversation_id?: string | undefined;
34
34
  sync_type?: "all" | "dm" | "comments" | undefined;
35
35
  }, {
36
36
  action: "send" | "sync";
37
+ account_id?: number | undefined;
38
+ workspace_id?: string | undefined;
37
39
  confirm?: boolean | undefined;
38
40
  preview_id?: string | undefined;
39
- workspace_id?: string | undefined;
40
- account_id?: number | undefined;
41
41
  content?: string | undefined;
42
42
  conversation_id?: string | undefined;
43
43
  sync_type?: "all" | "dm" | "comments" | undefined;
@@ -30,10 +30,10 @@ export declare const manageGoogleBusinessMediaTool: {
30
30
  preview_id: z.ZodOptional<z.ZodString>;
31
31
  }, "strip", z.ZodTypeAny, {
32
32
  action: "delete" | "add";
33
+ account_id?: number | undefined;
34
+ workspace_id?: string | undefined;
33
35
  confirm?: boolean | undefined;
34
36
  preview_id?: string | undefined;
35
- workspace_id?: string | undefined;
36
- account_id?: number | undefined;
37
37
  location_id?: string | undefined;
38
38
  category?: "COVER" | "PROFILE" | "LOGO" | "EXTERIOR" | "INTERIOR" | "PRODUCT" | "AT_WORK" | "FOOD_AND_DRINK" | "MENU" | "COMMON_AREA" | "ROOMS" | "TEAMS" | "ADDITIONAL" | undefined;
39
39
  source_url?: string | undefined;
@@ -41,10 +41,10 @@ export declare const manageGoogleBusinessMediaTool: {
41
41
  media_name?: string | undefined;
42
42
  }, {
43
43
  action: "delete" | "add";
44
+ account_id?: number | undefined;
45
+ workspace_id?: string | undefined;
44
46
  confirm?: boolean | undefined;
45
47
  preview_id?: string | undefined;
46
- workspace_id?: string | undefined;
47
- account_id?: number | undefined;
48
48
  location_id?: string | undefined;
49
49
  category?: "COVER" | "PROFILE" | "LOGO" | "EXTERIOR" | "INTERIOR" | "PRODUCT" | "AT_WORK" | "FOOD_AND_DRINK" | "MENU" | "COMMON_AREA" | "ROOMS" | "TEAMS" | "ADDITIONAL" | undefined;
50
50
  source_url?: string | undefined;
@@ -65,16 +65,16 @@ export declare const manageGoogleBusinessMediaTool: {
65
65
  confirm: true;
66
66
  category: "COVER" | "PROFILE" | "LOGO" | "EXTERIOR" | "INTERIOR" | "PRODUCT" | "AT_WORK" | "FOOD_AND_DRINK" | "MENU" | "COMMON_AREA" | "ROOMS" | "TEAMS" | "ADDITIONAL";
67
67
  source_url: string;
68
- workspace_id?: string | undefined;
69
68
  account_id?: number | undefined;
69
+ workspace_id?: string | undefined;
70
70
  location_id?: string | undefined;
71
71
  media_format?: "PHOTO" | "VIDEO" | undefined;
72
72
  }, {
73
73
  confirm: true;
74
74
  category: "COVER" | "PROFILE" | "LOGO" | "EXTERIOR" | "INTERIOR" | "PRODUCT" | "AT_WORK" | "FOOD_AND_DRINK" | "MENU" | "COMMON_AREA" | "ROOMS" | "TEAMS" | "ADDITIONAL";
75
75
  source_url: string;
76
- workspace_id?: string | undefined;
77
76
  account_id?: number | undefined;
77
+ workspace_id?: string | undefined;
78
78
  location_id?: string | undefined;
79
79
  media_format?: "PHOTO" | "VIDEO" | undefined;
80
80
  }>;
@@ -87,14 +87,14 @@ export declare const manageGoogleBusinessMediaTool: {
87
87
  }, "strip", z.ZodTypeAny, {
88
88
  confirm: true;
89
89
  media_name: string;
90
- workspace_id?: string | undefined;
91
90
  account_id?: number | undefined;
91
+ workspace_id?: string | undefined;
92
92
  location_id?: string | undefined;
93
93
  }, {
94
94
  confirm: true;
95
95
  media_name: string;
96
- workspace_id?: string | undefined;
97
96
  account_id?: number | undefined;
97
+ workspace_id?: string | undefined;
98
98
  location_id?: string | undefined;
99
99
  }>;
100
100
  };
@@ -37,10 +37,10 @@ export declare const manageGoogleBusinessReviewTool: {
37
37
  preview_id: z.ZodOptional<z.ZodString>;
38
38
  }, "strip", z.ZodTypeAny, {
39
39
  action: "suggest_reply" | "reply" | "delete_reply";
40
+ account_id?: number | undefined;
41
+ workspace_id?: string | undefined;
40
42
  confirm?: boolean | undefined;
41
43
  preview_id?: string | undefined;
42
- workspace_id?: string | undefined;
43
- account_id?: number | undefined;
44
44
  count?: number | undefined;
45
45
  location_id?: string | undefined;
46
46
  comment?: string | undefined;
@@ -52,10 +52,10 @@ export declare const manageGoogleBusinessReviewTool: {
52
52
  business_name?: string | undefined;
53
53
  }, {
54
54
  action: "suggest_reply" | "reply" | "delete_reply";
55
+ account_id?: number | undefined;
56
+ workspace_id?: string | undefined;
55
57
  confirm?: boolean | undefined;
56
58
  preview_id?: string | undefined;
57
- workspace_id?: string | undefined;
58
- account_id?: number | undefined;
59
59
  count?: number | undefined;
60
60
  location_id?: string | undefined;
61
61
  comment?: string | undefined;
@@ -80,8 +80,8 @@ export declare const manageGoogleBusinessReviewTool: {
80
80
  location_id: z.ZodOptional<z.ZodString>;
81
81
  }, "strip", z.ZodTypeAny, {
82
82
  star_rating: number;
83
- workspace_id?: string | undefined;
84
83
  account_id?: number | undefined;
84
+ workspace_id?: string | undefined;
85
85
  count?: number | undefined;
86
86
  location_id?: string | undefined;
87
87
  tone?: "professional" | "friendly" | "apologetic" | undefined;
@@ -90,8 +90,8 @@ export declare const manageGoogleBusinessReviewTool: {
90
90
  business_name?: string | undefined;
91
91
  }, {
92
92
  star_rating: number;
93
- workspace_id?: string | undefined;
94
93
  account_id?: number | undefined;
94
+ workspace_id?: string | undefined;
95
95
  count?: number | undefined;
96
96
  location_id?: string | undefined;
97
97
  tone?: "professional" | "friendly" | "apologetic" | undefined;
@@ -110,15 +110,15 @@ export declare const manageGoogleBusinessReviewTool: {
110
110
  confirm: true;
111
111
  comment: string;
112
112
  review_name: string;
113
- workspace_id?: string | undefined;
114
113
  account_id?: number | undefined;
114
+ workspace_id?: string | undefined;
115
115
  location_id?: string | undefined;
116
116
  }, {
117
117
  confirm: true;
118
118
  comment: string;
119
119
  review_name: string;
120
- workspace_id?: string | undefined;
121
120
  account_id?: number | undefined;
121
+ workspace_id?: string | undefined;
122
122
  location_id?: string | undefined;
123
123
  }>;
124
124
  delete_google_business_review_reply: z.ZodObject<{
@@ -130,14 +130,14 @@ export declare const manageGoogleBusinessReviewTool: {
130
130
  }, "strip", z.ZodTypeAny, {
131
131
  confirm: true;
132
132
  review_name: string;
133
- workspace_id?: string | undefined;
134
133
  account_id?: number | undefined;
134
+ workspace_id?: string | undefined;
135
135
  location_id?: string | undefined;
136
136
  }, {
137
137
  confirm: true;
138
138
  review_name: string;
139
- workspace_id?: string | undefined;
140
139
  account_id?: number | undefined;
140
+ workspace_id?: string | undefined;
141
141
  location_id?: string | undefined;
142
142
  }>;
143
143
  };
@@ -19,15 +19,15 @@ export declare const managePublishingPauseTool: {
19
19
  confirm: z.ZodOptional<z.ZodBoolean>;
20
20
  }, "strip", z.ZodTypeAny, {
21
21
  action: "pause" | "resume" | "publish_missed";
22
- confirm?: boolean | undefined;
23
22
  workspace_id?: string | undefined;
24
23
  brand_id?: string | undefined;
24
+ confirm?: boolean | undefined;
25
25
  post_ids?: number[] | undefined;
26
26
  }, {
27
27
  action: "pause" | "resume" | "publish_missed";
28
- confirm?: boolean | undefined;
29
28
  workspace_id?: string | undefined;
30
29
  brand_id?: string | undefined;
30
+ confirm?: boolean | undefined;
31
31
  post_ids?: number[] | undefined;
32
32
  }>;
33
33
  execute(client: PosterlyClient, input: ManagePublishingPauseInput, ctx: ToolContext): Promise<string>;
@@ -28,20 +28,20 @@ export declare const manageWebhookTool: {
28
28
  }, "strip", z.ZodTypeAny, {
29
29
  action: "update" | "delete" | "test";
30
30
  webhook_id: string;
31
+ workspace_id?: string | null | undefined;
31
32
  description?: string | null | undefined;
32
33
  confirm?: boolean | undefined;
33
34
  preview_id?: string | undefined;
34
- workspace_id?: string | null | undefined;
35
35
  url?: string | undefined;
36
36
  is_active?: boolean | undefined;
37
37
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced" | "approval.requested" | "approval.approved" | "approval.changes_requested" | "approval.rejected" | "approval.commented")[] | undefined;
38
38
  }, {
39
39
  action: "update" | "delete" | "test";
40
40
  webhook_id: string;
41
+ workspace_id?: string | null | undefined;
41
42
  description?: string | null | undefined;
42
43
  confirm?: boolean | undefined;
43
44
  preview_id?: string | undefined;
44
- workspace_id?: string | null | undefined;
45
45
  url?: string | undefined;
46
46
  is_active?: boolean | undefined;
47
47
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced" | "approval.requested" | "approval.approved" | "approval.changes_requested" | "approval.rejected" | "approval.commented")[] | undefined;
@@ -59,16 +59,16 @@ export declare const manageWebhookTool: {
59
59
  }, "strip", z.ZodTypeAny, {
60
60
  confirm: true;
61
61
  webhook_id: string;
62
- description?: string | null | undefined;
63
62
  workspace_id?: string | null | undefined;
63
+ description?: string | null | undefined;
64
64
  url?: string | undefined;
65
65
  is_active?: boolean | undefined;
66
66
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced" | "approval.requested" | "approval.approved" | "approval.changes_requested" | "approval.rejected" | "approval.commented")[] | undefined;
67
67
  }, {
68
68
  confirm: true;
69
69
  webhook_id: string;
70
- description?: string | null | undefined;
71
70
  workspace_id?: string | null | undefined;
71
+ description?: string | null | undefined;
72
72
  url?: string | undefined;
73
73
  is_active?: boolean | undefined;
74
74
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced" | "approval.requested" | "approval.approved" | "approval.changes_requested" | "approval.rejected" | "approval.commented")[] | undefined;
@@ -653,9 +653,9 @@ export declare const validatePostInputSchema: import("zod").ZodObject<{
653
653
  workspace_id: import("zod").ZodOptional<import("zod").ZodString>;
654
654
  }, "strip", import("zod").ZodTypeAny, {
655
655
  platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "gmb" | "google-business" | "google_business_profile" | undefined;
656
- username?: string | undefined;
657
- workspace_id?: string | undefined;
658
656
  account_id?: string | undefined;
657
+ workspace_id?: string | undefined;
658
+ username?: string | undefined;
659
659
  caption?: string | undefined;
660
660
  scheduled_at?: string | undefined;
661
661
  media_url?: string | undefined;
@@ -854,9 +854,9 @@ export declare const validatePostInputSchema: import("zod").ZodObject<{
854
854
  }, import("zod").ZodTypeAny, "passthrough"> | undefined;
855
855
  }, {
856
856
  platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "gmb" | "google-business" | "google_business_profile" | undefined;
857
- username?: string | undefined;
858
- workspace_id?: string | undefined;
859
857
  account_id?: string | undefined;
858
+ workspace_id?: string | undefined;
859
+ username?: string | undefined;
860
860
  caption?: string | undefined;
861
861
  scheduled_at?: string | undefined;
862
862
  media_url?: string | undefined;
@@ -1711,9 +1711,9 @@ export declare const validatePostTool: {
1711
1711
  workspace_id: import("zod").ZodOptional<import("zod").ZodString>;
1712
1712
  }, "strip", import("zod").ZodTypeAny, {
1713
1713
  platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "gmb" | "google-business" | "google_business_profile" | undefined;
1714
- username?: string | undefined;
1715
- workspace_id?: string | undefined;
1716
1714
  account_id?: string | undefined;
1715
+ workspace_id?: string | undefined;
1716
+ username?: string | undefined;
1717
1717
  caption?: string | undefined;
1718
1718
  scheduled_at?: string | undefined;
1719
1719
  media_url?: string | undefined;
@@ -1912,9 +1912,9 @@ export declare const validatePostTool: {
1912
1912
  }, import("zod").ZodTypeAny, "passthrough"> | undefined;
1913
1913
  }, {
1914
1914
  platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "gmb" | "google-business" | "google_business_profile" | undefined;
1915
- username?: string | undefined;
1916
- workspace_id?: string | undefined;
1917
1915
  account_id?: string | undefined;
1916
+ workspace_id?: string | undefined;
1917
+ username?: string | undefined;
1918
1918
  caption?: string | undefined;
1919
1919
  scheduled_at?: string | undefined;
1920
1920
  media_url?: string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posterly-mcp-server",
3
- "version": "0.48.5",
3
+ "version": "0.49.0",
4
4
  "mcpName": "io.github.awpthorp/posterly",
5
5
  "description": "MCP server for posterly: schedule and publish social media posts across 18 platforms from any MCP client (Claude, ChatGPT, Cursor, Windsurf, Cline, and more)",
6
6
  "license": "MIT",
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.awpthorp/posterly",
4
4
  "title": "posterly",
5
5
  "description": "Validate, schedule, publish, and analyze social content across 18 platforms with posterly.",
6
- "version": "0.48.5",
6
+ "version": "0.49.0",
7
7
  "websiteUrl": "https://www.poster.ly/mcp",
8
8
  "repository": {
9
9
  "url": "https://github.com/awpthorp/posterly",
@@ -14,7 +14,7 @@
14
14
  {
15
15
  "registryType": "npm",
16
16
  "identifier": "posterly-mcp-server",
17
- "version": "0.48.5",
17
+ "version": "0.49.0",
18
18
  "transport": {
19
19
  "type": "stdio"
20
20
  },
@@ -176,6 +176,11 @@ export interface PostSuggestion {
176
176
 
177
177
  export interface PostSuggestionsResponse {
178
178
  suggestions: PostSuggestion[];
179
+ total?: number;
180
+ limit?: number;
181
+ offset?: number;
182
+ has_more?: boolean;
183
+ next_offset?: number | null;
179
184
  }
180
185
 
181
186
  export interface DismissSuggestionResponse {
@@ -216,6 +221,63 @@ export interface Post {
216
221
  approval?: ApiPostApproval;
217
222
  }
218
223
 
224
+ /** Filters shared by GET /posts and GET /posts/counts. */
225
+ export interface ListPostsParams {
226
+ status?: string;
227
+ platform?: string;
228
+ account_id?: string;
229
+ workspace_id?: string;
230
+ approval_status?: string;
231
+ approval_waiting_on?: string;
232
+ brand_id?: string;
233
+ scheduled_from?: string;
234
+ scheduled_to?: string;
235
+ timezone?: string;
236
+ }
237
+
238
+ export interface PostsRangeEcho {
239
+ from: string | null;
240
+ to: string | null;
241
+ timezone: string;
242
+ }
243
+
244
+ export interface ListPostsResponse {
245
+ posts: Post[];
246
+ total: number;
247
+ limit?: number;
248
+ offset?: number;
249
+ has_more?: boolean;
250
+ next_offset?: number | null;
251
+ order?: 'asc' | 'desc';
252
+ range?: PostsRangeEcho | null;
253
+ }
254
+
255
+ export interface PostCountsResponse {
256
+ total: number;
257
+ counted: number;
258
+ truncated: boolean;
259
+ range: PostsRangeEcho | null;
260
+ by_day: Array<{ date: string; count: number }>;
261
+ by_status: Array<{ status: string; count: number }>;
262
+ by_account: Array<{ account_id: string | null; platform: string | null; username: string | null; count: number }>;
263
+ by_brand: Array<{ brand_id: string | null; name: string | null; count: number }>;
264
+ }
265
+
266
+ function postFilterParams(params?: ListPostsParams): URLSearchParams {
267
+ const searchParams = new URLSearchParams();
268
+ if (params?.status) searchParams.set('status', params.status);
269
+ if (params?.platform) searchParams.set('platform', params.platform);
270
+ if (params?.account_id) searchParams.set('account_id', params.account_id);
271
+ if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
272
+ if (params?.approval_status) searchParams.set('approval_status', params.approval_status);
273
+ if (params?.approval_waiting_on) searchParams.set('approval_waiting_on', params.approval_waiting_on);
274
+ if (params?.brand_id) searchParams.set('brand_id', params.brand_id);
275
+ if (params?.scheduled_from) searchParams.set('scheduled_from', params.scheduled_from);
276
+ if (params?.scheduled_to) searchParams.set('scheduled_to', params.scheduled_to);
277
+ if (params?.timezone) searchParams.set('timezone', params.timezone);
278
+ return searchParams;
279
+ }
280
+
219
281
  export interface InstagramPostSettings {
220
282
  __type?: 'instagram' | 'instagram-standalone';
221
283
  post_type?: 'post' | 'feed' | 'story' | 'reel' | 'carousel';
@@ -930,8 +992,12 @@ export interface ActivityItem {
930
992
 
931
993
  export interface ActivityResponse {
932
994
  items: ActivityItem[];
995
+ /** Items on this page (kept for older clients); use has_more to tell whether more exist. */
933
996
  total: number;
934
997
  limit: number;
998
+ offset?: number;
999
+ has_more?: boolean;
1000
+ next_offset?: number | null;
935
1001
  }
936
1002
 
937
1003
  export interface UpdateEntry {
@@ -950,6 +1016,11 @@ export interface UpdateEntry {
950
1016
 
951
1017
  export interface UpdatesResponse {
952
1018
  updates: UpdateEntry[];
1019
+ total?: number;
1020
+ limit?: number;
1021
+ offset?: number;
1022
+ has_more?: boolean;
1023
+ next_offset?: number | null;
953
1024
  }
954
1025
 
955
1026
  export interface ApiWebhook {
@@ -1647,11 +1718,13 @@ export class PosterlyClient {
1647
1718
  account_id?: string | number;
1648
1719
  status?: 'pending' | 'scheduled' | 'dismissed';
1649
1720
  limit?: number;
1721
+ offset?: number;
1650
1722
  }): Promise<PostSuggestionsResponse> {
1651
1723
  const searchParams = new URLSearchParams();
1652
1724
  if (params?.account_id) searchParams.set('account_id', String(params.account_id));
1653
1725
  if (params?.status) searchParams.set('status', params.status);
1654
1726
  if (params?.limit) searchParams.set('limit', String(params.limit));
1727
+ if (params?.offset) searchParams.set('offset', String(params.offset));
1655
1728
  const qs = searchParams.toString();
1656
1729
  return this.request('GET', `/suggestions${qs ? `?${qs}` : ''}`);
1657
1730
  }
@@ -1660,32 +1733,26 @@ export class PosterlyClient {
1660
1733
  return this.request('POST', `/suggestions/${encodeURIComponent(id)}/dismiss`, {});
1661
1734
  }
1662
1735
 
1663
- async listPosts(params?: {
1664
- status?: string;
1665
- platform?: string;
1666
- account_id?: string;
1736
+ async listPosts(params?: ListPostsParams & {
1667
1737
  limit?: number;
1668
1738
  offset?: number;
1669
- workspace_id?: string;
1670
- approval_status?: string;
1671
- approval_waiting_on?: string;
1672
- brand_id?: string;
1673
- }): Promise<{ posts: Post[]; total: number }> {
1674
- const searchParams = new URLSearchParams();
1675
- if (params?.status) searchParams.set('status', params.status);
1676
- if (params?.platform) searchParams.set('platform', params.platform);
1677
- if (params?.account_id) searchParams.set('account_id', params.account_id);
1739
+ order?: 'asc' | 'desc';
1740
+ }): Promise<ListPostsResponse> {
1741
+ const searchParams = postFilterParams(params);
1678
1742
  if (params?.limit) searchParams.set('limit', String(params.limit));
1679
1743
  if (params?.offset) searchParams.set('offset', String(params.offset));
1680
- if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
1681
- if (params?.approval_status) searchParams.set('approval_status', params.approval_status);
1682
- if (params?.approval_waiting_on) searchParams.set('approval_waiting_on', params.approval_waiting_on);
1683
- if (params?.brand_id) searchParams.set('brand_id', params.brand_id);
1744
+ if (params?.order) searchParams.set('order', params.order);
1684
1745
 
1685
1746
  const qs = searchParams.toString();
1686
1747
  return this.request('GET', `/posts${qs ? `?${qs}` : ''}`);
1687
1748
  }
1688
1749
 
1750
+ /** GET /posts/counts: exact totals per day, status, account, and brand for a scheduled range. */
1751
+ async countPosts(params: ListPostsParams): Promise<PostCountsResponse> {
1752
+ const qs = postFilterParams(params).toString();
1753
+ return this.request('GET', `/posts/counts${qs ? `?${qs}` : ''}`);
1754
+ }
1755
+
1689
1756
  async createPost(data: CreatePostPayload): Promise<CreatePostResponse> {
1690
1757
  return this.request('POST', '/posts', data);
1691
1758
  }
@@ -2053,6 +2120,7 @@ export class PosterlyClient {
2053
2120
  since?: string;
2054
2121
  type?: 'all' | 'activity' | 'publish';
2055
2122
  limit?: number;
2123
+ offset?: number;
2056
2124
  }): Promise<ActivityResponse> {
2057
2125
  const searchParams = new URLSearchParams();
2058
2126
  if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
@@ -2060,17 +2128,20 @@ export class PosterlyClient {
2060
2128
  if (params?.since) searchParams.set('since', params.since);
2061
2129
  if (params?.type) searchParams.set('type', params.type);
2062
2130
  if (params?.limit) searchParams.set('limit', String(params.limit));
2131
+ if (params?.offset) searchParams.set('offset', String(params.offset));
2063
2132
  const qs = searchParams.toString();
2064
2133
  return this.request('GET', `/activity${qs ? `?${qs}` : ''}`);
2065
2134
  }
2066
2135
 
2067
2136
  async getUpdates(params?: {
2068
2137
  limit?: number;
2138
+ offset?: number;
2069
2139
  since?: string;
2070
2140
  include_content?: boolean;
2071
2141
  }): Promise<UpdatesResponse> {
2072
2142
  const searchParams = new URLSearchParams();
2073
2143
  if (params?.limit) searchParams.set('limit', String(params.limit));
2144
+ if (params?.offset) searchParams.set('offset', String(params.offset));
2074
2145
  if (params?.since) searchParams.set('since', params.since);
2075
2146
  if (params?.include_content) searchParams.set('include_content', 'true');
2076
2147
  const qs = searchParams.toString();
@@ -2193,6 +2264,7 @@ export class PosterlyClient {
2193
2264
 
2194
2265
  async listMedia(params?: {
2195
2266
  limit?: number;
2267
+ offset?: number;
2196
2268
  dropSessionId?: string;
2197
2269
  }): Promise<{
2198
2270
  media: Array<{
@@ -2206,9 +2278,14 @@ export class PosterlyClient {
2206
2278
  drop_session_id: string | null;
2207
2279
  }>;
2208
2280
  total: number;
2281
+ limit?: number;
2282
+ offset?: number;
2283
+ has_more?: boolean;
2284
+ next_offset?: number | null;
2209
2285
  }> {
2210
2286
  const searchParams = new URLSearchParams();
2211
2287
  if (params?.limit) searchParams.set('limit', String(params.limit));
2288
+ if (params?.offset) searchParams.set('offset', String(params.offset));
2212
2289
  if (params?.dropSessionId) searchParams.set('drop_session_id', params.dropSessionId);
2213
2290
  const qs = searchParams.toString();
2214
2291
  return this.request('GET', `/media${qs ? `?${qs}` : ''}`);