posterly-mcp-server 0.43.1 → 0.43.3

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,13 +122,13 @@ Add the same server definition to your Cursor MCP settings:
122
122
 
123
123
  ## Available tools
124
124
 
125
- `posterly-mcp-server@0.43.1` exposes 90 tools.
125
+ `posterly-mcp-server@0.43.3` exposes 90 tools.
126
126
 
127
127
  Public setup tools work before `POSTERLY_API_KEY` exists:
128
128
 
129
129
  - `get_mcp_status` (show the installed server version, latest npm version, MCP endpoint health, API auth health, and update guidance)
130
130
  - `get_agent_signup_info`
131
- - `start_signup` (start paid signup and return a Posterly checkout handoff URL)
131
+ - `start_signup` (start paid signup and return a poll URL, browser Checkout fallback, and prepaid PaymentIntent fields when agent-card pay is enabled)
132
132
  - `get_signup_session` (poll checkout, payment, password, and agent-access status)
133
133
 
134
134
  Authenticated tools require `POSTERLY_API_KEY`:
@@ -821,6 +821,51 @@ export interface PublicSignupPayload {
821
821
  api_addon?: boolean;
822
822
  return_path?: string;
823
823
  source?: string;
824
+ tos_accepted?: boolean;
825
+ }
826
+ export interface PublicSignupAgentPay {
827
+ enabled?: boolean;
828
+ method?: string;
829
+ credential_type?: string;
830
+ amount?: number;
831
+ currency?: string;
832
+ amount_display?: string;
833
+ payment_intent_id?: string;
834
+ client_secret?: string | null;
835
+ publishable_key?: string | null;
836
+ confirm_url?: string;
837
+ poll_url?: string;
838
+ checkout_redirect_url?: string;
839
+ pay_instructions?: string;
840
+ status?: string;
841
+ period?: Record<string, unknown>;
842
+ requires_tos_acceptance?: boolean;
843
+ [key: string]: unknown;
844
+ }
845
+ export interface PublicSignupPaymentAgentWalletSpendRequest {
846
+ merchant_name?: string;
847
+ merchant_url?: string;
848
+ amount?: number | null;
849
+ currency?: string;
850
+ context?: string;
851
+ }
852
+ export interface PublicSignupPaymentAgentWallet {
853
+ supported?: boolean;
854
+ how?: string;
855
+ spend_request?: PublicSignupPaymentAgentWalletSpendRequest;
856
+ }
857
+ export interface PublicSignupPayment {
858
+ amount?: number | null;
859
+ currency?: string;
860
+ amount_display?: string | null;
861
+ billing?: string;
862
+ description?: string;
863
+ merchant_name?: string;
864
+ merchant_url?: string;
865
+ checkout_redirect_url?: string;
866
+ pay_with?: string;
867
+ agent_wallet?: PublicSignupPaymentAgentWallet;
868
+ [key: string]: unknown;
824
869
  }
