posterly-mcp-server 0.24.1 → 0.25.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.
- package/README.md +6 -1
- package/dist/index.js +50 -0
- package/dist/lib/api-client.d.ts +45 -1
- package/dist/lib/api-client.js +15 -0
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/tools/cancel-subscription.d.ts +30 -0
- package/dist/tools/cancel-subscription.js +41 -0
- package/dist/tools/create-api-key.d.ts +3 -3
- package/dist/tools/create-api-key.js +2 -2
- package/dist/tools/create-post.d.ts +18 -0
- package/dist/tools/create-post.js +1 -0
- package/dist/tools/create-posts-batch.d.ts +7 -0
- package/dist/tools/downgrade-subscription.d.ts +20 -0
- package/dist/tools/downgrade-subscription.js +23 -0
- package/dist/tools/get-subscription.d.ts +8 -0
- package/dist/tools/get-subscription.js +26 -0
- package/dist/tools/pause-subscription.d.ts +16 -0
- package/dist/tools/pause-subscription.js +21 -0
- package/dist/tools/resume-subscription.d.ts +8 -0
- package/dist/tools/resume-subscription.js +11 -0
- package/dist/tools/update-post.d.ts +8 -0
- package/dist/tools/update-post.js +1 -0
- package/package.json +1 -1
- package/src/index.ts +75 -0
- package/src/lib/api-client.ts +68 -1
- package/src/lib/version.ts +1 -1
- package/src/tools/cancel-subscription.ts +50 -0
- package/src/tools/create-api-key.ts +2 -2
- package/src/tools/create-post.ts +1 -0
- package/src/tools/downgrade-subscription.ts +29 -0
- package/src/tools/get-subscription.ts +31 -0
- package/src/tools/pause-subscription.ts +26 -0
- package/src/tools/resume-subscription.ts +15 -0
- package/src/tools/update-post.ts +1 -0
package/README.md
CHANGED
|
@@ -108,7 +108,7 @@ Add the same server definition to your Cursor MCP settings:
|
|
|
108
108
|
|
|
109
109
|
## Available tools
|
|
110
110
|
|
|
111
|
-
`posterly-mcp-server@0.
|
|
111
|
+
`posterly-mcp-server@0.25.0` exposes 72 tools.
|
|
112
112
|
|
|
113
113
|
Public setup tools work before `POSTERLY_API_KEY` exists:
|
|
114
114
|
|
|
@@ -127,6 +127,11 @@ Authenticated tools require `POSTERLY_API_KEY`:
|
|
|
127
127
|
- `get_connect_session` (poll connection progress while the user approves OAuth or enters credentials)
|
|
128
128
|
- `create_api_key` (create a new API key after explicit confirmation; scopes cannot exceed the calling dashboard key)
|
|
129
129
|
- `delete_api_key` (revoke a user-created API key after explicit confirmation)
|
|
130
|
+
- `get_subscription` (read subscription status, tier, and cancel/pause state; requires `billing:read`)
|
|
131
|
+
- `cancel_subscription` (cancel after explicit confirmation; the agent must ask for a `reason` first; requires `billing:write`)
|
|
132
|
+
- `pause_subscription` (pause 30 days, one per 90-day cooldown, after confirmation; requires `billing:write`)
|
|
133
|
+
- `resume_subscription` (resume a paused subscription; requires `billing:write`)
|
|
134
|
+
- `downgrade_subscription` (downgrade one tier at next renewal after confirmation; requires `billing:write`)
|
|
130
135
|
- `list_oauth_clients`
|
|
131
136
|
- `create_oauth_client` (create a public PKCE client after explicit confirmation)
|
|
132
137
|
- `update_oauth_client` (update redirect URIs/scopes after explicit confirmation)
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,11 @@ import { createConnectSessionTool } from './tools/create-connect-session.js';
|
|
|
66
66
|
import { getConnectSessionTool } from './tools/get-connect-session.js';
|
|
67
67
|
import { createApiKeyTool } from './tools/create-api-key.js';
|
|
68
68
|
import { deleteApiKeyTool } from './tools/delete-api-key.js';
|
|
69
|
+
import { getSubscriptionTool } from './tools/get-subscription.js';
|
|
70
|
+
import { cancelSubscriptionTool } from './tools/cancel-subscription.js';
|
|
71
|
+
import { pauseSubscriptionTool } from './tools/pause-subscription.js';
|
|
72
|
+
import { resumeSubscriptionTool } from './tools/resume-subscription.js';
|
|
73
|
+
import { downgradeSubscriptionTool } from './tools/downgrade-subscription.js';
|
|
69
74
|
import { listOAuthClientsTool } from './tools/list-oauth-clients.js';
|
|
70
75
|
import { createOAuthClientTool } from './tools/create-oauth-client.js';
|
|
71
76
|
import { updateOAuthClientTool } from './tools/update-oauth-client.js';
|
|
@@ -184,6 +189,51 @@ server.tool(deleteApiKeyTool.name, deleteApiKeyTool.description, deleteApiKeyToo
|
|
|
184
189
|
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
185
190
|
}
|
|
186
191
|
});
|
|
192
|
+
server.tool(getSubscriptionTool.name, getSubscriptionTool.description, getSubscriptionTool.inputSchema.shape, async () => {
|
|
193
|
+
try {
|
|
194
|
+
const text = await getSubscriptionTool.execute(client);
|
|
195
|
+
return { content: [{ type: 'text', text }] };
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
server.tool(cancelSubscriptionTool.name, cancelSubscriptionTool.description, cancelSubscriptionTool.inputSchema.shape, async (input) => {
|
|
202
|
+
try {
|
|
203
|
+
const text = await cancelSubscriptionTool.execute(client, input);
|
|
204
|
+
return { content: [{ type: 'text', text }] };
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
server.tool(pauseSubscriptionTool.name, pauseSubscriptionTool.description, pauseSubscriptionTool.inputSchema.shape, async (input) => {
|
|
211
|
+
try {
|
|
212
|
+
const text = await pauseSubscriptionTool.execute(client, input);
|
|
213
|
+
return { content: [{ type: 'text', text }] };
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
server.tool(resumeSubscriptionTool.name, resumeSubscriptionTool.description, resumeSubscriptionTool.inputSchema.shape, async () => {
|
|
220
|
+
try {
|
|
221
|
+
const text = await resumeSubscriptionTool.execute(client);
|
|
222
|
+
return { content: [{ type: 'text', text }] };
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
server.tool(downgradeSubscriptionTool.name, downgradeSubscriptionTool.description, downgradeSubscriptionTool.inputSchema.shape, async (input) => {
|
|
229
|
+
try {
|
|
230
|
+
const text = await downgradeSubscriptionTool.execute(client, input);
|
|
231
|
+
return { content: [{ type: 'text', text }] };
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
235
|
+
}
|
|
236
|
+
});
|
|
187
237
|
server.tool(listOAuthClientsTool.name, listOAuthClientsTool.description, listOAuthClientsTool.inputSchema.shape, async () => {
|
|
188
238
|
try {
|
|
189
239
|
const text = await listOAuthClientsTool.execute(client);
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -237,7 +237,7 @@ export type AskSupportPayload = {
|
|
|
237
237
|
request_human?: boolean;
|
|
238
238
|
confirm_escalation?: boolean;
|
|
239
239
|
};
|
|
240
|
-
export type ApiKeyScope = 'accounts:read' | 'accounts:write' | 'posts:read' | 'posts:write' | 'media:write' | 'analytics:read';
|
|
240
|
+
export type ApiKeyScope = 'accounts:read' | 'accounts:write' | 'posts:read' | 'posts:write' | 'media:write' | 'analytics:read' | 'billing:read' | 'billing:write';
|
|
241
241
|
export type CreateApiKeyPayload = {
|
|
242
242
|
name?: string;
|
|
243
243
|
scopes?: ApiKeyScope[];
|
|
@@ -279,6 +279,43 @@ export type DeleteApiKeyResponse = {
|
|
|
279
279
|
is_revoked?: boolean;
|
|
280
280
|
};
|
|
281
281
|
};
|
|
282
|
+
export type SubscriptionTierName = 'starter' | 'pro' | 'power_user' | 'agency';
|
|
283
|
+
export type SubscriptionSummary = {
|
|
284
|
+
id: string | null;
|
|
285
|
+
status: string | null;
|
|
286
|
+
tier: string | null;
|
|
287
|
+
cancel_at_period_end: boolean | null;
|
|
288
|
+
current_period_end: string | null;
|
|
289
|
+
trial_ends_at: string | null;
|
|
290
|
+
paused_at: string | null;
|
|
291
|
+
pause_resumes_at: string | null;
|
|
292
|
+
stripe_subscription_id: string | null;
|
|
293
|
+
};
|
|
294
|
+
export type SubscriptionSummaryResponse = {
|
|
295
|
+
subscription: SubscriptionSummary;
|
|
296
|
+
};
|
|
297
|
+
export type CancelSubscriptionPayload = {
|
|
298
|
+
reason: string;
|
|
299
|
+
feedback?: string;
|
|
300
|
+
immediate?: boolean;
|
|
301
|
+
};
|
|
302
|
+
export type CancelSubscriptionResponse = {
|
|
303
|
+
success: true;
|
|
304
|
+
immediate: boolean;
|
|
305
|
+
canceled_at: string | null;
|
|
306
|
+
cancel_at_period_end: boolean;
|
|
307
|
+
};
|
|
308
|
+
export type PauseSubscriptionResponse = {
|
|
309
|
+
success: true;
|
|
310
|
+
pause_resumes_at: string;
|
|
311
|
+
};
|
|
312
|
+
export type ResumeSubscriptionResponse = {
|
|
313
|
+
success: true;
|
|
314
|
+
};
|
|
315
|
+
export type DowngradeSubscriptionResponse = {
|
|
316
|
+
success: true;
|
|
317
|
+
tier: SubscriptionTierName;
|
|
318
|
+
};
|
|
282
319
|
export type AskSupportResponse = {
|
|
283
320
|
success: boolean;
|
|
284
321
|
workspace_id: string;
|
|
@@ -698,6 +735,13 @@ export declare class PosterlyClient {
|
|
|
698
735
|
deleteApiKey(keyId: string, data: {
|
|
699
736
|
confirm: true;
|
|
700
737
|
}): Promise<DeleteApiKeyResponse>;
|
|
738
|
+
getSubscription(): Promise<SubscriptionSummaryResponse>;
|
|
739
|
+
cancelSubscription(data: CancelSubscriptionPayload): Promise<CancelSubscriptionResponse>;
|
|
740
|
+
pauseSubscription(): Promise<PauseSubscriptionResponse>;
|
|
741
|
+
resumeSubscription(): Promise<ResumeSubscriptionResponse>;
|
|
742
|
+
downgradeSubscription(data: {
|
|
743
|
+
tier?: SubscriptionTierName;
|
|
744
|
+
}): Promise<DowngradeSubscriptionResponse>;
|
|
701
745
|
listAccounts(params?: {
|
|
702
746
|
workspace_id?: string;
|
|
703
747
|
}): Promise<Account[]>;
|
package/dist/lib/api-client.js
CHANGED
|
@@ -122,6 +122,21 @@ export class PosterlyClient {
|
|
|
122
122
|
async deleteApiKey(keyId, data) {
|
|
123
123
|
return this.request('DELETE', `/api-keys/${encodeURIComponent(keyId)}`, data);
|
|
124
124
|
}
|
|
125
|
+
async getSubscription() {
|
|
126
|
+
return this.request('GET', '/subscription');
|
|
127
|
+
}
|
|
128
|
+
async cancelSubscription(data) {
|
|
129
|
+
return this.request('POST', '/subscription/cancel', data);
|
|
130
|
+
}
|
|
131
|
+
async pauseSubscription() {
|
|
132
|
+
return this.request('POST', '/subscription/pause', {});
|
|
133
|
+
}
|
|
134
|
+
async resumeSubscription() {
|
|
135
|
+
return this.request('POST', '/subscription/resume', {});
|
|
136
|
+
}
|
|
137
|
+
async downgradeSubscription(data) {
|
|
138
|
+
return this.request('POST', '/subscription/downgrade', data);
|
|
139
|
+
}
|
|
125
140
|
async listAccounts(params) {
|
|
126
141
|
const searchParams = new URLSearchParams();
|
|
127
142
|
if (params?.workspace_id)
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const POSTERLY_MCP_VERSION = "0.
|
|
1
|
+
export declare const POSTERLY_MCP_VERSION = "0.25.0";
|
package/dist/lib/version.js
CHANGED
|
@@ -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.
|
|
8
|
+
export const POSTERLY_MCP_VERSION = '0.25.0';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
declare const CANCELLATION_REASONS: readonly ["too_expensive", "not_using", "missing_features", "technical_issues", "switching_service", "temporary_break", "other"];
|
|
4
|
+
export declare const cancelSubscriptionTool: {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
inputSchema: z.ZodObject<{
|
|
8
|
+
reason: z.ZodEnum<["too_expensive", "not_using", "missing_features", "technical_issues", "switching_service", "temporary_break", "other"]>;
|
|
9
|
+
feedback: z.ZodOptional<z.ZodString>;
|
|
10
|
+
immediate: z.ZodOptional<z.ZodBoolean>;
|
|
11
|
+
confirm: z.ZodLiteral<true>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
confirm: true;
|
|
14
|
+
reason: "too_expensive" | "not_using" | "missing_features" | "technical_issues" | "switching_service" | "temporary_break" | "other";
|
|
15
|
+
feedback?: string | undefined;
|
|
16
|
+
immediate?: boolean | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
confirm: true;
|
|
19
|
+
reason: "too_expensive" | "not_using" | "missing_features" | "technical_issues" | "switching_service" | "temporary_break" | "other";
|
|
20
|
+
feedback?: string | undefined;
|
|
21
|
+
immediate?: boolean | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
execute(client: PosterlyClient, input: {
|
|
24
|
+
reason: (typeof CANCELLATION_REASONS)[number];
|
|
25
|
+
feedback?: string;
|
|
26
|
+
immediate?: boolean;
|
|
27
|
+
confirm: true;
|
|
28
|
+
}): Promise<string>;
|
|
29
|
+
};
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
3
|
+
// Mirrors CANCELLATION_REASONS in the main app (lib/subscription-reasons.ts).
|
|
4
|
+
// Kept in sync manually because the npm package cannot import from the app.
|
|
5
|
+
const CANCELLATION_REASONS = [
|
|
6
|
+
'too_expensive',
|
|
7
|
+
'not_using',
|
|
8
|
+
'missing_features',
|
|
9
|
+
'technical_issues',
|
|
10
|
+
'switching_service',
|
|
11
|
+
'temporary_break',
|
|
12
|
+
'other',
|
|
13
|
+
];
|
|
14
|
+
function formatCanceled(result) {
|
|
15
|
+
return [
|
|
16
|
+
mdTitle(result.immediate ? 'Subscription cancelled immediately' : 'Subscription set to cancel at period end'),
|
|
17
|
+
mdSection('Details', mdKeyValue([
|
|
18
|
+
['Immediate', result.immediate ? 'yes' : 'no'],
|
|
19
|
+
['Cancel at period end', result.cancel_at_period_end ? 'yes' : 'no'],
|
|
20
|
+
['Canceled at', result.canceled_at || 'at end of current period'],
|
|
21
|
+
])),
|
|
22
|
+
].join('\n\n');
|
|
23
|
+
}
|
|
24
|
+
export const cancelSubscriptionTool = {
|
|
25
|
+
name: 'cancel_subscription',
|
|
26
|
+
description: "Cancel the authenticated user's posterly subscription. DESTRUCTIVE billing action; requires the billing:write scope. ALWAYS ask the user why they are cancelling FIRST and pass their answer as `reason` (one of the allowed values). By default the subscription is set to cancel at the end of the current period; pass immediate=true only if the user explicitly wants it cancelled right now. Only call after the user explicitly confirms.",
|
|
27
|
+
inputSchema: z.object({
|
|
28
|
+
reason: z.enum(CANCELLATION_REASONS).describe('Why the user is cancelling. Ask the user before calling; do not guess.'),
|
|
29
|
+
feedback: z.string().max(2000).optional().describe('Optional free-text detail the user gave about why they are cancelling.'),
|
|
30
|
+
immediate: z.boolean().optional().describe('Cancel immediately instead of at period end. Defaults to false (cancel at period end).'),
|
|
31
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms the cancellation.'),
|
|
32
|
+
}),
|
|
33
|
+
async execute(client, input) {
|
|
34
|
+
const result = await client.cancelSubscription({
|
|
35
|
+
reason: input.reason,
|
|
36
|
+
feedback: input.feedback,
|
|
37
|
+
immediate: input.immediate === true,
|
|
38
|
+
});
|
|
39
|
+
return formatCanceled(result);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -5,7 +5,7 @@ export declare const createApiKeyTool: {
|
|
|
5
5
|
description: string;
|
|
6
6
|
inputSchema: z.ZodObject<{
|
|
7
7
|
name: z.ZodOptional<z.ZodString>;
|
|
8
|
-
scopes: z.ZodOptional<z.ZodArray<z.ZodEnum<["accounts:read", "accounts:write", "posts:read", "posts:write", "media:write", "analytics:read"]>, "many">>;
|
|
8
|
+
scopes: z.ZodOptional<z.ZodArray<z.ZodEnum<["accounts:read", "accounts:write", "posts:read", "posts:write", "media:write", "analytics:read", "billing:read", "billing:write"]>, "many">>;
|
|
9
9
|
workspace_id: z.ZodOptional<z.ZodString>;
|
|
10
10
|
expires_in_days: z.ZodOptional<z.ZodNumber>;
|
|
11
11
|
confirm: z.ZodLiteral<true>;
|
|
@@ -13,13 +13,13 @@ export declare const createApiKeyTool: {
|
|
|
13
13
|
confirm: true;
|
|
14
14
|
workspace_id?: string | undefined;
|
|
15
15
|
name?: string | undefined;
|
|
16
|
-
scopes?: ("accounts:read" | "accounts:write" | "posts:read" | "posts:write" | "media:write" | "analytics:read")[] | undefined;
|
|
16
|
+
scopes?: ("accounts:read" | "accounts:write" | "posts:read" | "posts:write" | "media:write" | "analytics:read" | "billing:read" | "billing:write")[] | undefined;
|
|
17
17
|
expires_in_days?: number | undefined;
|
|
18
18
|
}, {
|
|
19
19
|
confirm: true;
|
|
20
20
|
workspace_id?: string | undefined;
|
|
21
21
|
name?: string | undefined;
|
|
22
|
-
scopes?: ("accounts:read" | "accounts:write" | "posts:read" | "posts:write" | "media:write" | "analytics:read")[] | undefined;
|
|
22
|
+
scopes?: ("accounts:read" | "accounts:write" | "posts:read" | "posts:write" | "media:write" | "analytics:read" | "billing:read" | "billing:write")[] | undefined;
|
|
23
23
|
expires_in_days?: number | undefined;
|
|
24
24
|
}>;
|
|
25
25
|
execute(client: PosterlyClient, input: CreateApiKeyPayload): Promise<string>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { code, mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
3
|
-
const scopeSchema = z.enum(['accounts:read', 'accounts:write', 'posts:read', 'posts:write', 'media:write', 'analytics:read']);
|
|
3
|
+
const scopeSchema = z.enum(['accounts:read', 'accounts:write', 'posts:read', 'posts:write', 'media:write', 'analytics:read', 'billing:read', 'billing:write']);
|
|
4
4
|
function formatCreatedApiKey(result) {
|
|
5
5
|
const key = result.api_key;
|
|
6
6
|
return [
|
|
@@ -23,7 +23,7 @@ export const createApiKeyTool = {
|
|
|
23
23
|
description: 'Create a new Posterly API key for the authenticated user. SECRET-CREATING WRITE: only use after explicit user confirmation. The new key can only request scopes already present on the calling dashboard-created API key; OAuth and managed assistant tokens cannot mint keys.',
|
|
24
24
|
inputSchema: z.object({
|
|
25
25
|
name: z.string().trim().min(1).max(120).optional().describe('Human-readable key name.'),
|
|
26
|
-
scopes: z.array(scopeSchema).min(1).max(
|
|
26
|
+
scopes: z.array(scopeSchema).min(1).max(8).optional().describe('Scopes for the new key. Omit to copy the calling key scopes. Cannot exceed the calling key scopes. billing:read and billing:write allow managing the posterly subscription (cancel/pause/resume/downgrade).'),
|
|
27
27
|
workspace_id: z.string().trim().min(1).optional().describe('Optional workspace restriction. Workspace-scoped calling keys cannot create keys outside their workspace.'),
|
|
28
28
|
expires_in_days: z.number().int().min(1).max(365).optional().describe('Optional expiry from now, up to 365 days. Omit for no expiry.'),
|
|
29
29
|
confirm: z.literal(true).describe('Must be true after the user explicitly confirms that a new secret API key should be created.'),
|
|
@@ -117,6 +117,7 @@ export declare const platformSettingsSchema: z.ZodObject<{
|
|
|
117
117
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
118
118
|
title: z.ZodOptional<z.ZodString>;
|
|
119
119
|
media_type: z.ZodOptional<z.ZodString>;
|
|
120
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
120
121
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
121
122
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
122
123
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -193,6 +194,7 @@ export declare const platformSettingsSchema: z.ZodObject<{
|
|
|
193
194
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
194
195
|
title: z.ZodOptional<z.ZodString>;
|
|
195
196
|
media_type: z.ZodOptional<z.ZodString>;
|
|
197
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
196
198
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
197
199
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
198
200
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -269,6 +271,7 @@ export declare const platformSettingsSchema: z.ZodObject<{
|
|
|
269
271
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
270
272
|
title: z.ZodOptional<z.ZodString>;
|
|
271
273
|
media_type: z.ZodOptional<z.ZodString>;
|
|
274
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
272
275
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
273
276
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
274
277
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -430,6 +433,7 @@ export declare const createPostPayloadInputSchema: z.ZodObject<{
|
|
|
430
433
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
431
434
|
title: z.ZodOptional<z.ZodString>;
|
|
432
435
|
media_type: z.ZodOptional<z.ZodString>;
|
|
436
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
433
437
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
434
438
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
435
439
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -506,6 +510,7 @@ export declare const createPostPayloadInputSchema: z.ZodObject<{
|
|
|
506
510
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
507
511
|
title: z.ZodOptional<z.ZodString>;
|
|
508
512
|
media_type: z.ZodOptional<z.ZodString>;
|
|
513
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
509
514
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
510
515
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
511
516
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -582,6 +587,7 @@ export declare const createPostPayloadInputSchema: z.ZodObject<{
|
|
|
582
587
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
583
588
|
title: z.ZodOptional<z.ZodString>;
|
|
584
589
|
media_type: z.ZodOptional<z.ZodString>;
|
|
590
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
585
591
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
586
592
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
587
593
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -691,6 +697,7 @@ export declare const createPostPayloadInputSchema: z.ZodObject<{
|
|
|
691
697
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
692
698
|
title: z.ZodOptional<z.ZodString>;
|
|
693
699
|
media_type: z.ZodOptional<z.ZodString>;
|
|
700
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
694
701
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
695
702
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
696
703
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -799,6 +806,7 @@ export declare const createPostPayloadInputSchema: z.ZodObject<{
|
|
|
799
806
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
800
807
|
title: z.ZodOptional<z.ZodString>;
|
|
801
808
|
media_type: z.ZodOptional<z.ZodString>;
|
|
809
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
802
810
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
803
811
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
804
812
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -961,6 +969,7 @@ export declare const createPostInputSchema: z.ZodObject<{
|
|
|
961
969
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
962
970
|
title: z.ZodOptional<z.ZodString>;
|
|
963
971
|
media_type: z.ZodOptional<z.ZodString>;
|
|
972
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
964
973
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
965
974
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
966
975
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1037,6 +1046,7 @@ export declare const createPostInputSchema: z.ZodObject<{
|
|
|
1037
1046
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1038
1047
|
title: z.ZodOptional<z.ZodString>;
|
|
1039
1048
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1049
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1040
1050
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1041
1051
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1042
1052
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1113,6 +1123,7 @@ export declare const createPostInputSchema: z.ZodObject<{
|
|
|
1113
1123
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1114
1124
|
title: z.ZodOptional<z.ZodString>;
|
|
1115
1125
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1126
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1116
1127
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1117
1128
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1118
1129
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1225,6 +1236,7 @@ export declare const createPostInputSchema: z.ZodObject<{
|
|
|
1225
1236
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1226
1237
|
title: z.ZodOptional<z.ZodString>;
|
|
1227
1238
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1239
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1228
1240
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1229
1241
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1230
1242
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1334,6 +1346,7 @@ export declare const createPostInputSchema: z.ZodObject<{
|
|
|
1334
1346
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1335
1347
|
title: z.ZodOptional<z.ZodString>;
|
|
1336
1348
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1349
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1337
1350
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1338
1351
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1339
1352
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1502,6 +1515,7 @@ export declare const createPostTool: {
|
|
|
1502
1515
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1503
1516
|
title: z.ZodOptional<z.ZodString>;
|
|
1504
1517
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1518
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1505
1519
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1506
1520
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1507
1521
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1578,6 +1592,7 @@ export declare const createPostTool: {
|
|
|
1578
1592
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1579
1593
|
title: z.ZodOptional<z.ZodString>;
|
|
1580
1594
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1595
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1581
1596
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1582
1597
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1583
1598
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1654,6 +1669,7 @@ export declare const createPostTool: {
|
|
|
1654
1669
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1655
1670
|
title: z.ZodOptional<z.ZodString>;
|
|
1656
1671
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1672
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1657
1673
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1658
1674
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1659
1675
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1766,6 +1782,7 @@ export declare const createPostTool: {
|
|
|
1766
1782
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1767
1783
|
title: z.ZodOptional<z.ZodString>;
|
|
1768
1784
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1785
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1769
1786
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1770
1787
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1771
1788
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1875,6 +1892,7 @@ export declare const createPostTool: {
|
|
|
1875
1892
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
1876
1893
|
title: z.ZodOptional<z.ZodString>;
|
|
1877
1894
|
media_type: z.ZodOptional<z.ZodString>;
|
|
1895
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
1878
1896
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
1879
1897
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
1880
1898
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -53,6 +53,7 @@ export const platformSettingsSchema = z.object({
|
|
|
53
53
|
allow_stitch: z.boolean().optional(),
|
|
54
54
|
title: z.string().optional(),
|
|
55
55
|
media_type: z.string().optional(), // TikTok: 'PHOTO' forces a photo slideshow; image media is auto-detected when omitted
|
|
56
|
+
video_cover_timestamp_ms: z.number().nonnegative().optional(), // TikTok: millisecond timestamp of the video frame to use as the cover (direct post only)
|
|
56
57
|
is_commercial_content: z.boolean().optional(),
|
|
57
58
|
is_your_brand: z.boolean().optional(),
|
|
58
59
|
is_branded_content: z.boolean().optional(),
|
|
@@ -132,6 +132,7 @@ export declare const createPostsBatchTool: {
|
|
|
132
132
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
133
133
|
title: z.ZodOptional<z.ZodString>;
|
|
134
134
|
media_type: z.ZodOptional<z.ZodString>;
|
|
135
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
135
136
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
136
137
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
137
138
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -208,6 +209,7 @@ export declare const createPostsBatchTool: {
|
|
|
208
209
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
209
210
|
title: z.ZodOptional<z.ZodString>;
|
|
210
211
|
media_type: z.ZodOptional<z.ZodString>;
|
|
212
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
211
213
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
212
214
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
213
215
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -284,6 +286,7 @@ export declare const createPostsBatchTool: {
|
|
|
284
286
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
285
287
|
title: z.ZodOptional<z.ZodString>;
|
|
286
288
|
media_type: z.ZodOptional<z.ZodString>;
|
|
289
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
287
290
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
288
291
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
289
292
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -393,6 +396,7 @@ export declare const createPostsBatchTool: {
|
|
|
393
396
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
394
397
|
title: z.ZodOptional<z.ZodString>;
|
|
395
398
|
media_type: z.ZodOptional<z.ZodString>;
|
|
399
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
396
400
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
397
401
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
398
402
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -501,6 +505,7 @@ export declare const createPostsBatchTool: {
|
|
|
501
505
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
502
506
|
title: z.ZodOptional<z.ZodString>;
|
|
503
507
|
media_type: z.ZodOptional<z.ZodString>;
|
|
508
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
504
509
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
505
510
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
506
511
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -613,6 +618,7 @@ export declare const createPostsBatchTool: {
|
|
|
613
618
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
614
619
|
title: z.ZodOptional<z.ZodString>;
|
|
615
620
|
media_type: z.ZodOptional<z.ZodString>;
|
|
621
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
616
622
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
617
623
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
618
624
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -724,6 +730,7 @@ export declare const createPostsBatchTool: {
|
|
|
724
730
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
725
731
|
title: z.ZodOptional<z.ZodString>;
|
|
726
732
|
media_type: z.ZodOptional<z.ZodString>;
|
|
733
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
727
734
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
728
735
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
729
736
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient, SubscriptionTierName } from '../lib/api-client.js';
|
|
3
|
+
export declare const downgradeSubscriptionTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{
|
|
7
|
+
tier: z.ZodOptional<z.ZodEnum<["starter", "pro", "power_user", "agency"]>>;
|
|
8
|
+
confirm: z.ZodLiteral<true>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
confirm: true;
|
|
11
|
+
tier?: "starter" | "pro" | "power_user" | "agency" | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
confirm: true;
|
|
14
|
+
tier?: "starter" | "pro" | "power_user" | "agency" | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
execute(client: PosterlyClient, input: {
|
|
17
|
+
tier?: SubscriptionTierName;
|
|
18
|
+
confirm: true;
|
|
19
|
+
}): Promise<string>;
|
|
20
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
3
|
+
const TIER_VALUES = ['starter', 'pro', 'power_user', 'agency'];
|
|
4
|
+
function formatDowngraded(result) {
|
|
5
|
+
return [
|
|
6
|
+
mdTitle('Subscription downgrade scheduled'),
|
|
7
|
+
mdSection('Details', mdKeyValue([
|
|
8
|
+
['New tier at next renewal', result.tier],
|
|
9
|
+
])),
|
|
10
|
+
].join('\n\n');
|
|
11
|
+
}
|
|
12
|
+
export const downgradeSubscriptionTool = {
|
|
13
|
+
name: 'downgrade_subscription',
|
|
14
|
+
description: "Downgrade the authenticated user's posterly subscription one tier (or to an explicit lower `tier`) at the next renewal with no proration. Billing action; requires the billing:write scope. Only call after the user explicitly confirms.",
|
|
15
|
+
inputSchema: z.object({
|
|
16
|
+
tier: z.enum(TIER_VALUES).optional().describe('Optional explicit target tier. Omit to drop one tier automatically.'),
|
|
17
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms the downgrade.'),
|
|
18
|
+
}),
|
|
19
|
+
async execute(client, input) {
|
|
20
|
+
const result = await client.downgradeSubscription({ tier: input.tier });
|
|
21
|
+
return formatDowngraded(result);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
export declare const getSubscriptionTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
7
|
+
execute(client: PosterlyClient): Promise<string>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { formatDateTime, mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
3
|
+
function formatSubscription(result) {
|
|
4
|
+
const sub = result.subscription;
|
|
5
|
+
return [
|
|
6
|
+
mdTitle('posterly subscription'),
|
|
7
|
+
mdSection('Details', mdKeyValue([
|
|
8
|
+
['Status', sub.status || 'unknown'],
|
|
9
|
+
['Tier', sub.tier || 'unknown'],
|
|
10
|
+
['Cancel at period end', sub.cancel_at_period_end ? 'yes' : 'no'],
|
|
11
|
+
['Current period end', sub.current_period_end ? formatDateTime(sub.current_period_end) : 'n/a'],
|
|
12
|
+
['Trial ends', sub.trial_ends_at ? formatDateTime(sub.trial_ends_at) : 'n/a'],
|
|
13
|
+
['Paused at', sub.paused_at ? formatDateTime(sub.paused_at) : 'n/a'],
|
|
14
|
+
['Pause resumes at', sub.pause_resumes_at ? formatDateTime(sub.pause_resumes_at) : 'n/a'],
|
|
15
|
+
])),
|
|
16
|
+
].join('\n\n');
|
|
17
|
+
}
|
|
18
|
+
export const getSubscriptionTool = {
|
|
19
|
+
name: 'get_subscription',
|
|
20
|
+
description: "Get the authenticated user's posterly subscription: status, tier, cancel-at-period-end, current period end, trial end, and pause state. Read-only. Requires the billing:read scope.",
|
|
21
|
+
inputSchema: z.object({}),
|
|
22
|
+
async execute(client) {
|
|
23
|
+
const result = await client.getSubscription();
|
|
24
|
+
return formatSubscription(result);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
export declare const pauseSubscriptionTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{
|
|
7
|
+
confirm: z.ZodLiteral<true>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
confirm: true;
|
|
10
|
+
}, {
|
|
11
|
+
confirm: true;
|
|
12
|
+
}>;
|
|
13
|
+
execute(client: PosterlyClient, _input: {
|
|
14
|
+
confirm: true;
|
|
15
|
+
}): Promise<string>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { formatDateTime, mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
3
|
+
function formatPaused(result) {
|
|
4
|
+
return [
|
|
5
|
+
mdTitle('Subscription paused'),
|
|
6
|
+
mdSection('Details', mdKeyValue([
|
|
7
|
+
['Resumes at', result.pause_resumes_at ? formatDateTime(result.pause_resumes_at) : 'n/a'],
|
|
8
|
+
])),
|
|
9
|
+
].join('\n\n');
|
|
10
|
+
}
|
|
11
|
+
export const pauseSubscriptionTool = {
|
|
12
|
+
name: 'pause_subscription',
|
|
13
|
+
description: "Pause the authenticated user's posterly subscription for 30 days (one pause allowed per 90-day cooldown). Billing action; requires the billing:write scope. Only call after the user explicitly confirms.",
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms pausing the subscription.'),
|
|
16
|
+
}),
|
|
17
|
+
async execute(client, _input) {
|
|
18
|
+
const result = await client.pauseSubscription();
|
|
19
|
+
return formatPaused(result);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
export declare const resumeSubscriptionTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
7
|
+
execute(client: PosterlyClient): Promise<string>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { mdTitle } from '../lib/format.js';
|
|
3
|
+
export const resumeSubscriptionTool = {
|
|
4
|
+
name: 'resume_subscription',
|
|
5
|
+
description: "Resume the authenticated user's paused posterly subscription, restoring active billing. Requires the billing:write scope.",
|
|
6
|
+
inputSchema: z.object({}),
|
|
7
|
+
async execute(client) {
|
|
8
|
+
await client.resumeSubscription();
|
|
9
|
+
return mdTitle('Subscription resumed', 'Billing has been restored to active.');
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -116,6 +116,7 @@ declare const platformSettingsSchema: z.ZodObject<{
|
|
|
116
116
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
117
117
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
118
118
|
title: z.ZodOptional<z.ZodString>;
|
|
119
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
119
120
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
120
121
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
121
122
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -191,6 +192,7 @@ declare const platformSettingsSchema: z.ZodObject<{
|
|
|
191
192
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
192
193
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
193
194
|
title: z.ZodOptional<z.ZodString>;
|
|
195
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
194
196
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
195
197
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
196
198
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -266,6 +268,7 @@ declare const platformSettingsSchema: z.ZodObject<{
|
|
|
266
268
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
267
269
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
268
270
|
title: z.ZodOptional<z.ZodString>;
|
|
271
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
269
272
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
270
273
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
271
274
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -426,6 +429,7 @@ export declare const updatePostTool: {
|
|
|
426
429
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
427
430
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
428
431
|
title: z.ZodOptional<z.ZodString>;
|
|
432
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
429
433
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
430
434
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
431
435
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -501,6 +505,7 @@ export declare const updatePostTool: {
|
|
|
501
505
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
502
506
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
503
507
|
title: z.ZodOptional<z.ZodString>;
|
|
508
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
504
509
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
505
510
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
506
511
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -576,6 +581,7 @@ export declare const updatePostTool: {
|
|
|
576
581
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
577
582
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
578
583
|
title: z.ZodOptional<z.ZodString>;
|
|
584
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
579
585
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
580
586
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
581
587
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -681,6 +687,7 @@ export declare const updatePostTool: {
|
|
|
681
687
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
682
688
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
683
689
|
title: z.ZodOptional<z.ZodString>;
|
|
690
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
684
691
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
685
692
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
686
693
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -785,6 +792,7 @@ export declare const updatePostTool: {
|
|
|
785
792
|
allow_duet: z.ZodOptional<z.ZodBoolean>;
|
|
786
793
|
allow_stitch: z.ZodOptional<z.ZodBoolean>;
|
|
787
794
|
title: z.ZodOptional<z.ZodString>;
|
|
795
|
+
video_cover_timestamp_ms: z.ZodOptional<z.ZodNumber>;
|
|
788
796
|
is_commercial_content: z.ZodOptional<z.ZodBoolean>;
|
|
789
797
|
is_your_brand: z.ZodOptional<z.ZodBoolean>;
|
|
790
798
|
is_branded_content: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -40,6 +40,7 @@ const platformSettingsSchema = z.object({
|
|
|
40
40
|
allow_duet: z.boolean().optional(),
|
|
41
41
|
allow_stitch: z.boolean().optional(),
|
|
42
42
|
title: z.string().optional(),
|
|
43
|
+
video_cover_timestamp_ms: z.number().nonnegative().optional(), // TikTok: millisecond timestamp of the video frame to use as the cover (direct post only)
|
|
43
44
|
is_commercial_content: z.boolean().optional(),
|
|
44
45
|
is_your_brand: z.boolean().optional(),
|
|
45
46
|
is_branded_content: z.boolean().optional(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "posterly-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "MCP server for posterly: schedule and publish social media posts across 11 platforms from any MCP client (Claude, ChatGPT, Cursor, Windsurf, Cline, and more)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://www.poster.ly/mcp",
|
package/src/index.ts
CHANGED
|
@@ -67,6 +67,11 @@ import { createConnectSessionTool } from './tools/create-connect-session.js';
|
|
|
67
67
|
import { getConnectSessionTool } from './tools/get-connect-session.js';
|
|
68
68
|
import { createApiKeyTool } from './tools/create-api-key.js';
|
|
69
69
|
import { deleteApiKeyTool } from './tools/delete-api-key.js';
|
|
70
|
+
import { getSubscriptionTool } from './tools/get-subscription.js';
|
|
71
|
+
import { cancelSubscriptionTool } from './tools/cancel-subscription.js';
|
|
72
|
+
import { pauseSubscriptionTool } from './tools/pause-subscription.js';
|
|
73
|
+
import { resumeSubscriptionTool } from './tools/resume-subscription.js';
|
|
74
|
+
import { downgradeSubscriptionTool } from './tools/downgrade-subscription.js';
|
|
70
75
|
import { listOAuthClientsTool } from './tools/list-oauth-clients.js';
|
|
71
76
|
import { createOAuthClientTool } from './tools/create-oauth-client.js';
|
|
72
77
|
import { updateOAuthClientTool } from './tools/update-oauth-client.js';
|
|
@@ -248,6 +253,76 @@ server.tool(
|
|
|
248
253
|
}
|
|
249
254
|
);
|
|
250
255
|
|
|
256
|
+
server.tool(
|
|
257
|
+
getSubscriptionTool.name,
|
|
258
|
+
getSubscriptionTool.description,
|
|
259
|
+
getSubscriptionTool.inputSchema.shape,
|
|
260
|
+
async () => {
|
|
261
|
+
try {
|
|
262
|
+
const text = await getSubscriptionTool.execute(client);
|
|
263
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
264
|
+
} catch (err: any) {
|
|
265
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
server.tool(
|
|
271
|
+
cancelSubscriptionTool.name,
|
|
272
|
+
cancelSubscriptionTool.description,
|
|
273
|
+
cancelSubscriptionTool.inputSchema.shape,
|
|
274
|
+
async (input) => {
|
|
275
|
+
try {
|
|
276
|
+
const text = await cancelSubscriptionTool.execute(client, input as any);
|
|
277
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
278
|
+
} catch (err: any) {
|
|
279
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
server.tool(
|
|
285
|
+
pauseSubscriptionTool.name,
|
|
286
|
+
pauseSubscriptionTool.description,
|
|
287
|
+
pauseSubscriptionTool.inputSchema.shape,
|
|
288
|
+
async (input) => {
|
|
289
|
+
try {
|
|
290
|
+
const text = await pauseSubscriptionTool.execute(client, input as any);
|
|
291
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
292
|
+
} catch (err: any) {
|
|
293
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
server.tool(
|
|
299
|
+
resumeSubscriptionTool.name,
|
|
300
|
+
resumeSubscriptionTool.description,
|
|
301
|
+
resumeSubscriptionTool.inputSchema.shape,
|
|
302
|
+
async () => {
|
|
303
|
+
try {
|
|
304
|
+
const text = await resumeSubscriptionTool.execute(client);
|
|
305
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
306
|
+
} catch (err: any) {
|
|
307
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
server.tool(
|
|
313
|
+
downgradeSubscriptionTool.name,
|
|
314
|
+
downgradeSubscriptionTool.description,
|
|
315
|
+
downgradeSubscriptionTool.inputSchema.shape,
|
|
316
|
+
async (input) => {
|
|
317
|
+
try {
|
|
318
|
+
const text = await downgradeSubscriptionTool.execute(client, input as any);
|
|
319
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
320
|
+
} catch (err: any) {
|
|
321
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
|
|
251
326
|
server.tool(
|
|
252
327
|
listOAuthClientsTool.name,
|
|
253
328
|
listOAuthClientsTool.description,
|
package/src/lib/api-client.ts
CHANGED
|
@@ -255,7 +255,9 @@ export type ApiKeyScope =
|
|
|
255
255
|
| 'posts:read'
|
|
256
256
|
| 'posts:write'
|
|
257
257
|
| 'media:write'
|
|
258
|
-
| 'analytics:read'
|
|
258
|
+
| 'analytics:read'
|
|
259
|
+
| 'billing:read'
|
|
260
|
+
| 'billing:write';
|
|
259
261
|
|
|
260
262
|
export type CreateApiKeyPayload = {
|
|
261
263
|
name?: string;
|
|
@@ -301,6 +303,51 @@ export type DeleteApiKeyResponse = {
|
|
|
301
303
|
};
|
|
302
304
|
};
|
|
303
305
|
|
|
306
|
+
export type SubscriptionTierName = 'starter' | 'pro' | 'power_user' | 'agency';
|
|
307
|
+
|
|
308
|
+
export type SubscriptionSummary = {
|
|
309
|
+
id: string | null;
|
|
310
|
+
status: string | null;
|
|
311
|
+
tier: string | null;
|
|
312
|
+
cancel_at_period_end: boolean | null;
|
|
313
|
+
current_period_end: string | null;
|
|
314
|
+
trial_ends_at: string | null;
|
|
315
|
+
paused_at: string | null;
|
|
316
|
+
pause_resumes_at: string | null;
|
|
317
|
+
stripe_subscription_id: string | null;
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
export type SubscriptionSummaryResponse = {
|
|
321
|
+
subscription: SubscriptionSummary;
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
export type CancelSubscriptionPayload = {
|
|
325
|
+
reason: string;
|
|
326
|
+
feedback?: string;
|
|
327
|
+
immediate?: boolean;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
export type CancelSubscriptionResponse = {
|
|
331
|
+
success: true;
|
|
332
|
+
immediate: boolean;
|
|
333
|
+
canceled_at: string | null;
|
|
334
|
+
cancel_at_period_end: boolean;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
export type PauseSubscriptionResponse = {
|
|
338
|
+
success: true;
|
|
339
|
+
pause_resumes_at: string;
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
export type ResumeSubscriptionResponse = {
|
|
343
|
+
success: true;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
export type DowngradeSubscriptionResponse = {
|
|
347
|
+
success: true;
|
|
348
|
+
tier: SubscriptionTierName;
|
|
349
|
+
};
|
|
350
|
+
|
|
304
351
|
export type AskSupportResponse = {
|
|
305
352
|
success: boolean;
|
|
306
353
|
workspace_id: string;
|
|
@@ -862,6 +909,26 @@ export class PosterlyClient {
|
|
|
862
909
|
return this.request('DELETE', `/api-keys/${encodeURIComponent(keyId)}`, data);
|
|
863
910
|
}
|
|
864
911
|
|
|
912
|
+
async getSubscription(): Promise<SubscriptionSummaryResponse> {
|
|
913
|
+
return this.request('GET', '/subscription');
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
async cancelSubscription(data: CancelSubscriptionPayload): Promise<CancelSubscriptionResponse> {
|
|
917
|
+
return this.request('POST', '/subscription/cancel', data);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
async pauseSubscription(): Promise<PauseSubscriptionResponse> {
|
|
921
|
+
return this.request('POST', '/subscription/pause', {});
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
async resumeSubscription(): Promise<ResumeSubscriptionResponse> {
|
|
925
|
+
return this.request('POST', '/subscription/resume', {});
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
async downgradeSubscription(data: { tier?: SubscriptionTierName }): Promise<DowngradeSubscriptionResponse> {
|
|
929
|
+
return this.request('POST', '/subscription/downgrade', data);
|
|
930
|
+
}
|
|
931
|
+
|
|
865
932
|
async listAccounts(params?: { workspace_id?: string }): Promise<Account[]> {
|
|
866
933
|
const searchParams = new URLSearchParams();
|
|
867
934
|
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
package/src/lib/version.ts
CHANGED
|
@@ -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.
|
|
8
|
+
export const POSTERLY_MCP_VERSION = '0.25.0';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CancelSubscriptionResponse, PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
4
|
+
|
|
5
|
+
// Mirrors CANCELLATION_REASONS in the main app (lib/subscription-reasons.ts).
|
|
6
|
+
// Kept in sync manually because the npm package cannot import from the app.
|
|
7
|
+
const CANCELLATION_REASONS = [
|
|
8
|
+
'too_expensive',
|
|
9
|
+
'not_using',
|
|
10
|
+
'missing_features',
|
|
11
|
+
'technical_issues',
|
|
12
|
+
'switching_service',
|
|
13
|
+
'temporary_break',
|
|
14
|
+
'other',
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
function formatCanceled(result: CancelSubscriptionResponse): string {
|
|
18
|
+
return [
|
|
19
|
+
mdTitle(result.immediate ? 'Subscription cancelled immediately' : 'Subscription set to cancel at period end'),
|
|
20
|
+
mdSection('Details', mdKeyValue([
|
|
21
|
+
['Immediate', result.immediate ? 'yes' : 'no'],
|
|
22
|
+
['Cancel at period end', result.cancel_at_period_end ? 'yes' : 'no'],
|
|
23
|
+
['Canceled at', result.canceled_at || 'at end of current period'],
|
|
24
|
+
])),
|
|
25
|
+
].join('\n\n');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const cancelSubscriptionTool = {
|
|
29
|
+
name: 'cancel_subscription',
|
|
30
|
+
description:
|
|
31
|
+
"Cancel the authenticated user's posterly subscription. DESTRUCTIVE billing action; requires the billing:write scope. ALWAYS ask the user why they are cancelling FIRST and pass their answer as `reason` (one of the allowed values). By default the subscription is set to cancel at the end of the current period; pass immediate=true only if the user explicitly wants it cancelled right now. Only call after the user explicitly confirms.",
|
|
32
|
+
inputSchema: z.object({
|
|
33
|
+
reason: z.enum(CANCELLATION_REASONS).describe('Why the user is cancelling. Ask the user before calling; do not guess.'),
|
|
34
|
+
feedback: z.string().max(2000).optional().describe('Optional free-text detail the user gave about why they are cancelling.'),
|
|
35
|
+
immediate: z.boolean().optional().describe('Cancel immediately instead of at period end. Defaults to false (cancel at period end).'),
|
|
36
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms the cancellation.'),
|
|
37
|
+
}),
|
|
38
|
+
|
|
39
|
+
async execute(
|
|
40
|
+
client: PosterlyClient,
|
|
41
|
+
input: { reason: (typeof CANCELLATION_REASONS)[number]; feedback?: string; immediate?: boolean; confirm: true },
|
|
42
|
+
) {
|
|
43
|
+
const result = await client.cancelSubscription({
|
|
44
|
+
reason: input.reason,
|
|
45
|
+
feedback: input.feedback,
|
|
46
|
+
immediate: input.immediate === true,
|
|
47
|
+
});
|
|
48
|
+
return formatCanceled(result);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import type { CreateApiKeyPayload, CreateApiKeyResponse, PosterlyClient } from '../lib/api-client.js';
|
|
3
3
|
import { code, mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
4
4
|
|
|
5
|
-
const scopeSchema = z.enum(['accounts:read', 'accounts:write', 'posts:read', 'posts:write', 'media:write', 'analytics:read']);
|
|
5
|
+
const scopeSchema = z.enum(['accounts:read', 'accounts:write', 'posts:read', 'posts:write', 'media:write', 'analytics:read', 'billing:read', 'billing:write']);
|
|
6
6
|
|
|
7
7
|
function formatCreatedApiKey(result: CreateApiKeyResponse): string {
|
|
8
8
|
const key = result.api_key;
|
|
@@ -28,7 +28,7 @@ export const createApiKeyTool = {
|
|
|
28
28
|
'Create a new Posterly API key for the authenticated user. SECRET-CREATING WRITE: only use after explicit user confirmation. The new key can only request scopes already present on the calling dashboard-created API key; OAuth and managed assistant tokens cannot mint keys.',
|
|
29
29
|
inputSchema: z.object({
|
|
30
30
|
name: z.string().trim().min(1).max(120).optional().describe('Human-readable key name.'),
|
|
31
|
-
scopes: z.array(scopeSchema).min(1).max(
|
|
31
|
+
scopes: z.array(scopeSchema).min(1).max(8).optional().describe('Scopes for the new key. Omit to copy the calling key scopes. Cannot exceed the calling key scopes. billing:read and billing:write allow managing the posterly subscription (cancel/pause/resume/downgrade).'),
|
|
32
32
|
workspace_id: z.string().trim().min(1).optional().describe('Optional workspace restriction. Workspace-scoped calling keys cannot create keys outside their workspace.'),
|
|
33
33
|
expires_in_days: z.number().int().min(1).max(365).optional().describe('Optional expiry from now, up to 365 days. Omit for no expiry.'),
|
|
34
34
|
confirm: z.literal(true).describe('Must be true after the user explicitly confirms that a new secret API key should be created.'),
|
package/src/tools/create-post.ts
CHANGED
|
@@ -56,6 +56,7 @@ export const platformSettingsSchema = z.object({
|
|
|
56
56
|
allow_stitch: z.boolean().optional(),
|
|
57
57
|
title: z.string().optional(),
|
|
58
58
|
media_type: z.string().optional(), // TikTok: 'PHOTO' forces a photo slideshow; image media is auto-detected when omitted
|
|
59
|
+
video_cover_timestamp_ms: z.number().nonnegative().optional(), // TikTok: millisecond timestamp of the video frame to use as the cover (direct post only)
|
|
59
60
|
is_commercial_content: z.boolean().optional(),
|
|
60
61
|
is_your_brand: z.boolean().optional(),
|
|
61
62
|
is_branded_content: z.boolean().optional(),
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { DowngradeSubscriptionResponse, PosterlyClient, SubscriptionTierName } from '../lib/api-client.js';
|
|
3
|
+
import { mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
4
|
+
|
|
5
|
+
const TIER_VALUES = ['starter', 'pro', 'power_user', 'agency'] as const;
|
|
6
|
+
|
|
7
|
+
function formatDowngraded(result: DowngradeSubscriptionResponse): string {
|
|
8
|
+
return [
|
|
9
|
+
mdTitle('Subscription downgrade scheduled'),
|
|
10
|
+
mdSection('Details', mdKeyValue([
|
|
11
|
+
['New tier at next renewal', result.tier],
|
|
12
|
+
])),
|
|
13
|
+
].join('\n\n');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const downgradeSubscriptionTool = {
|
|
17
|
+
name: 'downgrade_subscription',
|
|
18
|
+
description:
|
|
19
|
+
"Downgrade the authenticated user's posterly subscription one tier (or to an explicit lower `tier`) at the next renewal with no proration. Billing action; requires the billing:write scope. Only call after the user explicitly confirms.",
|
|
20
|
+
inputSchema: z.object({
|
|
21
|
+
tier: z.enum(TIER_VALUES).optional().describe('Optional explicit target tier. Omit to drop one tier automatically.'),
|
|
22
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms the downgrade.'),
|
|
23
|
+
}),
|
|
24
|
+
|
|
25
|
+
async execute(client: PosterlyClient, input: { tier?: SubscriptionTierName; confirm: true }) {
|
|
26
|
+
const result = await client.downgradeSubscription({ tier: input.tier });
|
|
27
|
+
return formatDowngraded(result);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient, SubscriptionSummaryResponse } from '../lib/api-client.js';
|
|
3
|
+
import { formatDateTime, mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
4
|
+
|
|
5
|
+
function formatSubscription(result: SubscriptionSummaryResponse): string {
|
|
6
|
+
const sub = result.subscription;
|
|
7
|
+
return [
|
|
8
|
+
mdTitle('posterly subscription'),
|
|
9
|
+
mdSection('Details', mdKeyValue([
|
|
10
|
+
['Status', sub.status || 'unknown'],
|
|
11
|
+
['Tier', sub.tier || 'unknown'],
|
|
12
|
+
['Cancel at period end', sub.cancel_at_period_end ? 'yes' : 'no'],
|
|
13
|
+
['Current period end', sub.current_period_end ? formatDateTime(sub.current_period_end) : 'n/a'],
|
|
14
|
+
['Trial ends', sub.trial_ends_at ? formatDateTime(sub.trial_ends_at) : 'n/a'],
|
|
15
|
+
['Paused at', sub.paused_at ? formatDateTime(sub.paused_at) : 'n/a'],
|
|
16
|
+
['Pause resumes at', sub.pause_resumes_at ? formatDateTime(sub.pause_resumes_at) : 'n/a'],
|
|
17
|
+
])),
|
|
18
|
+
].join('\n\n');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const getSubscriptionTool = {
|
|
22
|
+
name: 'get_subscription',
|
|
23
|
+
description:
|
|
24
|
+
"Get the authenticated user's posterly subscription: status, tier, cancel-at-period-end, current period end, trial end, and pause state. Read-only. Requires the billing:read scope.",
|
|
25
|
+
inputSchema: z.object({}),
|
|
26
|
+
|
|
27
|
+
async execute(client: PosterlyClient) {
|
|
28
|
+
const result = await client.getSubscription();
|
|
29
|
+
return formatSubscription(result);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PauseSubscriptionResponse, PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { formatDateTime, mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
4
|
+
|
|
5
|
+
function formatPaused(result: PauseSubscriptionResponse): string {
|
|
6
|
+
return [
|
|
7
|
+
mdTitle('Subscription paused'),
|
|
8
|
+
mdSection('Details', mdKeyValue([
|
|
9
|
+
['Resumes at', result.pause_resumes_at ? formatDateTime(result.pause_resumes_at) : 'n/a'],
|
|
10
|
+
])),
|
|
11
|
+
].join('\n\n');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const pauseSubscriptionTool = {
|
|
15
|
+
name: 'pause_subscription',
|
|
16
|
+
description:
|
|
17
|
+
"Pause the authenticated user's posterly subscription for 30 days (one pause allowed per 90-day cooldown). Billing action; requires the billing:write scope. Only call after the user explicitly confirms.",
|
|
18
|
+
inputSchema: z.object({
|
|
19
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms pausing the subscription.'),
|
|
20
|
+
}),
|
|
21
|
+
|
|
22
|
+
async execute(client: PosterlyClient, _input: { confirm: true }) {
|
|
23
|
+
const result = await client.pauseSubscription();
|
|
24
|
+
return formatPaused(result);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { mdTitle } from '../lib/format.js';
|
|
4
|
+
|
|
5
|
+
export const resumeSubscriptionTool = {
|
|
6
|
+
name: 'resume_subscription',
|
|
7
|
+
description:
|
|
8
|
+
"Resume the authenticated user's paused posterly subscription, restoring active billing. Requires the billing:write scope.",
|
|
9
|
+
inputSchema: z.object({}),
|
|
10
|
+
|
|
11
|
+
async execute(client: PosterlyClient) {
|
|
12
|
+
await client.resumeSubscription();
|
|
13
|
+
return mdTitle('Subscription resumed', 'Billing has been restored to active.');
|
|
14
|
+
},
|
|
15
|
+
};
|
package/src/tools/update-post.ts
CHANGED
|
@@ -43,6 +43,7 @@ const platformSettingsSchema = z.object({
|
|
|
43
43
|
allow_duet: z.boolean().optional(),
|
|
44
44
|
allow_stitch: z.boolean().optional(),
|
|
45
45
|
title: z.string().optional(),
|
|
46
|
+
video_cover_timestamp_ms: z.number().nonnegative().optional(), // TikTok: millisecond timestamp of the video frame to use as the cover (direct post only)
|
|
46
47
|
is_commercial_content: z.boolean().optional(),
|
|
47
48
|
is_your_brand: z.boolean().optional(),
|
|
48
49
|
is_branded_content: z.boolean().optional(),
|