Manage Google Business Profile locations and performance insights — with Agents.
A Model Context Protocol (MCP) server that exposes Google's My Business Business Information API and Business Profile Performance API for managing business location profiles, their attributes, and analyzing how those locations perform on Google Search and Maps.
Overview
The mewcp-google-business MCP Server provides direct, OAuth-authenticated access to Google Business Profile location data and performance analytics:
Full location lifecycle management — list, create, read, update, and delete locations and their custom attributes, with before/after records for every update
Reference lookups against Google's category, chain, and attribute-metadata taxonomies, plus matching against Google's own location records
Business Profile Performance analytics — daily and multi-metric time series and monthly search-keyword impression counts
The server reaches both upstream Google APIs — mybusinessbusinessinformation v1 and businessprofileperformance v1 — via OAuth: it exchanges your connected Google credential's access token for calls made through the official Google API Python Client SDK (googleapiclient), requesting the https://www.googleapis.com/auth/business.manage scope.
Perfect for:
Agencies and business owners managing multi-location Business Profiles programmatically
Marketing and operations teams tracking impressions, clicks, and search-keyword trends across locations
Developers building Business Profile integrations that need category, attribute, and chain reference data alongside location CRUD
Tools
Locations
Lists the locations for the specified account, optionally filtered and sorted, and returns the matching Location objects with pagination info.
Inputs:
- `parent` (string, required) — The name of the account to fetch locations from. If the parent Account is of type PERSONAL, only directly-owned Locations are returned; otherwise all accessible locations (direct or indirect) are returned.- `read_mask` (string, required) — Comma-separated list of fully qualified field names to return. Example: "user.displayName,photo".- `page_size` (integer, optional) — How many locations to fetch per page. Default 10, minimum 1, maximum 100.- `page_token` (string, optional) — Fetches the next page; returned by a previous call when more locations exist than fit the page size.- `filter_` (string, optional) — Filter constraining which locations to return. Empty means no constraints (all locations, paginated). See Google's "Work with Location Data" guide for valid fields.- `order_by` (string, optional) — Comma-separated sort fields (SQL syntax). Default ascending; append " desc" for descending. Valid fields: title, storeCode. E.g.
Creates a new Location that will be owned by the logged-in user, and returns the newly created Location.
Inputs:
- `parent` (string, required) — The name of the account in which to create this location.- `location` (object, required) — Location object to create. Required sub-fields: title (and primaryCategory within categories if categories are set).- `validate_only` (boolean, optional) — If true, validates the request without actually creating the location.- `request_id` (string, optional) — A unique request ID for the server to detect duplicate requests. UUIDs recommended. Max 50 characters.
output data schema:
Returns the specified location as last set by the merchant; may not reflect updates from Google or user-generated content live on Google Maps.
Inputs:
- `name` (string, required) — The name of the location to fetch.- `read_mask` (string, required) — Read mask specifying which fields to return in the response. Comma-separated list of fully qualified field names. Example: "title,websiteUri".
output data schema:
{ name: string; languageCode: string | null;
Updates the specified location's fields per the given update mask, and returns the updated Location. Only the fields you provide are changed — others keep their current value. NOTE: this overwrites the current field values — the original state is not stored after the call. The response includes both the before and after state so you have a full record of what changed.
Inputs:
- `location_name` (string, required) — Google identifier for this location, in the form locations/{locationId}.- `update_mask` (string, required) — The specific fields to update. Comma-separated list of fully qualified field names.- `location` (object, required) — Location object carrying the updated field values.- `validate_only` (boolean, optional) — If true, validates the request without actually updating; response is empty unless there are validation errors.
output data schema:
DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Permanently deletes the location. This action is irreversible — the location and its data cannot be recovered via this API (the Google Business Profile website may offer other recovery paths). NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly what will be deleted and that it is permanent, and wait for their explicit written confirmation before proceeding.
Inputs:
- `name` (string, required) — The name of the location to delete.
output data schema:
{ // no fields — deletion is confirmed by the envelope's success/statusCode}
Returns the specified location as it appears live on Google Maps and Search, which may differ from the merchant's version, along with masks of what Google changed and what's still pending.
Inputs:
- `name` (string, required) — The name of the location to fetch.- `read_mask` (string, required) — Comma-separated list of fully qualified field names to return.
Updates attributes for a given location per the given attribute mask, and returns the updated Attributes. Only the fields you provide are changed — others keep their current value. NOTE: this overwrites the current field values — the original state is not stored after the call. The response includes both the before and after state so you have a full record of what changed.
Inputs:
- `attributes_name` (string, required) — Google identifier for this location, in the form locations/{locationId}/attributes.- `attribute_mask` (string, required) — Attribute names (as attributes/{attribute}) to update. Every attribute you want updated must be in both attributes and attributeMask. To delete an attribute, put it in attributeMask with no matching entry in attributes.- `name` (string, required) — Google identifier for this location, in the form locations/{locationId}/attributes (body field, same value as attributes.name).- `attributes` (array<object>, optional) — The attributes to set (each with name, valueType, values, repeatedEnumValue, uriValues). May be empty when deleting all attributes via attributeMask.
Retrieves attributes for a location as they appear live on Google Maps and Search, which may differ from the merchant's version.
Inputs:
- `name` (string, required) — Google identifier for this location, in the form locations/{locationId}/attributes.
Searches for a chain based on chain name and returns the list of matching chains.
Inputs:
- `chain_name` (string, required) — Search for a chain by its name. Exact/partial/fuzzy/related queries are supported. Examples: "walmart", "wal-mart", "walmmmart", "沃尔玛".- `page_size` (integer, optional, default: 10) — The maximum number of matched chains to return from this query. Default is 10, maximum is 500.
output data schema:
Categories
Returns a list of business categories matched by the front of the category name (e.g. 'food' matches 'Food Court' but not 'Fast Food Restaurant').
Inputs:
- `region_code` (string, required) — The ISO 3166-1 alpha-2 country code.- `language_code` (string, required) — The BCP 47 code of the language.- `view` (string, required) — Specifies which parts of the Category resource to return. Values: `CATEGORY_VIEW_UNSPECIFIED` (equivalent to `BASIC`), `BASIC` (only `displayName`, `category_id`, `languageCode`), `FULL` (all fields).- `filter_` (string, optional) — Filter string from the user; the only supported field is `displayName`, e.g. `filter=displayName=foo`.- `page_size` (integer, optional) — How many categories to fetch per page. Default is 100, minimum is 1, maximum is 100.- `page_token` (string, optional) — If specified, fetches the next page of categories.
Returns a list of business categories for the provided language and category (GConcept) IDs.
Inputs:
- `names` (array<string>, required) — The GConcept ids the localized category names should be returned for. Repeat this parameter to request more than one category; at least one name must be set.- `language_code` (string, required) — The BCP 47 code of the language that the category names should be returned in.- `view` (string, required) — Specifies which parts of the Category resource to return. Values: `CATEGORY_VIEW_UNSPECIFIED` (equivalent to `BASIC`), `BASIC` (only `displayName`, `category_id`, `languageCode`), `FULL` (all fields).- `region_code` (string, optional) — The ISO 3166-1 alpha-2 country code used to infer non-standard language.
output schema:
Attributes
Returns the list of attributes that would be available for a location with the given primary category and country. Provide exactly one of: parent (the resource name of an existing location), OR category_name together with region_code and language_code. Set show_all to true to get metadata for all available attributes regardless of parent/category_name — in that case region_code and language_code are required. Use page_token from a previous response to page through results.
Google Locations
Searches all of the possible locations on Google that are a match to the specified request and returns the matching GoogleLocation entries. Exactly one of location or query must be provided.
Inputs:
- `page_size` (integer, optional) — The number of matches to return. Default is 3, maximum is 10. No pagination.- `location` (object, optional) — Union field `search_query` — exactly one of `location` or `query` is required. Location to search for; if provided, finds locations matching the provided details.- `query` (string, optional) — Union field `search_query` — exactly one of `location` or `query` is required. Text query to search for. Less accurate than an exact location, but can surface more inexact matches.
Performance
Returns the values for each date in a given time range for a single specified daily metric. Only daily data is available; hourly metrics are not supported.
Inputs:
- `name` (string, required) — The location for which the time series should be fetched. Format: `locations/{locationId}` where `locationId` is an unobfuscated listing id.- `daily_metric` (string, required) — The metric to retrieve time series for. One of: `DAILY_METRIC_UNKNOWN`, `BUSINESS_IMPRESSIONS_DESKTOP_MAPS`, `BUSINESS_IMPRESSIONS_DESKTOP_SEARCH`, `BUSINESS_IMPRESSIONS_MOBILE_MAPS`, `BUSINESS_IMPRESSIONS_MOBILE_SEARCH`, `BUSINESS_CONVERSATIONS`, `BUSINESS_DIRECTION_REQUESTS`, `CALL_CLICKS`, `WEBSITE_CLICKS`, `BUSINESS_BOOKINGS`, `BUSINESS_FOOD_ORDERS`, `BUSINESS_FOOD_MENU_CLICKS`.- `daily_range` (object, required) — The timerange to fetch. `{ "startDate": {"year", "month", "day"}, "endDate": {"year", "month",
Returns the values for each date in a given time range for multiple specified daily metrics at once. Only daily data is available; hourly metrics are not supported.
Inputs:
- `location` (string, required) — The location for which the time series should be fetched. Format: `locations/{locationId}` where `locationId` is an unobfuscated listing id.- `daily_metrics` (array<string>, required) — The metrics to retrieve time series for. Same enum values as `get_daily_metrics_time_series`. Repeat this parameter for multiple metrics.- `daily_range` (object, required) — The timerange to fetch. `{ "startDate": {"year", "month", "day"}, "endDate": {"year", "month", "day"} }`, both inclusive.
Returns the search keywords used to find a business in Search or Maps, each accompanied by impression counts aggregated on a monthly basis.
Inputs:
- `parent` (string, required) — The location for which the time series should be fetched. Format: `locations/{locationId}` where `locationId` is an unobfuscated listing id.- `monthly_range` (object, required) — The range in months to aggregate search keyword impressions over. `{ "startMonth": {"year", "month", "day"}, "endMonth": {"year", "month", "day"} }`, both inclusive — only year and month are considered.- `page_size` (integer, optional, default: 100
API Parameters Reference
Every tool returns the same top-level envelope. Only data varies per tool.
page_size — Maximum number of results to return per page. Every list/search tool defines its own default and maximum — see that tool's Inputs.
page_token — Opaque pagination token from a previous response's nextPageToken (or equivalent), used to fetch the next page of results.
filter_ — Tool-specific filter expression constraining which records are returned; the supported fields differ per tool (see list_locations and list_categories).
- `parent` (string, optional) — Resource name of the location to look up available attributes for. If set, category_name, region_code, language_code and show_all are not required and must not be set.- `category_name` (string, optional) — The primary category stable ID to find available attributes. Must be of the format categories/{category_id}.- `region_code` (string, optional) — The ISO 3166-1 alpha-2 country code to find available attributes.- `language_code` (string, optional) — The BCP 47 code of language to get attribute display names in. Falls back to English if unavailable.- `show_all` (boolean, optional) — If true, metadata for all available attributes is returned, disregarding parent and category_name. region_code and language_code are required when this is true.- `page_size` (integer, optional) — How many attributes to include per page. Default is 200, minimum is 1.- `page_token` (string, optional) — If specified, the next page of attribute metadata is retrieved.
- `daily_sub_entity_type` (object, optional) — The sub-entity type/id the time series relates to. Currently no `DailyMetric` supports this (breakdown not available). Union of `dayOfWeek` (enum) or `timeOfDay` (`{"hours", "minutes", "seconds", "nanos"}`).
"error": { "code": "VALIDATION_ERROR", "message": "page_size must be between 1 and 100", "details": null },
"data": null
}
retriable — true when it is safe to retry (rate limit, network error, 503). false for validation and auth errors.
retry_after_seconds — seconds to wait before retrying; present only when retriable is true and the upstream specifies a delay.
error.code — machine-readable string: VALIDATION_ERROR (bad input, caught before the call is made), AUTH_ERROR (no OAuth access token on the credential), UPSTREAM_ERROR (Google's API returned an error status), SERVER_ERROR (unexpected failure).