posterly-mcp-server 0.20.4 → 0.20.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 +2 -1
- package/dist/index.js +10 -0
- package/dist/lib/api-client.d.ts +29 -0
- package/dist/lib/api-client.js +3 -0
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/tools/create-api-key.d.ts +26 -0
- package/dist/tools/create-api-key.js +35 -0
- package/package.json +1 -1
- package/src/index.ts +15 -0
- package/src/lib/api-client.ts +41 -0
- package/src/lib/version.ts +1 -1
- package/src/tools/create-api-key.ts +41 -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.20.
|
|
111
|
+
`posterly-mcp-server@0.20.5` exposes 59 tools.
|
|
112
112
|
|
|
113
113
|
Public setup tools work before `POSTERLY_API_KEY` exists:
|
|
114
114
|
|
|
@@ -125,6 +125,7 @@ Authenticated tools require `POSTERLY_API_KEY`:
|
|
|
125
125
|
- `get_connect_link`
|
|
126
126
|
- `create_connect_session` (create a guided browser handoff for connecting a social account)
|
|
127
127
|
- `get_connect_session` (poll connection progress while the user approves OAuth or enters credentials)
|
|
128
|
+
- `create_api_key` (create a new API key after explicit confirmation; scopes cannot exceed the calling dashboard key)
|
|
128
129
|
- `list_oauth_clients`
|
|
129
130
|
- `create_oauth_client` (create a public PKCE client after explicit confirmation)
|
|
130
131
|
- `update_oauth_client` (update redirect URIs/scopes after explicit confirmation)
|
package/dist/index.js
CHANGED
|
@@ -56,6 +56,7 @@ import { uploadMediaFromUrlTool } from './tools/upload-media-from-url.js';
|
|
|
56
56
|
import { getConnectLinkTool } from './tools/get-connect-link.js';
|
|
57
57
|
import { createConnectSessionTool } from './tools/create-connect-session.js';
|
|
58
58
|
import { getConnectSessionTool } from './tools/get-connect-session.js';
|
|
59
|
+
import { createApiKeyTool } from './tools/create-api-key.js';
|
|
59
60
|
import { listOAuthClientsTool } from './tools/list-oauth-clients.js';
|
|
60
61
|
import { createOAuthClientTool } from './tools/create-oauth-client.js';
|
|
61
62
|
import { updateOAuthClientTool } from './tools/update-oauth-client.js';
|
|
@@ -156,6 +157,15 @@ server.tool(getConnectSessionTool.name, getConnectSessionTool.description, getCo
|
|
|
156
157
|
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
157
158
|
}
|
|
158
159
|
});
|
|
160
|
+
server.tool(createApiKeyTool.name, createApiKeyTool.description, createApiKeyTool.inputSchema.shape, async (input) => {
|
|
161
|
+
try {
|
|
162
|
+
const text = await createApiKeyTool.execute(client, input);
|
|
163
|
+
return { content: [{ type: 'text', text }] };
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
167
|
+
}
|
|
168
|
+
});
|
|
159
169
|
server.tool(listOAuthClientsTool.name, listOAuthClientsTool.description, listOAuthClientsTool.inputSchema.shape, async () => {
|
|
160
170
|
try {
|
|
161
171
|
const text = await listOAuthClientsTool.execute(client);
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -159,6 +159,34 @@ export type AskSupportPayload = {
|
|
|
159
159
|
request_human?: boolean;
|
|
160
160
|
confirm_escalation?: boolean;
|
|
161
161
|
};
|
|
162
|
+
export type ApiKeyScope = 'accounts:read' | 'accounts:write' | 'posts:read' | 'posts:write' | 'media:write' | 'analytics:read';
|
|
163
|
+
export type CreateApiKeyPayload = {
|
|
164
|
+
name?: string;
|
|
165
|
+
scopes?: ApiKeyScope[];
|
|
166
|
+
workspace_id?: string;
|
|
167
|
+
expires_in_days?: number;
|
|
168
|
+
confirm: true;
|
|
169
|
+
};
|
|
170
|
+
export type CreateApiKeyResponse = {
|
|
171
|
+
key: string;
|
|
172
|
+
api_key: {
|
|
173
|
+
id: string;
|
|
174
|
+
name: string;
|
|
175
|
+
key_prefix: string;
|
|
176
|
+
scopes: ApiKeyScope[];
|
|
177
|
+
workspace_id?: string | null;
|
|
178
|
+
expires_at?: string | null;
|
|
179
|
+
created_at: string;
|
|
180
|
+
};
|
|
181
|
+
warning?: string;
|
|
182
|
+
limits?: {
|
|
183
|
+
tier?: string;
|
|
184
|
+
max_user_keys?: number;
|
|
185
|
+
active_user_keys?: number;
|
|
186
|
+
remaining_user_keys?: number;
|
|
187
|
+
uses_grandfathered_keys?: boolean;
|
|
188
|
+
};
|
|
189
|
+
};
|
|
162
190
|
export type AskSupportResponse = {
|
|
163
191
|
success: boolean;
|
|
164
192
|
workspace_id: string;
|
|
@@ -552,6 +580,7 @@ export declare class PosterlyClient {
|
|
|
552
580
|
startSignup(data: PublicSignupPayload): Promise<PublicSignupResponse>;
|
|
553
581
|
getSignupSession(sessionId: string): Promise<PublicSignupSessionResponse>;
|
|
554
582
|
whoami(): Promise<Whoami>;
|
|
583
|
+
createApiKey(data: CreateApiKeyPayload): Promise<CreateApiKeyResponse>;
|
|
555
584
|
listAccounts(params?: {
|
|
556
585
|
workspace_id?: string;
|
|
557
586
|
}): Promise<Account[]>;
|
package/dist/lib/api-client.js
CHANGED
|
@@ -113,6 +113,9 @@ export class PosterlyClient {
|
|
|
113
113
|
async whoami() {
|
|
114
114
|
return this.request('GET', '/whoami');
|
|
115
115
|
}
|
|
116
|
+
async createApiKey(data) {
|
|
117
|
+
return this.request('POST', '/api-keys', data);
|
|
118
|
+
}
|
|
116
119
|
async listAccounts(params) {
|
|
117
120
|
const searchParams = new URLSearchParams();
|
|
118
121
|
if (params?.workspace_id)
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const POSTERLY_MCP_VERSION = "0.20.
|
|
1
|
+
export declare const POSTERLY_MCP_VERSION = "0.20.5";
|
package/dist/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const POSTERLY_MCP_VERSION = '0.20.
|
|
1
|
+
export const POSTERLY_MCP_VERSION = '0.20.5';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CreateApiKeyPayload, PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
export declare const createApiKeyTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{
|
|
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">>;
|
|
9
|
+
workspace_id: z.ZodOptional<z.ZodString>;
|
|
10
|
+
expires_in_days: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
confirm: z.ZodLiteral<true>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
confirm: true;
|
|
14
|
+
workspace_id?: string | undefined;
|
|
15
|
+
name?: string | undefined;
|
|
16
|
+
scopes?: ("accounts:read" | "accounts:write" | "posts:read" | "posts:write" | "media:write" | "analytics:read")[] | undefined;
|
|
17
|
+
expires_in_days?: number | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
confirm: true;
|
|
20
|
+
workspace_id?: string | undefined;
|
|
21
|
+
name?: string | undefined;
|
|
22
|
+
scopes?: ("accounts:read" | "accounts:write" | "posts:read" | "posts:write" | "media:write" | "analytics:read")[] | undefined;
|
|
23
|
+
expires_in_days?: number | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
execute(client: PosterlyClient, input: CreateApiKeyPayload): Promise<string>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
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']);
|
|
4
|
+
function formatCreatedApiKey(result) {
|
|
5
|
+
const key = result.api_key;
|
|
6
|
+
return [
|
|
7
|
+
mdTitle('API key created'),
|
|
8
|
+
`Full key (shown once): ${code(result.key)}`,
|
|
9
|
+
mdSection('Details', mdKeyValue([
|
|
10
|
+
['Name', key.name],
|
|
11
|
+
['Key ID', code(key.id)],
|
|
12
|
+
['Prefix', code(key.key_prefix)],
|
|
13
|
+
['Scopes', key.scopes.join(', ')],
|
|
14
|
+
['Workspace', key.workspace_id ? code(key.workspace_id) : 'all accessible workspaces'],
|
|
15
|
+
['Expires', key.expires_at || 'no expiry'],
|
|
16
|
+
['Remaining key slots', result.limits?.remaining_user_keys ?? 'unknown'],
|
|
17
|
+
])),
|
|
18
|
+
mdSection('Warning', result.warning || 'Store this securely. It will not be shown again.'),
|
|
19
|
+
].filter(Boolean).join('\n\n');
|
|
20
|
+
}
|
|
21
|
+
export const createApiKeyTool = {
|
|
22
|
+
name: 'create_api_key',
|
|
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
|
+
inputSchema: z.object({
|
|
25
|
+
name: z.string().trim().min(1).max(120).optional().describe('Human-readable key name.'),
|
|
26
|
+
scopes: z.array(scopeSchema).min(1).max(6).optional().describe('Scopes for the new key. Omit to copy the calling key scopes. Cannot exceed the calling key scopes.'),
|
|
27
|
+
workspace_id: z.string().trim().min(1).optional().describe('Optional workspace restriction. Workspace-scoped calling keys cannot create keys outside their workspace.'),
|
|
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
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms that a new secret API key should be created.'),
|
|
30
|
+
}),
|
|
31
|
+
async execute(client, input) {
|
|
32
|
+
const result = await client.createApiKey(input);
|
|
33
|
+
return formatCreatedApiKey(result);
|
|
34
|
+
},
|
|
35
|
+
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -57,6 +57,7 @@ import { uploadMediaFromUrlTool } from './tools/upload-media-from-url.js';
|
|
|
57
57
|
import { getConnectLinkTool } from './tools/get-connect-link.js';
|
|
58
58
|
import { createConnectSessionTool } from './tools/create-connect-session.js';
|
|
59
59
|
import { getConnectSessionTool } from './tools/get-connect-session.js';
|
|
60
|
+
import { createApiKeyTool } from './tools/create-api-key.js';
|
|
60
61
|
import { listOAuthClientsTool } from './tools/list-oauth-clients.js';
|
|
61
62
|
import { createOAuthClientTool } from './tools/create-oauth-client.js';
|
|
62
63
|
import { updateOAuthClientTool } from './tools/update-oauth-client.js';
|
|
@@ -210,6 +211,20 @@ server.tool(
|
|
|
210
211
|
}
|
|
211
212
|
);
|
|
212
213
|
|
|
214
|
+
server.tool(
|
|
215
|
+
createApiKeyTool.name,
|
|
216
|
+
createApiKeyTool.description,
|
|
217
|
+
createApiKeyTool.inputSchema.shape,
|
|
218
|
+
async (input) => {
|
|
219
|
+
try {
|
|
220
|
+
const text = await createApiKeyTool.execute(client, input as any);
|
|
221
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
222
|
+
} catch (err: any) {
|
|
223
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
|
|
213
228
|
server.tool(
|
|
214
229
|
listOAuthClientsTool.name,
|
|
215
230
|
listOAuthClientsTool.description,
|
package/src/lib/api-client.ts
CHANGED
|
@@ -163,6 +163,43 @@ export type AskSupportPayload = {
|
|
|
163
163
|
confirm_escalation?: boolean;
|
|
164
164
|
};
|
|
165
165
|
|
|
166
|
+
export type ApiKeyScope =
|
|
167
|
+
| 'accounts:read'
|
|
168
|
+
| 'accounts:write'
|
|
169
|
+
| 'posts:read'
|
|
170
|
+
| 'posts:write'
|
|
171
|
+
| 'media:write'
|
|
172
|
+
| 'analytics:read';
|
|
173
|
+
|
|
174
|
+
export type CreateApiKeyPayload = {
|
|
175
|
+
name?: string;
|
|
176
|
+
scopes?: ApiKeyScope[];
|
|
177
|
+
workspace_id?: string;
|
|
178
|
+
expires_in_days?: number;
|
|
179
|
+
confirm: true;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export type CreateApiKeyResponse = {
|
|
183
|
+
key: string;
|
|
184
|
+
api_key: {
|
|
185
|
+
id: string;
|
|
186
|
+
name: string;
|
|
187
|
+
key_prefix: string;
|
|
188
|
+
scopes: ApiKeyScope[];
|
|
189
|
+
workspace_id?: string | null;
|
|
190
|
+
expires_at?: string | null;
|
|
191
|
+
created_at: string;
|
|
192
|
+
};
|
|
193
|
+
warning?: string;
|
|
194
|
+
limits?: {
|
|
195
|
+
tier?: string;
|
|
196
|
+
max_user_keys?: number;
|
|
197
|
+
active_user_keys?: number;
|
|
198
|
+
remaining_user_keys?: number;
|
|
199
|
+
uses_grandfathered_keys?: boolean;
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
|
|
166
203
|
export type AskSupportResponse = {
|
|
167
204
|
success: boolean;
|
|
168
205
|
workspace_id: string;
|
|
@@ -693,6 +730,10 @@ export class PosterlyClient {
|
|
|
693
730
|
return this.request<Whoami>('GET', '/whoami');
|
|
694
731
|
}
|
|
695
732
|
|
|
733
|
+
async createApiKey(data: CreateApiKeyPayload): Promise<CreateApiKeyResponse> {
|
|
734
|
+
return this.request('POST', '/api-keys', data);
|
|
735
|
+
}
|
|
736
|
+
|
|
696
737
|
async listAccounts(params?: { workspace_id?: string }): Promise<Account[]> {
|
|
697
738
|
const searchParams = new URLSearchParams();
|
|
698
739
|
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
package/src/lib/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const POSTERLY_MCP_VERSION = '0.20.
|
|
1
|
+
export const POSTERLY_MCP_VERSION = '0.20.5';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CreateApiKeyPayload, CreateApiKeyResponse, PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, mdKeyValue, mdSection, mdTitle } from '../lib/format.js';
|
|
4
|
+
|
|
5
|
+
const scopeSchema = z.enum(['accounts:read', 'accounts:write', 'posts:read', 'posts:write', 'media:write', 'analytics:read']);
|
|
6
|
+
|
|
7
|
+
function formatCreatedApiKey(result: CreateApiKeyResponse): string {
|
|
8
|
+
const key = result.api_key;
|
|
9
|
+
return [
|
|
10
|
+
mdTitle('API key created'),
|
|
11
|
+
`Full key (shown once): ${code(result.key)}`,
|
|
12
|
+
mdSection('Details', mdKeyValue([
|
|
13
|
+
['Name', key.name],
|
|
14
|
+
['Key ID', code(key.id)],
|
|
15
|
+
['Prefix', code(key.key_prefix)],
|
|
16
|
+
['Scopes', key.scopes.join(', ')],
|
|
17
|
+
['Workspace', key.workspace_id ? code(key.workspace_id) : 'all accessible workspaces'],
|
|
18
|
+
['Expires', key.expires_at || 'no expiry'],
|
|
19
|
+
['Remaining key slots', result.limits?.remaining_user_keys ?? 'unknown'],
|
|
20
|
+
])),
|
|
21
|
+
mdSection('Warning', result.warning || 'Store this securely. It will not be shown again.'),
|
|
22
|
+
].filter(Boolean).join('\n\n');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const createApiKeyTool = {
|
|
26
|
+
name: 'create_api_key',
|
|
27
|
+
description:
|
|
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
|
+
inputSchema: z.object({
|
|
30
|
+
name: z.string().trim().min(1).max(120).optional().describe('Human-readable key name.'),
|
|
31
|
+
scopes: z.array(scopeSchema).min(1).max(6).optional().describe('Scopes for the new key. Omit to copy the calling key scopes. Cannot exceed the calling key scopes.'),
|
|
32
|
+
workspace_id: z.string().trim().min(1).optional().describe('Optional workspace restriction. Workspace-scoped calling keys cannot create keys outside their workspace.'),
|
|
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
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms that a new secret API key should be created.'),
|
|
35
|
+
}),
|
|
36
|
+
|
|
37
|
+
async execute(client: PosterlyClient, input: CreateApiKeyPayload) {
|
|
38
|
+
const result = await client.createApiKey(input);
|
|
39
|
+
return formatCreatedApiKey(result);
|
|
40
|
+
},
|
|
41
|
+
};
|