UNPKG

@bdmarvin/mcp-server-gbp

Version:

MCP server for Google Business Profile Performance API.

221 lines (175 loc) 11.9 kB
# Google Business Profile (GBP) MCP Server This is a Model Context Protocol (MCP) server designed to interact with the Google Business Profile (GBP) APIs, including Account Management, Business Information, and Performance. It integrates with an MCP OAuth Controller (like `@bdmarvin/typingmind-mcp`) to securely access GBP data on behalf of an authenticated user. ## Overview This server acts as a specialized tool provider, enabling applications to query and retrieve data from Google Business Profile. It relies on an upstream MCP OAuth Controller to handle the Google OAuth 2.0 flow and to provide a valid Google Access Token for API calls. The server listens for requests over STDIO (standard input/output) when launched by an MCP controller. ## Prerequisites * Node.js (Version 18.x or later recommended). * MCP OAuth Controller: A running instance of an MCP OAuth Controller (e.g., `@bdmarvin/typingmind-mcp`) properly configured with Google Cloud Project credentials (OAuth Client ID & Secret) and the necessary GBP APIs enabled in the Google Cloud Console. * Enabled APIs in Google Cloud Project: * My Business Account Management API * My Business Business Information API * Business Profile Performance API * OAuth Scopes: The access token provided by the OAuth Controller must have been granted with sufficient scopes to access the GBP APIs. The `https://www.googleapis.com/auth/business.manage` scope is generally recommended for comprehensive access to these APIs. * User Permissions: The authenticated Google user must have appropriate permissions (Owner, Manager, etc.) for the GBP accounts and locations they intend to query. ## How it Works with an MCP OAuth Controller 1. The MCP OAuth Controller launches this `mcp-server-gbp` process (typically via `npx @bdmarvin/mcp-server-gbp`). 2. The controller establishes communication with this server over STDIO and handles the MCP initialization handshake. 3. When a tool on this server is called (via the controller's API), the controller injects a fresh Google Access Token (as `__google_access_token__`) and potentially user identifiers (`__google_user_id__`, `__google_user_email__`) into the tool arguments. 4. This server uses the provided access token to make authenticated calls to the relevant Google Business Profile APIs. 5. Results are returned to the controller, which then relays them to the end-user or application. ## Setup and Installation (for Development or Direct Use) 1. **Clone the repository:** ```bash git clone https://github.com/bdmarvin1/mcp-server-gbp.git cd mcp-server-gbp ``` 2. **Install dependencies:** ```bash npm install ``` 3. **Build the project (compiles TypeScript):** ```bash npm run build ``` ## Running Locally (for Development and STDIO Testing) While primarily designed to be run by an MCP OAuth Controller, you can run the server directly for local development and testing using STDIO JSON-RPC messages: 1. Build the project: `npm run build` 2. Run the server: `node dist/index.js` * The server will print: `Google Business Profile MCP Server (vX.Y.Z) running on stdio, expecting __google_access_token__` 3. Paste properly formatted JSON-RPC 2.0 messages (as single lines) into the terminal and press Enter. See "Manual STDIO Testing" section below for examples. ## Using with `npx` (Intended for MCP Controllers) Once published to NPM (e.g., as `@bdmarvin/mcp-server-gbp`), MCP OAuth Controllers can launch it using `npx`: ```bash npx @bdmarvin/mcp-server-gbp ``` ## Available Tools This server provides tools to navigate and retrieve Google Business Profile data. A typical workflow is: 1. `list_managed_accounts`: To find the `accountId` for the desired business entity. 2. `list_businesses`: To list locations under that `accountId` and get their `locationName` (e.g., `locations/12345`). 3. Use the `locationName` with `get_business_information` or performance tools. --- ### 1. Account Management Tools #### `list_managed_accounts` Lists all Google Business Profile accounts (Personal, Location Groups, Organizations) that the authenticated user has access to. * **Input Parameters (`arguments`):** * `pageSize` (number, optional): Accounts per page (1-20, default usually 20 by API). * `pageToken` (string, optional): Token for paginating results. * `filterAccountType` (string, optional): Filter by account type. Valid values: `"PERSONAL"`, `"LOCATION_GROUP"`, `"USER_GROUP"`, `"ORGANIZATION"`. * **Output:** The `result.content[0].text` will be a JSON string. * **Success Example (JSON string content):** ```json { "accounts": [ { "name": "accounts/113493492542427782722", "accountName": "Client Services", "type": "PERSONAL", "verificationState": "UNVERIFIED", "vettedState": "NOT_VETTED" }, { "name": "accounts/107454337197860553297", "accountName": "Absolute Storage", "type": "LOCATION_GROUP", "role": "MANAGER", "verificationState": "VERIFIED", "vettedState": "NOT_VETTED" } ], "nextPageToken": "ABHRLX..." } ``` * The numerical part of the `name` field (e.g., `113493492542427782722`) is the `accountId` needed for the `list_businesses` tool. --- ### 2. Business Information Tools #### `list_businesses` Lists businesses (locations) associated with a specific `accountId` (obtained from `list_managed_accounts`). * **Input Parameters (`arguments`):** * `accountId` (string, **required**): The numerical ID of the Google Account. * `readMask` (string, optional): Comma-separated list of fields to return for each location (e.g., `"name,title,storefrontAddress.postalCode"`). See Google's documentation for `Location` fields. Default returns: `locations.name,locations.title,locations.storeCode,locations.storefrontAddress,locations.openInfo.status`. * `pageSize` (number, optional): Locations per page (1-100). * `pageToken` (string, optional): Pagination token. * `filter` (string, optional): Filter string (e.g., `"title = \"My Awesome Store\""`). See [Location Data Guide](https://developers.google.com/my-business/content/location-data#filter_results_when_you_list_locations). * `orderBy` (string, optional): Order results (e.g., `"title, store_code desc"`). Valid fields: `title`, `store_code`. * **Output:** JSON string containing a list of `Location` objects. * **Success Example (JSON string content, partial):** ```json { "locations": [ { "name": "locations/12345678901234567890", "title": "My Awesome Store", "storefrontAddress": { "postalCode": "94043" } } ], "nextPageToken": "CIV..." } ``` * The `name` field (e.g., `locations/12345678901234567890`) is the `locationName` for other tools. #### `get_business_information` Fetches detailed information for a specific `locationName` (obtained from `list_businesses`). * **Input Parameters (`arguments`):** * `locationName` (string, **required**): Format `locations/{location_id}`. * `readMask` (string, optional): Comma-separated list of fields to return. Default returns a comprehensive set of fields (see `DEFAULT_GET_LOCATION_READ_MASK` in the service class). Example: `"name,title,phoneNumbers,regularHours.periods"`. * **Output:** JSON string of the detailed `Location` object. #### `get_multiple_business_information` Fetches detailed information for multiple `locationName`s. * **Input Parameters (`arguments`):** * `locationNames` (array of strings, **required**): E.g., `["locations/123", "locations/456"]`. * `readMask` (string, optional): Field mask applied to each location. Uses same default as `get_business_information` if omitted. * **Output:** JSON string. The structure will be: ```json { "results": [ // Location object for first locationName, or an error object if that call failed { "name": "locations/123", "title": "Store 1", ... }, // Location object for second locationName, or an error object { "locationName": "locations/456", "error": { "message": "API error message...", "data": { ... } } } ] } ``` --- ### 3. Performance Data Tools #### `get_daily_performance_metrics` Fetches daily performance metrics for a specific `locationName`. * **Input Parameters (`arguments`):** * `locationName` (string, **required**): Format `locations/{location_id}`. * `dailyMetrics` (array of strings, **required**): E.g., `["WEBSITE_CLICKS", "CALL_CLICKS"]`. See `DailyMetricEnum` in `src/schemas.ts` for all valid metric names. * `startDate` (object, **required**): `{ "year": number, "month": number, "day": number }`. * `endDate` (object, **required**): `{ "year": number, "month": number, "day": number }`. * **Output:** JSON string containing time series data for the requested metrics. #### `get_monthly_search_keywords` Fetches monthly search keyword impressions for a specific `locationName`. * **Input Parameters (`arguments`):** * `parentLocationName` (string, **required**): Format `locations/{location_id}` (this is the `locationName`). * `startMonth` (object, **required**): `{ "year": number, "month": number, "day": number }` (day is usually 0 or 1). * `endMonth` (object, **required**): `{ "year": number, "month": number, "day": number }` (day is usually 0 or 1). * `pageSize` (number, optional): Max 100. * `pageToken` (string, optional): Pagination token. * **Output:** JSON string listing search keywords and their impression counts. --- ## Manual STDIO Testing (for Local Development) When running `node dist/index.js` directly, you can send JSON-RPC 2.0 messages to test tools. Ensure the JSON is a **single line**. 1. **List Tools:** ```json {"jsonrpc":"2.0","id":"local-list-tools","method":"tools/list","params":{}} ``` 2. **Call a Tool (Example: `list_managed_accounts`):** * Replace `YOUR_ACCESS_TOKEN` with a valid token. ```json {"jsonrpc":"2.0","id":"local-call-list-accounts","method":"tools/call","params":{"name":"list_managed_accounts","arguments":{"__google_access_token__":"YOUR_ACCESS_TOKEN","pageSize":5}}} ``` *(Refer to the "Available Tools" section for argument structures for other tools.)* ## Error Handling The server will attempt to catch errors from Google APIs and Zod validation. * **Zod Validation Errors:** Will indicate invalid arguments provided to a tool. * **Google API Errors:** Will often include a message and details from Google (logged to `stderr` and returned in the JSON-RPC error response). Common issues include expired access tokens, insufficient permissions for the authenticated user, incorrect `accountId` or `locationName`, or invalid `readMask` values. ## Development * **Watch Mode:** `npm run watch` for continuous compilation. * **API Documentation:** * [Account Management API](https://developers.google.com/my-business/reference/accountmanagement/rest) * [Business Information API](https://developers.google.com/my-business/reference/businessinformation/rest) * [Performance API](https://developers.google.com/my-business/reference/performance/rest) ## License This project is licensed under the MIT License. See the `LICENSE` file for details.