Skip to content

Releases

v2.17.0

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 01 Nov 11:31
b8f114e

This release carries 2.12.1, 2.13.0, 2.14.0, 2.15.0, 2.16.0, 2.16.1 and 2.17.0.

2.17.0 - 2026-11-01

Added: ga_get_metadata, which answers a metadata question instead of returning the catalogue

  • The generated gadata_props_get_meta returned Google's whole field catalogue - every standard and custom dimension and metric, each with a long description - and cut it off at the result limit, so the custom fields, the answer to "what can I report on", were lost (adversarial review of ganalytics, F2). The new hand-written ga_get_metadata takes the property id, answers the custom dimensions and metrics by default (the API name a report takes, the display name, the category and a short description, 300 characters), and takes search, category, limit (25 by default) and offset. custom_only: false asks for Google's whole catalogue; fields that do not fit the result limit are left out of the larger list, and next_offset counts only the fields shown.
  • The generated tool keeps its own name in all and curated; in the google toolset the new tool takes its place, as it does the same method better. ga_run_report and the structured query fields now point at ga_get_metadata.

Fixed (docs): the counts and the tool descriptions

  • The page said 75 tools; the server registers 83. It said "five hand-written tools", and its counts disagreeing with the skill and the capability page (the review saw 82 against 84). All say what the server registers, and the page names the new tool.

Not changed

  • No tool's kind, scope, name or request: every existing tool's map entry is byte-identical, ga_get_metadata is the one addition, a read with the analytics and analytics.readonly scopes the generated tool already listed, so gsm scopes asks for the same scopes in every case (compared across the business group: no scope URL added or removed). tool-aliases.json is untouched, and the frozen files and the goldens have no diff.
  • Verified and left as they are: a large report no longer loses its row_count and next_offset, which reportAnswer puts first and sizes with the result limit since 1.28.0/1.29.0, and a test pins it (review F1).
  • Reported, not changed: ga_get_metadata was not run against live Google; its request shape comes from Discovery (analyticsdata.properties.getMetadata) and its answer shape from the response schema.

Tests

  • tests/analytics-parity.test.mjs: the custom-only answer (the standard field absent, a long description cut, whitespace folded), the whole catalogue with custom_only: false, search and category, paging with limit and offset and next_offset, the notes for no match and for the property having no custom fields, and the tool's scopes. tests/curated-contract.test.mjs: two ga_get_metadata rows against analyticsdata.properties.getMetadata (165 curated tools). tests/toolset.test.mjs and tests/curated.test.mjs follow the new list and count.

2.16.1 - 2026-11-01

Fixed: the YouTube quota note, which was off by a factor of 100

  • The google toolset's search note said "Each call costs 100 units of the project's daily YouTube quota", and the plugin's skill said the same. Google's quota page says the opposite: "The search.list and videos.insert methods have their own quota buckets", "Each of these methods has a default daily limit of 100 per day", and "The quota cost is 1 per call" (https://developers.google.com/youtube/v3/determine_quota_cost, checked 2026-11-01). Both now say that, and the page adds the costs of the calls that are expensive (videos.update, comments.insert and captions.list 50, liveChatMessages.list 5).

Fixed (docs): what cannot be done here, and the comments example

  • The page said the plugin "manages captions" and that 125 tools were registered; captions are listed only (their text is a download, which is a media method), 132 tools register, and neither videos, thumbnails nor caption tracks can be uploaded, because those are media uploads the per-method tools and the gateway both skip. The page now says so, names the methods, and points to a hand-written upload tool as its own change.
  • Its example "Show the top 10 comments on my last video. No prompt" contradicted its own login note: a readonly login cannot read comment threads (youtube.force-ssl has no read-only form). The example says which login it needs.

Not changed

  • No tool's kind, scope, name, request or toolset list: the google list is still 17 tools and gsm scopes asks for the same scopes in every case. tool-aliases.json is untouched, and the frozen files and the goldens have no diff.
  • Verified and left as they are: videos.update has been destructive since 1.26.3 and the note tells a caller to send the whole part (F1); liveStreams.list never returns the stream key, which src/core/credential-fields.ts redacts (IngestionInfo.streamName, F2); the four reports.query parameters Discovery marks "required: true" are required in the tool since 1.30.1 (requiredByText), and the parameter descriptions are no longer clipped, so channel==CHANNEL_ID and channel==MINE are in them (F6).
  • Reported, not changed: video, thumbnail and caption uploads (F4) want a hand-written tool with a local path and a gate, like Play's bundle upload, and that is its own change; the all toolset still lists the junk methods the review named (youtube_tests_insert, the server-streamed live chat method, four unscoped third_party_links writes), because removing them is narrowing.

Tests

  • No test change: the suite pins the lists, the kinds and the counts, and all of them are unchanged (npm test 1482 tests, 1479 pass, 3 skipped).

2.16.0 - 2026-11-01

