posterly-mcp-server 0.50.3 → 0.50.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/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/index.js +8 -3
- package/dist/lib/alias-transport.d.ts +2 -1
- package/dist/lib/alias-transport.js +17 -4
- package/dist/lib/claude-directory-profile.d.ts +5 -0
- package/dist/lib/claude-directory-profile.js +95 -0
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/package.json +11 -4
- package/server.json +4 -5
- package/RELEASING.md +0 -115
- package/SUBMISSIONS.md +0 -109
- package/scripts/test-alias-transport.mjs +0 -368
- package/scripts/test-client-header-sanitization.mjs +0 -78
- package/scripts/test-payload-builders.mjs +0 -210
- package/scripts/test-tool-annotations.mjs +0 -68
- package/src/generated/platform-manifest.ts +0 -753
- package/src/index.ts +0 -286
- package/src/lib/alias-transport.ts +0 -233
- package/src/lib/api-client.ts +0 -2638
- package/src/lib/format.ts +0 -446
- package/src/lib/preview-token-core.ts +0 -157
- package/src/lib/preview-token.ts +0 -54
- package/src/lib/tool-annotations.ts +0 -47
- package/src/lib/tool-registry.ts +0 -538
- package/src/lib/tool-runtime.ts +0 -117
- package/src/lib/version.ts +0 -8
- package/src/tools/ask-support.ts +0 -55
- package/src/tools/audit-google-business-profile.ts +0 -57
- package/src/tools/cancel-subscription.ts +0 -50
- package/src/tools/connect-account.ts +0 -91
- package/src/tools/create-api-key.ts +0 -41
- package/src/tools/create-connect-session.ts +0 -55
- package/src/tools/create-media-drop.ts +0 -41
- package/src/tools/create-post.ts +0 -430
- package/src/tools/create-posts-batch.ts +0 -80
- package/src/tools/create-signed-upload.ts +0 -29
- package/src/tools/create-webhook.ts +0 -34
- package/src/tools/delete-api-key.ts +0 -31
- package/src/tools/delete-post.ts +0 -86
- package/src/tools/disconnect-account.ts +0 -30
- package/src/tools/dismiss-suggestion.ts +0 -22
- package/src/tools/downgrade-subscription.ts +0 -29
- package/src/tools/find-slot.ts +0 -101
- package/src/tools/generate-captions.ts +0 -77
- package/src/tools/generate-image.ts +0 -108
- package/src/tools/generate-video.ts +0 -45
- package/src/tools/get-agent-signup-info.ts +0 -47
- package/src/tools/get-credits.ts +0 -38
- package/src/tools/get-post.ts +0 -49
- package/src/tools/get-signup-session.ts +0 -100
- package/src/tools/get-subscription.ts +0 -31
- package/src/tools/get-updates.ts +0 -55
- package/src/tools/get-video-options.ts +0 -30
- package/src/tools/get-x-posting-quota.ts +0 -25
- package/src/tools/list-accounts.ts +0 -202
- package/src/tools/list-activity.ts +0 -65
- package/src/tools/list-analytics.ts +0 -447
- package/src/tools/list-brands.ts +0 -175
- package/src/tools/list-comments.ts +0 -125
- package/src/tools/list-conversations.ts +0 -119
- package/src/tools/list-google-business-media.ts +0 -33
- package/src/tools/list-google-business-reviews.ts +0 -165
- package/src/tools/list-jobs.ts +0 -91
- package/src/tools/list-media.ts +0 -69
- package/src/tools/list-oauth-clients.ts +0 -18
- package/src/tools/list-platforms.ts +0 -149
- package/src/tools/list-post-suggestions.ts +0 -69
- package/src/tools/list-posts.ts +0 -120
- package/src/tools/list-publishing-pauses.ts +0 -98
- package/src/tools/list-webhooks.ts +0 -29
- package/src/tools/list-workspace-members.ts +0 -75
- package/src/tools/manage-comment.ts +0 -142
- package/src/tools/manage-conversation.ts +0 -89
- package/src/tools/manage-google-business-media.ts +0 -147
- package/src/tools/manage-google-business-review.ts +0 -139
- package/src/tools/manage-oauth-client.ts +0 -116
- package/src/tools/manage-publishing-pause.ts +0 -62
- package/src/tools/manage-webhook.ts +0 -103
- package/src/tools/manage-workspace-member.ts +0 -163
- package/src/tools/pause-subscription.ts +0 -26
- package/src/tools/resume-subscription.ts +0 -15
- package/src/tools/run-video-function.ts +0 -32
- package/src/tools/start-signup.ts +0 -150
- package/src/tools/submit-agent-feedback.ts +0 -47
- package/src/tools/submit-product-feedback.ts +0 -56
- package/src/tools/trigger-platform-helper.ts +0 -34
- package/src/tools/update-post.ts +0 -334
- package/src/tools/upload-media.ts +0 -107
- package/src/tools/validate-post.ts +0 -42
- package/src/tools/webhook-events.ts +0 -20
- package/src/tools/whoami.ts +0 -262
- package/tsconfig.json +0 -14
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Grassroots Marketing LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Posterly also exposes the same authenticated toolset over HTTP at [poster.ly/mcp
|
|
|
25
25
|
- Agent reference: `https://www.poster.ly/llms-full.txt`
|
|
26
26
|
- Signup and API-key acquisition: `https://www.poster.ly/agents/signup`
|
|
27
27
|
- Smithery: `https://smithery.ai/servers/awpthorp/posterly`
|
|
28
|
-
- Source: `https://github.com/awpthorp/posterly
|
|
28
|
+
- Source: `https://github.com/awpthorp/posterly-mcp-server`
|
|
29
29
|
|
|
30
30
|
The official MCP Registry metadata is in `server.json`. Its canonical registry
|
|
31
31
|
name is `io.github.awpthorp/posterly`, matching this package's `mcpName`.
|
|
@@ -123,7 +123,7 @@ Add the same server definition to your Cursor MCP settings:
|
|
|
123
123
|
|
|
124
124
|
## Available tools
|
|
125
125
|
|
|
126
|
-
`posterly-mcp-server@0.50.
|
|
126
|
+
`posterly-mcp-server@0.50.5` exposes 64 tools covering 100 actions. The hosted HTTP endpoint exposes the same catalog minus the three signup tools: 61 tools covering 97 actions.
|
|
127
127
|
|
|
128
128
|
Many tools pick what to do with one parameter: `view` (reads), `action` (writes), or `type`. A few pick their mode from which parameters you pass (for example `update_post` with `status` changes the status instead of editing). Every tool description names all of its views and actions.
|
|
129
129
|
|
|
@@ -532,3 +532,11 @@ The package reads:
|
|
|
532
532
|
- optional `POSTERLY_API_KEY` for authenticated posterly tools
|
|
533
533
|
- optional `POSTERLY_URL` if you need to point at a non-production environment
|
|
534
534
|
- optional `POSTERLY_TOOLSETS` (for example `core,inbox`) to list fewer tool sets
|
|
535
|
+
|
|
536
|
+
## Claude directory profile
|
|
537
|
+
|
|
538
|
+
The optional directory profile provides 52 tools over HTTP or 55 tools over local stdio for social publishing, existing-media uploads, analytics, and inbox work. AI image and video generation, generation-job helpers, billing mutations, and legacy tool aliases are unavailable in this profile. Text caption suggestions and read-only subscription information remain available. Tool descriptions are functional summaries; input schemas retain their validation constraints.
|
|
539
|
+
|
|
540
|
+
Hosted endpoint: `https://www.poster.ly/api/mcp?profile=claude`. For local stdio, set `POSTERLY_DIRECTORY_PROFILE=claude` alongside the existing API key. The default catalogs remain 61 hosted tools and 64 local tools. This profile does not grant authorization, bypass scopes, or change the existing preview and confirmation checks.
|
|
541
|
+
|
|
542
|
+
Directory approval remains Anthropic's decision. This profile addresses the generation and financial-transaction restrictions in the [Anthropic Software Directory Policy](https://support.claude.com/en/articles/13145358-anthropic-software-directory-policy).
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
5
5
|
import { PosterlyClient, setMcpClientNameResolver } from './lib/api-client.js';
|
|
6
6
|
import { POSTERLY_MCP_VERSION } from './lib/version.js';
|
|
7
7
|
import { getToolAnnotations } from './lib/tool-annotations.js';
|
|
8
|
+
import { CLAUDE_DIRECTORY_INSTRUCTIONS, isClaudeDirectoryTool } from './lib/claude-directory-profile.js';
|
|
8
9
|
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
|
9
10
|
import { AliasTransport } from './lib/alias-transport.js';
|
|
10
11
|
import { StdioPreviewTokens } from './lib/preview-token.js';
|
|
@@ -148,6 +149,10 @@ const STDIO_TOOLS = [
|
|
|
148
149
|
// tool-annotations.json; dist/index.js reads it from one level up.
|
|
149
150
|
const require = createRequire(import.meta.url);
|
|
150
151
|
const registry = require('../tool-registry.json');
|
|
152
|
+
const directoryProfile = process.env.POSTERLY_DIRECTORY_PROFILE;
|
|
153
|
+
if (directoryProfile && directoryProfile !== 'claude')
|
|
154
|
+
throw new Error('Unknown posterly directory profile');
|
|
155
|
+
const claudeDirectoryProfile = directoryProfile === 'claude';
|
|
151
156
|
/**
|
|
152
157
|
* Tool sets to list (POSTERLY_TOOLSETS env or --toolsets=core,inbox). Default
|
|
153
158
|
* is every set, so nobody loses tools. Signup tools are always listed. Sets
|
|
@@ -169,7 +174,7 @@ const server = new McpServer({
|
|
|
169
174
|
}, {
|
|
170
175
|
// Which tool sets exist, that every set is on by default, how to load
|
|
171
176
|
// fewer, and how preview then confirm works (built from the registry).
|
|
172
|
-
instructions: toolsetInstructions(registry, 'stdio'),
|
|
177
|
+
instructions: claudeDirectoryProfile ? CLAUDE_DIRECTORY_INSTRUCTIONS : toolsetInstructions(registry, 'stdio'),
|
|
173
178
|
});
|
|
174
179
|
const client = new PosterlyClient();
|
|
175
180
|
// The SDK only learns the connected client's identity (e.g. "claude-ai",
|
|
@@ -201,7 +206,7 @@ const legacyValidator = (aliasName, args) => {
|
|
|
201
206
|
// Renamed tools (aliases) are never registered with McpServer: the transport
|
|
202
207
|
// rewrites an alias call onto its target before the SDK sees it, and handlers
|
|
203
208
|
// read the called name back through getCallInfo(extra.requestId).
|
|
204
|
-
const transport = new AliasTransport(new StdioServerTransport(), registry, toolsets.all ? null : visibleTools(registry, toolsets.enabled, 'stdio'), legacyValidator);
|
|
209
|
+
const transport = new AliasTransport(new StdioServerTransport(), registry, toolsets.all ? null : visibleTools(registry, toolsets.enabled, 'stdio'), legacyValidator, claudeDirectoryProfile);
|
|
205
210
|
// Preview then confirm tokens: a random key and an in-memory one-time-use
|
|
206
211
|
// set per process (UX protection only; REST authorization is unchanged).
|
|
207
212
|
const previews = new StdioPreviewTokens();
|
|
@@ -230,7 +235,7 @@ function registerAll(tools) {
|
|
|
230
235
|
});
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
|
-
registerAll(STDIO_TOOLS);
|
|
238
|
+
registerAll(claudeDirectoryProfile ? STDIO_TOOLS.filter((tool) => isClaudeDirectoryTool(tool.name)) : STDIO_TOOLS);
|
|
234
239
|
// Start the server
|
|
235
240
|
async function main() {
|
|
236
241
|
await server.connect(transport);
|
|
@@ -58,6 +58,7 @@ export declare class AliasTransport implements Transport {
|
|
|
58
58
|
private readonly registry;
|
|
59
59
|
private readonly visibleTools;
|
|
60
60
|
private readonly legacyValidator;
|
|
61
|
+
private readonly claudeDirectoryProfile;
|
|
61
62
|
onclose?: () => void;
|
|
62
63
|
onerror?: (error: Error) => void;
|
|
63
64
|
onmessage?: <T extends JSONRPCMessage>(message: T, extra?: MessageExtraInfo) => void;
|
|
@@ -68,7 +69,7 @@ export declare class AliasTransport implements Transport {
|
|
|
68
69
|
* @param visibleTools names to list in tools/list, or null to list every
|
|
69
70
|
* registered tool unchanged (the default: every set).
|
|
70
71
|
*/
|
|
71
|
-
constructor(inner: Transport, registry: ToolRegistry, visibleTools?: Set<string> | null, legacyValidator?: LegacyAliasValidator | null);
|
|
72
|
+
constructor(inner: Transport, registry: ToolRegistry, visibleTools?: Set<string> | null, legacyValidator?: LegacyAliasValidator | null, claudeDirectoryProfile?: boolean);
|
|
72
73
|
get sessionId(): string | undefined;
|
|
73
74
|
setProtocolVersion(version: string): void;
|
|
74
75
|
start(): Promise<void>;
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
*
|
|
30
30
|
* Only the public Transport interface is used; no SDK private fields.
|
|
31
31
|
*/
|
|
32
|
+
import { claudeDirectoryDescription, claudeDirectorySchema, isClaudeDirectoryTool } from './claude-directory-profile.js';
|
|
32
33
|
import { DEPRECATION_META_KEY, deprecationNote, resolveAlias, translateArgs, validateMode, } from './tool-registry.js';
|
|
33
34
|
function requestKey(id) {
|
|
34
35
|
return `${typeof id}:${String(id)}`;
|
|
@@ -41,6 +42,7 @@ export class AliasTransport {
|
|
|
41
42
|
registry;
|
|
42
43
|
visibleTools;
|
|
43
44
|
legacyValidator;
|
|
45
|
+
claudeDirectoryProfile;
|
|
44
46
|
onclose;
|
|
45
47
|
onerror;
|
|
46
48
|
onmessage;
|
|
@@ -51,11 +53,12 @@ export class AliasTransport {
|
|
|
51
53
|
* @param visibleTools names to list in tools/list, or null to list every
|
|
52
54
|
* registered tool unchanged (the default: every set).
|
|
53
55
|
*/
|
|
54
|
-
constructor(inner, registry, visibleTools = null, legacyValidator = null) {
|
|
56
|
+
constructor(inner, registry, visibleTools = null, legacyValidator = null, claudeDirectoryProfile = false) {
|
|
55
57
|
this.inner = inner;
|
|
56
58
|
this.registry = registry;
|
|
57
59
|
this.visibleTools = visibleTools;
|
|
58
60
|
this.legacyValidator = legacyValidator;
|
|
61
|
+
this.claudeDirectoryProfile = claudeDirectoryProfile;
|
|
59
62
|
inner.onmessage = (message, extra) => this.handleIncoming(message, extra);
|
|
60
63
|
inner.onclose = () => this.onclose?.();
|
|
61
64
|
inner.onerror = (error) => this.onerror?.(error);
|
|
@@ -95,7 +98,7 @@ export class AliasTransport {
|
|
|
95
98
|
this.onmessage?.(message, extra);
|
|
96
99
|
return;
|
|
97
100
|
}
|
|
98
|
-
if (request.method === 'tools/list' && this.visibleTools && request.id !== undefined && request.id !== null) {
|
|
101
|
+
if (request.method === 'tools/list' && (this.visibleTools || this.claudeDirectoryProfile) && request.id !== undefined && request.id !== null) {
|
|
99
102
|
this.listRequests.add(requestKey(request.id));
|
|
100
103
|
this.onmessage?.(message, extra);
|
|
101
104
|
return;
|
|
@@ -105,6 +108,12 @@ export class AliasTransport {
|
|
|
105
108
|
return;
|
|
106
109
|
}
|
|
107
110
|
const name = request.params.name;
|
|
111
|
+
if (this.claudeDirectoryProfile && (typeof name !== 'string' || !isClaudeDirectoryTool(name))) {
|
|
112
|
+
// Omitted tools and legacy aliases reach the SDK unchanged and fail as
|
|
113
|
+
// unregistered names, rather than being rewritten into callable tools.
|
|
114
|
+
this.onmessage?.(message, extra);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
108
117
|
const alias = typeof name === 'string' ? resolveAlias(this.registry, name) : null;
|
|
109
118
|
if (!alias) {
|
|
110
119
|
this.onmessage?.(message, extra);
|
|
@@ -150,7 +159,7 @@ export class AliasTransport {
|
|
|
150
159
|
}
|
|
151
160
|
filterToolsList(message) {
|
|
152
161
|
const response = message;
|
|
153
|
-
if (!this.visibleTools || response.method !== undefined || response.id === undefined || response.id === null)
|
|
162
|
+
if ((!this.visibleTools && !this.claudeDirectoryProfile) || response.method !== undefined || response.id === undefined || response.id === null)
|
|
154
163
|
return message;
|
|
155
164
|
const key = requestKey(response.id);
|
|
156
165
|
if (!this.listRequests.has(key))
|
|
@@ -163,7 +172,11 @@ export class AliasTransport {
|
|
|
163
172
|
...message,
|
|
164
173
|
result: {
|
|
165
174
|
...response.result,
|
|
166
|
-
tools: response.result.tools
|
|
175
|
+
tools: response.result.tools
|
|
176
|
+
.filter((tool) => typeof tool?.name === 'string' && (!visible || visible.has(tool.name)) && (!this.claudeDirectoryProfile || isClaudeDirectoryTool(tool.name)))
|
|
177
|
+
.map((tool) => this.claudeDirectoryProfile ? {
|
|
178
|
+
...tool, description: claudeDirectoryDescription(tool.name), inputSchema: claudeDirectorySchema(tool.inputSchema),
|
|
179
|
+
} : tool),
|
|
167
180
|
},
|
|
168
181
|
};
|
|
169
182
|
return filtered;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const CLAUDE_DIRECTORY_INSTRUCTIONS = "posterly provides social account discovery, existing-media uploads, social post validation and publication, analytics, and inbox management. AI image, video, and audio generation and billing mutations are unavailable in this directory profile. Public and destructive actions use the existing preview and confirmation contract.";
|
|
2
|
+
export declare function isClaudeDirectoryTool(name: string): boolean;
|
|
3
|
+
export declare function claudeDirectoryDescription(name: string): string;
|
|
4
|
+
/** Keep validation constraints but omit prose referring to other tools or model behavior. */
|
|
5
|
+
export declare function claudeDirectorySchema<T>(schema: T): T;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in catalog for the Anthropic Software Directory. Both MCP transports
|
|
3
|
+
* use this explicit allowlist; omitted tools are unavailable, including aliases.
|
|
4
|
+
* REST authorization and preview confirmation still apply to every operation.
|
|
5
|
+
* Policy: https://support.claude.com/en/articles/13145358
|
|
6
|
+
*/
|
|
7
|
+
const descriptions = {
|
|
8
|
+
get_agent_signup_info: 'Return posterly signup requirements and the human signup link.',
|
|
9
|
+
start_signup: 'Create a short-lived signup session with a browser link for human completion. This operation does not take payment.',
|
|
10
|
+
get_signup_session: 'Read the completion status of a signup session.',
|
|
11
|
+
whoami: 'Return connection status or the authenticated user, scopes, and accessible workspaces.',
|
|
12
|
+
create_api_key: 'Create a scoped posterly API key for the authenticated user. The new key cannot exceed the caller key permissions.',
|
|
13
|
+
delete_api_key: 'Revoke an API key owned by the authenticated user. The current authentication key and managed OAuth keys cannot be revoked here.',
|
|
14
|
+
list_workspace_members: 'List workspace members, pending invites, roles, brand access, API access, and occupied seats.',
|
|
15
|
+
manage_workspace_member: 'Invite, update, or remove a workspace colleague using the action selector. Workspace administrator permissions and existing seat limits apply.',
|
|
16
|
+
list_publishing_pauses: 'Read workspace and brand publishing pauses and the caller permissions to manage them.',
|
|
17
|
+
manage_publishing_pause: 'Pause or resume workspace or brand publishing using the action selector. Resume can keep missed posts paused or publish them.',
|
|
18
|
+
list_accounts: 'List connected social accounts, or read account brand profiles, learned voice, performance profiles, and connection-session status using the view selector.',
|
|
19
|
+
disconnect_account: 'Disconnect a social account, removing its connection and affecting its scheduled posts.',
|
|
20
|
+
connect_account: 'Connect a credential-based Telegram, Bluesky, Discord, WordPress, Dev.to, Hashnode, or Lemmy account.',
|
|
21
|
+
create_connect_session: 'Create a short-lived browser handoff session for a human to connect a social account.',
|
|
22
|
+
list_oauth_clients: 'List self-serve OAuth developer clients owned by the authenticated user.',
|
|
23
|
+
manage_oauth_client: 'Create, update, or delete a public OAuth 2.1 developer client using the action selector. Client secrets are not created.',
|
|
24
|
+
list_platforms: 'List supported platforms, read platform or account settings schemas, or return browser connection links using the view selector.',
|
|
25
|
+
trigger_platform_helper: 'Read account-specific platform discovery data: Pinterest boards, TikTok creator information, LinkedIn recent mentions, or X quota.',
|
|
26
|
+
list_brands: 'List accessible brands, read one brand, or list its social accounts using the view selector.',
|
|
27
|
+
list_post_suggestions: 'List suggested social post drafts, their performance rationale, and their scheduling status.',
|
|
28
|
+
dismiss_suggestion: 'Dismiss a pending post suggestion. Suggestions already converted into posts are unchanged.',
|
|
29
|
+
list_posts: 'List social posts accessible to the caller, filtered by account, brand, workspace, platform, status, or approval state.',
|
|
30
|
+
get_post: 'Read one social post and its current content, media, platform settings, and publication status.',
|
|
31
|
+
ask_support: 'Answer a posterly support question with documentation and read-only workspace diagnostics. A continued support conversation can request a human ticket with explicit escalation confirmation.',
|
|
32
|
+
find_available_slot: 'Find available posting times with a one-hour spacing rule, preferred hours, and an explicit timezone.',
|
|
33
|
+
submit_agent_feedback: 'Record private operational feedback about a completed posterly workflow. Content and credentials are not accepted as telemetry.',
|
|
34
|
+
submit_product_feedback: 'Submit a confirmed title, category, and description to the public posterly feedback board.',
|
|
35
|
+
validate_post: 'Validate and normalize proposed post content without saving, uploading, scheduling, or publishing it.',
|
|
36
|
+
create_post: 'Create one scheduled or immediate social post. Omitting scheduled_at requests immediate publication. The operation creates content on the selected connected social account.',
|
|
37
|
+
create_posts_batch: 'Create one to 25 scheduled or immediate social posts. Partial success is possible and failed items retain their input index.',
|
|
38
|
+
update_post: 'Edit a draft or scheduled post, change its status, assign release and group identifiers, or manage client approval using the action selector. Published posts cannot be edited.',
|
|
39
|
+
delete_post: 'Delete one draft or scheduled post, or all eligible posts in a selected group using the action selector. Published posts cannot be deleted.',
|
|
40
|
+
get_x_posting_quota: 'Read managed X posting usage, quota, remaining posts, URL restrictions, and existing add-on information.',
|
|
41
|
+
upload_media: 'Upload an existing image or video to posterly storage from a file, base64 content, or a public HTTPS URL. Returns a reusable media URL and does not publish content.',
|
|
42
|
+
create_signed_upload: 'Create a signed storage upload URL for an existing large image or video.',
|
|
43
|
+
create_media_drop: 'Create a short-lived browser page for a human to upload existing media without a dashboard login.',
|
|
44
|
+
list_media: 'List uploaded media assets or files uploaded to a selected media-drop session.',
|
|
45
|
+
generate_captions: 'Generate or adapt text caption suggestions for social platforms. Uses the caption allowance and does not create or publish posts.',
|
|
46
|
+
list_analytics: 'Read account analytics, post analytics, post feedback insights, or missing-post requirements using the view selector.',
|
|
47
|
+
list_google_business_reviews: 'Read Google Business Profile reviews or the public review link using the view selector.',
|
|
48
|
+
audit_google_business_profile: 'Read and audit a connected Google Business Profile location: completeness, categories, media, attributes, reviews, and recommendations.',
|
|
49
|
+
manage_google_business_review: 'Suggest text replies, publish owner replies, or delete owner replies to Google Business reviews using the action selector. Suggestions do not publish a reply.',
|
|
50
|
+
list_google_business_media: 'Read existing photos and videos in connected Google Business Profile galleries.',
|
|
51
|
+
manage_google_business_media: 'Add an existing photo or video to a Google Business gallery, or delete a gallery item using the action selector.',
|
|
52
|
+
list_conversations: 'List Instagram or Facebook Page inbox conversations, or read one conversation using the view selector. Requires a Pro plan and posts:read.',
|
|
53
|
+
manage_conversation: 'Reply to an Instagram or Facebook Page inbox conversation, or synchronize supported social inbox data using the action selector. Requires a Pro plan and posts:write.',
|
|
54
|
+
list_comments: 'List Instagram, Facebook Page, Threads, or LinkedIn Page comments, or read one comment using the view selector. Requires a Pro plan and posts:read.',
|
|
55
|
+
manage_comment: 'Reply to, hide, unhide, mark, or delete a social inbox comment using the action selector. Platform limitations apply. Requires a Pro plan and posts:write.',
|
|
56
|
+
list_activity: 'Read recent post activity, status changes, publish attempts, failures, and retries.',
|
|
57
|
+
list_webhooks: 'Read webhook subscriptions, event filters, destinations, and recent delivery status.',
|
|
58
|
+
create_webhook: 'Create a webhook subscription for post, account, or analytics events and return its signing secret once.',
|
|
59
|
+
manage_webhook: 'Update or delete a webhook subscription, or send a signed test event using the action selector.',
|
|
60
|
+
get_credits: 'Read the workspace AI credit balance, included allowance, purchased balance, and next reset time. Does not buy or spend credits.',
|
|
61
|
+
get_subscription: 'Read subscription status, tier, current period, trial end, cancellation-at-period-end, and pause state. Does not change billing.',
|
|
62
|
+
get_updates: 'Read recent posterly product updates.',
|
|
63
|
+
};
|
|
64
|
+
export const CLAUDE_DIRECTORY_INSTRUCTIONS = 'posterly provides social account discovery, existing-media uploads, social post validation and publication, analytics, and inbox management. AI image, video, and audio generation and billing mutations are unavailable in this directory profile. Public and destructive actions use the existing preview and confirmation contract.';
|
|
65
|
+
export function isClaudeDirectoryTool(name) {
|
|
66
|
+
return Object.hasOwn(descriptions, name);
|
|
67
|
+
}
|
|
68
|
+
export function claudeDirectoryDescription(name) {
|
|
69
|
+
const description = descriptions[name];
|
|
70
|
+
if (!description)
|
|
71
|
+
throw new Error(`Tool is unavailable in the Claude directory profile: ${name}`);
|
|
72
|
+
return description;
|
|
73
|
+
}
|
|
74
|
+
/** Keep validation constraints but omit prose referring to other tools or model behavior. */
|
|
75
|
+
export function claudeDirectorySchema(schema) {
|
|
76
|
+
const copy = structuredClone(schema);
|
|
77
|
+
function visit(value) {
|
|
78
|
+
if (Array.isArray(value))
|
|
79
|
+
value.forEach(visit);
|
|
80
|
+
else if (value && typeof value === 'object') {
|
|
81
|
+
const object = value;
|
|
82
|
+
if (typeof object.description === 'string')
|
|
83
|
+
delete object.description;
|
|
84
|
+
for (const key of ['properties', 'patternProperties', 'definitions', '$defs', 'dependentSchemas']) {
|
|
85
|
+
const schemas = object[key];
|
|
86
|
+
if (schemas && typeof schemas === 'object' && !Array.isArray(schemas))
|
|
87
|
+
Object.values(schemas).forEach(visit);
|
|
88
|
+
}
|
|
89
|
+
for (const key of ['items', 'additionalProperties', 'additionalItems', 'contains', 'not', 'if', 'then', 'else', 'propertyNames', 'unevaluatedProperties', 'unevaluatedItems', 'allOf', 'oneOf', 'anyOf', 'prefixItems'])
|
|
90
|
+
visit(object[key]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
visit(copy);
|
|
94
|
+
return copy;
|
|
95
|
+
}
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const POSTERLY_MCP_VERSION = "0.50.
|
|
1
|
+
export declare const POSTERLY_MCP_VERSION = "0.50.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.50.
|
|
8
|
+
export const POSTERLY_MCP_VERSION = '0.50.5';
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "posterly-mcp-server",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.5",
|
|
4
4
|
"mcpName": "io.github.awpthorp/posterly",
|
|
5
5
|
"description": "MCP server for posterly: schedule and publish social media posts across 18 platforms from any MCP client (Claude, ChatGPT, Cursor, Windsurf, Cline, and more)",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://www.poster.ly/mcp",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/awpthorp/posterly.git"
|
|
11
|
-
"directory": "mcp-server"
|
|
10
|
+
"url": "git+https://github.com/awpthorp/posterly-mcp-server.git"
|
|
12
11
|
},
|
|
13
12
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/awpthorp/posterly/issues"
|
|
13
|
+
"url": "https://github.com/awpthorp/posterly-mcp-server/issues"
|
|
15
14
|
},
|
|
16
15
|
"keywords": [
|
|
17
16
|
"mcp",
|
|
@@ -28,6 +27,14 @@
|
|
|
28
27
|
"posterly-mcp": "dist/index.js"
|
|
29
28
|
},
|
|
30
29
|
"main": "./dist/index.js",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"tool-registry.json",
|
|
33
|
+
"tool-annotations.json",
|
|
34
|
+
"server.json",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
31
38
|
"scripts": {
|
|
32
39
|
"build": "tsc",
|
|
33
40
|
"dev": "tsc --watch",
|
package/server.json
CHANGED
|
@@ -3,18 +3,17 @@
|
|
|
3
3
|
"name": "io.github.awpthorp/posterly",
|
|
4
4
|
"title": "posterly",
|
|
5
5
|
"description": "Validate, schedule, publish, and analyze social content across 18 platforms with posterly.",
|
|
6
|
-
"version": "0.50.
|
|
6
|
+
"version": "0.50.5",
|
|
7
7
|
"websiteUrl": "https://www.poster.ly/mcp",
|
|
8
8
|
"repository": {
|
|
9
|
-
"url": "https://github.com/awpthorp/posterly",
|
|
10
|
-
"source": "github"
|
|
11
|
-
"subfolder": "mcp-server"
|
|
9
|
+
"url": "https://github.com/awpthorp/posterly-mcp-server",
|
|
10
|
+
"source": "github"
|
|
12
11
|
},
|
|
13
12
|
"packages": [
|
|
14
13
|
{
|
|
15
14
|
"registryType": "npm",
|
|
16
15
|
"identifier": "posterly-mcp-server",
|
|
17
|
-
"version": "0.50.
|
|
16
|
+
"version": "0.50.5",
|
|
18
17
|
"transport": {
|
|
19
18
|
"type": "stdio"
|
|
20
19
|
},
|
package/RELEASING.md
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# Releasing the MCP surfaces
|
|
2
|
-
|
|
3
|
-
posterly has two MCP surfaces sharing one version namespace:
|
|
4
|
-
|
|
5
|
-
| Surface | Where it lives | How it reaches users |
|
|
6
|
-
| --- | --- | --- |
|
|
7
|
-
| Hosted HTTP | `lib/mcp/` → `POST /api/mcp` | **Automatically**, with the Vercel deploy of `main` |
|
|
8
|
-
| npm stdio | `mcp-server/src/` → `posterly-mcp-server` | **Only when someone runs `npm publish`** |
|
|
9
|
-
|
|
10
|
-
That asymmetry is the whole reason this file exists.
|
|
11
|
-
|
|
12
|
-
## The failure this prevents
|
|
13
|
-
|
|
14
|
-
The docs tell users to install with `npx -y posterly-mcp-server@latest`, so most
|
|
15
|
-
MCP traffic is the npm package. The package is a thin client over `/api/v1/*`,
|
|
16
|
-
which makes it tempting to assume a server-side fix reaches everyone. It does
|
|
17
|
-
not. **The npm package does its own output formatting**, so anything the client
|
|
18
|
-
renders itself stays broken until a publish:
|
|
19
|
-
|
|
20
|
-
- tool output formatting (truncation, row caps, what columns are shown)
|
|
21
|
-
- input schemas (new parameters like `limit` / `offset`)
|
|
22
|
-
- tool descriptions and names
|
|
23
|
-
|
|
24
|
-
This is not hypothetical. In Aug 2026 the Google Business review truncation was
|
|
25
|
-
fixed server-side and merged. Hosted users got the fix on deploy. npm users kept
|
|
26
|
-
seeing reviews clipped to ~180 characters, capped at 25 rows, with no dates —
|
|
27
|
-
because that formatting lives in `mcp-server/src/tools/`. Only a publish fixed it.
|
|
28
|
-
|
|
29
|
-
## Release order
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
change an MCP surface -> bump the version -> merge -> deploy -> npm publish
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Bumping and publishing are separate steps with different failure modes:
|
|
36
|
-
|
|
37
|
-
- **Skipping the bump is unrecoverable.** npm versions are immutable. Tool
|
|
38
|
-
changes merged under a version already on npm can never be delivered under
|
|
39
|
-
that version. `npm run check:mcp-version-bump` fails the build to prevent it.
|
|
40
|
-
- **Skipping the publish is recoverable** — just publish. `npm run
|
|
41
|
-
check:mcp-published` tells you when one is outstanding.
|
|
42
|
-
|
|
43
|
-
## 1. Bump the version
|
|
44
|
-
|
|
45
|
-
The version appears in six places and `npm run check:mcp-parity` enforces that
|
|
46
|
-
they all agree:
|
|
47
|
-
|
|
48
|
-
- `lib/mcp/version.ts` — hosted endpoint
|
|
49
|
-
- `mcp-server/src/lib/version.ts` — stdio package
|
|
50
|
-
- `mcp-server/package.json`
|
|
51
|
-
- `mcp-server/package-lock.json` (two entries)
|
|
52
|
-
- `mcp-server/server.json` (two entries)
|
|
53
|
-
- `mcp-server/README.md` — the `posterly-mcp-server@X.Y.Z exposes N tools` line
|
|
54
|
-
|
|
55
|
-
Then rebuild so the compiled output matches, since the parity check reads
|
|
56
|
-
`mcp-server/dist/lib/version.js` too:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
npm --prefix mcp-server run build
|
|
60
|
-
npm run check:mcp-parity
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Use a patch bump for tool fixes and additive schema changes; a minor bump for
|
|
64
|
-
new tools or a changed tool surface.
|
|
65
|
-
|
|
66
|
-
## 2. Merge and deploy
|
|
67
|
-
|
|
68
|
-
Land the PR and let `main` deploy. The hosted endpoint is live at this point;
|
|
69
|
-
npm users are not.
|
|
70
|
-
|
|
71
|
-
## 3. Publish
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
cd mcp-server
|
|
75
|
-
npm whoami # must be an account that can publish posterly-mcp-server
|
|
76
|
-
npm publish # add --otp=<code> if 2FA prompts
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
`prepack` rebuilds `dist/` and re-runs the parity check before packing, so a
|
|
80
|
-
stale build or a drifted version cannot ship. `dist/` is gitignored but is
|
|
81
|
-
included in the tarball — `prepack` is what puts it there.
|
|
82
|
-
|
|
83
|
-
Sanity-check the tarball first if you want:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
npm pack --dry-run
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## 4. Verify
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
npm view posterly-mcp-server version dist-tags
|
|
93
|
-
npm run check:mcp-published
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Both should report the version you just published. Users on `@latest` pick it
|
|
97
|
-
up on their next client restart; there is nothing for them to do.
|
|
98
|
-
|
|
99
|
-
## If you published something broken
|
|
100
|
-
|
|
101
|
-
Do not `npm unpublish` and do not republish the same number — npm versions are
|
|
102
|
-
immutable and unpublishing breaks anyone who already resolved it. Cut the next
|
|
103
|
-
patch version and publish that.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
## Publishing from GitHub (trusted publishing)
|
|
107
|
-
|
|
108
|
-
npm now requires 2FA or a trusted publisher to publish. The repo has a manual
|
|
109
|
-
workflow, `.github/workflows/publish-mcp.yml` ("Publish MCP"), that publishes
|
|
110
|
-
`mcp-server/` with GitHub OIDC, so no npm token or one-time code is needed.
|
|
111
|
-
One-time setup on npmjs.com: package `posterly-mcp-server` > Settings >
|
|
112
|
-
Trusted Publisher > GitHub Actions, owner `awpthorp`, repository `posterly`,
|
|
113
|
-
workflow `publish-mcp.yml`. After an MCP change merges and deploys, run it from
|
|
114
|
-
the Actions tab (or `gh workflow run publish-mcp.yml`), then
|
|
115
|
-
`npm run check:mcp-published`. It skips if the version is already on npm.
|
package/SUBMISSIONS.md
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# MCP connector submissions
|
|
2
|
-
|
|
3
|
-
Notes for listing the hosted MCP server as a one-click connector. The pipework
|
|
4
|
-
(hosted HTTP MCP + stdio MCP) already works with API keys. Dynamic Client
|
|
5
|
-
Registration and refresh-token rotation are what Claude.ai / ChatGPT-style hosts
|
|
6
|
-
need for a connect flow without a human-allowlisted `client_id`.
|
|
7
|
-
|
|
8
|
-
Do not publish these notes as user-facing marketing copy. They are for the
|
|
9
|
-
person who applies the production migration and files the directory forms.
|
|
10
|
-
|
|
11
|
-
## Preconditions
|
|
12
|
-
|
|
13
|
-
1. Apply the DCR / refresh-token migration
|
|
14
|
-
(`supabase/migrations/20260906140000_oauth_dynamic_registration_and_refresh.sql`)
|
|
15
|
-
**before or with** the production deploy, not after. Shipping the app first
|
|
16
|
-
leaves `oauth_refresh_tokens` missing: the token endpoint then falls back to
|
|
17
|
-
a 365-day access-only grant for dynamic clients, and DCR verification that
|
|
18
|
-
expects refresh tokens will fail. Do not apply the SQL from an agent session
|
|
19
|
-
that can write straight to prod.
|
|
20
|
-
2. Confirm `NEXT_PUBLIC_SITE_URL` is `https://www.poster.ly` in the production
|
|
21
|
-
deploy so discovery documents advertise the right issuer.
|
|
22
|
-
3. Create a reviewer test account with the API add-on enabled, plus a short
|
|
23
|
-
setup note they can follow.
|
|
24
|
-
4. Confirm discovery before submitting:
|
|
25
|
-
- `GET /.well-known/oauth-authorization-server` includes
|
|
26
|
-
`registration_endpoint` and `refresh_token` in `grant_types_supported`
|
|
27
|
-
- `POST /api/oauth/register` returns `201` with a `dyn_` `client_id`
|
|
28
|
-
- consent shows the self-registered warning, callback host, and `client_id`
|
|
29
|
-
for that client
|
|
30
|
-
- refresh-token reuse within 30 seconds returns `invalid_grant` without
|
|
31
|
-
revoking the chain; reuse older than 30 seconds revokes the chain
|
|
32
|
-
- `/api/mcp` returns `403` `origin_not_allowed` for an untrusted Origin
|
|
33
|
-
- `tools/list` includes annotations on every tool
|
|
34
|
-
|
|
35
|
-
## Anthropic Connectors Directory
|
|
36
|
-
|
|
37
|
-
This is the remote MCP connector listing (Claude.ai / Claude desktop
|
|
38
|
-
connectors). It is distinct from the Claude Code plugin already pending review.
|
|
39
|
-
|
|
40
|
-
Submit the remote MCP server at
|
|
41
|
-
https://claude.ai/admin-settings/directory/submissions/new or
|
|
42
|
-
https://clau.de/mcp-directory-submission.
|
|
43
|
-
|
|
44
|
-
Fallback contact: mcp-review@anthropic.com.
|
|
45
|
-
|
|
46
|
-
Use:
|
|
47
|
-
|
|
48
|
-
- Server URL: `https://www.poster.ly/api/mcp`
|
|
49
|
-
- Server card: `https://www.poster.ly/.well-known/mcp/server-card.json`
|
|
50
|
-
- Docs: `https://www.poster.ly/mcp` and `https://www.poster.ly/agents`
|
|
51
|
-
(public pages only; do not submit auth-gated `https://www.poster.ly/docs/...`
|
|
52
|
-
URLs)
|
|
53
|
-
- Auth: OAuth 2.1 + PKCE, RFC 7591 Dynamic Client Registration, rotating
|
|
54
|
-
refresh tokens (1-hour access, 30-day refresh for DCR clients)
|
|
55
|
-
- Platforms: all 18 production platforms
|
|
56
|
-
|
|
57
|
-
Connectors Connect (the in-product connect form) uses a Client ID Metadata
|
|
58
|
-
Document, not DCR, for this flow:
|
|
59
|
-
|
|
60
|
-
- `client_id`: `https://claude.ai/oauth/mcp-oauth-client-metadata`
|
|
61
|
-
- `redirect_uri`: `https://claude.ai/api/mcp/auth_callback`
|
|
62
|
-
|
|
63
|
-
DCR at `POST /api/oauth/register` remains available for other hosts. It is
|
|
64
|
-
not what Claude Connectors uses for Connect.
|
|
65
|
-
|
|
66
|
-
Do not claim Autopilot ships. Do not claim the connector is already listed.
|
|
67
|
-
|
|
68
|
-
Optional after deploy: bump and publish `posterly-mcp-server` if you want the
|
|
69
|
-
stdio README changes on npm. Hosted `/api/mcp` picks up this repo deploy
|
|
70
|
-
without an npm publish.
|
|
71
|
-
|
|
72
|
-
## ChatGPT / OpenAI Plugins Directory
|
|
73
|
-
|
|
74
|
-
This is a different form from the Claude plugin directory (already submitted)
|
|
75
|
-
and from the Anthropic Connectors Directory above. File it after the OAuth DCR
|
|
76
|
-
deploy is live. An agent cannot submit the form: Alex must complete OpenAI org
|
|
77
|
-
verification / Apps Management write access.
|
|
78
|
-
|
|
79
|
-
Portal: https://platform.openai.com/plugins
|
|
80
|
-
|
|
81
|
-
Use:
|
|
82
|
-
|
|
83
|
-
- MCP URL: `https://www.poster.ly/api/mcp`
|
|
84
|
-
- Auth: OAuth 2.1 + PKCE + DCR at `POST /api/oauth/register` (now live on prod)
|
|
85
|
-
- Domain verification: set `OPENAI_APPS_CHALLENGE_TOKEN` in Vercel to the
|
|
86
|
-
portal token, deploy, then Scan Tools. OpenAI fetches
|
|
87
|
-
`https://www.poster.ly/.well-known/openai-apps-challenge` and expects the
|
|
88
|
-
exact token as `text/plain` (no JSON).
|
|
89
|
-
- Homepage: `https://www.poster.ly/agents`
|
|
90
|
-
- Privacy: `https://www.poster.ly/privacy`
|
|
91
|
-
- Terms: `https://www.poster.ly/terms`
|
|
92
|
-
- Support: `https://www.poster.ly/dashboard/support` (or `/agents`)
|
|
93
|
-
|
|
94
|
-
Do not claim the plugin is listed until OpenAI publishes it.
|
|
95
|
-
|
|
96
|
-
## Other hosted hosts
|
|
97
|
-
|
|
98
|
-
ChatGPT-style hosts follow the same DCR + authorize + token flow. HTTPS
|
|
99
|
-
callbacks such as `https://chatgpt.com/oauth/callback` are already accepted by
|
|
100
|
-
the redirect URI validator. Extra browser origins can be added with
|
|
101
|
-
`MCP_TRUSTED_ORIGINS` (comma-separated hostnames or full URLs).
|
|
102
|
-
|
|
103
|
-
The ChatGPT plugin / app directory form is covered in the section above.
|
|
104
|
-
|
|
105
|
-
## Registry metadata
|
|
106
|
-
|
|
107
|
-
`server.json` is the official MCP Registry metadata for the stdio package
|
|
108
|
-
(`io.github.awpthorp/posterly`). Publishing that package is a separate release
|
|
109
|
-
step. See `RELEASING.md`.
|