posterly-mcp-server 0.43.3 → 0.43.5
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 +18 -18
- package/dist/lib/api-client.d.ts +14 -0
- package/dist/lib/api-client.js +6 -2
- package/dist/lib/format.js +1 -1
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/tools/ask-support.js +3 -3
- package/dist/tools/create-api-key.js +1 -1
- package/dist/tools/create-connect-session.js +3 -3
- package/dist/tools/create-post.js +6 -6
- package/dist/tools/create-posts-batch.js +2 -2
- package/dist/tools/create-webhook.d.ts +3 -3
- package/dist/tools/delete-api-key.js +1 -1
- package/dist/tools/delete-post.js +2 -2
- package/dist/tools/generate-captions.js +1 -1
- package/dist/tools/generate-image.js +1 -1
- package/dist/tools/get-agent-signup-info.js +8 -8
- package/dist/tools/get-comment.js +1 -1
- package/dist/tools/get-connect-link.js +1 -1
- package/dist/tools/get-connect-session.js +4 -4
- package/dist/tools/get-mcp-status.js +4 -4
- package/dist/tools/get-post.js +1 -1
- package/dist/tools/get-signup-session.js +7 -7
- package/dist/tools/list-accounts.js +1 -1
- package/dist/tools/list-brands.js +1 -1
- package/dist/tools/list-comments.d.ts +4 -4
- package/dist/tools/list-comments.js +3 -3
- package/dist/tools/list-platforms.js +1 -1
- package/dist/tools/list-posts.d.ts +8 -0
- package/dist/tools/list-posts.js +24 -5
- package/dist/tools/reply-to-comment.js +1 -1
- package/dist/tools/start-signup.js +11 -11
- package/dist/tools/submit-agent-feedback.d.ts +4 -4
- package/dist/tools/submit-product-feedback.d.ts +4 -4
- package/dist/tools/sync-inbox.js +2 -2
- package/dist/tools/update-post.js +2 -2
- package/dist/tools/update-webhook.d.ts +3 -3
- package/dist/tools/upload-media-from-url.js +1 -1
- package/dist/tools/webhook-events.d.ts +2 -2
- package/dist/tools/webhook-events.js +5 -0
- package/dist/tools/whoami.js +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/lib/api-client.ts +20 -2
- package/src/lib/format.ts +1 -1
- package/src/lib/version.ts +1 -1
- package/src/tools/ask-support.ts +3 -3
- package/src/tools/create-api-key.ts +1 -1
- package/src/tools/create-connect-session.ts +3 -3
- package/src/tools/create-post.ts +6 -6
- package/src/tools/create-posts-batch.ts +2 -2
- package/src/tools/delete-api-key.ts +1 -1
- package/src/tools/delete-post.ts +2 -2
- package/src/tools/generate-captions.ts +1 -1
- package/src/tools/generate-image.ts +1 -1
- package/src/tools/get-agent-signup-info.ts +8 -8
- package/src/tools/get-comment.ts +1 -1
- package/src/tools/get-connect-link.ts +1 -1
- package/src/tools/get-connect-session.ts +4 -4
- package/src/tools/get-mcp-status.ts +4 -4
- package/src/tools/get-post.ts +1 -1
- package/src/tools/get-signup-session.ts +7 -7
- package/src/tools/list-accounts.ts +1 -1
- package/src/tools/list-brands.ts +1 -1
- package/src/tools/list-comments.ts +4 -4
- package/src/tools/list-platforms.ts +1 -1
- package/src/tools/list-posts.ts +23 -5
- package/src/tools/reply-to-comment.ts +1 -1
- package/src/tools/start-signup.ts +11 -11
- package/src/tools/sync-inbox.ts +2 -2
- package/src/tools/update-post.ts +2 -2
- package/src/tools/upload-media-from-url.ts +1 -1
- package/src/tools/webhook-events.ts +5 -0
- package/src/tools/whoami.ts +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# posterly MCP Server
|
|
2
2
|
|
|
3
|
-
Use
|
|
3
|
+
Use posterly from any MCP-compatible AI client.
|
|
4
4
|
|
|
5
5
|
This package gives Claude Desktop, Cursor, Windsurf, Cline, and other local MCP clients a `stdio` server that can:
|
|
6
6
|
|
|
7
|
-
- start paid
|
|
7
|
+
- start paid posterly signup before an API key exists
|
|
8
8
|
- poll signup progress while the user completes checkout and password setup
|
|
9
9
|
- list connected social accounts
|
|
10
10
|
- resolve brands/clients into the right accounts
|
|
@@ -34,13 +34,13 @@ name is `io.github.awpthorp/posterly`, matching this package's `mcpName`.
|
|
|
34
34
|
|
|
35
35
|
- Node.js `20+`
|
|
36
36
|
- No API key is required for the public setup tools: `get_mcp_status`, `get_agent_signup_info`, `start_signup`, and `get_signup_session`
|
|
37
|
-
- A
|
|
37
|
+
- A posterly account, API add-on, and API key are required for authenticated tools like `whoami`, `list_accounts`, `create_connect_session`, and `create_post`
|
|
38
38
|
|
|
39
39
|
## Install
|
|
40
40
|
|
|
41
41
|
Recommended: use it via `npx` in your MCP config so your client runs the current server without a global install.
|
|
42
42
|
|
|
43
|
-
To let an AI agent start signup before a
|
|
43
|
+
To let an AI agent start signup before a posterly API key exists, install the server without `POSTERLY_API_KEY`:
|
|
44
44
|
|
|
45
45
|
```json
|
|
46
46
|
{
|
|
@@ -53,7 +53,7 @@ To let an AI agent start signup before a Posterly API key exists, install the se
|
|
|
53
53
|
}
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
After paid signup is complete and
|
|
56
|
+
After paid signup is complete and posterly shows an API key, add `POSTERLY_API_KEY` to unlock the authenticated tools:
|
|
57
57
|
|
|
58
58
|
```json
|
|
59
59
|
{
|
|
@@ -71,16 +71,16 @@ After paid signup is complete and Posterly shows an API key, add `POSTERLY_API_K
|
|
|
71
71
|
|
|
72
72
|
## Quick setup
|
|
73
73
|
|
|
74
|
-
1. Add the
|
|
75
|
-
2. If you do not have
|
|
76
|
-
3. Pay in Stripe Checkout and set your
|
|
77
|
-
4. When
|
|
74
|
+
1. Add the posterly MCP server to your AI client.
|
|
75
|
+
2. If you do not have posterly yet, ask the AI to call `start_signup`.
|
|
76
|
+
3. Pay in Stripe Checkout and set your posterly password in the browser.
|
|
77
|
+
4. When posterly shows your API key, add it as `POSTERLY_API_KEY`.
|
|
78
78
|
5. Restart your AI client.
|
|
79
79
|
6. Ask the AI to call `get_mcp_status`, then `whoami`, then continue by connecting your first social account.
|
|
80
80
|
|
|
81
81
|
The signup and connect tools return user-facing next steps by default, so agents should report progress in plain language instead of showing raw curl, HTTP payloads, or JSON. Pass `debug: true` to `start_signup`, `get_signup_session`, `get_connect_link`, `create_connect_session`, or `get_connect_session` only when troubleshooting.
|
|
82
82
|
|
|
83
|
-
Post tools return `View in
|
|
83
|
+
Post tools return `View in posterly` dashboard links. After scheduling, listing, reading, or deleting posts, share the returned link with the user. Current-month scheduled posts open in Calendar with the post selected; broader/future post views use Table.
|
|
84
84
|
|
|
85
85
|
## Example configs
|
|
86
86
|
|
|
@@ -122,7 +122,7 @@ Add the same server definition to your Cursor MCP settings:
|
|
|
122
122
|
|
|
123
123
|
## Available tools
|
|
124
124
|
|
|
125
|
-
`posterly-mcp-server@0.43.
|
|
125
|
+
`posterly-mcp-server@0.43.5` exposes 90 tools.
|
|
126
126
|
|
|
127
127
|
Public setup tools work before `POSTERLY_API_KEY` exists:
|
|
128
128
|
|
|
@@ -196,7 +196,7 @@ Authenticated tools require `POSTERLY_API_KEY`:
|
|
|
196
196
|
- `list_conversations` (Instagram and Facebook Page inbox DMs; Threads has no DMs)
|
|
197
197
|
- `get_conversation`
|
|
198
198
|
- `send_message` (DM reply after explicit confirmation; honors Meta 24-hour windows)
|
|
199
|
-
- `list_comments` (Instagram, Facebook Page, and
|
|
199
|
+
- `list_comments` (Instagram, Facebook Page, Threads, and LinkedIn Page inbox comments)
|
|
200
200
|
- `get_comment`
|
|
201
201
|
- `reply_to_comment` (comment reply after explicit confirmation)
|
|
202
202
|
- `update_comment` (hide/unhide or mark read; hide is reversible)
|
|
@@ -245,19 +245,19 @@ The brand tools let an assistant work at the same level a human does:
|
|
|
245
245
|
This makes prompts like:
|
|
246
246
|
|
|
247
247
|
- "How is Grassroots doing on Instagram?"
|
|
248
|
-
- "Write a post for the
|
|
248
|
+
- "Write a post for the posterly brand voice"
|
|
249
249
|
- "Schedule something for our Dubai dental client"
|
|
250
250
|
|
|
251
251
|
much more reliable than forcing the agent to guess from raw account handles alone.
|
|
252
252
|
|
|
253
253
|
## Example prompts
|
|
254
254
|
|
|
255
|
-
- `What
|
|
255
|
+
- `What posterly accounts do I have connected?`
|
|
256
256
|
- `Disconnect the old Instagram account after I confirm the exact account ID`
|
|
257
|
-
- `List my brands in
|
|
257
|
+
- `List my brands in posterly`
|
|
258
258
|
- `Show me the brand profile for Grassroots`
|
|
259
259
|
- `Find the next 3 posting slots for my LinkedIn account`
|
|
260
|
-
- `Schedule a post for tomorrow at 9am for the
|
|
260
|
+
- `Schedule a post for tomorrow at 9am for the posterly Instagram account`
|
|
261
261
|
- `Pause post 971 after I confirm it is the right scheduled post`
|
|
262
262
|
- `Schedule this as an Instagram Story with a first comment and @partner as collaborator`
|
|
263
263
|
- `Schedule this YouTube video as unlisted, add the thumbnail URL, and put it in our launch playlist`
|
|
@@ -268,7 +268,7 @@ much more reliable than forcing the agent to guess from raw account handles alon
|
|
|
268
268
|
|
|
269
269
|
## Pricing
|
|
270
270
|
|
|
271
|
-
This package uses the
|
|
271
|
+
This package uses the posterly API/MCP add-on:
|
|
272
272
|
|
|
273
273
|
- `$3/month` add-on
|
|
274
274
|
- `100 create-post requests/hour` per API key, with separate media/read limits
|
|
@@ -312,5 +312,5 @@ npm start
|
|
|
312
312
|
|
|
313
313
|
The package reads:
|
|
314
314
|
|
|
315
|
-
- optional `POSTERLY_API_KEY` for authenticated
|
|
315
|
+
- optional `POSTERLY_API_KEY` for authenticated posterly tools
|
|
316
316
|
- optional `POSTERLY_URL` if you need to point at a non-production environment
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -128,6 +128,15 @@ export interface DismissSuggestionResponse {
|
|
|
128
128
|
ok: boolean;
|
|
129
129
|
status: string;
|
|
130
130
|
}
|
|
131
|
+
export type ApiPostApprovalStatus = 'none' | 'pending_client' | 'approved' | 'changes_requested' | 'rejected';
|
|
132
|
+
export interface ApiPostApproval {
|
|
133
|
+
status: ApiPostApprovalStatus;
|
|
134
|
+
asset_status: ApiPostApprovalStatus;
|
|
135
|
+
caption_status: ApiPostApprovalStatus;
|
|
136
|
+
waiting_on: 'client' | 'team' | null;
|
|
137
|
+
requested_at: string | null;
|
|
138
|
+
completed_at: string | null;
|
|
139
|
+
}
|
|
131
140
|
export interface Post {
|
|
132
141
|
id: number;
|
|
133
142
|
content: string;
|
|
@@ -144,6 +153,9 @@ export interface Post {
|
|
|
144
153
|
reel_cover_url?: string | null;
|
|
145
154
|
reel_cover_method?: string | null;
|
|
146
155
|
reel_thumb_offset?: number | null;
|
|
156
|
+
brand_id?: string | null;
|
|
157
|
+
content_plan_id?: string | null;
|
|
158
|
+
approval?: ApiPostApproval;
|
|
147
159
|
}
|
|
148
160
|
export interface InstagramPostSettings {
|
|
149
161
|
__type?: 'instagram' | 'instagram-standalone';
|
|
@@ -1090,6 +1102,8 @@ export declare class PosterlyClient {
|
|
|
1090
1102
|
limit?: number;
|
|
1091
1103
|
offset?: number;
|
|
1092
1104
|
workspace_id?: string;
|
|
1105
|
+
approval_status?: string;
|
|
1106
|
+
brand_id?: string;
|
|
1093
1107
|
}): Promise<{
|
|
1094
1108
|
posts: Post[];
|
|
1095
1109
|
total: number;
|
package/dist/lib/api-client.js
CHANGED
|
@@ -68,7 +68,7 @@ export class PosterlyClient {
|
|
|
68
68
|
}
|
|
69
69
|
requireApiKey() {
|
|
70
70
|
if (!this.apiKey) {
|
|
71
|
-
throw new Error('
|
|
71
|
+
throw new Error('posterly access is not installed yet. Use start_signup to begin paid setup, or set POSTERLY_API_KEY after signup.');
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
async request(method, path, body) {
|
|
@@ -257,6 +257,10 @@ export class PosterlyClient {
|
|
|
257
257
|
searchParams.set('offset', String(params.offset));
|
|
258
258
|
if (params?.workspace_id)
|
|
259
259
|
searchParams.set('workspace_id', params.workspace_id);
|
|
260
|
+
if (params?.approval_status)
|
|
261
|
+
searchParams.set('approval_status', params.approval_status);
|
|
262
|
+
if (params?.brand_id)
|
|
263
|
+
searchParams.set('brand_id', params.brand_id);
|
|
260
264
|
const qs = searchParams.toString();
|
|
261
265
|
return this.request('GET', `/posts${qs ? `?${qs}` : ''}`);
|
|
262
266
|
}
|
|
@@ -742,7 +746,7 @@ export function validatePosterlyBaseUrlForKeyUse(baseUrl) {
|
|
|
742
746
|
if (!check.trustedPosterlyHost &&
|
|
743
747
|
!check.localDevelopmentHost &&
|
|
744
748
|
!flagEnabled('POSTERLY_ALLOW_CUSTOM_BASE_URL')) {
|
|
745
|
-
throw new Error(`Refusing to send an API key to custom host ${baseUrl}. Set POSTERLY_ALLOW_CUSTOM_BASE_URL=true only for a trusted
|
|
749
|
+
throw new Error(`Refusing to send an API key to custom host ${baseUrl}. Set POSTERLY_ALLOW_CUSTOM_BASE_URL=true only for a trusted posterly deployment.`);
|
|
746
750
|
}
|
|
747
751
|
}
|
|
748
752
|
function parseJson(text) {
|
package/dist/lib/format.js
CHANGED
package/dist/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const POSTERLY_MCP_VERSION = "0.43.
|
|
1
|
+
export declare const POSTERLY_MCP_VERSION = "0.43.5";
|
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.43.
|
|
8
|
+
export const POSTERLY_MCP_VERSION = '0.43.5';
|
|
@@ -17,7 +17,7 @@ function formatSupportAnswer(result) {
|
|
|
17
17
|
supportAccess.ticket_created && result.ticket?.id ? `Ticket: ${result.ticket.id} (${result.ticket.status})` : '',
|
|
18
18
|
].filter(Boolean);
|
|
19
19
|
return [
|
|
20
|
-
mdTitle('
|
|
20
|
+
mdTitle('posterly Support'),
|
|
21
21
|
mdQuote(result.message?.content || 'No support answer returned.'),
|
|
22
22
|
sources.length ? mdSection('Sources', mdBullets(sources)) : '',
|
|
23
23
|
mdSection('Status', mdBullets(status)),
|
|
@@ -27,7 +27,7 @@ const supportInputSchema = z.object({
|
|
|
27
27
|
question: z.string().trim().min(1).max(4000),
|
|
28
28
|
workspace_id: z.string().optional().describe('Workspace to inspect. Omit to use the API-key scoped workspace or personal workspace.'),
|
|
29
29
|
conversation_id: z.string().optional().describe('Continue a previous support conversation.'),
|
|
30
|
-
page_url: z.string().max(2000).optional().describe('Optional
|
|
30
|
+
page_url: z.string().max(2000).optional().describe('Optional posterly page URL for context.'),
|
|
31
31
|
post_id: z.number().int().positive().optional().describe('Optional post ID to inspect directly.'),
|
|
32
32
|
referenced_post_ids: z.array(z.number().int().positive()).max(5).optional().describe('Optional post IDs to include in read-only diagnostics.'),
|
|
33
33
|
request_human: z.boolean().default(false).optional().describe('Ask for human review. Does not create a ticket unless confirm_escalation is also true.'),
|
|
@@ -42,7 +42,7 @@ async function executeSupport(client, input) {
|
|
|
42
42
|
}
|
|
43
43
|
export const askSupportTool = {
|
|
44
44
|
name: 'ask_support',
|
|
45
|
-
description: 'Ask
|
|
45
|
+
description: 'Ask posterly Support AI an authenticated question using posterly docs plus read-only account/post diagnostics for the caller workspace. Requires POSTERLY_API_KEY with accounts:read and posts:read scopes. Human ticket creation requires request_human=true and confirm_escalation=true after explicit user confirmation.',
|
|
46
46
|
inputSchema: supportInputSchema,
|
|
47
47
|
execute: executeSupport,
|
|
48
48
|
};
|
|
@@ -20,7 +20,7 @@ function formatCreatedApiKey(result) {
|
|
|
20
20
|
}
|
|
21
21
|
export const createApiKeyTool = {
|
|
22
22
|
name: 'create_api_key',
|
|
23
|
-
description: 'Create a new
|
|
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
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).'),
|
|
@@ -3,7 +3,7 @@ import { DASHBOARD_CONNECT_URL, formatConnectedAccounts, formatLocalDateTime } f
|
|
|
3
3
|
import { CONNECT_INPUTS } from '../generated/platform-manifest.js';
|
|
4
4
|
export const createConnectSessionTool = {
|
|
5
5
|
name: 'create_connect_session',
|
|
6
|
-
description: 'Create a short-lived
|
|
6
|
+
description: 'Create a short-lived posterly dashboard handoff session for connecting a social account. Send the secure connection URL to the user, then poll get_connect_session to narrate progress. Do not ask for social media passwords or OAuth codes; posterly handles those browser steps.',
|
|
7
7
|
inputSchema: z.object({
|
|
8
8
|
platform: z
|
|
9
9
|
.enum(CONNECT_INPUTS)
|
|
@@ -30,7 +30,7 @@ export const createConnectSessionTool = {
|
|
|
30
30
|
function formatConnectSession(session, includeRaw) {
|
|
31
31
|
const connected = session.connected_count ?? session.connected_accounts?.length ?? 0;
|
|
32
32
|
return [
|
|
33
|
-
`
|
|
33
|
+
`posterly connect session created: ${session.id}`,
|
|
34
34
|
`Platform: ${session.platform}`,
|
|
35
35
|
`Status: ${session.status}`,
|
|
36
36
|
`Message: ${session.status_message}`,
|
|
@@ -41,7 +41,7 @@ function formatConnectSession(session, includeRaw) {
|
|
|
41
41
|
`Expires: ${formatLocalDateTime(session.expires_at)}`,
|
|
42
42
|
`Dashboard connect page: ${DASHBOARD_CONNECT_URL}`,
|
|
43
43
|
'',
|
|
44
|
-
'Next step for the AI agent: send the secure connection URL to the user, explain that
|
|
44
|
+
'Next step for the AI agent: send the secure connection URL to the user, explain that posterly will handle the browser OAuth step, then poll get_connect_session until the account is connected or the session ends.',
|
|
45
45
|
includeRaw ? `\nRaw connect session:\n${JSON.stringify(session, null, 2)}` : '',
|
|
46
46
|
].filter(Boolean).join('\n');
|
|
47
47
|
}
|
|
@@ -136,11 +136,11 @@ export const createPostPayloadInputSchema = z.object({
|
|
|
136
136
|
.string()
|
|
137
137
|
.optional()
|
|
138
138
|
.describe('ISO 8601 datetime for scheduling (e.g. 2026-03-05T09:00:00Z). Omit for immediate publish.'),
|
|
139
|
-
media_url: z.string().optional().describe('Media URL to attach. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into
|
|
139
|
+
media_url: z.string().optional().describe('Media URL to attach. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into posterly storage before the post is saved. Short-lived signed URLs must still be live when this tool runs. For threads, attaches to the lead post only.'),
|
|
140
140
|
media_urls: z
|
|
141
141
|
.array(z.string())
|
|
142
142
|
.optional()
|
|
143
|
-
.describe('Multiple media URLs for carousel or multi-image posts. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into
|
|
143
|
+
.describe('Multiple media URLs for carousel or multi-image posts. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into posterly storage before the post is saved. For TikTok, 2 or more images auto-create a photo slideshow (up to 35 images) and every image is posted.'),
|
|
144
144
|
post_type: z
|
|
145
145
|
.string()
|
|
146
146
|
.optional()
|
|
@@ -216,9 +216,9 @@ export const createPostTool = {
|
|
|
216
216
|
'2. Show the user a preview containing ALL of: account(s) and platform(s), final caption text, scheduled time (in the user\'s timezone), media attached (if any), and workspace name.\n' +
|
|
217
217
|
'3. Get explicit confirmation from the user (e.g. "post it", "yes schedule that", "looks good") BEFORE calling this tool. Do NOT infer consent from earlier instructions like "post about X every Monday" - confirm each individual post or the entire batch.\n' +
|
|
218
218
|
'4. If scheduling multiple posts in one turn, list every post first and confirm the batch as a whole, then prefer `create_posts_batch` so they are created in one API request.\n\n' +
|
|
219
|
-
'AFTER CALLING: Tell the user the post was created, include the
|
|
219
|
+
'AFTER CALLING: Tell the user the post was created, include the posterly dashboard link returned by the tool, and offer the next natural action. Do not narrate raw HTTP, curl, or API plumbing.\n\n' +
|
|
220
220
|
'Provide either account_id OR username+platform to identify the account. If scheduled_at is omitted, the post publishes immediately. If workspace_id is omitted, the server resolves one from the social account, falling back to the caller\'s default (personal) workspace - pass workspace_id explicitly if the user has more than one workspace.\n\n' +
|
|
221
|
-
'MEDIA URLS: Posterly storage URLs are used as-is. Third-party HTTP(S) media URLs are copied into
|
|
221
|
+
'MEDIA URLS: Posterly storage URLs are used as-is. Third-party HTTP(S) media URLs are copied into posterly storage before the post is saved, so API-created posts do not later fail on expired signed URLs. Short-lived signed URLs must still be live when this tool runs. You can also call `upload_media_from_url` first if you want to upload once and reuse the returned posterly URL across posts.\n\n' +
|
|
222
222
|
'THREADS: Pass `thread_posts` (an array of 2+ strings) to schedule a multi-post thread on X (Twitter) or Threads (Meta). The first entry is the lead post; the rest are published as replies in the same chain. X entries are capped at 280 characters each (4000 for verified, 25000 for organization accounts); Threads entries are capped at 500 characters each. When `thread_posts` is set, `caption` is ignored.\n\n' +
|
|
223
223
|
'PLATFORM SETTINGS: Pass `platform_settings` for composer-equivalent controls: Facebook story/reel/backgrounds, YouTube title/privacy/thumbnail/brandPartner, LinkedIn document titles/mentions/polls/content_call_to_action_label (including BUY_NOW and SHOP_NOW), TikTok direct-post privacy/toggles/commercial disclosure, Pinterest board/title/link/product_tags, GBP event/offer/CTA/recurrence, X reply settings/polls/paid_partnership, Threads reply controls/text attachments/ghost posts/spoilers/reply approvals/GIPHY, Telegram polls/buttons/video cover/live photo, Slack markdown/blocks, Mastodon visibility/quote/poll (media+poll allowed), and Instagram feed/story/reel/carousel/native media tags/collaborators/first comments/trial Reels/is_ai_generated/audio_id. For Instagram, @username in caption is only a caption mention; `user_tags` creates native media tags and `collaborators` sends co-author invitations only when the selected Meta-linked account reports those capabilities. Call `get_platform_schema` with the account ID first. `instagram_settings` remains as a backwards-compatible alias.\n\n' +
|
|
224
224
|
'TIKTOK MEDIA: TikTok supports a single video or a photo slideshow of 1 to 35 images, never multiple videos. Image media auto-detects as a slideshow, so you usually do not set post_type or media_type for photos and every image is posted. Pass `platform_settings.media_type: "PHOTO"` to force a slideshow explicitly.',
|
|
@@ -242,7 +242,7 @@ export const createPostTool = {
|
|
|
242
242
|
`• Type: ${p.post_type}`,
|
|
243
243
|
`• Status: ${p.status}`,
|
|
244
244
|
`• Scheduled: ${when}`,
|
|
245
|
-
`• View in
|
|
245
|
+
`• View in posterly: ${dashboardUrl}`,
|
|
246
246
|
];
|
|
247
247
|
if (thread_posts) {
|
|
248
248
|
lines.push(`• Thread: ${thread_posts.length} posts`);
|
|
@@ -259,7 +259,7 @@ export const createPostTool = {
|
|
|
259
259
|
if (ws) {
|
|
260
260
|
lines.push(`• Workspace: ${ws.name} (${ws.id}) - resolved from ${ws.resolved_from}`);
|
|
261
261
|
}
|
|
262
|
-
lines.push('', 'Next step for the AI agent: tell the user the post is in
|
|
262
|
+
lines.push('', 'Next step for the AI agent: tell the user the post is in posterly, share the dashboard link above, then ask whether they want to create another post, adjust this one, or connect another account.');
|
|
263
263
|
return lines.join('\n');
|
|
264
264
|
},
|
|
265
265
|
};
|
|
@@ -8,7 +8,7 @@ export const createPostsBatchTool = {
|
|
|
8
8
|
'1. Call `whoami` at the start of any new session to confirm which workspace and user you are acting for.\n' +
|
|
9
9
|
'2. Show the user a preview of EVERY post: account/platform, final caption or thread text, scheduled time in their timezone, media, platform settings, and workspace.\n' +
|
|
10
10
|
'3. Get explicit confirmation for the whole batch before calling. Do not infer consent from an earlier content plan.\n\n' +
|
|
11
|
-
'AFTER CALLING: Summarize the batch result in natural language, include the
|
|
11
|
+
'AFTER CALLING: Summarize the batch result in natural language, include the posterly dashboard link returned by the tool, and avoid narrating raw HTTP, curl, or API plumbing.\n\n' +
|
|
12
12
|
'Each item accepts the same fields as `create_post`, including `thread_posts`, `platform_settings`, `instagram_settings`, media URLs, and workspace_id. The endpoint may partially succeed; failed items are returned with their index.',
|
|
13
13
|
inputSchema: z.object({
|
|
14
14
|
posts: z
|
|
@@ -32,7 +32,7 @@ export const createPostsBatchTool = {
|
|
|
32
32
|
`• Created: ${result.created}`,
|
|
33
33
|
`• Replayed: ${result.replayed}`,
|
|
34
34
|
`• Failed: ${result.failed}`,
|
|
35
|
-
`• View in
|
|
35
|
+
`• View in posterly: ${dashboardUrl}`,
|
|
36
36
|
];
|
|
37
37
|
for (const item of result.posts.slice(0, 25)) {
|
|
38
38
|
const post = item.post;
|
|
@@ -5,7 +5,7 @@ export declare const createWebhookTool: {
|
|
|
5
5
|
description: string;
|
|
6
6
|
inputSchema: z.ZodObject<{
|
|
7
7
|
url: z.ZodString;
|
|
8
|
-
events: z.ZodOptional<z.ZodArray<z.ZodEnum<["webhook.test", "post.created", "post.updated", "post.deleted", "post.publishing", "post.published", "post.failed", "account.disconnected", "analytics.synced"]>, "many">>;
|
|
8
|
+
events: z.ZodOptional<z.ZodArray<z.ZodEnum<["webhook.test", "post.created", "post.updated", "post.deleted", "post.publishing", "post.published", "post.failed", "account.disconnected", "analytics.synced", "approval.requested", "approval.approved", "approval.changes_requested", "approval.rejected", "approval.commented"]>, "many">>;
|
|
9
9
|
workspace_id: z.ZodOptional<z.ZodString>;
|
|
10
10
|
description: z.ZodOptional<z.ZodString>;
|
|
11
11
|
is_active: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -15,14 +15,14 @@ export declare const createWebhookTool: {
|
|
|
15
15
|
confirm: true;
|
|
16
16
|
description?: string | undefined;
|
|
17
17
|
workspace_id?: string | undefined;
|
|
18
|
-
events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
|
|
18
|
+
events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced" | "approval.requested" | "approval.approved" | "approval.changes_requested" | "approval.rejected" | "approval.commented")[] | undefined;
|
|
19
19
|
is_active?: boolean | undefined;
|
|
20
20
|
}, {
|
|
21
21
|
url: string;
|
|
22
22
|
confirm: true;
|
|
23
23
|
description?: string | undefined;
|
|
24
24
|
workspace_id?: string | undefined;
|
|
25
|
-
events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced")[] | undefined;
|
|
25
|
+
events?: ("webhook.test" | "post.created" | "post.updated" | "post.deleted" | "post.publishing" | "post.published" | "post.failed" | "account.disconnected" | "analytics.synced" | "approval.requested" | "approval.approved" | "approval.changes_requested" | "approval.rejected" | "approval.commented")[] | undefined;
|
|
26
26
|
is_active?: boolean | undefined;
|
|
27
27
|
}>;
|
|
28
28
|
execute(client: PosterlyClient, input: {
|
|
@@ -14,7 +14,7 @@ function formatDeletedApiKey(result) {
|
|
|
14
14
|
}
|
|
15
15
|
export const deleteApiKeyTool = {
|
|
16
16
|
name: 'delete_api_key',
|
|
17
|
-
description: 'Revoke a
|
|
17
|
+
description: 'Revoke a posterly API key owned by the authenticated user. DESTRUCTIVE: call whoami or use a known key ID, show the user the exact key ID/prefix/name if available, and get explicit confirmation before calling. Cannot revoke the key currently authenticating this request, OAuth-issued keys, or managed assistant keys.',
|
|
18
18
|
inputSchema: z.object({
|
|
19
19
|
key_id: z.string().uuid().describe('API key ID to revoke. This is the API key resource ID, not the secret pst_live_ value.'),
|
|
20
20
|
confirm: z.literal(true).describe('Must be true after the user explicitly confirms API key revocation.'),
|
|
@@ -15,8 +15,8 @@ export const deletePostTool = {
|
|
|
15
15
|
const result = await client.deletePost(input.post_id);
|
|
16
16
|
return [
|
|
17
17
|
`Post #${result.id} deleted successfully.`,
|
|
18
|
-
'It has been removed from the
|
|
19
|
-
`View queue in
|
|
18
|
+
'It has been removed from the posterly queue.',
|
|
19
|
+
`View queue in posterly: ${dashboardUrlForPosts()}`,
|
|
20
20
|
'',
|
|
21
21
|
'Next step for the AI agent: tell the user the post is gone and offer to create, reschedule, or review the next post.',
|
|
22
22
|
].join('\n');
|
|
@@ -38,7 +38,7 @@ export const generateCaptionsTool = {
|
|
|
38
38
|
preserve_call_to_action: z.boolean().default(true).optional(),
|
|
39
39
|
social_account_id: z.string().optional().describe('Optional connected account ID for brand voice and workspace billing context.'),
|
|
40
40
|
workspace_id: z.string().optional(),
|
|
41
|
-
manual_brand_voice: manualBrandVoiceSchema.optional().describe('Use when
|
|
41
|
+
manual_brand_voice: manualBrandVoiceSchema.optional().describe('Use when posterly asks for brand voice input.'),
|
|
42
42
|
}),
|
|
43
43
|
async execute(client, input) {
|
|
44
44
|
if (input.mode === 'adapt' && !input.source_caption?.trim()) {
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { mdKeyValue, mdTitle } from '../lib/format.js';
|
|
3
3
|
export const generateImageTool = {
|
|
4
4
|
name: 'generate_image',
|
|
5
|
-
description: 'Queue an AI image job via
|
|
5
|
+
description: 'Queue an AI image job via posterly using Nano Banana (Gemini) or Grok Imagine Image 2.0 (xAI). Returns job_id. Poll get_image_job until status is completed, then pass urls to create_post as media_url / media_urls. Gemini thinking high does not change the credit price.\n\n' +
|
|
6
6
|
'COSTS CREDITS. Every call consumes part of the user\'s monthly AI image quota (or purchased credits once the quota is exhausted). Do NOT call speculatively - always describe the image you\'re about to generate (subject, style, aspect ratio, quality/thinking, resolution) to the user and get confirmation before calling.\n\n' +
|
|
7
7
|
'If the user is over their plan limit and has no credits, this tool returns a 402 with upgrade info. Surface that message verbatim - do not retry.\n\n' +
|
|
8
8
|
'Common aspect ratios by platform:\n' +
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export const getAgentSignupInfoTool = {
|
|
3
3
|
name: 'get_agent_signup_info',
|
|
4
|
-
description: 'Explain how to use
|
|
4
|
+
description: 'Explain how to use posterly MCP for agent-led signup before an API key exists, including the safe human-in-the-browser boundaries.',
|
|
5
5
|
inputSchema: z.object({}),
|
|
6
6
|
async execute(client) {
|
|
7
7
|
const authState = client.hasApiKey()
|
|
8
|
-
? '
|
|
9
|
-
: 'No
|
|
8
|
+
? 'posterly API key is installed. Authenticated scheduling and connect tools are available.'
|
|
9
|
+
: 'No posterly API key is installed. Only public setup tools are available until the user completes paid setup and gives this AI posterly access.';
|
|
10
10
|
return [
|
|
11
|
-
'
|
|
11
|
+
'posterly agent signup info',
|
|
12
12
|
'',
|
|
13
13
|
authState,
|
|
14
14
|
'',
|
|
@@ -17,7 +17,7 @@ export const getAgentSignupInfoTool = {
|
|
|
17
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
18
|
'- get_signup_session: polls payment, password, and agent-access status.',
|
|
19
19
|
'',
|
|
20
|
-
'After
|
|
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.',
|
|
22
22
|
'- About you: confirm name and IANA timezone.',
|
|
23
23
|
'- create_connect_session / get_connect_session: first social account in the browser.',
|
|
@@ -26,17 +26,17 @@ export const getAgentSignupInfoTool = {
|
|
|
26
26
|
'',
|
|
27
27
|
'Conversation style:',
|
|
28
28
|
'- Keep the user updated in plain language: checkout pending, payment confirmed, password setup needed, account connected, post scheduled.',
|
|
29
|
-
'- Prefer the
|
|
29
|
+
'- Prefer the posterly dashboard links returned by tools when the user wants to inspect posts.',
|
|
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
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
34
|
'- Where enabled, payment can instead be a one-time Link Agent Wallet virtual card (credential_type: card) on a prepaid PaymentIntent.',
|
|
35
35
|
'- Never send card numbers to posterly. Confirm the PaymentIntent with Stripe, or send checkout_redirect_url.',
|
|
36
|
-
'- The user sets their
|
|
36
|
+
'- The user sets their posterly password in their browser.',
|
|
37
37
|
'- The user approves social OAuth in their browser.',
|
|
38
38
|
'- Publish approval stays with the user.',
|
|
39
|
-
'- The AI should never ask for card details,
|
|
39
|
+
'- The AI should never ask for card details, posterly passwords, social passwords, or OAuth codes.',
|
|
40
40
|
].join('\n');
|
|
41
41
|
},
|
|
42
42
|
};
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { formatLocalDateTime } from '../lib/format.js';
|
|
3
3
|
export const getCommentTool = {
|
|
4
4
|
name: 'get_comment',
|
|
5
|
-
description: 'Get one social inbox comment and its replies. Instagram, Facebook Page, and
|
|
5
|
+
description: 'Get one social inbox comment and its replies. Instagram, Facebook Page, Threads, and LinkedIn Page comments. Requires a Pro plan or higher plus posts:read.',
|
|
6
6
|
inputSchema: z.object({
|
|
7
7
|
comment_id: z.string().min(1).describe('Comment ID from list_comments.'),
|
|
8
8
|
workspace_id: z.string().optional().describe('Filter to a workspace ID from whoami.'),
|
|
@@ -29,7 +29,7 @@ export const getConnectLinkTool = {
|
|
|
29
29
|
}
|
|
30
30
|
const options = result.connect_options || [];
|
|
31
31
|
const lines = options.map((option) => formatConnectOption(option, false));
|
|
32
|
-
return `
|
|
32
|
+
return `posterly connection options (${options.length}):\n${lines.join('\n\n')}`;
|
|
33
33
|
},
|
|
34
34
|
};
|
|
35
35
|
function formatConnectOption(option, includeRaw) {
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { DASHBOARD_CONNECT_URL, formatConnectedAccounts, formatLocalDateTime } from '../lib/format.js';
|
|
3
3
|
export const getConnectSessionTool = {
|
|
4
4
|
name: 'get_connect_session',
|
|
5
|
-
description: 'Poll a
|
|
5
|
+
description: 'Poll a posterly connect session. Use the returned status and next-step guidance to keep the user updated in plain language. Stop when status is connected, failed, cancelled, or expired.',
|
|
6
6
|
inputSchema: z.object({
|
|
7
7
|
session_id: z.string().describe('Connect session ID returned by create_connect_session.'),
|
|
8
8
|
debug: z
|
|
@@ -18,7 +18,7 @@ export const getConnectSessionTool = {
|
|
|
18
18
|
function formatConnectSession(session, includeRaw) {
|
|
19
19
|
const connected = session.connected_count ?? session.connected_accounts?.length ?? 0;
|
|
20
20
|
return [
|
|
21
|
-
`
|
|
21
|
+
`posterly connect session: ${session.id}`,
|
|
22
22
|
`Platform: ${session.platform}`,
|
|
23
23
|
`Status: ${session.status}`,
|
|
24
24
|
`Message: ${session.status_message}`,
|
|
@@ -37,9 +37,9 @@ function guidanceForStatus(session) {
|
|
|
37
37
|
case 'created':
|
|
38
38
|
case 'opened':
|
|
39
39
|
case 'awaiting_provider':
|
|
40
|
-
return 'Next step for the AI agent: tell the user
|
|
40
|
+
return 'Next step for the AI agent: tell the user posterly is waiting for browser approval, then keep polling this session. Do not ask for social passwords or OAuth codes.';
|
|
41
41
|
case 'awaiting_credentials':
|
|
42
|
-
return 'Next step for the AI agent: tell the user
|
|
42
|
+
return 'Next step for the AI agent: tell the user posterly needs them to finish the browser credential step, then keep polling. Do not ask the user to paste credentials into chat.';
|
|
43
43
|
case 'connected':
|
|
44
44
|
return `Next step for the AI agent: tell the user ${formatConnectedAccounts(session.connected_accounts)} is connected, then ask what they want to schedule first or offer to create a test post.`;
|
|
45
45
|
case 'failed':
|
|
@@ -5,7 +5,7 @@ import { code, mdKeyValue, mdTitle } from '../lib/format.js';
|
|
|
5
5
|
const NPM_LATEST_URL = 'https://registry.npmjs.org/posterly-mcp-server/latest';
|
|
6
6
|
export const getMcpStatusTool = {
|
|
7
7
|
name: 'get_mcp_status',
|
|
8
|
-
description: 'Report the
|
|
8
|
+
description: 'Report the posterly MCP server version, latest npm version, MCP endpoint health, API key health, and update guidance. Safe to call before POSTERLY_API_KEY is configured.',
|
|
9
9
|
inputSchema: z.object({}),
|
|
10
10
|
async execute(client) {
|
|
11
11
|
const apiOrigin = client.getBaseUrl();
|
|
@@ -21,7 +21,7 @@ export const getMcpStatusTool = {
|
|
|
21
21
|
['Current server version', POSTERLY_MCP_VERSION],
|
|
22
22
|
['Latest npm version', latest.version || 'unknown'],
|
|
23
23
|
['Update status', updateStatus],
|
|
24
|
-
['
|
|
24
|
+
['posterly API origin', code(apiOrigin)],
|
|
25
25
|
['MCP endpoint health', formatApiProbe(apiProbe)],
|
|
26
26
|
['Hosted MCP version', apiProbe.version || 'unknown'],
|
|
27
27
|
['Version match', versionMatch],
|
|
@@ -32,7 +32,7 @@ export const getMcpStatusTool = {
|
|
|
32
32
|
rows.push(['User', authProbe.whoami.user.email || code(authProbe.whoami.user.id)], ['Default workspace', `${authProbe.whoami.default_workspace.name} (${code(authProbe.whoami.default_workspace.id)})`], ['API scopes', authProbe.whoami.api_key.scopes.join(', ') || 'none']);
|
|
33
33
|
}
|
|
34
34
|
return [
|
|
35
|
-
mdTitle('
|
|
35
|
+
mdTitle('posterly MCP status'),
|
|
36
36
|
mdKeyValue(rows),
|
|
37
37
|
latest.error ? `**Latest check:** ${latest.error}` : '',
|
|
38
38
|
apiProbe.error ? `**MCP endpoint check:** ${apiProbe.error}` : '',
|
|
@@ -142,7 +142,7 @@ function nextStep(input) {
|
|
|
142
142
|
return '**Next step:** Add `POSTERLY_API_KEY` after activating API and MCP access, then call `whoami`.';
|
|
143
143
|
}
|
|
144
144
|
if (authProbe && !authProbe.ok) {
|
|
145
|
-
return '**Next step:** Create or reinstall a valid
|
|
145
|
+
return '**Next step:** Create or reinstall a valid posterly API key, then restart the MCP client and call `get_mcp_status` again.';
|
|
146
146
|
}
|
|
147
147
|
return '**Next step:** Call `whoami` to confirm the user, workspace, and scopes before scheduling posts.';
|
|
148
148
|
}
|
package/dist/tools/get-post.js
CHANGED
|
@@ -15,7 +15,7 @@ export const getPostTool = {
|
|
|
15
15
|
`• Caption: ${p.content || '(empty)'}`,
|
|
16
16
|
`• Type: ${p.post_type || 'unknown'}`,
|
|
17
17
|
`• Scheduled: ${formatLocalDateTime(p.scheduled_at)}`,
|
|
18
|
-
`• View in
|
|
18
|
+
`• View in posterly: ${dashboardUrlForPost({ id: p.id, scheduled_at: p.scheduled_at })}`,
|
|
19
19
|
];
|
|
20
20
|
if (p.platform_post_url)
|
|
21
21
|
lines.push(`• Published URL: ${p.platform_post_url}`);
|
|
@@ -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
|
|
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()
|
|
@@ -26,7 +26,7 @@ function formatSignupSession(session, includeRaw) {
|
|
|
26
26
|
const agentPay = session.agent_pay;
|
|
27
27
|
const payment = session.payment;
|
|
28
28
|
const lines = [
|
|
29
|
-
`
|
|
29
|
+
`posterly signup session: ${session.id}`,
|
|
30
30
|
`Status: ${session.status}`,
|
|
31
31
|
session.status_message ? `Message: ${session.status_message}` : '',
|
|
32
32
|
nextAction?.label ? `Next action: ${nextAction.label}` : '',
|
|
@@ -72,15 +72,15 @@ function guidanceForStatus(status, agentPayAvailable = false, requiresTosAccepta
|
|
|
72
72
|
case 'checkout_expired':
|
|
73
73
|
return 'Tell the user checkout expired and offer to call start_signup again.';
|
|
74
74
|
case 'payment_confirmed':
|
|
75
|
-
return 'Tell the user payment is confirmed and
|
|
75
|
+
return 'Tell the user payment is confirmed and posterly is preparing access. Keep polling.';
|
|
76
76
|
case 'password_required':
|
|
77
|
-
return 'Tell the user
|
|
77
|
+
return 'Tell the user posterly has sent a password setup email. They need to open that email and set a password in the browser.';
|
|
78
78
|
case 'authorize_agent':
|
|
79
|
-
return 'Tell the user
|
|
79
|
+
return 'Tell the user posterly is ready for agent authorization. Send them the provided authorization or completion link if one is present.';
|
|
80
80
|
case 'agent_access_required':
|
|
81
|
-
return 'Tell the user API access is active, but this AI still needs
|
|
81
|
+
return 'Tell the user API access is active, but this AI still needs posterly access. Ask them to paste the posterly MCP/API setup instructions here or install the posterly MCP server. Then onboard them IN THIS chat: about you, connect, brand voice, first post. Do not send them to /onboarding-v2.';
|
|
82
82
|
case 'api_access_active':
|
|
83
|
-
return '
|
|
83
|
+
return 'posterly API access is active. Call whoami, then onboard them IN THIS chat: about you (name and timezone), connect the first account, brand voice, first post. Do not send them to /onboarding-v2.';
|
|
84
84
|
default:
|
|
85
85
|
return 'Explain the current status to the user and keep polling unless the session is terminal.';
|
|
86
86
|
}
|
|
@@ -14,7 +14,7 @@ export const listAccountsTool = {
|
|
|
14
14
|
if (accounts.length === 0) {
|
|
15
15
|
return input.workspace_id
|
|
16
16
|
? mdEmpty('connected accounts', 'This workspace does not have any social accounts connected yet.')
|
|
17
|
-
: mdEmpty('connected accounts', '
|
|
17
|
+
: mdEmpty('connected accounts', 'posterly does not see any connected social accounts yet.', 'Connect accounts in the posterly dashboard, then run this again.');
|
|
18
18
|
}
|
|
19
19
|
const hasInstagram = accounts.some((account) => account.platform === 'instagram');
|
|
20
20
|
return [
|