Added: the reads a Business Profile change needs, in the google toolset

  • The list could not complete its own documented example. Changing a location's primary category needs the category id, and a location's attribute values, what Google has changed and whether the profile is verified are the questions a listing owner asks most (adversarial review of gbusiness, C). Five reads join the list, and the noisy single-metric performance tool leaves it: mbinfo_categories_list, mbinfo_attributes_list, mbinfo_locations_get_attributes, mbinfo_get_google_updated and mbveri_locations_merchant_state (getVoiceOfMerchantState), plus mbaccount_accounts_admins_list. The list is 13 tools.
  • bpperf_loc_get_dai_met_tim_seri leaves the list because its 15-argument shape (six date parts and five dailySubEntityType fields, which Google's own text calls unsupported) is covered by bpperf_locations_time_series, which takes one metric or several and was already in the list. The generated tool stays in all and curated, so nothing is removed from the product.
  • The plugin's skill now walks the category change (list the categories, read the location, patch categories.primaryCategory) and names getGoogleUpdated and the Voice of Merchant state.

Fixed (docs): what the plugin does not cover, and why

  • The page said 52 tools; the server registers 59. It now says plainly that reviews, local posts and media are not covered, and why: they live in the older My Business API v4, which Google does not list in its Discovery directory, and its direct Discovery URL (https://mybusiness.googleapis.com/$discovery/rest?version=v4) answered 404 on 2026-11-01, so no snapshot can be made here; adding v4 also needs an include list and a decision on where those tools belong. It also says why the flat performance call left the google list and that the 15-argument form stays in all.

Not changed

  • No tool's kind, scope, name or request: the map is byte-identical, gsm scopes for the business group asks for the same scopes in every case (compared: no scope URL added or removed), and tool-aliases.json is untouched. The frozen files and the goldens have no diff.
  • Verified and left as they are: admins.create, admins.patch, locations.transfer and admin deletes have been destructive since 1.26.3, so they ask twice (review F6). Parameters Google's text marks "Required." — readMask and the masks on the Business Information reads — are required in the tools since 1.30.1 (requiredByText), checked on the snapshot's own text. business.manage and the Not covered: line came with 1.24.1 and 1.32.0.
  • Reported, not changed: a body object still strips fields the snapshot does not know (review F11), which could matter for a newer Location field named in updateMask; nothing was run against live Google.

Tests

  • tests/toolset.test.mjs (the 13-tool google list and every one of their kinds), tests/toolset-scopes.test.mjs (13 requirements, a readonly login covers none of them), tests/not-covered.test.mjs (the Not covered: line now says 13 tools).

2.15.0 - 2026-11-01

Added: a manager account per call, and customer ids as the Ads UI shows them

  • The manager account Google Ads calls act through was one setting for the whole session (GSM_ADS_LOGIN_CUSTOMER_ID), so reaching a direct account and a manager's client, or two managers, needed a config change and a restart (adversarial review of gads, G3). ads_search, ads_resource_metadata and ads_mutate now take login_customer_id, sent as Google's login-customer-id header for that call only; without it the configured account applies, as before.
  • customer_id and login_customer_id are taken with or without dashes, and as a number: the Ads UI shows 123-456-7890 and Google's own tools strip the dashes, where this suite refused them (G9). A value that is not digits is still refused before any request, with a message that says dashes are allowed.

Added: an ads_mutate approval that lists every operation

  • The approval for a big mutate batch was the raw arguments as pretty-printed JSON, cut at 2,000 characters, so about 14 removals filled it and later operations went unseen (G5). The approval the server shows now lists one line per operation - th...
Read more

v2.12.0

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 01 Nov 09:14
bc0de84

This release carries 2.10.0, 2.11.0, 2.11.1 and 2.12.0.

2.12.0 - 2026-11-01

Added: androidpub_upload_bundle, so a new build can be released

  • The per-method tools leave out every media-upload method (src/core/discovery/tools.ts skips them, and api_call refuses them), and Play's edits.bundles.upload is one of them: a new Android App Bundle could not reach a track by any route, so "release a build" was impossible from here (adversarial review of gplay, F3). The new hand-written tool does that one step: it takes a package name, the full path of an .aab and, optionally, an edit_id, a track, the release's status, user_fraction, a name and release notes, and commit.
    • It creates an edit when none is given (or uses the one given), uploads the file as a stream through the media-upload endpoint (uploadType=media, Content-Type: application/octet-stream), reads the track, writes the new version code at the front of the track's releases (the releases already there are kept, never cleared), and commits the edit only when commit is true. Without it the edit stays open and the answer says how to finish it: androidpub_edits_commit publishes, androidpub_edits_delete drops it, and Google discards an edit nobody commits.
    • A staged rollout is release_status: "inProgress" with user_fraction (0 to 1); a call with one and not the other is refused before any request, as is a file that is not .aab and a path in the folder that holds the Google sign-in data.
    • It works its approval out in prepare: the file (path, size, SHA-256), the track and the releases it holds right now, the release that would be added, and what committing does. The SHA-256 is of the local file, read in chunks. A write: it asks first, and a call with commit: true is gated as destructive (publishing is), so it asks twice.

Fixed (docs): the build upload, the zero-touch tools and a stale kind

  • The product page said nothing about uploading, so androidpub_edits_commit could never be reached with a build of your own. It now describes the new tool, names the classic flow it completes, and gives an example.
  • The page listed androidpub_edits_commit as a plain write; it has been destructive since 1.26.3.
  • The 27 androiddeviceprovisioning tools are described: Google's Discovery document for that API lists no scope, so they load at any profile and with any key, but the key's token does not ask for androidworkzerotouchemm or androidworkprovisioning, and Google answers 403 (review F4). Making them work needs a scopeOverrides entry that would add those scopes to the key's single token request, where one refused scope fails every request of the product; that is reported for the owner and not done.

Not changed

  • No tool's kind, scope, name or request: the tool map gains one entry (androidpub_upload_bundle, a write, with androidpublisher), and every other entry is byte-identical. The google toolset still lists its 16 tools. gsm scopes asks for the same scopes in every case but one: with the curated toolset, readwrite and full now list androidpublisher, because the new tool needs it — the same scope the key already asks for, so no login asks Google for anything new, and the generated service-account scope list is unchanged (node scripts/gen-service-account-scopes.mjs --check: 13 scopes). Only the counts move (curated 9 → 10 tools). tool-aliases.json is untouched, and the frozen files and the goldens have no diff.
  • src/servers/cloud-http.ts takes PUT among the methods a curated tool may send: the track update is a PUT, as Discovery says. Nothing else in that module changed.

Reported, not changed

  • The review's F1 (Vitals query reads) was fixed in 1.26.3, and F2 (getServiceAccount as a write) in 1.26.2. F5's kinds are the decision of 1.26.3: edits.commit, orders.refund, the external-transaction refund, basePlans.migratePrices (and batchMigratePrices) and androidmanagement.devices.issueCommand all ask twice; the AMAPI command is destructive for every command type, so the per-type rule the review suggested is not needed. F6's paging is already solved by the shaping of 1.28.0, which moves next_page_token to the front of a result; a test now proves it for these answers. Still open and reported: the google list's Publishing half (the review would drop androidpub_edits_tracks_list and androidpub_reviews_reply and add the Vitals reads), the Reporting limits in the reviews and vitals descriptions (F8), the service-account key's 12 fixed scopes (F9, touches auth.ts), and whether the Games and Smart Device Management tools can work with a service account at all (F11, UNVERIFIED).

Tests

  • tests/play-parity.test.mjs: the upload end to end (the edit, the streamed upload, the track read and its merged body with the existing release kept, the open-edit note), the commit case with a staged rollout and release notes, the no-track case, the approval preview (nothing read for a new edit, the track read for a given one, the refusal cases before any request), and the page-token order through shapeResult. tests/curated-contract.test.mjs: two rows against edits.bundles.upload, edits.insert, edits.tracks.get, edits.tracks.update and edits.commit, with androidpublisher.v3 added to the documents it checks (162 curated tools). tests/curated.test.mjs: the gplay module count.

2.11.1 - 2026-11-01

Fixed (docs and wording): the Merchant Center access rights the key needs

  • Every place that set a service account up (the setup-service-account output, gsm login, the guided flow, gsm explain, the chat tool auth_setup_service_account, the readiness console steps and the product page) said to add the account "as an Admin user of Merchant Center" (adversarial review of gmerchant, F10). Admin can change anything, including accounts and users, and Google asks for "the most restrictive access rights possible". They now name the access rights that match what the tools do: READ_ONLY when they only read ("Has access to the same read-only methods as STANDARD, but no access to any mutating methods"), STANDARD to change product data, and ADMIN only for accounts and users. The rights are Discovery's User.accessRights (STANDARD, READ_ONLY, ADMIN, PERFORMANCE_REPORTING, API_DEVELOPER, in data/discovery/merchantapi.accounts_v1.json).
  • docs/SETUP.md keeps the Merchant API quickstart's own wording, which says Admin, and says why we suggest less.

Fixed (docs): what the key's one scope reaches, and the counts

  • The product page now says which APIs the key's content scope reaches (the 13 Merchant API v1 resource APIs, Reviews v1alpha and the CSS API) and that Manufacturer Center, which declares only manufacturercenter, is the one it does not. The tool counts are what the server registers, with the read/write/destructive/dynamic split; the old page gave a writes-off total that no longer matched.
  • The google toolset's source URL answers 200 (checked 2026-11-01), and the page names no discontinued version.

Not changed

  • No tool's kind, scope, name or request, no toolset list, and no scope a login asks for: gsm scopes for every group, profile and toolset is byte-identical, the tool maps are unchanged, and tool-aliases.json is untouched. tools/list changes only for auth_setup_service_account on the two service-account servers, in its description.
  • Reported, not changed (the frozen kind file): the review's two candidates are already the decision of 1.26.3, and this release adds the evidence. merchantapi.issueresolution.renderaccountissues and renderproductissues are reads (their output is "meant to be rendered and shown in third-party applications"); merchantapi.accounts.developerRegistration.unregisterGcp and merchantapi.accounts.homepage.unclaim are destructive, so they ask twice, because unregistering cuts API access and unclaiming drops the website claim.

Tests

  • No test changes: the wording is not pinned, and the scopes, kinds and tool maps the suite checks are unchanged (npm test 1458 tests, 1455 pass, 3 skipped).

2.11.0 - 2026-11-01

Added: firebase_get_sdk_config hands back the configuration file, decoded

  • The Firebase Management API returns an Android or iOS app's configuration as base64 (AndroidAppConfig.configFileContents), and the three generated *_get_config tools returned it that way, where Google's own get_sdk_config decodes it (adversarial review of gfirebase, F2). The new hand-written firebase_get_sdk_config takes a project and an app id (its platform decides which configuration is read) or a platform, picks the first app of that platform when no id is given (web, then Android, then iOS otherwise), and answers sdk_config as the text of google-services.json or GoogleService-Info.plist with its file name. A web app's configuration is the object Google returns, which has no file to decode. Base64 that is not text comes back as sdk_config_base64 with a note saying so.
  • It matches Google's get_sdk_config, so in the google toolset it takes the place of the three generated per-platform tools. They stay in all and curated, so nothing is lost there.

Added: the operation poller and the rules release lookup in the google toolset

  • firebase_operations_get and firebaser_projects_releases_get join it (review F3): a create in this product returns a long-running Operation, and without the poller a caller had to reach for api_call, which the google toolset does not have. Neither has a Google equivalent, and each note says so. The list still holds 38 tools.

Fixed (docs): what can and cannot be deployed from here

  • The product page and the plugin's skill said "deploy hosting and backends", and the safety section said Hosting deploys ask first (review F8). A classic Hosting deploy cannot be finished here: a version's files go through versions.populateFiles, a media...
Read more

v2.9.0

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 01 Nov 06:18
b11df00

This release carries 2.6.0, 2.7.0, 2.8.0 and 2.9.0.

2.9.0 - 2026-11-01

Added: two hand-written coursework writes in place of three raw generated tools

  • classroom_create_coursework makes an assignment, a question or a quiz in one call: a title, a type and its choices, instructions, up to 20 links and Drive files, a topic, points, a due date given as YYYY-MM-DD and HH:MM read in a time zone (Classroom keeps the pair in UTC), a schedule, individual students and the submission mode. It is a draft unless publish is true or scheduled_time is set, as Google's own tool is, and both of those ask as destructive calls, because they show the work to the students.
  • classroom_update_coursework changes only the fields you pass (they build Google's updateMask), takes a field away with clear, and sets the students through courseWork.modifyAssignees (the adds and removes worked out from a read of the item). Both work their approval out in prepare, so the form names the course, or the item as it is now and the fields that change, instead of a course id and a raw body.
  • They take the place of the generated classroom_courses_work_create, classroom_courses_work_patch and classr_work_modify_assignees in the google toolset, which now holds 19 tools: those three took a raw CourseWork body or a raw updateMask, with a description that had lost the field list and Google's project rule. Both tools match Google's create_course_work and update_course_work in part, which their notes say: Google's tool has its own date form, and no tool can add or remove a material on an item that exists, because Google's update mask has no such field.
  • Both need classroom.coursework.students, the one scope Discovery lists for courseWork.create, patch and modifyAssignees, so no login's scopes change: gsm scopes for gclassroom is identical in every profile and toolset, and only the tool and covered counts move.

Added: the same-project rule in the one generated tool that lacked it

  • Google allows only the Google Cloud project that made a coursework item or material to change, grade or delete it. Discovery states that in the text of courseWork.create, patch, delete, studentSubmissions.patch and courseWorkMaterials.delete, and those tools have carried it whole since 1.29.1 raised the description limit; courseWorkMaterials.patch leaves it out, so its tool carries a methodNote (config/products.json) that says it, with Google's guide (adversarial review of gclassroom, F3). The two new curated tools say it in their own descriptions.

Fixed (docs): the gclassroom page's counts, and its "no hand-written tools"

  • docs/products/gclassroom.md said the plugin has 119 tools, that the plugin option google lists 20, and that "there are no hand-written tools" (there have been 14 since 1.14.0, and 16 now). The page and the plugin's skill say what the server registers, what the two new tools do, and that the client-side filters look at one page.

Not changed

  • No tool's kind and no other product's tool map, scopes or tools/list. classroom_materials_create and classroom_materials_patch keep their generated form, so a material can still be made and changed with a raw body. tool-aliases.json is untouched (no generated tool was renamed), and the frozen files and the goldens have no diff.
  • The client-side filters of classroom_list_courses (name_contains), classroom_list_coursework (types, topic_ids, title_contains) and classroom_list_announcements (text_contains) still look at one page. Each description says so, since the honest and cheap option is to name the limit: reaching a match on a later page is what next_page_token is for, and looping would spend a caller's quota on pages nobody asked for (review F4).
  • Reported, not changed (owner decision needed): the destructive rule (docs/SECURITY.md, (b) sharing and permissions) may also cover classroom.courses.students.create and classroom.courses.teachers.create, which add a person to a course; classroom.courses.students.delete and both invitation creates already ask twice, and an announcement that publishes does too (1.26.3). Raising the two creates means entries in config/tool-kinds.json, which is frozen.
  • Reported, not changed: student answers, announcement text and coursework instructions come back as data with no note that they are untrusted text (review F10); the submission overview still calls a one-submission list "your_submission" (F7); classwork_link uses the raw course id (F12, UNVERIFIED); checkRubric does not check Google's "levels in the same order" rule (F13). Each wants its own change.

Tests

  • tests/classroom-parity.test.mjs: dueFields (UTC, a zone, an impossible date); create_coursework (a draft by default, the published quiz with its choices, materials, assignees, destructiveWhen, the five refusals that send nothing, and the prepare that names the course); update_coursework (the mask from the fields passed, clear, the modifyAssignees add and remove, three refusals, destructiveWhen, and the prepare that names the item); and the same-project text. tests/curated-contract.test.mjs: rows for both, against courseWork.create, courseWork.patch and courseWork.modifyAssignees (160 curated tools). tests/curated.test.mjs and tests/toolset.test.mjs: the 16 curated tools and the 19-tool google list.

2.8.0 - 2026-11-01

Added: contacts_list pages through every contact

  • Google's People MCP server has three tools and no way to walk the contact list; its two searches find a person from the start of a name, email, phone or organization, and the generated people_people_connections_list wants a raw readMask, a sort order and a page size from the caller. contacts_list sets the readMask (names, email addresses, phone numbers, organizations; fields picks others), takes Google's own page size (up to 1,000, 100 by default) and sort order, and answers short entries with the total when Google sends it (adversarial review of gcontacts, F4).
  • A read, with the scopes of people.connections.list (contacts, contacts.readonly), so a readonly login lists it.

Added: a contact delete whose approval names the contact

  • A generated write or destructive tool reads its target first and adds a few naming fields to the approval (1.27.0), but a Person has no top-level title, display name or subject, so the approval of people.deleteContact showed people/c123... and nothing else (review F5). contacts_delete works the read out in prepare instead: the approval names the contact with its email addresses and phones, and the handler sends the same DELETE the generated tool sends.
  • It is destructive, so it asks twice, and it needs the contacts write scope. src/servers/cloud-http.ts takes DELETE for it (no curated tool sent one before).

Fixed (docs and wording): the warm-up search does not promise a new contact

  • contacts_search's description and docs/USING.md said the warm-up search means "new contacts are found". Google only says "Before searching, clients should send a warmup request with an empty query to update the cache" (Discovery's searchContacts text), so both now say that the warm-up refreshes the cache and that a contact added a moment before can still take a moment to appear. It also no longer claims to be what makes a search work.

Not changed

  • No tool's kind and no other product's tool map, scopes or tools/list. The gcontacts google toolset is still Google's three reads: the two new tools are not in it. tool-aliases.json is untouched, and the frozen files and the goldens have no diff.
  • The other findings of the gcontacts review were already fixed and are left as they are: health.*.rollUp and dailyRollUp are reads (1.26.3, F1); Health webhooks and Data Portability are optional parts, so a contacts login no longer asks for cloud-platform or a Data Portability scope (1.35.0, F2); the clipped readMask lists are whole since 1.29.1 (F3); results are compact, budgeted and keep their page token since 1.28.0 (F4); userinfo.profile is preferred by every profile since 1.35.1, so profile_me returns the name (F6); the docs' counts follow the server since 1.38.3 (F9).
  • Reported, not changed (owner decision needed): a Person-shaped target would name a contact in a search result or an update's approval too if the generic target preview looked one level into names[0].displayName and emailAddresses[0].value. That is src/core/target-preview.ts, a rule for every product's approvals, so it is not here.
  • Reported, not changed: personSummary still returns emails and phones as plain values, without the type label Google gives each (review F11). Adding the label changes the shape of an answer that callers may already parse, so it wants its own change. people.people.batchDeleteContacts and people.contactGroups.delete keep their generated form: the group delete already names the group from its target read.

Tests

  • tests/contacts-parity.test.mjs: contacts_list (the connections list for people/me, the readMask, the page size, the sort order, the page token, the total, the schema limits), contacts_delete (the prepare read and the names it shows, the DELETE alone, and the same request when called without prepare), and the corrected warm-up wording. tests/curated-contract.test.mjs: rows for both (158 curated tools). tests/curated.test.mjs: the gcontacts count, and the meet module of 2.6.0 joins the module list it was missing from.

2.7.0 - 2026-11-01

Added: the move and the list create in the gtasks google toolset

  • tasks_tasks_move and tasks_tasklists_insert join the list, which now holds 10 tools (adversarial review of gtasks, section C). Both already existed in the all toolset: without the move a model could not reorder a task, make it a subtask or move it to another list, and without the insert it c...
Read more

v2.5.0

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 01 Nov 04:22
e75371f

This release carries 2.3.0, 2.4.0 and 2.5.0.

2.5.0 - 2026-11-01

Added: what scripts.run needs before it works, in the tool that runs it

  • Discovery gives scripts.run an empty description, so the generated tool said only that it calls the method, and the scriptId text Google ships does not say what the call needs. Google's guide, "Execute functions with the Google Apps Script API" (https://developers.google.com/apps-script/api/how-tos/execute, read 2026-11-01), states it: the script project is deployed as an API executable and the call passes the DEPLOYMENT id, not the script id; the script and the calling OAuth client share a standard Google Cloud project with the Apps Script API enabled (a default Apps Script project is not enough); the sign-in holds every scope the script uses, not only the called function's; a run may take six minutes, passes and returns basic types only, and the Apps Script API does not work with service accounts. That text is a methodNote (config/products.json), so it reaches the one tool it describes and no other, after the API's own note (adversarial review of gapps, F1 and F9).

Added: redeploying and listing versions in the gapps google toolset

  • appsscript_projects_deployments_update (a write) and appsscript_projects_versions_list (a read) join the google toolset, which now holds 10 tools (review F8). Redeploying needs the update: deployments.create makes a new deployment each time, with a new id and a new web-app URL, while deployments.update keeps the deployment id and its URL and points it at another version. Both tools already existed in the all toolset and need no new scope (script.deployments and script.projects.readonly are already in the cover), so gsm scopes for gapps is identical in every profile and toolset; the covered counts move (google readonly 4 → 5 of 10, readwrite and full 8 → 10 of 10).

Fixed (docs): how to set up a script for scripts.run

  • docs/products/gapps.md said the setup scripts.run needs was UNVERIFIED. Google states it, so the page now lists it and cites the page above, and the plugin's skill names the deployment id and the standard Cloud project in its run flow.

Not changed

  • No tool's kind, scope or request: the tool map of gapps is byte-identical (the two tools were already there), tool-aliases.json is untouched, and every other product is unchanged. gsm scopes for gapps: the same scope lists in all nine profile and toolset cases.
  • Reported, not changed (owner decision needed): a script error comes back as HTTP 200 with an error on the Operation, so isError is false and the model sees a normal result; and a 503 on the POST is retried, which could run a function twice if Google answered after dispatch (the same requestId reasoning as Chat does not exist here).

Tests

  • tests/method-notes.test.mjs: the script.scripts.run note reaches that tool and only that tool, after the API note from config/tool-kinds.json, and the plugin's servers.json carries it unchanged. tests/toolset.test.mjs: the 10-tool list, its notes and the kinds (the update is a write, the versions list a read).

2.4.0 - 2026-11-01

Added: two reads in the gadmin google toolset

  • admin_group_get and admin_orgunit_get join the google toolset, which now holds 12 tools (adversarial review of gadmin, section C). Both were already curated tools (Directory API groups.get and orgunits.get): the lists let you find a group or an org unit, and nothing let you read one. They need no new scope: admin.directory.group.readonly and admin.directory.orgunit.readonly were already in the readonly cover and in the readwrite preference, so gsm scopes for gadmin is identical in every profile and toolset; only the covered counts move (google readonly 7 → 9 of 12, readwrite and full 10 → 12 of 12).

Fixed: admin_user_get declares the scopes its second call needs

  • The tool reads the user (users.get, a user scope) and then the groups the user belongs to (groups.list, a group scope, which Discovery lists only under admin.directory.group and .readonly). It declared the user scopes only, so a sign-in with those alone registered the tool and then failed the whole call (review G9). It now declares both families, and a 403 on the groups call no longer loses the user: groups comes back null with a note naming the missing scope. Any other failure still fails the call.
  • It is the only tool map entry that changes: the same kind, the same four scopes on no other tool, and no rename (tool-aliases.json untouched).

Fixed: the four curated admin deletes show what they delete

  • admin_user_delete, admin_group_delete, admin_member_remove and admin_orgunit_delete had a preview that the gate never showed (only prepare reaches the approval; learning of 2026-10-31), so the form showed the raw key you passed. Each now works the same read out in prepare, so the approval names the user and their org unit, the group and its member count, the member, or the org unit with its children and users. Nothing else moves: the request the gate approves and the request the handler sends are the same as before, and prepare only reads.

Fixed (docs): a doubled period on eight capability pages

  • scripts/gen-capabilities.mjs adds a period after a source that is a sentence, and eight products' sources already end with one, so their docs/capabilities/<id>.md read "…a lean set chosen here..". The generator strips a trailing period now; the eight pages (gadmin, gapps, gbusiness, gmeet, gsc, gtasks, gtm, gyoutube) read "…chosen here." A source that is a URL is unchanged.

Not changed

  • No tool's kind and no other tool's scopes. The gadmin tool map gains the two group scopes on admin_user_get and nothing else; the gapps, gchat and every other product's tool map, tools/list and scopes are byte-identical to 2.3.0. gsm scopes for gadmin, every profile and toolset: the same scope lists in all nine cases.
  • Reported, not changed (owner decision needed): a generated tool of the admin group mints a new JWT and a fresh access token on every call, because getAuthClient('workspace-admin') builds a client per call and caches nothing (the service-account group caches per key file and scope set); the fix belongs in src/core/auth.ts, which is frozen. The curated tools keep the SDK client they build once, so the two paths differ. And domain-wide delegation cannot be checked without a live call: gsm doctor can only see that the setup file, key and subject exist.

Tests

  • tests/admin-tools.test.mjs: the four deletes' prepare (reads only, names the resource, and the handler sends the same DELETE), admin_user_get's declared scopes, its answer with and without a group scope (a 403 leaves the user and a note; a 500 still fails), and the two tools the google list gains.
  • tests/curated-contract.test.mjs: the four rows run prepare instead of preview (155 tests, 154 curated tools). tests/toolset.test.mjs: the 12-tool list, its notes and matches, and still no delete.

2.3.0 - 2026-11-01

Added: the two notification-setting tools of Google's Chat MCP server, as curated tools

  • chat_get_notification_settings and chat_update_notification_settings replace the generated chat_spaces_space_notif_setting_get and chat_spaces_space_notif_setting_patch in the google toolset, which now holds all nine tools of Google's Chat MCP server (adversarial review of gchat, F6). Like Google's tools they take a conversation id and two enums (ALL, MAIN_CONVERSATIONS, FOR_YOU, OFF; MUTED, UNMUTED), not a raw resource name, updateMask and body, and they return the setting. The update builds updateMask from what the call passes, refuses a call with neither field before any request, and is a write that asks once: it changes your own setting and can be changed back at once, so it is not destructive. Google marks update_notification_settings idempotent and so does ours. FOR_YOU is refused by Google in a 1:1 direct message, and the tool says so.
  • Both need https://www.googleapis.com/auth/chat.users.spacesettings, for reading too: Google's get_notification_settings asks for it and the Chat API has no read-only scope for it (spaceNotificationSetting.get lists only that scope), so a readonly login does not list the read.

Changed: a readonly Chat login asks for the read-state scope, so unread_only works

  • chat_search_messages takes unread_only, which sends is_unread(); Google's message-search page gives that filter chat.users.readstate or .readonly. The google toolset's readonly profile asked for neither, so the search was refused at Google. The tool now declares chat.users.readstate.readonly as well, and gchat's scopePolicy.prefer names it for readonly, so a readonly login of the google or curated toolset asks for it. Readwrite is unchanged: the greedy cover still takes chat.messages, which covers the search.

Changed: a login no longer asks a person for the Chat app scopes

  • The generated Chat tools list the Chat app scopes chat.bot and chat.import next to the user scopes, so a readwrite or full login of the default all toolset asked a person to grant an app's scope (gsm scopes printed chat.bot and chat.import). gchat's scopePolicy.onlyIn now lists both with an empty profile list, as Gmail does for gmail.settings.sharing: no login of any profile asks for them. The three generated tools that accept only them (chat_spaces_messages_attachments_get, chat_spaces_messages_replace_cards, chat_spaces_complete_import) are app-only and stay uncovered; the space delete now resolves to chat.delete, the shortest scope it accepts.
  • An account that already holds chat.bot or chat.import keeps them: both stay in the group's scope universe, so the stored-scope merge keeps them and its tools load. Only a login that ...
Read more

v2.2.0

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 01 Nov 02:51
b851e68

This release carries 2.1.0 and 2.2.0.

2.2.0 - 2026-11-01

Fixed: the project IAM policy is read in version 3, so IAM conditions come back

  • cloud_project_iam_policy sent an empty GetIamPolicyRequest, so IAM answered in policy version 1: a role binding that carries an IAM condition lost its condition and had its role renamed _withcond_<hash>, which hides who has conditional access (review of gcloud, F5). It now sends options.requestedPolicyVersion: 3, the field Discovery's GetPolicyOptions documents ("Requests for policies with any conditional role bindings must specify version 3"). The answer is the same Policy object as before: a policy with no conditions still comes back as version 1, unchanged.
  • The six google toolset source URLs under docs.cloud.google.com that ended in /tools_list answered 404; they are now the parent reference pages, which answer 200 and carry the tool table for API Keys, BigQuery, Cloud Billing, IAM, Logging and Monitoring (checked with curl, 2026-11-01). Resource Manager, Storage and the two .../tools_list/<tool> pages already answered 200 and are unchanged.

Reported, not changed (owner decision needed)

  • bigquery_jobs_query (method bigquery.jobs.query) is a plain write, so under confirmation: destructive-only a DROP TABLE, DELETE, MERGE or script runs without a prompt: a write runs unasked in that mode and only destructive asks (src/core/policy.ts, defaultDecision). The 12 setIamPolicy tools of this server already ask twice since 1.26.3, and the gateway's api_call asks for a write method through the hook, so the hole is this one per-method tool. Raising it means "bigquery.jobs.query": "destructive" in config/tool-kinds.json (frozen, a double prompt for every query through that tool, SELECTs included) or a curated write tool that decides by the statement, neither of which this release does.
  • bq_query_read's dry run calls bigquery.jobs.insert, whose Discovery scopes are bigquery, cloud-platform and devstorage.* only: a readonly login holds cloud-platform.read-only, which that method does not accept, while bigquery.jobs.query does list cloud-platform.read-only (data/discovery/bigquery.v2.json, checked 2026-11-01). So the dry run may be refused with a readonly login (NOT checked live). The fix would move the dry run to jobs.query with dryRun, or change the tool's scopes; both change behaviour, so neither is here.
  • Google's google toolset parity: 21 official tools (5 Logging, 12 Cloud Billing, 4 IAM role) have no tool here and are reachable only through api_call; a toolset list can name only tools the server defines. The 16 tools the review calls noise (10 Cloud Billing A2A agent methods, 2 write-only Cloud Trace methods, 4 Cloud Profiler methods) sit in the 350-tool generated budget, not in the google list, and only the Profiler four have no gateway route, so dropping them would lose coverage unless the profiler API joins the gateway. Proposal in the product page.

Not changed

  • No tool's kind, scopes or request other than the IAM policy body; the gcloud tool map, the gateway method kinds and gsm scopes are byte-identical, and the frozen files and goldens are untouched.

Tests

  • tests/cloud-parity.test.mjs: cloud_project_iam_policy sends { options: { requestedPolicyVersion: 3 } } to projects/{id}:getIamPolicy, answers the conditional Policy unchanged, and answers a version 1 policy unchanged too.

2.1.0 - 2026-11-01

Added: rename, move and restore a Drive file

  • drive_update_file renames a file (name), moves it (parent_id, or add_parent_id and remove_parent_id one folder at a time), stars or unstars it and sets its description. Google's Drive MCP server has no such tool, so it is not in the google toolset. It sends Drive's files.update, which is a PATCH: only the fields given change, and every other field keeps its value. parent_id reads the file's folders first, adds the new one and takes out the others (the new one stays if the file is there already). The tool takes no mime_type, because Drive converts a Google file when that field changes (review of gdrive, G2).
  • drive_untrash_file restores a file from the trash, the inverse of drive_trash_file, with its folder and sharing kept. Both work their approval out in prepare, so the form names the file from a read of it: drive_trash_file's preview was never shown before (a preview alone does not reach the gate; learning of 2026-10-31).

Added: the text types and the sheets of drive_read_text

  • drive_read_text reads JSON, XML (SVG included), YAML, TOML, CSV and source-code types as text, as it read text/*: the check is isTextMime, so application/json no longer falls through to the refusal. It still refuses a PDF or an image rather than return nonsense, and the refusal now says why and names drive_download.
  • A spreadsheet is read one sheet deep, which is all Drive's CSV export gives. The answer now names the sheet it read (sheet), lists the others (sheets), and says so in sheet_note when there is more than one. A new sheet argument reads a named sheet through spreadsheets.values.get and renders it as the same CSV text, in parts like any other text (offset, next_offset). When the sheet list cannot be read (the Sheets API is off, say), the export is returned as before, without those fields.

Changed: Books and Drive Labels are optional parts of a gdrive login

  • The all toolset carries Google Books (51 tools) and the Drive Labels API (25 tools and 25 gateway methods), so an all login used to ask for books, drive.labels and drive.labels.readonly (review of gdrive, G8). They are now optional parts (scopePolicy.optional in config/products.json), like Gmail's postmaster: no profile asks for their scopes unless the login names them with --with books,labels (in the chat, auth_login with "with"). An all readwrite or full login now asks for drive, drive.activity and drive.apps.readonly; a readonly one for drive.readonly, drive.activity.readonly, drive.apps.readonly and forms.responses.readonly.
  • Named, a login asks exactly what it asked before: gsm scopes for gdrive over three profiles and three toolsets is identical with --with books,labels, so no tool is lost for someone who wants them. An account that already holds those scopes keeps them (the stored-scope merge), and the tools load for it; a login that names no account and would drop them saves nothing and says so. The google and curated toolsets list no Books or Labels tool and resolve exactly as before.
  • The google toolset's source was a documentation URL that answers 404 (.../workspace/drive/api/reference/mcp/tools_list). It is now .../workspace/drive/api/reference/mcp, which answers 200 and carries the tool table (checked with curl, 2026-11-01). The same URL shape on Chat and Classroom is also 404; those products are not in this change.

Not changed

  • drive_download already reads a file in parts (offset, next_offset, 1.28.0), so the 36 KB problem the review names (G4) has no code change; it needed no save_to_path and got none.
  • No other tool's kind, scopes or request. The tool map of gdrive gains exactly the two new tools (both write); every other entry is byte-identical. The curated toolset counts 14 tools instead of 12, and the server registers 200 instead of 198 (the two new tools).

Tests

  • tests/drive-update.test.mjs (14): isTextMime and the CSV renderer; drive_update_file (a rename and a star in one PATCH with no read, a move that reads the folders then sends addParents/removeParents, a move to the folder the file is already in, one folder at a time, an empty description, and the three refusals before any request); drive_untrash_file and drive_trash_file approvals (prepare reads, sizes and effects, and the same request as before); drive_read_text for every text type, for the PDF and image refusals, for a spreadsheet's sheet names and note, and for a named sheet read as CSV in parts.
  • tests/optional-parts.test.mjs: gdrive joins the parts (the server map, the pinned scope lists with and without books,labels, the Held back: lines, the stored-scope merge, and gen-servers refusing a part of an unknown API); tests/gmail-scopes.test.mjs lists gdrive among the servers with a policy; tests/curated.test.mjs and tests/curated-contract.test.mjs carry the two new tools (152 curated tools, request rows for the update, the restore, the spreadsheet and the named sheet).

by FiredMosquito831

v2.0.0

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 01 Nov 00:13
c937c56

This release is 2.0.0: every generated per-method tool has a readable name, and every old name keeps working until 3.0.0.

2.0.0 - 2026-11-01

Changed (breaking): readable names for the generated tools

  • The generated per-method tools no longer get hashed or chopped names. A tool's name is built from its method in a fixed order and the first form that fits the server's budget wins: the API prefix, then the resource chain, then the method name; when that is too long, container words go (projects, locations, customers, users, version segments), then common words are shortened (configurations to configs, accounts to accts, permissions to perms, …), then a resource that repeats the API prefix goes, then a resource is reduced to its head word (managedFolders to folders, but not to a word that says nothing: smimeInfo keeps smime), then the API prefix is shortened (only when it is longer than 8 characters), then the leading resources go, and the method's words are reduced to their last two (never to one: asyncBatchAnnotate must not read like annotate). A name that comes out too long is clipped, never hashed. The rule lives in src/core/discovery/tool-names.ts.
  • 1,609 generated tools take a new name. gcloud monitor_projects_metric_descri_list is monitor_metric_descriptors_list; gmail gmail_users_settin_send_as_smime_i_list is gmail_send_as_smime_info_list; gdrive drivelabel_labe_revi_permi_batch_52b2 is drivelabel_revs_perms_batch_delete; gai discoverye_projec_locati_collec_engine_list is discoverye_collections_engines_list. A name that already fitted keeps its spelling. No generated name is hashed any more: the 4-character hash is gone (the proposal counted 1,545 hashed or clipped names in the 1.31.1 tree).
  • Every generated name still fits the 64-character Claude Code limit, is unique within its server and matches ^[a-z0-9_]+$. So do the old names: the old rule is still computed next to the new one, and where they differ the old name becomes an alias.

Migration: the old names keep working until 3.0.0

  • tools/call with an old name runs the same tool: the server rewrites the name before it dispatches, so a script, a prompt or a client that still uses the old name works. tools/list lists each tool once, under its new name; the old names are not listed.
  • A policy.json rule that names an old tool still applies, and so does one that names the new tool: the decision is made against every name of the tool, and a deny on either name wins. Claude Code permission rules that name an old tool keep working for the same reason (they match on the name the call used).
  • The aliases are data: each plugin ships tool-aliases.json (old name → new name, one entry per renamed tool), written by the build from the generator's own rename list. The hook and the server read it; the hook resolves an old name to the same tool-map entry, so it decides exactly as it does for the new name.
  • No policy file, no toolset setting and no install needs to change. toolset lists (google, curated, all) and the number of tools a product registers are unchanged; only the names in them are new. Docs, the capability pages and the site follow the new names.
  • Those old names go away in 3.0.0. Until then nothing warns; a plugin built by 2.0.0 accepts both.
  • One pair keeps a numeric suffix: two tools of gai (vision.projects.locations.images.annotate and its neighbour) both read vision_projects_locations_images_annotate, so one is _2. Two API versions of one method can also carry _2. The old rule had the same case and hashed both.

Naming details that may surprise

  • The API prefix stays whole (up to 8 characters): monitor, monitor.acct-style cuts no longer happen. A longer prefix (displayvid, discoverye) is shortened only after the resource chain has given way.
  • projects and locations are dropped where the budget needs it, so monitoring.projects.alertPolicies.delete is monitor_alert_policies_delete while monitoring.projects.groups.delete keeps its projects (it fits).
  • The list tool keeps its name (api_methods), and curated tools are never renamed: a generated tool that would take a curated name takes another readable form instead of a hash.

Compared with the proposal of 2026-10-31

  • The proposal (names-proposal.md) named 1,395 tools and left 149 to the owner. This build follows the same rules but orders them by "keep the API prefix whole first", so 741 of the 1,395 match exactly and 654 differ, mostly because the proposal shortened the API prefix (discl_, displ_) where this build drops or shortens a resource instead, and because the proposal sometimes dropped a method qualifier (bulk) that this build keeps. The 149 open ones are chosen by the same rules; the rule above is the one applied.

Tests

  • tests/tool-aliases.test.mjs: the naming rules (budget, pattern, uniqueness per server, the reduction order, a name that fits is not renamed), every plugin's alias table (each old name points at a tool, no old name is a tool), every old name of all 23 plugins decides exactly as its new name does under eight policies and a deny/allow mix (about 38,000 decisions), a bundled server that answers to an old name with the same answer as the new one while tools/list shows only the new name, and the bundled hook deciding the same way for both names.
  • tests/discovery.test.mjs and tests/products-build.test.mjs: a reserved name now yields another readable form, not a hash.
  • The tests that name a generated tool carry the new names (159 references in 12 files).

by FiredMosquito831

v1.41.4

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 31 Oct 20:22
9785947

This release carries 1.41.2, 1.41.3 and 1.41.4.

1.41.4 - 2026-10-31

Changed: seven methods that only read are reads now

  • Google Ads generateKeywordIdeas, generateKeywordHistoricalMetrics and suggestKeywordThemes, and Vertex AI countTokens in its four bindings, are reads by exact id in config/tool-kinds.json. This is the outcome Q1 of the 2026-10-30 review names; 1.41.3 fixed the rule, and this is the decision that names them, because a POST with no read rule is a write.
  • What the user sees: googleads_customers_generate_keyword_idea is listed with writes off (gads lists 133 tools instead of 132), and the six gateway methods no longer prompt through api_call. gsm scopes asks for the same scopes as before; only its read and write counts move (gads 99/186 → 100/185, gai 1389/1226 → 1393/1222).

Not changed, on purpose

  • The same RPCs on other APIs still ask: Search Ads 360 generateKeywordIdeas, generateKeywordHistoricalMetrics, suggestKeywordThemes and generateKeywordForecastMetrics, Google Ads generateKeywordForecastMetrics, Firebase ML countTokens and Gemini generativelanguage.models.countTokens. They need their own decision; tests/credential-reads.test.mjs pins that they still ask, so the difference stays visible.
  • No other method's kind moves, no scope list changes, and the tool maps and gateway tables differ only in these seven ids.

Tests

  • tests/credential-reads.test.mjs: the seven entries exist as the catalog spells them; both classifiers give read for every version; the built plugin tables carry read; the generated tool is listed with writes off by a real server with a fake sign-in; the bundled hooks print nothing for the seven and still ask for the seven left out.
  • tests/kinds-postreads.test.mjs: countTokens moved from "stays a write" to "is a read, on the owner's decision of 2026-10-31", in the classifier, the built table, the hook and the server.

1.41.3 - 2026-10-31

Fixed: a credential word is a whole word of the method name

  • The rule that makes a non-GET method a write when its name holds a credential word ran one regular expression over the whole name, /token|credential|secret|password|authoriz|key/i, so a longer word that merely contains one counted: "Keyword" held "key", and countTokens held "token". Google Ads generateKeywordIdeas and Vertex AI countTokens were writes only through that accident (Q1 of the 2026-10-30 review).
  • hasCredentialWord (methodWords + CREDENTIAL_WORDS in src/core/discovery/methods.ts, and the same in the copy at src/cli/method-kinds.ts) now splits the name at camelCase boundaries, at digits and at separators and tests each word whole: generateKeywordIdeas is generate, keyword, ideas and countTokens is count, tokens. The words are token, credential, secret, password and key; authoriz stays a prefix, as it was (authorization, authorize). Plurals are not credential words: a list of secrets or of keys returns no credential value.

Unchanged, on purpose

  • No catalog method's kind moves. Every method the old expression caught and the words rule does not is a POST or a PATCH, and a POST is a write unless a read rule names it, so the kind is the same with or without the rule. The exact list is 49 (API version, method) pairs: Vertex AI countTokens and computeTokens (16 bindings), Google Ads and Search Ads 360 generateKeywordIdeas, generateKeywordHistoricalMetrics, suggestKeywordThemes and generateKeywordForecastMetrics, Identity Toolkit getPublicKeys and getSessionCookiePublicKeys, Cloud KMS getAutokeyConfig and showEffectiveAutokeyConfig, Dataproc injectCredentials, VMware Engine resetVcenterCredentials and resetNsxCredentials, Workstations pushCredentials, Tag Manager reauthorize, Games retrieveTokens and gamesPlayerTokens, oauth2.tokeninfo and webcontentpublisher.users.generatePlatformSiteTokens.
  • So no write entry was needed in config/tool-kinds.json, and none was added. Making the four methods the decision names generateKeywordIdeas, generateKeywordHistoricalMetrics, suggestKeywordThemes (and the Search Ads 360 copies) and Vertex AI countTokens reads needs a further decision: an exact read entry in config/tool-kinds.json, or the names in READ_POST_EXACT. This release did neither.
  • Tool maps, gateway method-kinds.json, gsm scopes (207 cases), the requests and the approval text are unchanged. Both classifiers give the same kind for every catalog method, every version.

Tests

  • tests/credential-words.test.mjs: the split and the words; every method whose name holds a credential word as a whole word is never a read in either classifier; and the old rule and the new one give the same kind for all 31,641 catalog methods, every API version, with both classifiers agreeing.

1.41.2 - 2026-10-31

Fixed: the hook reads the policy file from the plugin's token folder

  • A plugin option reaches the MCP server as GSM_TOKEN_DIR, but a hook process gets it as CLAUDE_PLUGIN_OPTION_TOKEN_DIR (code.claude.com/docs/en/plugins-reference, "Reference a saved value": CLAUDE_PLUGIN_OPTION_<KEY> is "exported to hook processes for every option, with <KEY> uppercased"). The hook read GSM_TOKEN_DIR only, so with a custom token_dir it read policy.json from the default folder while the server's gate read the custom one: a deny rule written in the configured folder did not stop the call the hook guards, and a rule in the default folder applied although the server no longer used it.
  • tokenDirectory (src/hook/pretooluse.ts) now resolves the folder as loadConfig does: GSM_TOKEN_DIR, else CLAUDE_PLUGIN_OPTION_TOKEN_DIR, else ~/.google-services-mcps. Both values go through optionValue, so an empty value and an unexpanded ${user_config.token_dir} still mean unset (1.37.1), and GSM_TOKEN_DIR still wins when both are set. The hook reads nothing else from that folder: policy.json is its only file there.

Verified

  • The hook's decision for every tool of all 23 plugins, with the default folder and with a folder holding no policy file, is byte-identical before and after: 22,284 runs (every tool-map entry, four foreign tool names, the three folder cases and both confirmation modes), the same 7,698,947 bytes of output, 14,601 silent and 7,683 asks.
  • tests/hook.test.mjs runs the bundled hook with a deny, an allow and an ask rule in a folder named only by CLAUDE_PLUGIN_OPTION_TOKEN_DIR, with GSM_TOKEN_DIR winning when both are set, with the default folder under a redirected home, and with an empty and an unexpanded option value. Reverting the change fails four of them.

Not changed

  • The gate, approval.ts, policy.ts, the tool maps, the kinds, gsm scopes and every request. A hook with no plugin option set resolves the folder it resolved before.

by FiredMosquito831

v1.41.1

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 31 Oct 13:25
c4c4e7c

This release carries 1.38.4, 1.39.0, 1.40.0, 1.40.1, 1.41.0 and 1.41.1.

1.41.1 - 2026-10-31

Fixed: the Search Console delete approvals show what the delete does

  • sc_site_delete and sc_sitemap_delete are destructive, and each had a preview with the exact effect ("Property is removed from this account. Its performance, indexing and sitemap history are no longer accessible through this account. The website itself is not changed."; "Sitemap is removed from Search Console, not from the site. The sitemap file stays on the server, and the pages it lists are not de-indexed by this call."). The gate never read it: only a tool's prepare reaches the approval, so the form showed the raw arguments (review of gsc, F6). The preview is now worked out in prepare, from the arguments alone (no request), and the form shows the property, the sitemap, the account the call runs as and the effect. A property string that is not one is refused before the form, as the handler refused it before.
  • approval.ts is unchanged: the same gate path gmail_send and calendar_delete_event use.

Not changed

  • Tool maps and kinds, tools/list (the two tools keep their descriptions and arguments), gsm scopes, the requests. Policy rules decide as before; the audit line hashes what the form showed.

1.41.0 - 2026-10-31

Added: the search analytics options Google documents

  • sc_search_analytics_query takes what Google's searchAnalytics.query takes (https://developers.google.com/webmaster-tools/v1/searchanalytics/query) and it lacked (review of gsc, F2):
    • data_state: final (Google's default: "the returned data will include only finalized data", so the latest days are missing), all ("data will include fresh data"; the answer's metadata.first_incomplete_date says where it starts) or hourly_all ("hourly breakdown", for the hour dimension; metadata.first_incomplete_hour).
    • the hour dimension.
    • aggregation_type: auto, byPage, byProperty or byNewsShowcasePanel, with Google's limits in its description.
    • filters: a typed list of { dimension, operator, expression } (dimensions query, page, country, device, searchAppearance; operators equals, notEquals, contains, notContains, includingRegex, excludingRegex; expression up to 4,096 characters), sent as one group whose filters must all match ("All filter groups must match"; "and" is the one group type Google supports). The untyped dimension_filter_groups still works and is sent as given; with both, every group must pass.
  • The values go to Google as its reference spells them, and only when given: a call without them sends the same body as before, field for field. Google's metadata object comes through in the answer.

Fixed: smaller Search Console gaps

  • sc_url_inspect says what Google's reference says: only the indexed version is read ("you cannot test the indexability of a live URL"), and the quota is 2,000 inspections a day and 600 a minute per property (https://developers.google.com/webmaster-tools/limits). A page under a URL-prefix property is matched with its host compared without case, so https://Example.com/x belongs to https://example.com/; a page whose host only starts with the property's (https://example.co against https://example.com/x) is no longer taken as part of it (F11).
  • Google's "User does not have sufficient permission for site" error now ends with how to find the exact property string (sc_sites_list; a URL-prefix property ends with a slash, a domain property is sc-domain:), for every curated tool (F8).
  • The ten generated Search Console tools that a curated tool covers name it in their descriptions (methodNotes, F7), as Gmail's do since 1.39.0.

Not changed

  • Tool maps and tool kinds, gsm scopes, the hook, and the requests of every earlier call. Not checked against live Google.

1.40.1 - 2026-10-31

Fixed: a readonly Calendar login with the google toolset asks for Google's three read scopes

  • Google's Calendar MCP server asks for calendar.calendarlist.readonly, calendar.events.freebusy and calendar.events.readonly (https://developers.google.com/workspace/calendar/api/guides/configure-mcp-server, "paste the scopes for the Google Calendar MCP server"). A readonly login with toolset: google asked for calendar.readonly ("See and download any calendar you can access using your Google Calendar"), the one scope that covers its four read tools (review of Calendar, F10). It now asks for the three, as its readwrite login has asked for calendar.events, calendar.calendarlist.readonly and calendar.events.freebusy since 1.25.0, by the same reading of Google's scope descriptions ("View events on all your calendars", "See the list of Google calendars you're subscribed to", "See the availability on Google calendars you have access to"): the same reach for listing calendars, reading events and finding free time.
  • The two Calendar free/busy scopes join the view-only scopes the readonly profile may ask for (VIEW_ONLY_SCOPES): calendar.events.freebusy ("See the availability on Google calendars you have access to") and calendar.freebusy ("View your availability in your calendars"), quoted from https://developers.google.com/identity/protocols/oauth2/scopes. Their names do not end in readonly, so before, no readonly login could take them.
  • A token that holds calendar.readonly keeps every tool: each tool still accepts it.

Not changed

  • gsm scopes over all 207 plugin, profile and toolset cases: 206 identical; gcalendar readonly google asks for calendar.calendarlist.readonly, calendar.events.freebusy and calendar.events.readonly instead of calendar.readonly, with the same tools covered. The all and curated toolsets of gcalendar still ask for calendar.readonly (and calendar.acls.readonly). Tool maps, tool kinds and tools/list. Not checked against live Google.

1.40.0 - 2026-10-31

Added: Calendar times without an offset

  • Every Calendar tool that takes a time now also takes a local date and time without an offset (2026-11-02T10:00), read in time_zone, else in the calendar's own time zone, as Google's Calendar MCP server does ("Time zone (IANA ID, for example Europe/Zurich) used to resolve timezone-less dates. Default: calendar's timezone", list_events, https://developers.google.com/workspace/calendar/api/v3/reference/mcp/tools_list/list_events). Before, such a time was refused, and a model had to work out the offset itself, where a wrong one books the wrong hour (review of Calendar, F4).
    • calendar_create_event and calendar_update_event send it as Calendar takes it: dateTime without an offset and timeZone (Discovery, EventDateTime: "A time zone offset is required unless a time zone is explicitly specified in timeZone"). Without time_zone, the calendar's zone is read first (one events.list request for its timeZone field, a read with the scopes the tools already have); calendar_update_event takes the event's own zone when it has one.
    • calendar_list_events, calendar_freebusy and calendar_suggest_time turn it into a UTC instant (Calendar takes timeMin and timeMax with an offset only). calendar_freebusy takes time_zone (also the zone of its answer, FreeBusyRequest.timeZone); calendar_suggest_time answers in the primary calendar's zone for a local window.
    • A time with an offset is sent as before. When it also has a time_zone whose offset at that moment differs, the answer has a time_note: Calendar keeps the instant the offset gives, so the event is not at that hour of time_zone's clock. The request is unchanged.
  • A recurring event with a local start no longer needs time_zone: it takes the calendar's zone.

Fixed: calendar_update_event keeps the duration when only the start moves

  • Google's update_event: "New start time (ISO 8601). Preserves duration if updating only start." (https://developers.google.com/workspace/calendar/api/v3/reference/mcp/tools_list/update_event). calendar_update_event patched the start alone, so moving an event later gave an empty range (refused by Google) or shortened it (F3). Now a start without end reads the event first and moves the end with it: a timed event keeps its length (the end written as the start is), an all-day event its number of days; the answer says duration_kept. A date for a timed event (or a time for an all-day one) cannot keep a duration, and the error asks for end too. With start and end both, the request is as before (one PATCH, no read).
  • time_zone without start or end was ignored without a word; the answer now says it was not used, and the "nothing to change" error says that it applies to start and end.

Added: more of Google's create_event and update_event

  • visibility (default, public, private, confidential), color_id (the event palette, 1 to 11) and availability (busy or free, Calendar's transparency) on both; attachments on create and add_attachments / remove_attachments on update: links to files (for Drive, the file's link), at most 25 per event (Discovery, Event.attachments), sent with supportsAttachments=true ("In order to modify attachments the supportsAttachments request parameter should be set to true"). The update keeps the other attachments, as it keeps the other guests (F6).
  • event_type on create: focusTime, outOfOffice and workingLocation, with auto_decline, decline_message, chat_status and working_location, set as Google's guide requires (https://developers.google.com/workspace/calendar/api/guides/calendar-status: focus time and out of office are timed and opaque; a working location is public and transparent, timed or one whole day; "These features are only available on primary calendars, and to some Google Calendar users"). Arguments that do not fit the type are refused before any request. Birthdays and Gmail events are not made here.
  • The ans...
Read more

v1.38.3

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 31 Oct 10:04
4447f79

This release carries 1.37.0, 1.37.1, 1.37.2, 1.38.0, 1.38.1, 1.38.2 and 1.38.3.

1.38.3 - 2026-10-31

Fixed: the docs count the tools a server registers

  • README's products block, docs/SURFACES.md, docs/CAPABILITIES.md, each docs/capabilities/.md and the site counted every entry of a plugin's tool map. Every map lists all nine runtime tools so the consent hook knows each name, but a server registers only those of its sign-in kind (two to seven), and gmerchant's map also holds 8 Manufacturer Center tools its service account key's fixed scopes never cover. So every product was overcounted by 2 to 8, and the capability pages listed sign-in tools the server does not have (for example auth_setup_admin for gsc). The reviews of gsc, gmeet, gcontacts, gtasks, gmaps, gsearch and gbusiness reported it.
  • The generators now count and list only what the server registers, by one rule, registersEntry (src/core/runtime-tools.ts), which the skills use too: README 3,542 tools in total (was 3,621). Each capability page names the map entries it leaves out, in a "Not registered by this server" section. The SURFACES column that held the total is named Tools (it said Per-method tools). The installer's own count for the Antigravity warning (toolsetCount without options) is unchanged.
  • A test checks that every tool description, of every server, starts with what the tool does: a generated tool with Google's description of its method before this suite's note and method line, every other tool with a sentence (descriptions were already checked to be at most 2,048 characters). Claude Code: "When tool search matches Claude's query against a tool's description, it reads only the part within the shorter limit, so put the words Claude would search for near the start too" (https://code.claude.com/docs/en/mcp).

Not changed

  • tools/list, instructions, tool maps and kinds, gsm scopes, the hook. The server bundles differ from 1.38.2 only by their version string.

1.38.2 - 2026-10-31

Changed: the hook runs for its own server's tools only, and trusts Claude Code's server source

  • Each plugin's PreToolUse matcher was ^mcp__plugin_<plugin>_, which also matches another plugin whose name starts with this one and an underscore. It is now anchored to the plugin's own server: ^mcp__plugin_<plugin>_<server>__, the prefix Claude Code gives every tool of a plugin's server ("mcp__plugin_<plugin-name>_<server-name>__<tool>", https://code.claude.com/docs/en/hooks). It matches every tool of the plugin's map and none of another plugin's (tested over all 23).
  • The hook now reads mcp_server from the hook input: "For an MCP tool, the input also carries mcp_server, an object with the server's name and a source that says where the server's definition came from. The source values include plugin, sdk, and configuration scopes such as user and project. ... Base trust decisions on source rather than on name or the mcp__<server>__ tool-name prefix. The mcp_server field requires Claude Code v2.1.274 or later." (same page). When source is a string other than plugin, the call comes from a server the person configured (or an SDK), not from this plugin, so the hook prints nothing and Claude Code's own permission rules apply. Fail closed: when mcp_server or its source is missing or not a string (an older Claude Code), the hook decides by the tool name exactly as before.
  • gsm doctor checks for the anchored matcher of a server in the plugin's .mcp.json, and still accepts the older ^mcp__plugin_<plugin>_, so a plugin folder built before 1.38.2 passes as before. scripts/smoke.mjs expects the anchored matcher.

Not changed

  • The hook's answer for every call of this plugin's tools: over every tool-map entry of every plugin and four other names each, with confirmation unset and destructive-only, and with mcp_server absent, source: "plugin", no source, a non-string source or a non-object mcp_server, the output equals 1.36.1's (tests/hook-source.test.mjs, and a full dump: 29,704 hook runs, 25,704 identical). The 4,000 that differ are the calls whose source is user or project that asked before: they print nothing now. tools/list, instructions, tool maps and kinds.

1.38.1 - 2026-10-31

Changed: plugin manifests name their homepage, repository and licence; each plugin has a README; the marketplace has categories and tags

  • Every plugin.json now has homepage (the product's page, docs/products/<id>.md on GitHub), repository and license: "Apache-2.0", the manifest fields of https://code.claude.com/docs/en/plugins-reference ("homepage | String | Documentation URL. Must parse as a URL, or the plugin fails to load"; "license | String | SPDX identifier such as MIT or Apache-2.0").
  • Every plugin folder has a generated README.md: what it covers, the install line (claude plugin install <id>@google-services-mcps), how to sign in from the chat, the options, how to update from this marketplace, and links to the product page, its tool list and docs/SECURITY.md. claude plugin validate prints the line to paste when a README has no install line (Claude Code 2.1.295 changelog); it prints nothing now, and it no longer falls back to the repository's README.
  • Every marketplace entry has a category and tags ("Free-form category for organizing the catalog", "Free-form tags for search", https://code.claude.com/docs/en/plugins/marketplace-reference), from listing in config/plugin-text.json.

Not changed

  • tools/list, server instructions, tool maps and kinds, the hook. claude plugin validate --strict passes for the marketplace and every plugin (Claude Code 2.1.316).

1.38.0 - 2026-10-31

Added: destructive tools keep Claude Code's permission prompt in every mode

  • A destructive tool now carries _meta["anthropic/requiresUserInteraction"]: true in tools/list when this server's gate would ask before it (confirmation every-change or destructive-only, and no policy rule that allows or denies the tool). Claude Code: "Claude Code shows that tool's permission prompt on every call, even in acceptEdits, auto, and bypassPermissions permission modes, and doesn't offer a "don't ask again" option for it. Allow rules that match the tool don't skip the prompt either. In dontAsk mode, which never prompts, Claude Code denies the call instead." (https://code.claude.com/docs/en/mcp).
  • Why: the plugin's hook prompt could be passed over. bypassPermissions skips every prompt "except for the actions no mode auto-approves", which lists MCP tools marked requiresUserInteraction and not hook prompts (permission modes page), and a hook that times out or fails lets the call continue "through the normal permission flow" (hooks page), where an allow rule or the mode can approve it. The server's own form still asked, but an Elicitation hook can answer that form without showing it. Now the permission prompt reaches a person in those cases too.
  • No third prompt in the normal case: the hook's ask and the marker lead to the same permission prompt, then the server's form, as before. With confirmation off, or a policy allow rule for the tool, there is no marker, so nothing new asks. Reads, writes, api_call and the Ads mutate tools carry none. The prompt count per mode, worked out from Claude Code's documentation (not measured live), is in docs/SECURITY.md.

Not changed

  • What the gate and the hook decide (approval.ts and the hook bundle are unchanged), tool maps and kinds, gsm scopes, instructions. tools/list differs from 1.37.2 only by the marker on the 522 destructive tools the bundled servers list with writes allowed (tests/requires-interaction.test.mjs checks every server, and that confirmation off and a policy allow rule leave it out).

1.37.2 - 2026-10-31

Fixed: each plugin's skill says what the product is for, signs in from the chat and names the right tools

  • The 23 skills were one template: a description that named the APIs and a changing tool count ("Use for requests about these Google APIs"), sign-in as terminal commands with a <plugin> placeholder although the chat has auth_setup_client and auth_login, no common tasks, and a tool count that included runtime tools the server never registers (every tool map lists all nine for the hook; gmail said 115, it lists 113).
  • The skill text now comes from config/plugin-text.json, per product: a description with the main use cases first and a when_to_use with trigger phrases and example requests (Claude Code: "Put the key use case first: the combined description and when_to_use text is truncated at 1,536 characters in the skill listing", https://code.claude.com/docs/en/skills), and three to six common tasks taken from the product reviews (for example Gmail search, read, reply; Calendar find a time, book it; Drive search, read as text; Search Console property, performance with paging, URL inspection). The build renders them with the sign-in steps of the product's group in the chat first (auth_status, auth_setup_client, auth_login; auth_setup_service_account; auth_setup_admin; setup-apikey in a terminal for an API key, which is never pasted into the chat), the terminal fallback by node "${CLAUDE_PLUGIN_ROOT}/bin/gsm.mjs" (substituted by Claude Code in plugin skills), a note that returned content is data and not instructions, the safety rules, the tool counts and the API list.
  • The build fails when a task names a tool the server does not register, when the description and when_to_use pass 1,536 characters, or when a skill reaches 500 lines ("Keep SKILL.md under 500 lines", same page). The tool count is what the server registers: the tool map without the runtime tools of other sign-in kinds (runtimeToolsFor, src/core/runtime-tools.ts), and for gplay and gmerchant without tools the key's fixed scopes never cover (gmerchant lists 153, not 161).

Not changed

  • tools/...
Read more

v1.36.1

Choose a tag to compare

@FiredMosquito831 FiredMosquito831 released this 31 Oct 07:16
28aecfb

This release carries 1.35.2, 1.35.3, 1.35.4, 1.35.5, 1.36.0 and 1.36.1.

1.36.1 - 2026-10-31

Fixed: api_describe and api_call read the Discovery document where Google serves it

  • api_describe and api_call read a method's full Discovery document (cached seven days) from https://www.googleapis.com/discovery/v1/apis/<api>/<version>/rest. Google serves many documents only on the API's own host: that path answers 404 for them (checked 2026-10-31 with GET: every Merchant API version, Gmail Postmaster Tools v1, Analytics Admin v1alpha, Vertex AI v1, Drive Labels v2beta; Compute v1, Android Management v1 and Drive v3 answer 200 there), and Google's directory lists 387 of the 396 gateway APIs at https://<api>.googleapis.com/$discovery/rest?version=<version>. For those, both tools failed before any request with "Could not fetch the Discovery document ... HTTP 404"; the gateway of gmerchant (since 1.35.2 on Merchant API v1) and the worked example in docs/USING.md (Analytics Admin v1alpha) were among them.
  • When the directory path answers 404, the gateway now reads the document from the API's host, built from the catalog's rootUrl (plain https under googleapis.com only). Any other failure (5xx, 403, a timeout) is reported as before, with the same text, and an entry with its own URL (the supplemental ones, such as Google Ads) is read from that URL only. Checked against Google's public documents (no key, no sign-in): on 1.35.1, api_describe of merchantapi.accounts.products.get and of analyticsadmin.accountSummaries.list failed with HTTP 404; now both read the document from the host (merchantapi.googleapis.com, analyticsadmin.googleapis.com).

Not changed

  • Tool maps, tool kinds, tools/list and scopes. No Google API was called.

1.36.0 - 2026-10-31

Changed: a full gapps login no longer asks for the whole mailbox; --with mail asks for it

  • scripts.run (Apps Script) lists twelve scopes Google accepts for it, https://mail.google.com/ among them (the whole mailbox, permanent deletes included). The full profile takes the broadest, shortest scope, so every --profile full gapps login asked for the full Gmail scope only to run scripts; readwrite took userinfo.email for the same tool.
  • gapps gets a scope policy in config/products.json: the optional part mail (the full Gmail scope; as gyoutube's monetary, 1.35.0) and the preference full: userinfo.email (as gmeet's, 1.33.0). Without the preference, full would have taken the next-shortest scope of scripts.run, the legacy Contacts scope https://www.google.com/m8/feeds. Now full asks for what readwrite asks for; --with mail (in the chat: auth_login with "with": ["mail"]) adds the full Gmail scope, for a script that uses Gmail.
  • readonly and readwrite ask for the same scopes as before, with every toolset (tests compare them with the requirements without the policy). readwrite and full gain a Held back: line that names the part and how to add it.
  • An account that already holds https://mail.google.com/ keeps it: the scope stays in the group's scopes (Gmail's tools use it too), so a login that names the account merges it, and one that does not name it and would drop it saves nothing (the rule of 1.1.2; tested).

Not changed

  • Tool maps and tool kinds. tools/list changes only for auth_login on gapps, which takes with (mail). gsm scopes over all 207 cases against 1.35.5: 201 identical; the 3 gapps full cases ask for userinfo.email instead of https://mail.google.com/ with the same tools covered, and the 3 gapps readwrite cases only gain the Held back: line. Not checked against live Google.

1.35.5 - 2026-10-31

Fixed: gsearch says which tools an API key cannot run

  • gsearch signs every call with an API key, and ten of its tools are not expected to work that way. They stay (coverage), and their descriptions now say why:
  • New data in config/products.json: methodNotes, per generated API of a product, a note for single methods ({ source, reason, methods: { "<method id>": "<note>" } }). Only that method's tool carries it, after the API's note from config/tool-kinds.json (which every tool of the API carries): Note: <API note> <method note>. gen-servers checks each method id against the API's snapshot and copies the notes into config/servers.json and the plugin's servers.json; both registry loaders carry them. A product without notes is described as before.

Not changed

  • Tool maps, tool kinds and scopes. tools/list changes only for those 10 gsearch tools (4 of them with writes off: the two Fact Check page reads and the two Web Risk operation reads), in their descriptions. Not checked against live Google.

1.35.4 - 2026-10-31

Fixed: chat_list_messages orders messages with the direction Google documents

  • chat_list_messages sent orderBy as create_time desc (or create_time asc with order: oldest). Google lists the directions in upper case: "Valid ordering operation values are as follows: - ASC for ascending. - DESC for descending. The default ordering is create_time ASC." (spaces.messages.list, the Discovery document and the proto; https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/list shows the same text with the field rendered as createTime). It now sends create_time DESC and create_time ASC.
  • The field name stays create_time, in orderBy and in the time-window filter: it is how the proto, the Discovery document and its filter examples (create_time > "2012-04-21T11:30:00-04:00") spell it. The REST reference page shows createTime in the same sentences, because that page renders field names in their JSON form; it does not show create_time as wrong. chat_search_messages is unchanged: its request documents create_time desc in lower case ("Only descending order (desc) is supported").
  • tests/curated-contract.test.mjs rows can pin the query values a tool sends (sends); the two chat_list_messages rows do.

Not changed

  • Tool maps, tool kinds, tools/list and scopes. Whether Google also accepts the lower-case direction was never checked; nothing was checked against live Google.

1.35.3 - 2026-10-31

Fixed: Search Console no longer offers what Google retired or deprecated

  • The Mobile-Friendly Test tool is gone. Google: "Also starting December 1, 2023, we'll be retiring Search Console's "Mobile Usability" report, the Mobile-Friendly Test tool and Mobile-Friendly Test API." (https://developers.google.com/search/blog/2023/04/page-experience-in-search). The generated searchcons_url_testing_t_mobile_friendl_run still registered, even before a login (Discovery lists no scope for it), and with writes on it could be called. It is left out by data: gsc's searchconsole entry in config/products.json now has an include list (sites, sitemaps, searchanalytics, urlInspection.index) that covers every other method. gsc has 19 generated tools (was 20). A resource Google adds to the API later is not generated until it is listed.
  • sc_search_analytics_query sends the search type as type. Google's reference marks searchType "Deprecated, use type instead" (https://developers.google.com/webmaster-tools/v1/searchanalytics/query). The argument was already called type, and its default is still web; the request body keeps its field order.
  • Descriptions stop advertising deprecated fields: sc_sitemap_get no longer promises "indexed URL counts" (Google: WmxSitemapContent.indexed, "Deprecated; do not use.") and points to sc_url_inspect for whether a page is indexed; the google toolset notes of sc_sitemaps_list and sc_url_inspect no longer list indexed counts and mobile usability (mobileUsabilityResult is marked deprecated in Discovery). docs/products/gsc.md says what Google says now.
  • tests/curated-contract.test.mjs also treats a body field as deprecated when Google's reference page says so and Discovery does not (DEPRECATED_IN_REFERENCE, one entry: SearchAnalyticsQueryRequest.searchType).

Not changed

  • Tool kinds. The tool maps lose one entry, the Mobile-Friendly Test tool; nothing else changes. tools/list: gsc with writes on lists 37 tools (was 38); sc_sitemap_get and api_methods (19 methods) change their descriptions; with writes off only sc_sitemap_get and api_methods change. gsm scopes over all 207 cases: the same scopes everywhere; gsc all counts one tool fewer as covered in each profile. Not checked against live Google.

1.35.2 - 2026-10-31

Fixed: gmerchant uses the Merchant API versions Google serves

  • Google discontinued Merchant API v1beta: "The Merchant API v1beta version discontinued. All API calls must now be directed to the v1 or v1alpha versions." (May 2026, https://developers.google.com/merchant/api/latest-updates; the v1beta reference pages were removed in October 2026). gmerchant's gateway still reached 12 *_v1beta APIs, and its 8 Reviews tools called Reviews v1beta, so the curated toolset (the gateway tools) and every review call went to a discontinued version.
  • The gateway now reaches the same 12 sub-APIs at v1 (accounts, conversions, data sources, inventories, ...
Read more