posterly-mcp-server 0.43.2 → 0.43.4

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 CHANGED
@@ -122,7 +122,7 @@ Add the same server definition to your Cursor MCP settings:
122
122
 
123
123
  ## Available tools
124
124
 
125
- `posterly-mcp-server@0.43.2` exposes 90 tools.
125
+ `posterly-mcp-server@0.43.4` exposes 90 tools.
126
126
 
127
127
  Public setup tools work before `POSTERLY_API_KEY` exists:
128
128
 
@@ -128,6 +128,15 @@ export interface DismissSuggestionResponse {
128
128
  ok: boolean;
129
129
  status: string;
130
130
  }
131
+ export type ApiPostApprovalStatus = 'none' | 'pending_client' | 'approved' | 'changes_requested' | 'rejected';
132
+ export interface ApiPostApproval {
133
+ status: ApiPostApprovalStatus;
134
+ asset_status: ApiPostApprovalStatus;
135
+ caption_status: ApiPostApprovalStatus;
136
+ waiting_on: 'client' | 'team' | null;
137
+ requested_at: string | null;
138
+ completed_at: string | null;
139
+ }
131
140
  export interface Post {
132
141
  id: number;
133
142
  content: string;
@@ -144,6 +153,9 @@ export interface Post {
144
153
  reel_cover_url?: string | null;
145
154
  reel_cover_method?: string | null;
146
155
  reel_thumb_offset?: number | null;
156
+ brand_id?: string | null;
157
+ content_plan_id?: string | null;
158
+ approval?: ApiPostApproval;
147
159
  }
148
160
  export interface InstagramPostSettings {
149
161
  __type?: 'instagram' | 'instagram-standalone';
@@ -842,6 +854,31 @@ export interface PublicSignupAgentPay {
842
854
  requires_tos_acceptance?: boolean;
843
855
  [key: string]: unknown;
844
856
  }
857
+ export interface PublicSignupPaymentAgentWalletSpendRequest {
858
+ merchant_name?: string;
859
+ merchant_url?: string;
860
+ amount?: number | null;
861
+ currency?: string;
862
+ context?: string;
863
+ }
864
+ export interface PublicSignupPaymentAgentWallet {
865
+ supported?: boolean;
866
+ how?: string;
867
+ spend_request?: PublicSignupPaymentAgentWalletSpendRequest;
868
+ }
869
+ export interface PublicSignupPayment {
870
+ amount?: number | null;
871
+ currency?: string;
872
+ amount_display?: string | null;
873
+ billing?: string;
874
+ description?: string;
875
+ merchant_name?: string;
876
+ merchant_url?: string;
877
+ checkout_redirect_url?: string;
878
+ pay_with?: string;
879
+ agent_wallet?: PublicSignupPaymentAgentWallet;
880
+ [key: string]: unknown;
881
+ }
845
882
  export interface PublicSignupSession {
846
883
  id: string;
847
884
  status: string;
@@ -858,6 +895,7 @@ export interface PublicSignupSession {
858
895
  account?: Record<string, unknown>;
859
896
  billing?: Record<string, unknown>;
860
897
  agent_pay?: PublicSignupAgentPay | null;
898
+ payment?: PublicSignupPayment | null;
861
899
  links?: Record<string, unknown>;
862
900
  created_at?: string;
863
901
  updated_at?: string;
@@ -878,6 +916,7 @@ export interface PublicSignupResponse {
878
916
  account?: Record<string, unknown>;
879
917
  billing?: Record<string, unknown>;
880
918
  agent_pay?: PublicSignupAgentPay | null;
919
+ payment?: PublicSignupPayment | null;
881
920
  [key: string]: unknown;
882
921
  }
883
922
  export interface PublicSignupSessionResponse {
@@ -1063,6 +1102,8 @@ export declare class PosterlyClient {
1063
1102
  limit?: number;
1064
1103
  offset?: number;
1065
1104
  workspace_id?: string;
1105
+ approval_status?: string;
1106
+ brand_id?: string;
1066
1107
  }): Promise<{
1067
1108
  posts: Post[];
1068
1109
  total: number;
@@ -257,6 +257,10 @@ export class PosterlyClient {
257
257
  searchParams.set('offset', String(params.offset));
258
258
  if (params?.workspace_id)
259
259
  searchParams.set('workspace_id', params.workspace_id);
260
+ if (params?.approval_status)
261
+ searchParams.set('approval_status', params.approval_status);
262
+ if (params?.brand_id)
263
+ searchParams.set('brand_id', params.brand_id);
260
264
  const qs = searchParams.toString();
261
265
  return this.request('GET', `/posts${qs ? `?${qs}` : ''}`);
262
266
  }
@@ -1 +1 @@
1
- export declare const POSTERLY_MCP_VERSION = "0.43.2";
1
+ export declare const POSTERLY_MCP_VERSION = "0.43.4";
@@ -5,4 +5,4 @@
5
5
  // tool set (minus the intentional pre-auth signup tools that only this stdio
6
6
  // package exposes). `npm run check:mcp-parity` enforces both the version match
7
7
  // and the tool-list match, and runs in the pre-commit hook.
8
- export const POSTERLY_MCP_VERSION = '0.43.2';
8
+ export const POSTERLY_MCP_VERSION = '0.43.4';
@@ -5,7 +5,7 @@ export declare const createWebhookTool: {
5
5
  description: string;
6
6
  inputSchema: z.ZodObject<{
7
7
  url: z.ZodString;
8
- events: z.ZodOptional<z.ZodArray<z.ZodEnum<["webhook.test", "post.created", "post.updated", "post.deleted", "post.publishing", "post.published", "post.failed", "account.disconnected", "analytics.synced"]>, "many">>;
8
+ events: z.ZodOptional<z.ZodArray<z.ZodEnum<["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"]>, "many">>;
9
9
  workspace_id: z.ZodOptional<z.ZodString>;
10
10
  description: z.ZodOptional<z.ZodString>;
11
11
  is_active: z.ZodOptional<z.ZodBoolean>;
@@ -13,16 +13,16 @@ export declare const createWebhookTool: {
13
13
  }, "strip", z.ZodTypeAny, {
14
14
  url: string;
15
15
  confirm: true;
16
- workspace_id?: string | undefined;
17
16
  description?: string | undefined;
18
- events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
17
+ workspace_id?: string | undefined;
18
+ 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;
19
19
  is_active?: boolean | undefined;
20
20
  }, {
21
21
  url: string;
22
22
  confirm: true;
23
- workspace_id?: string | undefined;
24
23
  description?: string | undefined;
25
- events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
24
+ workspace_id?: string | undefined;
25
+ 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;
26
26
  is_active?: boolean | undefined;
27
27
  }>;
28
28
  execute(client: PosterlyClient, input: {
@@ -30,7 +30,8 @@ export const getAgentSignupInfoTool = {
30
30
  '- Do not narrate raw curl, HTTP, JSON, API keys, or implementation details unless the user explicitly asks for debugging.',
31
31
  '',
32
32
  'Boundaries:',
33
- '- Payment can be a one-time Link Agent Wallet virtual card (credential_type: card) on the prepaid PaymentIntent, or Stripe Checkout in the browser.',
33
+ '- Payment happens on Stripe Checkout, either by the user in their browser or by the agent with its own approved payment credential (for example a Link agent wallet); never card details in chat.',
34
+ '- Where enabled, payment can instead be a one-time Link Agent Wallet virtual card (credential_type: card) on a prepaid PaymentIntent.',
34
35
  '- Never send card numbers to posterly. Confirm the PaymentIntent with Stripe, or send checkout_redirect_url.',
35
36
  '- The user sets their Posterly password in their browser.',
36
37
  '- The user approves social OAuth in their browser.',
@@ -24,6 +24,7 @@ function formatSignupSession(session, includeRaw) {
24
24
  const passwordUrl = stringFromRecord(session.links, 'password_setup_url');
25
25
  const completeUrl = stringFromRecord(session.links, 'complete_url');
26
26
  const agentPay = session.agent_pay;
27
+ const payment = session.payment;
27
28
  const lines = [
28
29
  `Posterly signup session: ${session.id}`,
29
30
  `Status: ${session.status}`,
@@ -36,6 +37,12 @@ function formatSignupSession(session, includeRaw) {
36
37
  agentPay?.requires_tos_acceptance ? 'Terms acceptance required before client_secret is released.' : '',
37
38
  agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
38
39
  agentPay?.confirm_url ? `Confirm URL: ${agentPay.confirm_url}` : '',
40
+ !agentPay?.enabled && payment?.amount_display
41
+ ? `Amount due: ${payment.amount_display} ${String(payment.currency || 'usd').toUpperCase()} to ${payment.merchant_name || 'posterly'} (${payment.billing || 'subscription'})`
42
+ : '',
43
+ !agentPay?.enabled && payment?.agent_wallet?.how
44
+ ? `Agent wallet option: ${payment.agent_wallet.how}`
45
+ : '',
39
46
  checkoutRedirectUrl ? `Checkout handoff URL: ${checkoutRedirectUrl}` : '',
40
47
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
41
48
  passwordUrl ? `Password setup URL: ${passwordUrl}` : '',
@@ -61,7 +68,7 @@ function guidanceForStatus(status, agentPayAvailable = false, requiresTosAccepta
61
68
  }
62
69
  return agentPayAvailable
63
70
  ? 'Payment is still pending. Confirm the prepaid PaymentIntent with a Link virtual card (credential_type: card), or send the user the Checkout handoff URL. Keep polling; never ask for card numbers.'
64
- : 'Tell the user checkout is still pending. Keep polling; do not ask for card details.';
71
+ : 'Tell the user checkout is still pending. If you hold an approved payment credential such as a Link agent wallet, you may pay the Checkout handoff URL yourself instead of asking the user; otherwise keep polling. Never ask for card details.';
65
72
  case 'checkout_expired':
66
73
  return 'Tell the user checkout expired and offer to call start_signup again.';
67
74
  case 'payment_confirmed':
@@ -9,18 +9,24 @@ export declare const listPostsTool: {
9
9
  account_id: z.ZodOptional<z.ZodString>;
10
10
  limit: z.ZodOptional<z.ZodNumber>;
11
11
  workspace_id: z.ZodOptional<z.ZodString>;
12
+ approval_status: z.ZodOptional<z.ZodEnum<["none", "pending_client", "approved", "changes_requested", "rejected"]>>;
13
+ brand_id: z.ZodOptional<z.ZodString>;
12
14
  }, "strip", z.ZodTypeAny, {
13
15
  platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "slack" | "mastodon" | "devto" | "hashnode" | "wordpress" | "lemmy" | "gmb" | "google-business" | "google_business_profile" | undefined;
14
16
  status?: string | undefined;
15
17
  workspace_id?: string | undefined;
16
18
  account_id?: string | undefined;
17
19
  limit?: number | undefined;
20
+ approval_status?: "none" | "pending_client" | "approved" | "changes_requested" | "rejected" | undefined;
21
+ brand_id?: string | undefined;
18
22
  }, {
19
23
  platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "slack" | "mastodon" | "devto" | "hashnode" | "wordpress" | "lemmy" | "gmb" | "google-business" | "google_business_profile" | undefined;
20
24
  status?: string | undefined;
21
25
  workspace_id?: string | undefined;
22
26
  account_id?: string | undefined;
23
27
  limit?: number | undefined;
28
+ approval_status?: "none" | "pending_client" | "approved" | "changes_requested" | "rejected" | undefined;
29
+ brand_id?: string | undefined;
24
30
  }>;
25
31
  execute(client: PosterlyClient, input: {
26
32
  status?: string;
@@ -28,5 +34,7 @@ export declare const listPostsTool: {
28
34
  account_id?: string;
29
35
  limit?: number;
30
36
  workspace_id?: string;
37
+ approval_status?: string;
38
+ brand_id?: string;
31
39
  }): Promise<string>;
32
40
  };
@@ -3,7 +3,7 @@ import { dashboardUrlForPostList, formatLocalDateTime, truncateText } from '../l
3
3
  import { SUPPORTED_PLATFORM_INPUTS, SUPPORTED_PLATFORM_IDS } from '../generated/platform-manifest.js';
4
4
  export const listPostsTool = {
5
5
  name: 'list_posts',
6
- description: 'List upcoming or recent posts. Filter by status (scheduled, published, failed, draft), platform, account_id, or workspace_id. If workspace_id is omitted, posts across every workspace the caller is a member of are returned.',
6
+ description: 'List upcoming or recent posts. Filter by status (scheduled, published, failed, draft), platform, account_id, workspace_id, approval_status, or brand_id. If workspace_id is omitted, posts across every workspace the caller is a member of are returned.',
7
7
  inputSchema: z.object({
8
8
  status: z
9
9
  .string()
@@ -27,6 +27,14 @@ export const listPostsTool = {
27
27
  .string()
28
28
  .optional()
29
29
  .describe('Filter to posts in a specific workspace (get IDs via whoami).'),
30
+ approval_status: z
31
+ .enum(['none', 'pending_client', 'approved', 'changes_requested', 'rejected'])
32
+ .optional()
33
+ .describe('Filter by client review approval status. pending_client means the post is waiting on the client.'),
34
+ brand_id: z
35
+ .string()
36
+ .optional()
37
+ .describe('Filter to posts assigned to a specific brand/client (the id from list_brands).'),
30
38
  }),
31
39
  async execute(client, input) {
32
40
  const { posts, total } = await client.listPosts({
@@ -39,7 +47,18 @@ export const listPostsTool = {
39
47
  const lines = posts.map((p) => {
40
48
  const date = formatLocalDateTime(p.scheduled_at);
41
49
  const caption = truncateText(p.content, 60);
42
- return `• [${p.status}] #${p.id}: ${caption} (${date})`;
50
+ const approvalBits = [];
51
+ if (p.approval && p.approval.status !== 'none') {
52
+ approvalBits.push(`approval: ${p.approval.status}`);
53
+ if (p.approval.waiting_on)
54
+ approvalBits.push(`waiting on: ${p.approval.waiting_on}`);
55
+ }
56
+ if (p.brand_id)
57
+ approvalBits.push(`brand: ${p.brand_id}`);
58
+ if (p.content_plan_id)
59
+ approvalBits.push(`plan: ${p.content_plan_id}`);
60
+ const approvalSuffix = approvalBits.length > 0 ? ` [${approvalBits.join(', ')}]` : '';
61
+ return `• [${p.status}] #${p.id}: ${caption} (${date})${approvalSuffix}`;
43
62
  });
44
63
  return [
45
64
  `Posts (${posts.length} of ${total}):`,
@@ -70,6 +70,7 @@ function formatSignupStart(response, includeRaw) {
70
70
  const status = session?.status || response.status || 'checkout_pending';
71
71
  const message = session?.status_message || response.status_message;
72
72
  const agentPay = response.agent_pay || session?.agent_pay;
73
+ const payment = response.payment || session?.payment;
73
74
  const lines = [
74
75
  'Posterly signup started.',
75
76
  sessionId ? `Signup session: ${sessionId}` : '',
@@ -83,6 +84,12 @@ function formatSignupStart(response, includeRaw) {
83
84
  agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
84
85
  agentPay?.confirm_url ? `Confirm URL: ${agentPay.confirm_url}` : '',
85
86
  agentPay?.pay_instructions ? `Pay instructions: ${agentPay.pay_instructions}` : '',
87
+ !agentPay?.enabled && payment?.amount_display
88
+ ? `Amount due: ${payment.amount_display} ${String(payment.currency || 'usd').toUpperCase()} to ${payment.merchant_name || 'posterly'} (${payment.billing || 'subscription'})`
89
+ : '',
90
+ !agentPay?.enabled && payment?.agent_wallet?.how
91
+ ? `Agent wallet option: ${payment.agent_wallet.how}`
92
+ : '',
86
93
  checkoutRedirectUrl ? `Checkout handoff URL (browser fallback): ${checkoutRedirectUrl}` : '',
87
94
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
88
95
  pollUrl ? `Poll URL: ${pollUrl}` : '',
@@ -107,11 +114,12 @@ function formatSignupStart(response, includeRaw) {
107
114
  '6. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
108
115
  ]
109
116
  : [
110
- '1. Send the Checkout handoff URL to the user so they can pay securely in their browser. Use the raw Stripe checkout URL only if you preserve the full URL including any fragment. posterly does not email this link, so do not tell the user to check their inbox at this stage.',
111
- '2. Call get_signup_session with the signup session ID until the status changes.',
112
- '3. Tell the user when Posterly sends the password setup email.',
113
- '4. If status becomes agent_access_required, ask the user to install or paste the Posterly MCP/API setup instructions into this trusted AI chat, then onboard them in this conversation (about you, connect, brand voice, first post). Do not send them to /onboarding-v2.',
114
- '5. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
117
+ '1. If you hold an approved payment credential such as a Link agent wallet, you can pay the Checkout handoff URL yourself: create a spend request for the amount and merchant above, get the user\'s approval in the wallet, then complete the Checkout page with that credential. Never paste card numbers into chat or send them to posterly.',
118
+ '2. Otherwise, send the Checkout handoff URL to the user so they can pay securely in their browser. Use the raw Stripe checkout URL only if you preserve the full URL including any fragment. posterly does not email this link, so do not tell the user to check their inbox at this stage.',
119
+ '3. Call get_signup_session with the signup session ID until the status changes.',
120
+ '4. Tell the user when Posterly sends the password setup email.',
121
+ '5. If status becomes agent_access_required, ask the user to install or paste the Posterly MCP/API setup instructions into this trusted AI chat, then onboard them in this conversation (about you, connect, brand voice, first post). Do not send them to /onboarding-v2.',
122
+ '6. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
115
123
  ]),
116
124
  includeRaw ? `\nRaw signup response:\n${JSON.stringify(response, null, 2)}` : '',
117
125
  ];
@@ -27,8 +27,8 @@ export declare const submitAgentFeedbackInputSchema: z.ZodObject<{
27
27
  source: "mcp" | "cli" | "rest" | "skill";
28
28
  tool: string;
29
29
  outcome: "success" | "error" | "abandoned";
30
- error_code?: string | undefined;
31
30
  client?: string | undefined;
31
+ error_code?: string | undefined;
32
32
  comment?: string | undefined;
33
33
  context?: {
34
34
  request_id?: string | undefined;
@@ -40,8 +40,8 @@ export declare const submitAgentFeedbackInputSchema: z.ZodObject<{
40
40
  source: "mcp" | "cli" | "rest" | "skill";
41
41
  tool: string;
42
42
  outcome: "success" | "error" | "abandoned";
43
- error_code?: string | undefined;
44
43
  client?: string | undefined;
44
+ error_code?: string | undefined;
45
45
  comment?: string | undefined;
46
46
  context?: {
47
47
  request_id?: string | undefined;
@@ -81,8 +81,8 @@ export declare const submitAgentFeedbackTool: {
81
81
  source: "mcp" | "cli" | "rest" | "skill";
82
82
  tool: string;
83
83
  outcome: "success" | "error" | "abandoned";
84
- error_code?: string | undefined;
85
84
  client?: string | undefined;
85
+ error_code?: string | undefined;
86
86
  comment?: string | undefined;
87
87
  context?: {
88
88
  request_id?: string | undefined;
@@ -94,8 +94,8 @@ export declare const submitAgentFeedbackTool: {
94
94
  source: "mcp" | "cli" | "rest" | "skill";
95
95
  tool: string;
96
96
  outcome: "success" | "error" | "abandoned";
97
- error_code?: string | undefined;
98
97
  client?: string | undefined;
98
+ error_code?: string | undefined;
99
99
  comment?: string | undefined;
100
100
  context?: {
101
101
  request_id?: string | undefined;
@@ -21,9 +21,9 @@ export declare const submitProductFeedbackInputSchema: z.ZodObject<{
21
21
  title: string;
22
22
  confirm: true;
23
23
  category: "bug" | "idea" | "feedback";
24
+ client?: string | undefined;
24
25
  description?: string | undefined;
25
26
  source?: "mcp" | "cli" | "rest" | "skill" | undefined;
26
- client?: string | undefined;
27
27
  context?: {
28
28
  request_id?: string | undefined;
29
29
  related_tool?: string | undefined;
@@ -32,9 +32,9 @@ export declare const submitProductFeedbackInputSchema: z.ZodObject<{
32
32
  title: string;
33
33
  confirm: true;
34
34
  category: "bug" | "idea" | "feedback";
35
+ client?: string | undefined;
35
36
  description?: string | undefined;
36
37
  source?: "mcp" | "cli" | "rest" | "skill" | undefined;
37
- client?: string | undefined;
38
38
  context?: {
39
39
  request_id?: string | undefined;
40
40
  related_tool?: string | undefined;
@@ -65,9 +65,9 @@ export declare const submitProductFeedbackTool: {
65
65
  title: string;
66
66
  confirm: true;
67
67
  category: "bug" | "idea" | "feedback";
68
+ client?: string | undefined;
68
69
  description?: string | undefined;
69
70
  source?: "mcp" | "cli" | "rest" | "skill" | undefined;
70
- client?: string | undefined;
71
71
  context?: {
72
72
  request_id?: string | undefined;
73
73
  related_tool?: string | undefined;
@@ -76,9 +76,9 @@ export declare const submitProductFeedbackTool: {
76
76
  title: string;
77
77
  confirm: true;
78
78
  category: "bug" | "idea" | "feedback";
79
+ client?: string | undefined;
79
80
  description?: string | undefined;
80
81
  source?: "mcp" | "cli" | "rest" | "skill" | undefined;
81
- client?: string | undefined;
82
82
  context?: {
83
83
  request_id?: string | undefined;
84
84
  related_tool?: string | undefined;
@@ -6,7 +6,7 @@ export declare const updateWebhookTool: {
6
6
  inputSchema: z.ZodObject<{
7
7
  webhook_id: z.ZodString;
8
8
  url: z.ZodOptional<z.ZodString>;
9
- events: z.ZodOptional<z.ZodArray<z.ZodEnum<["webhook.test", "post.created", "post.updated", "post.deleted", "post.publishing", "post.published", "post.failed", "account.disconnected", "analytics.synced"]>, "many">>;
9
+ events: z.ZodOptional<z.ZodArray<z.ZodEnum<["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"]>, "many">>;
10
10
  workspace_id: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNull]>>;
11
11
  description: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNull]>>;
12
12
  is_active: z.ZodOptional<z.ZodBoolean>;
@@ -14,18 +14,18 @@ export declare const updateWebhookTool: {
14
14
  }, "strip", z.ZodTypeAny, {
15
15
  confirm: true;
16
16
  webhook_id: string;
17
+ description?: string | null | undefined;
17
18
  workspace_id?: string | null | undefined;
18
19
  url?: string | undefined;
19
- description?: string | null | undefined;
20
- events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
20
+ 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;
21
21
  is_active?: boolean | undefined;
22
22
  }, {
23
23
  confirm: true;
24
24
  webhook_id: string;
25
+ description?: string | null | undefined;
25
26
  workspace_id?: string | null | undefined;
26
27
  url?: string | undefined;
27
- description?: string | null | undefined;
28
- events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
28
+ 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;
29
29
  is_active?: boolean | undefined;
30
30
  }>;
31
31
  execute(client: PosterlyClient, input: {
@@ -1,3 +1,3 @@
1
1
  import { z } from 'zod';
2
- export declare const WEBHOOK_EVENTS: readonly ["webhook.test", "post.created", "post.updated", "post.deleted", "post.publishing", "post.published", "post.failed", "account.disconnected", "analytics.synced"];
3
- export declare const webhookEventSchema: z.ZodEnum<["webhook.test", "post.created", "post.updated", "post.deleted", "post.publishing", "post.published", "post.failed", "account.disconnected", "analytics.synced"]>;
2
+ export declare const WEBHOOK_EVENTS: readonly ["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"];
3
+ export declare const webhookEventSchema: z.ZodEnum<["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"]>;
@@ -9,5 +9,10 @@ export const WEBHOOK_EVENTS = [
9
9
  'post.failed',
10
10
  'account.disconnected',
11
11
  'analytics.synced',
12
+ 'approval.requested',
13
+ 'approval.approved',
14
+ 'approval.changes_requested',
15
+ 'approval.rejected',
16
+ 'approval.commented',
12
17
  ];
13
18
  export const webhookEventSchema = z.enum(WEBHOOK_EVENTS);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posterly-mcp-server",
3
- "version": "0.43.2",
3
+ "version": "0.43.4",
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.43.2",
6
+ "version": "0.43.4",
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.43.2",
17
+ "version": "0.43.4",
18
18
  "transport": {
19
19
  "type": "stdio"
20
20
  },
@@ -138,6 +138,17 @@ export interface DismissSuggestionResponse {
138
138
  status: string;
139
139
  }
140
140
 
141
+ export type ApiPostApprovalStatus = 'none' | 'pending_client' | 'approved' | 'changes_requested' | 'rejected';
142
+
143
+ export interface ApiPostApproval {
144
+ status: ApiPostApprovalStatus;
145
+ asset_status: ApiPostApprovalStatus;
146
+ caption_status: ApiPostApprovalStatus;
147
+ waiting_on: 'client' | 'team' | null;
148
+ requested_at: string | null;
149
+ completed_at: string | null;
150
+ }
151
+
141
152
  export interface Post {
142
153
  id: number;
143
154
  content: string;
@@ -154,6 +165,9 @@ export interface Post {
154
165
  reel_cover_url?: string | null;
155
166
  reel_cover_method?: string | null;
156
167
  reel_thumb_offset?: number | null;
168
+ brand_id?: string | null;
169
+ content_plan_id?: string | null;
170
+ approval?: ApiPostApproval;
157
171
  }
158
172
 
159
173
  export interface InstagramPostSettings {
@@ -878,6 +892,38 @@ export interface PublicSignupAgentPay {
878
892
  [key: string]: unknown;
879
893
  }
880
894
 
895
+ export interface PublicSignupPaymentAgentWalletSpendRequest {
896
+ merchant_name?: string;
897
+ merchant_url?: string;
898
+ amount?: number | null;
899
+ currency?: string;
900
+ context?: string;
901
+ }
902
+
903
+ export interface PublicSignupPaymentAgentWallet {
904
+ supported?: boolean;
905
+ how?: string;
906
+ spend_request?: PublicSignupPaymentAgentWalletSpendRequest;
907
+ }
908
+
909
+ // Always present while checkout is open, regardless of agent_pay/ENABLE_AGENT_CARD_PAY.
910
+ // Describes the Stripe-hosted Checkout session itself so an agent with its own
911
+ // approved payment credential (for example a Link agent wallet) can pay it
912
+ // directly. null once payment is confirmed or checkout has expired.
913
+ export interface PublicSignupPayment {
914
+ amount?: number | null;
915
+ currency?: string;
916
+ amount_display?: string | null;
917
+ billing?: string;
918
+ description?: string;
919
+ merchant_name?: string;
920
+ merchant_url?: string;
921
+ checkout_redirect_url?: string;
922
+ pay_with?: string;
923
+ agent_wallet?: PublicSignupPaymentAgentWallet;
924
+ [key: string]: unknown;
925
+ }
926
+
881
927
  export interface PublicSignupSession {
882
928
  id: string;
883
929
  status: string;
@@ -894,6 +940,7 @@ export interface PublicSignupSession {
894
940
  account?: Record<string, unknown>;
895
941
  billing?: Record<string, unknown>;
896
942
  agent_pay?: PublicSignupAgentPay | null;
943
+ payment?: PublicSignupPayment | null;
897
944
  links?: Record<string, unknown>;
898
945
  created_at?: string;
899
946
  updated_at?: string;
@@ -915,6 +962,7 @@ export interface PublicSignupResponse {
915
962
  account?: Record<string, unknown>;
916
963
  billing?: Record<string, unknown>;
917
964
  agent_pay?: PublicSignupAgentPay | null;
965
+ payment?: PublicSignupPayment | null;
918
966
  [key: string]: unknown;
919
967
  }
920
968
 
@@ -1320,6 +1368,8 @@ export class PosterlyClient {
1320
1368
  limit?: number;
1321
1369
  offset?: number;
1322
1370
  workspace_id?: string;
1371
+ approval_status?: string;
1372
+ brand_id?: string;
1323
1373
  }): Promise<{ posts: Post[]; total: number }> {
1324
1374
  const searchParams = new URLSearchParams();
1325
1375
  if (params?.status) searchParams.set('status', params.status);
@@ -1328,6 +1378,8 @@ export class PosterlyClient {
1328
1378
  if (params?.limit) searchParams.set('limit', String(params.limit));
1329
1379
  if (params?.offset) searchParams.set('offset', String(params.offset));
1330
1380
  if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
1381
+ if (params?.approval_status) searchParams.set('approval_status', params.approval_status);
1382
+ if (params?.brand_id) searchParams.set('brand_id', params.brand_id);
1331
1383
 
1332
1384
  const qs = searchParams.toString();
1333
1385
  return this.request('GET', `/posts${qs ? `?${qs}` : ''}`);
@@ -5,4 +5,4 @@
5
5
  // tool set (minus the intentional pre-auth signup tools that only this stdio
6
6
  // package exposes). `npm run check:mcp-parity` enforces both the version match
7
7
  // and the tool-list match, and runs in the pre-commit hook.
8
- export const POSTERLY_MCP_VERSION = '0.43.2';
8
+ export const POSTERLY_MCP_VERSION = '0.43.4';
@@ -35,7 +35,8 @@ export const getAgentSignupInfoTool = {
35
35
  '- Do not narrate raw curl, HTTP, JSON, API keys, or implementation details unless the user explicitly asks for debugging.',
36
36
  '',
37
37
  'Boundaries:',
38
- '- Payment can be a one-time Link Agent Wallet virtual card (credential_type: card) on the prepaid PaymentIntent, or Stripe Checkout in the browser.',
38
+ '- Payment happens on Stripe Checkout, either by the user in their browser or by the agent with its own approved payment credential (for example a Link agent wallet); never card details in chat.',
39
+ '- Where enabled, payment can instead be a one-time Link Agent Wallet virtual card (credential_type: card) on a prepaid PaymentIntent.',
39
40
  '- Never send card numbers to posterly. Confirm the PaymentIntent with Stripe, or send checkout_redirect_url.',
40
41
  '- The user sets their Posterly password in their browser.',
41
42
  '- The user approves social OAuth in their browser.',
@@ -29,6 +29,7 @@ function formatSignupSession(session: PublicSignupSession, includeRaw: boolean):
29
29
  const passwordUrl = stringFromRecord(session.links, 'password_setup_url');
30
30
  const completeUrl = stringFromRecord(session.links, 'complete_url');
31
31
  const agentPay = session.agent_pay;
32
+ const payment = session.payment;
32
33
 
33
34
  const lines = [
34
35
  `Posterly signup session: ${session.id}`,
@@ -42,6 +43,12 @@ function formatSignupSession(session: PublicSignupSession, includeRaw: boolean):
42
43
  agentPay?.requires_tos_acceptance ? 'Terms acceptance required before client_secret is released.' : '',
43
44
  agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
44
45
  agentPay?.confirm_url ? `Confirm URL: ${agentPay.confirm_url}` : '',
46
+ !agentPay?.enabled && payment?.amount_display
47
+ ? `Amount due: ${payment.amount_display} ${String(payment.currency || 'usd').toUpperCase()} to ${payment.merchant_name || 'posterly'} (${payment.billing || 'subscription'})`
48
+ : '',
49
+ !agentPay?.enabled && payment?.agent_wallet?.how
50
+ ? `Agent wallet option: ${payment.agent_wallet.how}`
51
+ : '',
45
52
  checkoutRedirectUrl ? `Checkout handoff URL: ${checkoutRedirectUrl}` : '',
46
53
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
47
54
  passwordUrl ? `Password setup URL: ${passwordUrl}` : '',
@@ -74,7 +81,7 @@ function guidanceForStatus(status: string, agentPayAvailable = false, requiresTo
74
81
  }
75
82
  return agentPayAvailable
76
83
  ? 'Payment is still pending. Confirm the prepaid PaymentIntent with a Link virtual card (credential_type: card), or send the user the Checkout handoff URL. Keep polling; never ask for card numbers.'
77
- : 'Tell the user checkout is still pending. Keep polling; do not ask for card details.';
84
+ : 'Tell the user checkout is still pending. If you hold an approved payment credential such as a Link agent wallet, you may pay the Checkout handoff URL yourself instead of asking the user; otherwise keep polling. Never ask for card details.';
78
85
  case 'checkout_expired':
79
86
  return 'Tell the user checkout expired and offer to call start_signup again.';
80
87
  case 'payment_confirmed':
@@ -6,7 +6,7 @@ import { SUPPORTED_PLATFORM_INPUTS, SUPPORTED_PLATFORM_IDS } from '../generated/
6
6
  export const listPostsTool = {
7
7
  name: 'list_posts',
8
8
  description:
9
- 'List upcoming or recent posts. Filter by status (scheduled, published, failed, draft), platform, account_id, or workspace_id. If workspace_id is omitted, posts across every workspace the caller is a member of are returned.',
9
+ 'List upcoming or recent posts. Filter by status (scheduled, published, failed, draft), platform, account_id, workspace_id, approval_status, or brand_id. If workspace_id is omitted, posts across every workspace the caller is a member of are returned.',
10
10
  inputSchema: z.object({
11
11
  status: z
12
12
  .string()
@@ -30,6 +30,14 @@ export const listPostsTool = {
30
30
  .string()
31
31
  .optional()
32
32
  .describe('Filter to posts in a specific workspace (get IDs via whoami).'),
33
+ approval_status: z
34
+ .enum(['none', 'pending_client', 'approved', 'changes_requested', 'rejected'])
35
+ .optional()
36
+ .describe('Filter by client review approval status. pending_client means the post is waiting on the client.'),
37
+ brand_id: z
38
+ .string()
39
+ .optional()
40
+ .describe('Filter to posts assigned to a specific brand/client (the id from list_brands).'),
33
41
  }),
34
42
 
35
43
  async execute(
@@ -40,6 +48,8 @@ export const listPostsTool = {
40
48
  account_id?: string;
41
49
  limit?: number;
42
50
  workspace_id?: string;
51
+ approval_status?: string;
52
+ brand_id?: string;
43
53
  }
44
54
  ) {
45
55
  const { posts, total } = await client.listPosts({
@@ -54,7 +64,15 @@ export const listPostsTool = {
54
64
  const lines = posts.map((p) => {
55
65
  const date = formatLocalDateTime(p.scheduled_at);
56
66
  const caption = truncateText(p.content, 60);
57
- return `• [${p.status}] #${p.id}: ${caption} (${date})`;
67
+ const approvalBits: string[] = [];
68
+ if (p.approval && p.approval.status !== 'none') {
69
+ approvalBits.push(`approval: ${p.approval.status}`);
70
+ if (p.approval.waiting_on) approvalBits.push(`waiting on: ${p.approval.waiting_on}`);
71
+ }
72
+ if (p.brand_id) approvalBits.push(`brand: ${p.brand_id}`);
73
+ if (p.content_plan_id) approvalBits.push(`plan: ${p.content_plan_id}`);
74
+ const approvalSuffix = approvalBits.length > 0 ? ` [${approvalBits.join(', ')}]` : '';
75
+ return `• [${p.status}] #${p.id}: ${caption} (${date})${approvalSuffix}`;
58
76
  });
59
77
 
60
78
  return [
@@ -91,6 +91,7 @@ function formatSignupStart(response: PublicSignupResponse, includeRaw: boolean):
91
91
  const status = session?.status || response.status || 'checkout_pending';
92
92
  const message = session?.status_message || response.status_message;
93
93
  const agentPay = response.agent_pay || session?.agent_pay;
94
+ const payment = response.payment || session?.payment;
94
95
 
95
96
  const lines = [
96
97
  'Posterly signup started.',
@@ -105,6 +106,12 @@ function formatSignupStart(response: PublicSignupResponse, includeRaw: boolean):
105
106
  agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
106
107
  agentPay?.confirm_url ? `Confirm URL: ${agentPay.confirm_url}` : '',
107
108
  agentPay?.pay_instructions ? `Pay instructions: ${agentPay.pay_instructions}` : '',
109
+ !agentPay?.enabled && payment?.amount_display
110
+ ? `Amount due: ${payment.amount_display} ${String(payment.currency || 'usd').toUpperCase()} to ${payment.merchant_name || 'posterly'} (${payment.billing || 'subscription'})`
111
+ : '',
112
+ !agentPay?.enabled && payment?.agent_wallet?.how
113
+ ? `Agent wallet option: ${payment.agent_wallet.how}`
114
+ : '',
108
115
  checkoutRedirectUrl ? `Checkout handoff URL (browser fallback): ${checkoutRedirectUrl}` : '',
109
116
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
110
117
  pollUrl ? `Poll URL: ${pollUrl}` : '',
@@ -129,11 +136,12 @@ function formatSignupStart(response: PublicSignupResponse, includeRaw: boolean):
129
136
  '6. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
130
137
  ]
131
138
  : [
132
- '1. Send the Checkout handoff URL to the user so they can pay securely in their browser. Use the raw Stripe checkout URL only if you preserve the full URL including any fragment. posterly does not email this link, so do not tell the user to check their inbox at this stage.',
133
- '2. Call get_signup_session with the signup session ID until the status changes.',
134
- '3. Tell the user when Posterly sends the password setup email.',
135
- '4. If status becomes agent_access_required, ask the user to install or paste the Posterly MCP/API setup instructions into this trusted AI chat, then onboard them in this conversation (about you, connect, brand voice, first post). Do not send them to /onboarding-v2.',
136
- '5. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
139
+ '1. If you hold an approved payment credential such as a Link agent wallet, you can pay the Checkout handoff URL yourself: create a spend request for the amount and merchant above, get the user\'s approval in the wallet, then complete the Checkout page with that credential. Never paste card numbers into chat or send them to posterly.',
140
+ '2. Otherwise, send the Checkout handoff URL to the user so they can pay securely in their browser. Use the raw Stripe checkout URL only if you preserve the full URL including any fragment. posterly does not email this link, so do not tell the user to check their inbox at this stage.',
141
+ '3. Call get_signup_session with the signup session ID until the status changes.',
142
+ '4. Tell the user when Posterly sends the password setup email.',
143
+ '5. If status becomes agent_access_required, ask the user to install or paste the Posterly MCP/API setup instructions into this trusted AI chat, then onboard them in this conversation (about you, connect, brand voice, first post). Do not send them to /onboarding-v2.',
144
+ '6. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
137
145
  ]),
138
146
  includeRaw ? `\nRaw signup response:\n${JSON.stringify(response, null, 2)}` : '',
139
147
  ];
@@ -10,6 +10,11 @@ export const WEBHOOK_EVENTS = [
10
10
  'post.failed',
11
11
  'account.disconnected',
12
12
  'analytics.synced',
13
+ 'approval.requested',
14
+ 'approval.approved',
15
+ 'approval.changes_requested',
16
+ 'approval.rejected',
17
+ 'approval.commented',
13
18
  ] as const;
14
19
 
15
20
  export const webhookEventSchema = z.enum(WEBHOOK_EVENTS);