generated: '2026-08-13' method: derived source: >- mcp/google-ads-mcp.yml (tool signatures read from ads_mcp/tools/*.py in github.com/googleads/google-ads-mcp) bound to operationIds in openapi/google-ads-api-v25-openapi.yml, which was converted from https://googleads.googleapis.com/$discovery/rest?version=v25 description: >- Binds every tool in Google's first-party MCP server to the REST operation that backs it, so an agent inherits a real inputSchema instead of a guessed one. The headline finding is the asymmetry: three read-only tools cover 174 REST operations, and every one of the ~140 mutate operations is rest_only. The MCP surface is a reporting surface; the REST surface is the control plane. surfaces: openapi: path: openapi/google-ads-api-v25-openapi.yml operations: 174 gated: false note: >- Derived by mechanical conversion of the public Google API Discovery Document. Calling any operation requires OAuth plus a developer token; the CONTRACT is anonymous-readable, the API is not. discovery: path: discovery/google-ads-api-v25-discovery.json url: https://googleads.googleapis.com/$discovery/rest?version=v25 gated: false mcp: url: null install: pipx run --spec git+https://github.com/googleads/google-ads-mcp.git google-ads-mcp mode: local-stdio gated: true note: >- No hosted endpoint exists, so tools/list could not be introspected over the wire. Tool names, descriptions and parameters were read from Google's own published source (ads_mcp/tools/core.py, search.py, get_resource_metadata.py), which is a stronger source than a docs list — the signatures below are the actual Python function signatures FastMCP turns into inputSchema. graphql: endpoint: null note: >- graphql/google-ads-graphql.md in this repo documents a modelling exercise, not a Google-served GraphQL endpoint. Google publishes no GraphQL API for Google Ads. crosswalk: - tool: list_accessible_customers category: customers rest: - googleads_customers_listAccessibleCustomers binding: direct confidence: high note: >- Calls CustomerService.ListAccessibleCustomers and strips the "customers/" prefix from each returned resource name. GET v25/customers:listAccessibleCustomers. - tool: search category: search rest: - googleads_customers_googleAds_searchStream - googleads_customers_googleAds_search binding: composite confidence: high note: >- The tool assembles a GAQL string (SELECT fields FROM resource [WHERE conditions] [ORDER BY orderings] [LIMIT n] PARAMETERS omit_unselected_resource_names=true) and executes it against SearchStream (POST v25/customers/{customersId}/googleAds:searchStream). The non-streaming googleAds:search operation takes the identical query and is the paginated equivalent, so both are listed. The tool's structured field/resource/ conditions arguments are a constrained front end over the query string in SearchGoogleAdsStreamRequest — the tool cannot express every GAQL clause the REST operation accepts. - tool: get_resource_metadata category: metadata rest: - googleads_googleAdsFields_search - googleads_googleAdsFields_get binding: composite confidence: high note: >- Issues two GoogleAdsFieldService queries — one for ATTRIBUTE fields matching ".%" and one for the compatible metrics and segments — and merges them into a single selectable/filterable/sortable response. POST v25/googleAdsFields:search. mcp_only: [] rest_only: count: 171 summary: >- Every operation except listAccessibleCustomers, googleAds:search/searchStream and googleAdsFields:search/get has no MCP tool. The unexposed surface is essentially the whole write side of Google Ads. families: - name: mutate operations approx: 118 examples: - googleads_customers_campaigns_mutate - googleads_customers_campaignBudgets_mutate - googleads_customers_adGroups_mutate - googleads_customers_adGroupAds_mutate - googleads_customers_adGroupCriteria_mutate - googleads_customers_biddingStrategies_mutate - googleads_customers_assets_mutate - googleads_customers_conversionActions_mutate - googleads_customers_googleAds_mutate reason: no tool — the MCP server exposes no write path - name: planning and forecasting approx: 14 examples: - googleads_customers_generateKeywordIdeas - googleads_customers_generateKeywordHistoricalMetrics - googleads_customers_generateKeywordForecastMetrics - googleads_customers_generateReachForecast - googleads_listPlannableLocations - googleads_listPlannableProducts reason: no tool - name: audience insights approx: 10 examples: - googleads_customers_generateAudienceCompositionInsights - googleads_customers_generateAudienceOverlapInsights - googleads_customers_generateCreatorInsights - googleads_customers_generateTrendingInsights reason: no tool - name: offline conversion and user-data upload approx: 6 examples: - googleads_customers_uploadClickConversions - googleads_customers_uploadCallConversions - googleads_customers_uploadConversionAdjustments - googleads_customers_uploadUserData - googleads_customers_offlineUserDataJobs_run reason: no tool - name: batch and long-running jobs approx: 9 examples: - googleads_customers_batchJobs_mutate - googleads_customers_batchJobs_addOperations - googleads_customers_batchJobs_run - googleads_customers_batchJobs_listResults - googleads_customers_operations_get reason: no tool - name: recommendations and experiments approx: 12 examples: - googleads_customers_recommendations_apply - googleads_customers_recommendations_generate - googleads_customers_experiments_promoteExperiment - googleads_customers_campaignDrafts_promote reason: no tool coverage: mcp_tools: 3 mcp_resources: 4 rest_operations: 174 rest_operations_bound: 5 rest_operations_unbound: 169 tools_bound: 3 tools_unbound: 0 bound_percent_of_rest: 2.9 note: >- Low REST coverage here is a design choice, not a gap in the crosswalk. One GAQL `search` tool reaches every readable resource in the schema, which no per-operation count captures. What the numbers do capture correctly is that no mutate operation is reachable from an agent through Google's MCP server.