825
870
  export interface PublicSignupSession {
826
871
  id: string;
@@ -837,6 +882,8 @@ export interface PublicSignupSession {
837
882
  checkout?: Record<string, unknown>;
838
883
  account?: Record<string, unknown>;
839
884
  billing?: Record<string, unknown>;
885
+ agent_pay?: PublicSignupAgentPay | null;
886
+ payment?: PublicSignupPayment | null;
840
887
  links?: Record<string, unknown>;
841
888
  created_at?: string;
842
889
  updated_at?: string;
@@ -856,6 +903,8 @@ export interface PublicSignupResponse {
856
903
  links?: Record<string, unknown>;
857
904
  account?: Record<string, unknown>;
858
905
  billing?: Record<string, unknown>;
906
+ agent_pay?: PublicSignupAgentPay | null;
907
+ payment?: PublicSignupPayment | null;
859
908
  [key: string]: unknown;
860
909
  }
861
910
  export interface PublicSignupSessionResponse {
@@ -1 +1 @@
1
- export declare const POSTERLY_MCP_VERSION = "0.43.1";
1
+ export declare const POSTERLY_MCP_VERSION = "0.43.3";
@@ -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.1';
8
+ export const POSTERLY_MCP_VERSION = '0.43.3';
@@ -13,15 +13,15 @@ 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;
17
+ workspace_id?: string | undefined;
18
18
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | 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;
24
+ workspace_id?: string | undefined;
25
25
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
26
26
  is_active?: boolean | undefined;
27
27
  }>;
@@ -14,8 +14,8 @@ export const getAgentSignupInfoTool = {
14
14
  '',
15
15
  'Pre-auth tools:',
16
16
  '- get_mcp_status: checks the installed server version, latest npm version, MCP endpoint health, API auth health, and whether POSTERLY_API_KEY is configured.',
17
- '- start_signup: starts paid signup and returns a Posterly checkout handoff URL plus a signup poll URL.',
18
- '- get_signup_session: polls checkout, payment, password, and agent-access status.',
17
+ '- start_signup: starts paid signup and returns a signup poll URL, a browser Checkout fallback, and, when enabled, a prepaid PaymentIntent for a Link virtual card (credential_type: card).',
18
+ '- get_signup_session: polls payment, password, and agent-access status.',
19
19
  '',
20
20
  'After Posterly access is installed, onboard the user IN THIS chat (do not send them to /onboarding-v2):',
21
21
  '- whoami: confirm the paid account and read onboarding.next_step.',
@@ -30,9 +30,12 @@ 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
- '- The user pays in Stripe Checkout in their 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.',
35
+ '- Never send card numbers to posterly. Confirm the PaymentIntent with Stripe, or send checkout_redirect_url.',
34
36
  '- The user sets their Posterly password in their browser.',
35
37
  '- The user approves social OAuth in their browser.',
38
+ '- Publish approval stays with the user.',
36
39
  '- The AI should never ask for card details, Posterly passwords, social passwords, or OAuth codes.',
37
40
  ].join('\n');
38
41
  },
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  export const getSignupSessionTool = {
3
3
  name: 'get_signup_session',
4
- description: 'Poll a public Posterly signup session created by start_signup. Use this to narrate checkout, payment, password setup, and agent access status before a Posterly API key is installed. Keep updates user-facing; do not narrate raw HTTP, curl, or API plumbing.',
4
+ description: 'Poll a public Posterly signup session created by start_signup. Use this to narrate payment (Link virtual card or browser Checkout), password setup, and agent access status before a Posterly API key is installed. Keep updates user-facing; do not narrate raw HTTP, curl, or API plumbing.',
5
5
  inputSchema: z.object({
6
6
  session_id: z
7
7
  .string()
@@ -23,18 +23,32 @@ function formatSignupSession(session, includeRaw) {
23
23
  const checkoutUrl = stringFromRecord(session.links, 'checkout_url');
24
24
  const passwordUrl = stringFromRecord(session.links, 'password_setup_url');
25
25
  const completeUrl = stringFromRecord(session.links, 'complete_url');
26
+ const agentPay = session.agent_pay;
27
+ const payment = session.payment;
26
28
  const lines = [
27
29
  `Posterly signup session: ${session.id}`,
28
30
  `Status: ${session.status}`,
29
31
  session.status_message ? `Message: ${session.status_message}` : '',
30
32
  nextAction?.label ? `Next action: ${nextAction.label}` : '',
31
33
  nextAction?.description ? `Next action detail: ${nextAction.description}` : '',
34
+ agentPay?.amount_display ? `Agent pay amount: ${agentPay.amount_display}` : '',
35
+ agentPay?.payment_intent_id ? `PaymentIntent: ${agentPay.payment_intent_id}` : '',
36
+ agentPay?.status ? `PaymentIntent status: ${agentPay.status}` : '',
37
+ agentPay?.requires_tos_acceptance ? 'Terms acceptance required before client_secret is released.' : '',
38
+ agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
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
+ : '',
32
46
  checkoutRedirectUrl ? `Checkout handoff URL: ${checkoutRedirectUrl}` : '',
33
47
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
34
48
  passwordUrl ? `Password setup URL: ${passwordUrl}` : '',
35
49
  completeUrl ? `Completion URL: ${completeUrl}` : '',
36
50
  '',
37
- guidanceForStatus(session.status),
51
+ guidanceForStatus(session.status, Boolean(agentPay?.enabled || agentPay?.payment_intent_id), Boolean(agentPay?.requires_tos_acceptance)),
38
52
  session.agent_next_steps?.length
39
53
  ? `Agent next steps:\n${session.agent_next_steps.map((step, index) => `${index + 1}. ${step}`).join('\n')}`
40
54
  : '',
@@ -46,10 +60,15 @@ function stringFromRecord(record, key) {
46
60
  const value = record?.[key];
47
61
  return typeof value === 'string' ? value : null;
48
62
  }
49
- function guidanceForStatus(status) {
63
+ function guidanceForStatus(status, agentPayAvailable = false, requiresTosAcceptance = false) {
50
64
  switch (status) {
51
65
  case 'checkout_pending':
52
- return 'Tell the user checkout is still pending. Keep polling; do not ask for card details.';
66
+ if (agentPayAvailable && requiresTosAcceptance) {
67
+ return 'Payment is still pending on terms acceptance. Ask the user to explicitly confirm they accept the posterly terms at https://www.poster.ly/terms, then POST { "tos_accepted": true } to Confirm URL to receive client_secret, or send the user the Checkout handoff URL. Keep polling; never ask for card numbers.';
68
+ }
69
+ return agentPayAvailable
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.'
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.';
53
72
  case 'checkout_expired':
54
73
  return 'Tell the user checkout expired and offer to call start_signup again.';
55
74
  case 'payment_confirmed':
@@ -11,6 +11,7 @@ export declare const startSignupTool: {
11
11
  api_addon: z.ZodDefault<z.ZodBoolean>;
12
12
  return_path: z.ZodDefault<z.ZodString>;
13
13
  source: z.ZodDefault<z.ZodString>;
14
+ tos_accepted: z.ZodOptional<z.ZodBoolean>;
14
15
  debug: z.ZodOptional<z.ZodBoolean>;
15
16
  }, "strip", z.ZodTypeAny, {
16
17
  email: string;
@@ -21,6 +22,7 @@ export declare const startSignupTool: {
21
22
  source: string;
22
23
  debug?: boolean | undefined;
23
24
  name?: string | undefined;
25
+ tos_accepted?: boolean | undefined;
24
26
  }, {
25
27
  email: string;
26
28
  debug?: boolean | undefined;
@@ -30,6 +32,7 @@ export declare const startSignupTool: {
30
32
  api_addon?: boolean | undefined;
31
33
  return_path?: string | undefined;
32
34
  source?: string | undefined;
35
+ tos_accepted?: boolean | undefined;
33
36
  }>;
34
37
  execute(client: PosterlyClient, input: {
35
38
  email: string;
@@ -39,6 +42,7 @@ export declare const startSignupTool: {
39
42
  api_addon?: boolean;
40
43
  return_path?: string;
41
44
  source?: string;
45
+ tos_accepted?: boolean;
42
46
  debug?: boolean;
43
47
  }): Promise<string>;
44
48
  };
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  const DEFAULT_RETURN_PATH = '/dashboard/api?api_signup=success';
3
3
  export const startSignupTool = {
4
4
  name: 'start_signup',
5
- description: 'Start the public Posterly paid signup flow for a user before Posterly API access exists. Returns a Posterly checkout handoff URL and signup poll URL. The user must handle payment and password setup in the browser. Do not ask for card details or a Posterly password in chat.',
5
+ description: 'Start the public Posterly paid signup flow for a user before Posterly API access exists. Returns a signup poll URL, a browser Checkout fallback URL, and, when enabled, a prepaid PaymentIntent the agent can pay with a Link Agent Wallet virtual card (credential_type: card). The user still sets a password and approves social OAuth in the browser. Never ask for card numbers, a Posterly password, or social passwords in chat.',
6
6
  inputSchema: z.object({
7
7
  email: z
8
8
  .string()
@@ -32,6 +32,10 @@ export const startSignupTool = {
32
32
  .string()
33
33
  .default('posterly_mcp_pre_auth_signup')
34
34
  .describe('Source label for analytics and support diagnostics.'),
35
+ tos_accepted: z
36
+ .boolean()
37
+ .optional()
38
+ .describe('Set true only after the user has explicitly confirmed, in this conversation, that they accept the posterly terms at https://www.poster.ly/terms. Sending it here avoids a separate terms-confirmation step before client_secret is released.'),
35
39
  debug: z
36
40
  .boolean()
37
41
  .optional()
@@ -46,6 +50,7 @@ export const startSignupTool = {
46
50
  api_addon: input.api_addon ?? true,
47
51
  return_path: input.return_path ?? DEFAULT_RETURN_PATH,
48
52
  source: input.source ?? 'posterly_mcp_pre_auth_signup',
53
+ tos_accepted: input.tos_accepted,
49
54
  });
50
55
  return formatSignupStart(response, Boolean(input.debug));
51
56
  },
@@ -64,22 +69,58 @@ function formatSignupStart(response, includeRaw) {
64
69
  const completeUrl = response.complete_url || valueFromLinks(response, 'complete_url');
65
70
  const status = session?.status || response.status || 'checkout_pending';
66
71
  const message = session?.status_message || response.status_message;
72
+ const agentPay = response.agent_pay || session?.agent_pay;
73
+ const payment = response.payment || session?.payment;
67
74
  const lines = [
68
75
  'Posterly signup started.',
69
76
  sessionId ? `Signup session: ${sessionId}` : '',
70
77
  `Status: ${status}`,
71
78
  message ? `Message: ${message}` : '',
72
- checkoutRedirectUrl ? `Checkout handoff URL: ${checkoutRedirectUrl}` : '',
79
+ agentPay?.amount_display
80
+ ? `Agent pay amount: ${agentPay.amount_display} ${String(agentPay.currency || 'usd').toUpperCase()}`
81
+ : '',
82
+ agentPay?.payment_intent_id ? `PaymentIntent: ${agentPay.payment_intent_id}` : '',
83
+ agentPay?.requires_tos_acceptance ? 'Terms acceptance required before client_secret is released.' : '',
84
+ agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
85
+ agentPay?.confirm_url ? `Confirm URL: ${agentPay.confirm_url}` : '',
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
+ : '',
93
+ checkoutRedirectUrl ? `Checkout handoff URL (browser fallback): ${checkoutRedirectUrl}` : '',
73
94
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
74
95
  pollUrl ? `Poll URL: ${pollUrl}` : '',
75
96
  completeUrl ? `Completion URL: ${completeUrl}` : '',
76
97
  '',
77
98
  'Next steps for the AI agent:',
78
- '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.',
79
- '2. Call get_signup_session with the signup session ID until the status changes.',
80
- '3. Tell the user when Posterly sends the password setup email.',
81
- '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.',
82
- '5. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
99
+ ...(agentPay?.enabled && agentPay?.requires_tos_acceptance
100
+ ? [
101
+ '1. Ask the user to explicitly confirm they accept the posterly terms at https://www.poster.ly/terms.',
102
+ '2. Once confirmed, POST { "tos_accepted": true } to Confirm URL (optionally with payment_method in the same call) to receive client_secret.',
103
+ '3. If the user would rather pay on the website, send them the Checkout handoff URL instead.',
104
+ '4. Call get_signup_session with the signup session ID until the status changes.',
105
+ '5. Do not ask for card details, the posterly password, social passwords, or OAuth codes.',
106
+ ]
107
+ : agentPay?.enabled
108
+ ? [
109
+ '1. Prefer agent_pay: confirm the PaymentIntent with a one-time Link Agent Wallet virtual card (credential_type: card). Never paste card numbers into chat or send them to posterly.',
110
+ '2. If the user would rather pay on the website, send them the Checkout handoff URL instead.',
111
+ '3. Call get_signup_session with the signup session ID until the status changes.',
112
+ '4. Tell the user when Posterly sends the password setup email. Password, social OAuth, and publish approval stay in the browser.',
113
+ '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.',
114
+ '6. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
115
+ ]
116
+ : [
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.',
123
+ ]),
83
124
  includeRaw ? `\nRaw signup response:\n${JSON.stringify(response, null, 2)}` : '',
84
125
  ];
85
126
  return lines.filter(Boolean).join('\n');
@@ -14,17 +14,17 @@ 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
20
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | 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
28
  events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
29
29
  is_active?: boolean | undefined;
30
30
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posterly-mcp-server",
3
- "version": "0.43.1",
3
+ "version": "0.43.3",
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.1",
6
+ "version": "0.43.3",
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.1",
17
+ "version": "0.43.3",
18
18
  "transport": {
19
19
  "type": "stdio"
20
20
  },
@@ -850,6 +850,64 @@ export interface PublicSignupPayload {
850
850
  api_addon?: boolean;
851
851
  return_path?: string;
852
852
  source?: string;
853
+ // Set true only after the user has explicitly confirmed, in this
854
+ // conversation, that they accept the posterly terms. Sending it on this
855
+ // first call avoids a separate terms-confirmation round trip.
856
+ tos_accepted?: boolean;
857
+ }
858
+
859
+ export interface PublicSignupAgentPay {
860
+ enabled?: boolean;
861
+ method?: string;
862
+ credential_type?: string;
863
+ amount?: number;
864
+ currency?: string;
865
+ amount_display?: string;
866
+ payment_intent_id?: string;
867
+ client_secret?: string | null;
868
+ publishable_key?: string | null;
869
+ confirm_url?: string;
870
+ poll_url?: string;
871
+ checkout_redirect_url?: string;
872
+ pay_instructions?: string;
873
+ status?: string;
874
+ period?: Record<string, unknown>;
875
+ // True until the user has explicitly accepted the posterly terms. While
876
+ // true, client_secret and publishable_key are withheld.
877
+ requires_tos_acceptance?: boolean;
878
+ [key: string]: unknown;
879
+ }
880
+
881
+ export interface PublicSignupPaymentAgentWalletSpendRequest {
882
+ merchant_name?: string;
883
+ merchant_url?: string;
884
+ amount?: number | null;
885
+ currency?: string;
886
+ context?: string;
887
+ }
888
+
889
+ export interface PublicSignupPaymentAgentWallet {
890
+ supported?: boolean;
891
+ how?: string;
892
+ spend_request?: PublicSignupPaymentAgentWalletSpendRequest;
893
+ }
894
+
895
+ // Always present while checkout is open, regardless of agent_pay/ENABLE_AGENT_CARD_PAY.
896
+ // Describes the Stripe-hosted Checkout session itself so an agent with its own
897
+ // approved payment credential (for example a Link agent wallet) can pay it
898
+ // directly. null once payment is confirmed or checkout has expired.
899
+ export interface PublicSignupPayment {
900
+ amount?: number | null;
901
+ currency?: string;
902
+ amount_display?: string | null;
903
+ billing?: string;
904
+ description?: string;
905
+ merchant_name?: string;
906
+ merchant_url?: string;
907
+ checkout_redirect_url?: string;
908
+ pay_with?: string;
909
+ agent_wallet?: PublicSignupPaymentAgentWallet;
910
+ [key: string]: unknown;
853
911
  }
854
912
 
855
913
  export interface PublicSignupSession {
@@ -867,6 +925,8 @@ export interface PublicSignupSession {
867
925
  checkout?: Record<string, unknown>;
868
926
  account?: Record<string, unknown>;
869
927
  billing?: Record<string, unknown>;
928
+ agent_pay?: PublicSignupAgentPay | null;
929
+ payment?: PublicSignupPayment | null;
870
930
  links?: Record<string, unknown>;
871
931
  created_at?: string;
872
932
  updated_at?: string;
@@ -887,6 +947,8 @@ export interface PublicSignupResponse {
887
947
  links?: Record<string, unknown>;
888
948
  account?: Record<string, unknown>;
889
949
  billing?: Record<string, unknown>;
950
+ agent_pay?: PublicSignupAgentPay | null;
951
+ payment?: PublicSignupPayment | null;
890
952
  [key: string]: unknown;
891
953
  }
892
954
 
@@ -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.1';
8
+ export const POSTERLY_MCP_VERSION = '0.43.3';
@@ -19,8 +19,8 @@ export const getAgentSignupInfoTool = {
19
19
  '',
20
20
  'Pre-auth tools:',
21
21
  '- get_mcp_status: checks the installed server version, latest npm version, MCP endpoint health, API auth health, and whether POSTERLY_API_KEY is configured.',
22
- '- start_signup: starts paid signup and returns a Posterly checkout handoff URL plus a signup poll URL.',
23
- '- get_signup_session: polls checkout, payment, password, and agent-access status.',
22
+ '- start_signup: starts paid signup and returns a signup poll URL, a browser Checkout fallback, and, when enabled, a prepaid PaymentIntent for a Link virtual card (credential_type: card).',
23
+ '- get_signup_session: polls payment, password, and agent-access status.',
24
24
  '',
25
25
  'After Posterly access is installed, onboard the user IN THIS chat (do not send them to /onboarding-v2):',
26
26
  '- whoami: confirm the paid account and read onboarding.next_step.',
@@ -35,9 +35,12 @@ 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
- '- The user pays in Stripe Checkout in their 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.',
40
+ '- Never send card numbers to posterly. Confirm the PaymentIntent with Stripe, or send checkout_redirect_url.',
39
41
  '- The user sets their Posterly password in their browser.',
40
42
  '- The user approves social OAuth in their browser.',
43
+ '- Publish approval stays with the user.',
41
44
  '- The AI should never ask for card details, Posterly passwords, social passwords, or OAuth codes.',
42
45
  ].join('\n');
43
46
  },
@@ -4,7 +4,7 @@ import type { PosterlyClient, PublicSignupSession } from '../lib/api-client.js';
4
4
  export const getSignupSessionTool = {
5
5
  name: 'get_signup_session',
6
6
  description:
7
- 'Poll a public Posterly signup session created by start_signup. Use this to narrate checkout, payment, password setup, and agent access status before a Posterly API key is installed. Keep updates user-facing; do not narrate raw HTTP, curl, or API plumbing.',
7
+ 'Poll a public Posterly signup session created by start_signup. Use this to narrate payment (Link virtual card or browser Checkout), password setup, and agent access status before a Posterly API key is installed. Keep updates user-facing; do not narrate raw HTTP, curl, or API plumbing.',
8
8
  inputSchema: z.object({
9
9
  session_id: z
10
10
  .string()
@@ -28,6 +28,8 @@ function formatSignupSession(session: PublicSignupSession, includeRaw: boolean):
28
28
  const checkoutUrl = stringFromRecord(session.links, 'checkout_url');
29
29
  const passwordUrl = stringFromRecord(session.links, 'password_setup_url');
30
30
  const completeUrl = stringFromRecord(session.links, 'complete_url');
31
+ const agentPay = session.agent_pay;
32
+ const payment = session.payment;
31
33
 
32
34
  const lines = [
33
35
  `Posterly signup session: ${session.id}`,
@@ -35,12 +37,28 @@ function formatSignupSession(session: PublicSignupSession, includeRaw: boolean):
35
37
  session.status_message ? `Message: ${session.status_message}` : '',
36
38
  nextAction?.label ? `Next action: ${nextAction.label}` : '',
37
39
  nextAction?.description ? `Next action detail: ${nextAction.description}` : '',
40
+ agentPay?.amount_display ? `Agent pay amount: ${agentPay.amount_display}` : '',
41
+ agentPay?.payment_intent_id ? `PaymentIntent: ${agentPay.payment_intent_id}` : '',
42
+ agentPay?.status ? `PaymentIntent status: ${agentPay.status}` : '',
43
+ agentPay?.requires_tos_acceptance ? 'Terms acceptance required before client_secret is released.' : '',
44
+ agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
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
+ : '',
38
52
  checkoutRedirectUrl ? `Checkout handoff URL: ${checkoutRedirectUrl}` : '',
39
53
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
40
54
  passwordUrl ? `Password setup URL: ${passwordUrl}` : '',
41
55
  completeUrl ? `Completion URL: ${completeUrl}` : '',
42
56
  '',
43
- guidanceForStatus(session.status),
57
+ guidanceForStatus(
58
+ session.status,
59
+ Boolean(agentPay?.enabled || agentPay?.payment_intent_id),
60
+ Boolean(agentPay?.requires_tos_acceptance),
61
+ ),
44
62
  session.agent_next_steps?.length
45
63
  ? `Agent next steps:\n${session.agent_next_steps.map((step, index) => `${index + 1}. ${step}`).join('\n')}`
46
64
  : '',
@@ -55,10 +73,15 @@ function stringFromRecord(record: Record<string, unknown> | undefined, key: stri
55
73
  return typeof value === 'string' ? value : null;
56
74
  }
57
75
 
58
- function guidanceForStatus(status: string): string {
76
+ function guidanceForStatus(status: string, agentPayAvailable = false, requiresTosAcceptance = false): string {
59
77
  switch (status) {
60
78
  case 'checkout_pending':
61
- return 'Tell the user checkout is still pending. Keep polling; do not ask for card details.';
79
+ if (agentPayAvailable && requiresTosAcceptance) {
80
+ return 'Payment is still pending on terms acceptance. Ask the user to explicitly confirm they accept the posterly terms at https://www.poster.ly/terms, then POST { "tos_accepted": true } to Confirm URL to receive client_secret, or send the user the Checkout handoff URL. Keep polling; never ask for card numbers.';
81
+ }
82
+ return agentPayAvailable
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.'
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.';
62
85
  case 'checkout_expired':
63
86
  return 'Tell the user checkout expired and offer to call start_signup again.';
64
87
  case 'payment_confirmed':
@@ -6,7 +6,7 @@ const DEFAULT_RETURN_PATH = '/dashboard/api?api_signup=success';
6
6
  export const startSignupTool = {
7
7
  name: 'start_signup',
8
8
  description:
9
- 'Start the public Posterly paid signup flow for a user before Posterly API access exists. Returns a Posterly checkout handoff URL and signup poll URL. The user must handle payment and password setup in the browser. Do not ask for card details or a Posterly password in chat.',
9
+ 'Start the public Posterly paid signup flow for a user before Posterly API access exists. Returns a signup poll URL, a browser Checkout fallback URL, and, when enabled, a prepaid PaymentIntent the agent can pay with a Link Agent Wallet virtual card (credential_type: card). The user still sets a password and approves social OAuth in the browser. Never ask for card numbers, a Posterly password, or social passwords in chat.',
10
10
  inputSchema: z.object({
11
11
  email: z
12
12
  .string()
@@ -36,6 +36,10 @@ export const startSignupTool = {
36
36
  .string()
37
37
  .default('posterly_mcp_pre_auth_signup')
38
38
  .describe('Source label for analytics and support diagnostics.'),
39
+ tos_accepted: z
40
+ .boolean()
41
+ .optional()
42
+ .describe('Set true only after the user has explicitly confirmed, in this conversation, that they accept the posterly terms at https://www.poster.ly/terms. Sending it here avoids a separate terms-confirmation step before client_secret is released.'),
39
43
  debug: z
40
44
  .boolean()
41
45
  .optional()
@@ -52,6 +56,7 @@ export const startSignupTool = {
52
56
  api_addon?: boolean;
53
57
  return_path?: string;
54
58
  source?: string;
59
+ tos_accepted?: boolean;
55
60
  debug?: boolean;
56
61
  },
57
62
  ) {
@@ -63,6 +68,7 @@ export const startSignupTool = {
63
68
  api_addon: input.api_addon ?? true,
64
69
  return_path: input.return_path ?? DEFAULT_RETURN_PATH,
65
70
  source: input.source ?? 'posterly_mcp_pre_auth_signup',
71
+ tos_accepted: input.tos_accepted,
66
72
  });
67
73
 
68
74
  return formatSignupStart(response, Boolean(input.debug));
@@ -84,23 +90,59 @@ function formatSignupStart(response: PublicSignupResponse, includeRaw: boolean):
84
90
  const completeUrl = response.complete_url || valueFromLinks(response, 'complete_url');
85
91
  const status = session?.status || response.status || 'checkout_pending';
86
92
  const message = session?.status_message || response.status_message;
93
+ const agentPay = response.agent_pay || session?.agent_pay;
94
+ const payment = response.payment || session?.payment;
87
95
 
88
96
  const lines = [
89
97
  'Posterly signup started.',
90
98
  sessionId ? `Signup session: ${sessionId}` : '',
91
99
  `Status: ${status}`,
92
100
  message ? `Message: ${message}` : '',
93
- checkoutRedirectUrl ? `Checkout handoff URL: ${checkoutRedirectUrl}` : '',
101
+ agentPay?.amount_display
102
+ ? `Agent pay amount: ${agentPay.amount_display} ${String(agentPay.currency || 'usd').toUpperCase()}`
103
+ : '',
104
+ agentPay?.payment_intent_id ? `PaymentIntent: ${agentPay.payment_intent_id}` : '',
105
+ agentPay?.requires_tos_acceptance ? 'Terms acceptance required before client_secret is released.' : '',
106
+ agentPay?.client_secret ? `PaymentIntent client_secret: ${agentPay.client_secret}` : '',
107
+ agentPay?.confirm_url ? `Confirm URL: ${agentPay.confirm_url}` : '',
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
+ : '',
115
+ checkoutRedirectUrl ? `Checkout handoff URL (browser fallback): ${checkoutRedirectUrl}` : '',
94
116
  checkoutUrl ? `Checkout URL: ${checkoutUrl}` : '',
95
117
  pollUrl ? `Poll URL: ${pollUrl}` : '',
96
118
  completeUrl ? `Completion URL: ${completeUrl}` : '',
97
119
  '',
98
120
  'Next steps for the AI agent:',
99
- '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.',
100
- '2. Call get_signup_session with the signup session ID until the status changes.',
101
- '3. Tell the user when Posterly sends the password setup email.',
102
- '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.',
103
- '5. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
121
+ ...(agentPay?.enabled && agentPay?.requires_tos_acceptance
122
+ ? [
123
+ '1. Ask the user to explicitly confirm they accept the posterly terms at https://www.poster.ly/terms.',
124
+ '2. Once confirmed, POST { "tos_accepted": true } to Confirm URL (optionally with payment_method in the same call) to receive client_secret.',
125
+ '3. If the user would rather pay on the website, send them the Checkout handoff URL instead.',
126
+ '4. Call get_signup_session with the signup session ID until the status changes.',
127
+ '5. Do not ask for card details, the posterly password, social passwords, or OAuth codes.',
128
+ ]
129
+ : agentPay?.enabled
130
+ ? [
131
+ '1. Prefer agent_pay: confirm the PaymentIntent with a one-time Link Agent Wallet virtual card (credential_type: card). Never paste card numbers into chat or send them to posterly.',
132
+ '2. If the user would rather pay on the website, send them the Checkout handoff URL instead.',
133
+ '3. Call get_signup_session with the signup session ID until the status changes.',
134
+ '4. Tell the user when Posterly sends the password setup email. Password, social OAuth, and publish approval stay in the browser.',
135
+ '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.',
136
+ '6. Do not ask for card details, the Posterly password, social passwords, or OAuth codes.',
137
+ ]
138
+ : [
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.',
145
+ ]),
104
146
  includeRaw ? `\nRaw signup response:\n${JSON.stringify(response, null, 2)}` : '',
105
147
  ];
106
148