posterly-mcp-server 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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.8` exposes 59 tools.
111
+ `posterly-mcp-server@0.23.0` exposes 62 tools.
112
112
 
113
113
  Public setup tools work before `POSTERLY_API_KEY` exists:
114
114
 
@@ -167,6 +167,9 @@ Authenticated tools require `POSTERLY_API_KEY`:
167
167
  - `suggest_google_business_review_reply`
168
168
  - `reply_google_business_review` (post/update a public GBP review reply after explicit confirmation)
169
169
  - `delete_google_business_review_reply` (delete a GBP review reply after explicit confirmation)
170
+ - `list_google_business_media` (list the photos/videos on a GBP profile gallery)
171
+ - `add_google_business_media` (add a photo/video to a GBP profile gallery from a public URL, after explicit confirmation)
172
+ - `delete_google_business_media` (remove a photo/video from a GBP profile gallery after explicit confirmation)
170
173
  - `list_activity`
171
174
  - `list_webhooks`
172
175
  - `create_webhook` (create a webhook after explicit confirmation)
package/dist/index.js CHANGED
@@ -41,6 +41,9 @@ import { auditGoogleBusinessProfileTool } from './tools/audit-google-business-pr
41
41
  import { suggestGoogleBusinessReviewReplyTool } from './tools/suggest-google-business-review-reply.js';
42
42
  import { replyGoogleBusinessReviewTool } from './tools/reply-google-business-review.js';
43
43
  import { deleteGoogleBusinessReviewReplyTool } from './tools/delete-google-business-review-reply.js';
44
+ import { listGoogleBusinessMediaTool } from './tools/list-google-business-media.js';
45
+ import { addGoogleBusinessMediaTool } from './tools/add-google-business-media.js';
46
+ import { deleteGoogleBusinessMediaTool } from './tools/delete-google-business-media.js';
44
47
  import { listActivityTool } from './tools/list-activity.js';
45
48
  import { listWebhooksTool } from './tools/list-webhooks.js';
46
49
  import { createWebhookTool } from './tools/create-webhook.js';
@@ -536,6 +539,33 @@ server.tool(deleteGoogleBusinessReviewReplyTool.name, deleteGoogleBusinessReview
536
539
  return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
537
540
  }
538
541
  });
542
+ server.tool(listGoogleBusinessMediaTool.name, listGoogleBusinessMediaTool.description, listGoogleBusinessMediaTool.inputSchema.shape, async (input) => {
543
+ try {
544
+ const text = await listGoogleBusinessMediaTool.execute(client, input);
545
+ return { content: [{ type: 'text', text }] };
546
+ }
547
+ catch (err) {
548
+ return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
549
+ }
550
+ });
551
+ server.tool(addGoogleBusinessMediaTool.name, addGoogleBusinessMediaTool.description, addGoogleBusinessMediaTool.inputSchema.shape, async (input) => {
552
+ try {
553
+ const text = await addGoogleBusinessMediaTool.execute(client, input);
554
+ return { content: [{ type: 'text', text }] };
555
+ }
556
+ catch (err) {
557
+ return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
558
+ }
559
+ });
560
+ server.tool(deleteGoogleBusinessMediaTool.name, deleteGoogleBusinessMediaTool.description, deleteGoogleBusinessMediaTool.inputSchema.shape, async (input) => {
561
+ try {
562
+ const text = await deleteGoogleBusinessMediaTool.execute(client, input);
563
+ return { content: [{ type: 'text', text }] };
564
+ }
565
+ catch (err) {
566
+ return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
567
+ }
568
+ });
539
569
  server.tool(listActivityTool.name, listActivityTool.description, listActivityTool.inputSchema.shape, async (input) => {
540
570
  try {
541
571
  const text = await listActivityTool.execute(client, input);
@@ -372,6 +372,28 @@ export interface GoogleBusinessReviewsResponse {
372
372
  total: number;
373
373
  locations: Array<Record<string, unknown>>;
374
374
  }
375
+ export interface GoogleBusinessMediaItem {
376
+ name: string;
377
+ mediaFormat: 'PHOTO' | 'VIDEO' | 'MEDIA_FORMAT_UNSPECIFIED';
378
+ category: string | null;
379
+ googleUrl: string | null;
380
+ thumbnailUrl: string | null;
381
+ createTime: string | null;
382
+ widthPixels: number | null;
383
+ heightPixels: number | null;
384
+ attribution: {
385
+ profileName?: string;
386
+ profilePhotoUrl?: string;
387
+ profileUrl?: string;
388
+ } | null;
389
+ account_id?: number;
390
+ location_id?: string | null;
391
+ }
392
+ export interface GoogleBusinessMediaResponse {
393
+ media: GoogleBusinessMediaItem[];
394
+ total: number;
395
+ locations: Array<Record<string, unknown>>;
396
+ }
375
397
  export interface GoogleBusinessReviewLinkResponse {
376
398
  reviewLink: string;
377
399
  placeId: string;
@@ -820,6 +842,25 @@ export declare class PosterlyClient {
820
842
  location_id?: string;
821
843
  review_name: string;
822
844
  }): Promise<Record<string, any>>;
845
+ listGoogleBusinessMedia(params?: {
846
+ workspace_id?: string;
847
+ account_id?: number;
848
+ location_id?: string;
849
+ }): Promise<GoogleBusinessMediaResponse>;
850
+ addGoogleBusinessMedia(data: {
851
+ workspace_id?: string;
852
+ account_id?: number;
853
+ location_id?: string;
854
+ source_url: string;
855
+ category: string;
856
+ media_format?: 'PHOTO' | 'VIDEO';
857
+ }): Promise<Record<string, any>>;
858
+ deleteGoogleBusinessMedia(data: {
859
+ workspace_id?: string;
860
+ account_id?: number;
861
+ location_id?: string;
862
+ media_name: string;
863
+ }): Promise<Record<string, any>>;
823
864
  listActivity(params?: {
824
865
  workspace_id?: string;
825
866
  post_id?: number;
@@ -333,6 +333,23 @@ export class PosterlyClient {
333
333
  async deleteGoogleBusinessReviewReply(data) {
334
334
  return this.request('DELETE', '/google-business/reviews/reply', data);
335
335
  }
336
+ async listGoogleBusinessMedia(params) {
337
+ const searchParams = new URLSearchParams();
338
+ if (params?.workspace_id)
339
+ searchParams.set('workspace_id', params.workspace_id);
340
+ if (params?.account_id)
341
+ searchParams.set('account_id', String(params.account_id));
342
+ if (params?.location_id)
343
+ searchParams.set('location_id', params.location_id);
344
+ const qs = searchParams.toString();
345
+ return this.request('GET', `/google-business/media${qs ? `?${qs}` : ''}`);
346
+ }
347
+ async addGoogleBusinessMedia(data) {
348
+ return this.request('POST', '/google-business/media', data);
349
+ }
350
+ async deleteGoogleBusinessMedia(data) {
351
+ return this.request('DELETE', '/google-business/media', data);
352
+ }
336
353
  async listActivity(params) {
337
354
  const searchParams = new URLSearchParams();
338
355
  if (params?.workspace_id)
@@ -1 +1 @@
1
- export declare const POSTERLY_MCP_VERSION = "0.20.8";
1
+ export declare const POSTERLY_MCP_VERSION = "0.23.0";
@@ -1 +1 @@
1
- export const POSTERLY_MCP_VERSION = '0.20.8';
1
+ export const POSTERLY_MCP_VERSION = '0.23.0';
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod';
2
+ import type { PosterlyClient } from '../lib/api-client.js';
3
+ declare const CATEGORIES: readonly ["COVER", "PROFILE", "LOGO", "EXTERIOR", "INTERIOR", "PRODUCT", "AT_WORK", "FOOD_AND_DRINK", "MENU", "COMMON_AREA", "ROOMS", "TEAMS", "ADDITIONAL"];
4
+ export declare const addGoogleBusinessMediaTool: {
5
+ name: string;
6
+ description: string;
7
+ inputSchema: z.ZodObject<{
8
+ workspace_id: z.ZodOptional<z.ZodString>;
9
+ account_id: z.ZodOptional<z.ZodNumber>;
10
+ location_id: z.ZodOptional<z.ZodString>;
11
+ source_url: z.ZodString;
12
+ category: z.ZodEnum<["COVER", "PROFILE", "LOGO", "EXTERIOR", "INTERIOR", "PRODUCT", "AT_WORK", "FOOD_AND_DRINK", "MENU", "COMMON_AREA", "ROOMS", "TEAMS", "ADDITIONAL"]>;
13
+ media_format: z.ZodOptional<z.ZodEnum<["PHOTO", "VIDEO"]>>;
14
+ confirm: z.ZodLiteral<true>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ confirm: true;
17
+ source_url: string;
18
+ category: "COVER" | "PROFILE" | "LOGO" | "EXTERIOR" | "INTERIOR" | "PRODUCT" | "AT_WORK" | "FOOD_AND_DRINK" | "MENU" | "COMMON_AREA" | "ROOMS" | "TEAMS" | "ADDITIONAL";
19
+ workspace_id?: string | undefined;
20
+ account_id?: number | undefined;
21
+ location_id?: string | undefined;
22
+ media_format?: "PHOTO" | "VIDEO" | undefined;
23
+ }, {
24
+ confirm: true;
25
+ source_url: string;
26
+ category: "COVER" | "PROFILE" | "LOGO" | "EXTERIOR" | "INTERIOR" | "PRODUCT" | "AT_WORK" | "FOOD_AND_DRINK" | "MENU" | "COMMON_AREA" | "ROOMS" | "TEAMS" | "ADDITIONAL";
27
+ workspace_id?: string | undefined;
28
+ account_id?: number | undefined;
29
+ location_id?: string | undefined;
30
+ media_format?: "PHOTO" | "VIDEO" | undefined;
31
+ }>;
32
+ execute(client: PosterlyClient, input: {
33
+ workspace_id?: string;
34
+ account_id?: number;
35
+ location_id?: string;
36
+ source_url: string;
37
+ category: (typeof CATEGORIES)[number];
38
+ media_format?: "PHOTO" | "VIDEO";
39
+ confirm: true;
40
+ }): Promise<any>;
41
+ };
42
+ export {};
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ const CATEGORIES = [
3
+ 'COVER',
4
+ 'PROFILE',
5
+ 'LOGO',
6
+ 'EXTERIOR',
7
+ 'INTERIOR',
8
+ 'PRODUCT',
9
+ 'AT_WORK',
10
+ 'FOOD_AND_DRINK',
11
+ 'MENU',
12
+ 'COMMON_AREA',
13
+ 'ROOMS',
14
+ 'TEAMS',
15
+ 'ADDITIONAL',
16
+ ];
17
+ export const addGoogleBusinessMediaTool = {
18
+ name: 'add_google_business_media',
19
+ description: 'Add a photo or video to a Google Business Profile gallery (the media shown on Maps and Search). Provide a public https source_url first by uploading via upload_media_from_url or upload_media. COVER and PROFILE are single-slot and replace the existing one. WRITE: show the location, category, and media URL to the user, then pass confirm=true only after explicit confirmation.',
20
+ inputSchema: z.object({
21
+ workspace_id: z.string().optional().describe('Filter to a workspace ID from whoami.'),
22
+ account_id: z.number().int().positive().optional().describe('Google Business account ID from list_accounts.'),
23
+ location_id: z.string().optional().describe('Google Business location/platform_user_id. Provide account_id or location_id.'),
24
+ source_url: z.string().url().describe('Public https URL of the photo or video (from upload_media / upload_media_from_url).'),
25
+ category: z.enum(CATEGORIES).describe('Which gallery category to add the media to.'),
26
+ media_format: z.enum(['PHOTO', 'VIDEO']).optional().describe('Defaults to PHOTO. Use VIDEO for videos (Google caps profile videos at 30s / 75MB).'),
27
+ confirm: z.literal(true).describe('Must be true after explicit user confirmation.'),
28
+ }),
29
+ async execute(client, input) {
30
+ const { confirm: _confirm, ...payload } = input;
31
+ const result = await client.addGoogleBusinessMedia(payload);
32
+ return result.message || 'Media added to the Google Business profile.';
33
+ },
34
+ };