posterly-mcp-server 0.2.1 → 0.2.2
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/dist/index.js +31 -1
- package/dist/lib/api-client.d.ts +17 -0
- package/dist/lib/api-client.js +9 -0
- package/dist/tools/delete-post.d.ts +16 -0
- package/dist/tools/delete-post.js +12 -0
- package/dist/tools/get-post.d.ts +16 -0
- package/dist/tools/get-post.js +26 -0
- package/dist/tools/update-post.d.ts +36 -0
- package/dist/tools/update-post.js +28 -0
- package/package.json +1 -1
- package/src/index.ts +46 -1
- package/src/lib/api-client.ts +22 -0
- package/src/tools/delete-post.ts +19 -0
- package/src/tools/get-post.ts +33 -0
- package/src/tools/update-post.ts +44 -0
package/dist/index.js
CHANGED
|
@@ -7,9 +7,12 @@ import { createPostTool } from './tools/create-post.js';
|
|
|
7
7
|
import { findSlotTool } from './tools/find-slot.js';
|
|
8
8
|
import { listPostsTool } from './tools/list-posts.js';
|
|
9
9
|
import { uploadMediaTool } from './tools/upload-media.js';
|
|
10
|
+
import { getPostTool } from './tools/get-post.js';
|
|
11
|
+
import { updatePostTool } from './tools/update-post.js';
|
|
12
|
+
import { deletePostTool } from './tools/delete-post.js';
|
|
10
13
|
const server = new McpServer({
|
|
11
14
|
name: 'posterly',
|
|
12
|
-
version: '0.
|
|
15
|
+
version: '0.2.2',
|
|
13
16
|
});
|
|
14
17
|
let client;
|
|
15
18
|
try {
|
|
@@ -65,6 +68,33 @@ server.tool(uploadMediaTool.name, uploadMediaTool.description, uploadMediaTool.i
|
|
|
65
68
|
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
66
69
|
}
|
|
67
70
|
});
|
|
71
|
+
server.tool(getPostTool.name, getPostTool.description, getPostTool.inputSchema.shape, async (input) => {
|
|
72
|
+
try {
|
|
73
|
+
const text = await getPostTool.execute(client, input);
|
|
74
|
+
return { content: [{ type: 'text', text }] };
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
server.tool(updatePostTool.name, updatePostTool.description, updatePostTool.inputSchema.shape, async (input) => {
|
|
81
|
+
try {
|
|
82
|
+
const text = await updatePostTool.execute(client, input);
|
|
83
|
+
return { content: [{ type: 'text', text }] };
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
server.tool(deletePostTool.name, deletePostTool.description, deletePostTool.inputSchema.shape, async (input) => {
|
|
90
|
+
try {
|
|
91
|
+
const text = await deletePostTool.execute(client, input);
|
|
92
|
+
return { content: [{ type: 'text', text }] };
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
96
|
+
}
|
|
97
|
+
});
|
|
68
98
|
// Start the server
|
|
69
99
|
async function main() {
|
|
70
100
|
const transport = new StdioServerTransport();
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -49,6 +49,23 @@ export declare class PosterlyClient {
|
|
|
49
49
|
}): Promise<{
|
|
50
50
|
post: Post;
|
|
51
51
|
}>;
|
|
52
|
+
getPost(id: number): Promise<{
|
|
53
|
+
post: Post;
|
|
54
|
+
}>;
|
|
55
|
+
updatePost(id: number, data: {
|
|
56
|
+
caption?: string;
|
|
57
|
+
scheduled_at?: string;
|
|
58
|
+
media_url?: string;
|
|
59
|
+
media_urls?: string[];
|
|
60
|
+
post_type?: string;
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
post: Post;
|
|
64
|
+
}>;
|
|
65
|
+
deletePost(id: number): Promise<{
|
|
66
|
+
deleted: boolean;
|
|
67
|
+
id: number;
|
|
68
|
+
}>;
|
|
52
69
|
findAvailableSlots(params?: {
|
|
53
70
|
account_ids?: string[];
|
|
54
71
|
timezone?: string;
|
package/dist/lib/api-client.js
CHANGED
|
@@ -50,6 +50,15 @@ export class PosterlyClient {
|
|
|
50
50
|
async createPost(data) {
|
|
51
51
|
return this.request('POST', '/posts', data);
|
|
52
52
|
}
|
|
53
|
+
async getPost(id) {
|
|
54
|
+
return this.request('GET', `/posts/${id}`);
|
|
55
|
+
}
|
|
56
|
+
async updatePost(id, data) {
|
|
57
|
+
return this.request('PATCH', `/posts/${id}`, data);
|
|
58
|
+
}
|
|
59
|
+
async deletePost(id) {
|
|
60
|
+
return this.request('DELETE', `/posts/${id}`);
|
|
61
|
+
}
|
|
53
62
|
async findAvailableSlots(params) {
|
|
54
63
|
const searchParams = new URLSearchParams();
|
|
55
64
|
if (params?.account_ids?.length)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
export declare const deletePostTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{
|
|
7
|
+
post_id: z.ZodNumber;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
post_id: number;
|
|
10
|
+
}, {
|
|
11
|
+
post_id: number;
|
|
12
|
+
}>;
|
|
13
|
+
execute(client: PosterlyClient, input: {
|
|
14
|
+
post_id: number;
|
|
15
|
+
}): Promise<string>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const deletePostTool = {
|
|
3
|
+
name: 'delete_post',
|
|
4
|
+
description: 'Delete a scheduled or draft post. Cannot delete published or currently publishing posts.',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
post_id: z.number().describe('The post ID to delete'),
|
|
7
|
+
}),
|
|
8
|
+
async execute(client, input) {
|
|
9
|
+
const result = await client.deletePost(input.post_id);
|
|
10
|
+
return `Post #${result.id} deleted successfully.`;
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
export declare const getPostTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{
|
|
7
|
+
post_id: z.ZodNumber;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
post_id: number;
|
|
10
|
+
}, {
|
|
11
|
+
post_id: number;
|
|
12
|
+
}>;
|
|
13
|
+
execute(client: PosterlyClient, input: {
|
|
14
|
+
post_id: number;
|
|
15
|
+
}): Promise<string>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const getPostTool = {
|
|
3
|
+
name: 'get_post',
|
|
4
|
+
description: 'Get details of a specific post by ID. Returns caption, status, scheduled time, media, and platform info.',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
post_id: z.number().describe('The post ID to look up'),
|
|
7
|
+
}),
|
|
8
|
+
async execute(client, input) {
|
|
9
|
+
const result = await client.getPost(input.post_id);
|
|
10
|
+
const p = result.post;
|
|
11
|
+
const lines = [
|
|
12
|
+
`Post #${p.id}`,
|
|
13
|
+
`• Status: ${p.status}`,
|
|
14
|
+
`• Caption: ${p.content || '(empty)'}`,
|
|
15
|
+
`• Type: ${p.post_type || 'unknown'}`,
|
|
16
|
+
`• Scheduled: ${p.scheduled_at ? new Date(p.scheduled_at).toLocaleString() : 'N/A'}`,
|
|
17
|
+
];
|
|
18
|
+
if (p.platform_post_url)
|
|
19
|
+
lines.push(`• Published URL: ${p.platform_post_url}`);
|
|
20
|
+
if (p.media_url)
|
|
21
|
+
lines.push(`• Media: ${p.media_url}`);
|
|
22
|
+
if (p.media_urls?.length)
|
|
23
|
+
lines.push(`• Media (${p.media_urls.length}): ${p.media_urls.join(', ')}`);
|
|
24
|
+
return lines.join('\n');
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
export declare const updatePostTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{
|
|
7
|
+
post_id: z.ZodNumber;
|
|
8
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
9
|
+
scheduled_at: z.ZodOptional<z.ZodString>;
|
|
10
|
+
media_url: z.ZodOptional<z.ZodString>;
|
|
11
|
+
media_urls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
12
|
+
post_type: z.ZodOptional<z.ZodString>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
post_id: number;
|
|
15
|
+
caption?: string | undefined;
|
|
16
|
+
scheduled_at?: string | undefined;
|
|
17
|
+
media_url?: string | undefined;
|
|
18
|
+
media_urls?: string[] | undefined;
|
|
19
|
+
post_type?: string | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
post_id: number;
|
|
22
|
+
caption?: string | undefined;
|
|
23
|
+
scheduled_at?: string | undefined;
|
|
24
|
+
media_url?: string | undefined;
|
|
25
|
+
media_urls?: string[] | undefined;
|
|
26
|
+
post_type?: string | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
execute(client: PosterlyClient, input: {
|
|
29
|
+
post_id: number;
|
|
30
|
+
caption?: string;
|
|
31
|
+
scheduled_at?: string;
|
|
32
|
+
media_url?: string;
|
|
33
|
+
media_urls?: string[];
|
|
34
|
+
post_type?: string;
|
|
35
|
+
}): Promise<string>;
|
|
36
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const updatePostTool = {
|
|
3
|
+
name: 'update_post',
|
|
4
|
+
description: 'Update a scheduled or draft post. Can change caption, scheduled time, media, or post type. Cannot edit published or currently publishing posts.',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
post_id: z.number().describe('The post ID to update'),
|
|
7
|
+
caption: z.string().optional().describe('New caption/text content'),
|
|
8
|
+
scheduled_at: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('New scheduled time (ISO 8601, e.g. 2026-03-10T09:00:00Z)'),
|
|
12
|
+
media_url: z.string().optional().describe('New media URL'),
|
|
13
|
+
media_urls: z.array(z.string()).optional().describe('New media URLs for carousel'),
|
|
14
|
+
post_type: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('New post type: text, image, video, carousel, reel, story'),
|
|
18
|
+
}),
|
|
19
|
+
async execute(client, input) {
|
|
20
|
+
const { post_id, ...updates } = input;
|
|
21
|
+
const result = await client.updatePost(post_id, updates);
|
|
22
|
+
const p = result.post;
|
|
23
|
+
const when = p.scheduled_at
|
|
24
|
+
? new Date(p.scheduled_at).toLocaleString()
|
|
25
|
+
: 'N/A';
|
|
26
|
+
return `Post #${p.id} updated successfully!\n• Status: ${p.status}\n• Caption: ${p.content || '(empty)'}\n• Scheduled: ${when}`;
|
|
27
|
+
},
|
|
28
|
+
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,10 +8,13 @@ import { createPostTool } from './tools/create-post.js';
|
|
|
8
8
|
import { findSlotTool } from './tools/find-slot.js';
|
|
9
9
|
import { listPostsTool } from './tools/list-posts.js';
|
|
10
10
|
import { uploadMediaTool } from './tools/upload-media.js';
|
|
11
|
+
import { getPostTool } from './tools/get-post.js';
|
|
12
|
+
import { updatePostTool } from './tools/update-post.js';
|
|
13
|
+
import { deletePostTool } from './tools/delete-post.js';
|
|
11
14
|
|
|
12
15
|
const server = new McpServer({
|
|
13
16
|
name: 'posterly',
|
|
14
|
-
version: '0.
|
|
17
|
+
version: '0.2.2',
|
|
15
18
|
});
|
|
16
19
|
|
|
17
20
|
let client: PosterlyClient;
|
|
@@ -94,6 +97,48 @@ server.tool(
|
|
|
94
97
|
}
|
|
95
98
|
);
|
|
96
99
|
|
|
100
|
+
server.tool(
|
|
101
|
+
getPostTool.name,
|
|
102
|
+
getPostTool.description,
|
|
103
|
+
getPostTool.inputSchema.shape,
|
|
104
|
+
async (input) => {
|
|
105
|
+
try {
|
|
106
|
+
const text = await getPostTool.execute(client, input as any);
|
|
107
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
108
|
+
} catch (err: any) {
|
|
109
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
server.tool(
|
|
115
|
+
updatePostTool.name,
|
|
116
|
+
updatePostTool.description,
|
|
117
|
+
updatePostTool.inputSchema.shape,
|
|
118
|
+
async (input) => {
|
|
119
|
+
try {
|
|
120
|
+
const text = await updatePostTool.execute(client, input as any);
|
|
121
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
122
|
+
} catch (err: any) {
|
|
123
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
server.tool(
|
|
129
|
+
deletePostTool.name,
|
|
130
|
+
deletePostTool.description,
|
|
131
|
+
deletePostTool.inputSchema.shape,
|
|
132
|
+
async (input) => {
|
|
133
|
+
try {
|
|
134
|
+
const text = await deletePostTool.execute(client, input as any);
|
|
135
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
136
|
+
} catch (err: any) {
|
|
137
|
+
return { content: [{ type: 'text' as const, text: `Error: ${err.message}` }], isError: true };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
|
|
97
142
|
// Start the server
|
|
98
143
|
async function main() {
|
|
99
144
|
const transport = new StdioServerTransport();
|
package/src/lib/api-client.ts
CHANGED
|
@@ -104,6 +104,28 @@ export class PosterlyClient {
|
|
|
104
104
|
return this.request('POST', '/posts', data);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
async getPost(id: number): Promise<{ post: Post }> {
|
|
108
|
+
return this.request('GET', `/posts/${id}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async updatePost(
|
|
112
|
+
id: number,
|
|
113
|
+
data: {
|
|
114
|
+
caption?: string;
|
|
115
|
+
scheduled_at?: string;
|
|
116
|
+
media_url?: string;
|
|
117
|
+
media_urls?: string[];
|
|
118
|
+
post_type?: string;
|
|
119
|
+
metadata?: Record<string, unknown>;
|
|
120
|
+
},
|
|
121
|
+
): Promise<{ post: Post }> {
|
|
122
|
+
return this.request('PATCH', `/posts/${id}`, data);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async deletePost(id: number): Promise<{ deleted: boolean; id: number }> {
|
|
126
|
+
return this.request('DELETE', `/posts/${id}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
107
129
|
async findAvailableSlots(params?: {
|
|
108
130
|
account_ids?: string[];
|
|
109
131
|
timezone?: string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
|
|
4
|
+
export const deletePostTool = {
|
|
5
|
+
name: 'delete_post',
|
|
6
|
+
description:
|
|
7
|
+
'Delete a scheduled or draft post. Cannot delete published or currently publishing posts.',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
post_id: z.number().describe('The post ID to delete'),
|
|
10
|
+
}),
|
|
11
|
+
|
|
12
|
+
async execute(
|
|
13
|
+
client: PosterlyClient,
|
|
14
|
+
input: { post_id: number },
|
|
15
|
+
) {
|
|
16
|
+
const result = await client.deletePost(input.post_id);
|
|
17
|
+
return `Post #${result.id} deleted successfully.`;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
|
|
4
|
+
export const getPostTool = {
|
|
5
|
+
name: 'get_post',
|
|
6
|
+
description:
|
|
7
|
+
'Get details of a specific post by ID. Returns caption, status, scheduled time, media, and platform info.',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
post_id: z.number().describe('The post ID to look up'),
|
|
10
|
+
}),
|
|
11
|
+
|
|
12
|
+
async execute(
|
|
13
|
+
client: PosterlyClient,
|
|
14
|
+
input: { post_id: number },
|
|
15
|
+
) {
|
|
16
|
+
const result = await client.getPost(input.post_id);
|
|
17
|
+
const p = result.post as Record<string, any>;
|
|
18
|
+
|
|
19
|
+
const lines = [
|
|
20
|
+
`Post #${p.id}`,
|
|
21
|
+
`• Status: ${p.status}`,
|
|
22
|
+
`• Caption: ${p.content || '(empty)'}`,
|
|
23
|
+
`• Type: ${p.post_type || 'unknown'}`,
|
|
24
|
+
`• Scheduled: ${p.scheduled_at ? new Date(p.scheduled_at).toLocaleString() : 'N/A'}`,
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
if (p.platform_post_url) lines.push(`• Published URL: ${p.platform_post_url}`);
|
|
28
|
+
if (p.media_url) lines.push(`• Media: ${p.media_url}`);
|
|
29
|
+
if (p.media_urls?.length) lines.push(`• Media (${p.media_urls.length}): ${p.media_urls.join(', ')}`);
|
|
30
|
+
|
|
31
|
+
return lines.join('\n');
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
|
|
4
|
+
export const updatePostTool = {
|
|
5
|
+
name: 'update_post',
|
|
6
|
+
description:
|
|
7
|
+
'Update a scheduled or draft post. Can change caption, scheduled time, media, or post type. Cannot edit published or currently publishing posts.',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
post_id: z.number().describe('The post ID to update'),
|
|
10
|
+
caption: z.string().optional().describe('New caption/text content'),
|
|
11
|
+
scheduled_at: z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('New scheduled time (ISO 8601, e.g. 2026-03-10T09:00:00Z)'),
|
|
15
|
+
media_url: z.string().optional().describe('New media URL'),
|
|
16
|
+
media_urls: z.array(z.string()).optional().describe('New media URLs for carousel'),
|
|
17
|
+
post_type: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('New post type: text, image, video, carousel, reel, story'),
|
|
21
|
+
}),
|
|
22
|
+
|
|
23
|
+
async execute(
|
|
24
|
+
client: PosterlyClient,
|
|
25
|
+
input: {
|
|
26
|
+
post_id: number;
|
|
27
|
+
caption?: string;
|
|
28
|
+
scheduled_at?: string;
|
|
29
|
+
media_url?: string;
|
|
30
|
+
media_urls?: string[];
|
|
31
|
+
post_type?: string;
|
|
32
|
+
},
|
|
33
|
+
) {
|
|
34
|
+
const { post_id, ...updates } = input;
|
|
35
|
+
const result = await client.updatePost(post_id, updates);
|
|
36
|
+
const p = result.post as Record<string, any>;
|
|
37
|
+
|
|
38
|
+
const when = p.scheduled_at
|
|
39
|
+
? new Date(p.scheduled_at).toLocaleString()
|
|
40
|
+
: 'N/A';
|
|
41
|
+
|
|
42
|
+
return `Post #${p.id} updated successfully!\n• Status: ${p.status}\n• Caption: ${p.content || '(empty)'}\n• Scheduled: ${when}`;
|
|
43
|
+
},
|
|
44
|
+
};
|