Repository navigation
Releases
Releases · FiredMosquito831/google-services-mcps
v2.17.0
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_metareturned 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-writtenga_get_metadatatakes 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 takessearch,category,limit(25 by default) andoffset.custom_only: falseasks for Google's whole catalogue; fields that do not fit the result limit are left out of the larger list, andnext_offsetcounts only the fields shown. - The generated tool keeps its own name in
allandcurated; in thegoogletoolset the new tool takes its place, as it does the same method better.ga_run_reportand the structured query fields now point atga_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_metadatais the one addition, a read with theanalyticsandanalytics.readonlyscopes the generated tool already listed, sogsm scopesasks for the same scopes in every case (compared across the business group: no scope URL added or removed).tool-aliases.jsonis 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_countandnext_offset, whichreportAnswerputs 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_metadatawas 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 withlimitandoffsetandnext_offset, the notes for no match and for the property having no custom fields, and the tool's scopes. tests/curated-contract.test.mjs: twoga_get_metadatarows againstanalyticsdata.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
googletoolset'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
readonlylogin cannot read comment threads (youtube.force-sslhas no read-only form). The example says which login it needs.
Not changed
- No tool's kind, scope, name, request or toolset list: the
googlelist is still 17 tools andgsm scopesasks for the same scopes in every case.tool-aliases.jsonis untouched, and the frozen files and the goldens have no diff. - Verified and left as they are:
videos.updatehas been destructive since 1.26.3 and the note tells a caller to send the whole part (F1);liveStreams.listnever returns the stream key, whichsrc/core/credential-fields.tsredacts (IngestionInfo.streamName, F2); the fourreports.queryparameters Discovery marks "required: true" are required in the tool since 1.30.1 (requiredByText), and the parameter descriptions are no longer clipped, sochannel==CHANNEL_IDandchannel==MINEare 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
alltoolset still lists the junk methods the review named (youtube_tests_insert, the server-streamed live chat method, four unscopedthird_party_linkswrites), 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_updatedandmbveri_locations_merchant_state(getVoiceOfMerchantState), plusmbaccount_accounts_admins_list. The list is 13 tools. bpperf_loc_get_dai_met_tim_serileaves the list because its 15-argument shape (six date parts and fivedailySubEntityTypefields, which Google's own text calls unsupported) is covered bybpperf_locations_time_series, which takes one metric or several and was already in the list. The generated tool stays inallandcurated, 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 namesgetGoogleUpdatedand 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 anincludelist and a decision on where those tools belong. It also says why the flat performance call left thegooglelist and that the 15-argument form stays inall.
Not changed
- No tool's kind, scope, name or request: the map is byte-identical,
gsm scopesfor the business group asks for the same scopes in every case (compared: no scope URL added or removed), andtool-aliases.jsonis untouched. The frozen files and the goldens have no diff. - Verified and left as they are:
admins.create,admins.patch,locations.transferand admin deletes have been destructive since 1.26.3, so they ask twice (review F6). Parameters Google's text marks "Required." —readMaskand 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.manageand theNot 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
googlelist 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 (theNot 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_metadataandads_mutatenow takelogin_customer_id, sent as Google'slogin-customer-idheader for that call only; without it the configured account applies, as before. customer_idandlogin_customer_idare taken with or without dashes, and as a number: the Ads UI shows123-456-7890and 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...
v2.12.0
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.tsskips them, andapi_callrefuses them), and Play'sedits.bundles.uploadis 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.aaband, optionally, anedit_id, atrack, the release's status,user_fraction, a name and release notes, andcommit.- 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 whencommitis true. Without it the edit stays open and the answer says how to finish it:androidpub_edits_commitpublishes,androidpub_edits_deletedrops it, and Google discards an edit nobody commits. - A staged rollout is
release_status: "inProgress"withuser_fraction(0 to 1); a call with one and not the other is refused before any request, as is a file that is not.aaband 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 withcommit: trueis gated as destructive (publishing is), so it asks twice.
- It creates an edit when none is given (or uses the one given), uploads the file as a stream through the media-upload endpoint (
Fixed (docs): the build upload, the zero-touch tools and a stale kind
- The product page said nothing about uploading, so
androidpub_edits_commitcould 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_commitas a plain write; it has been destructive since 1.26.3. - The 27
androiddeviceprovisioningtools 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 forandroidworkzerotouchemmorandroidworkprovisioning, and Google answers 403 (review F4). Making them work needs ascopeOverridesentry 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, withandroidpublisher), and every other entry is byte-identical. Thegoogletoolset still lists its 16 tools.gsm scopesasks for the same scopes in every case but one: with thecuratedtoolset,readwriteandfullnow listandroidpublisher, 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 (curated9 → 10 tools).tool-aliases.jsonis untouched, and the frozen files and the goldens have no diff. src/servers/cloud-http.tstakesPUTamong 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
queryreads) was fixed in 1.26.3, and F2 (getServiceAccountas 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(andbatchMigratePrices) andandroidmanagement.devices.issueCommandall 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 movesnext_page_tokento the front of a result; a test now proves it for these answers. Still open and reported: thegooglelist's Publishing half (the review would dropandroidpub_edits_tracks_listandandroidpub_reviews_replyand add the Vitals reads), the Reporting limits in the reviews and vitals descriptions (F8), the service-account key's 12 fixed scopes (F9, touchesauth.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 againstedits.bundles.upload,edits.insert,edits.tracks.get,edits.tracks.updateandedits.commit, withandroidpublisher.v3added 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-accountoutput,gsm login, the guided flow,gsm explain, the chat toolauth_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_ONLYwhen they only read ("Has access to the same read-only methods as STANDARD, but no access to any mutating methods"),STANDARDto change product data, andADMINonly for accounts and users. The rights are Discovery'sUser.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
contentscope reaches (the 13 Merchant API v1 resource APIs, Reviews v1alpha and the CSS API) and that Manufacturer Center, which declares onlymanufacturercenter, 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
googletoolset'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 scopesfor every group, profile and toolset is byte-identical, the tool maps are unchanged, andtool-aliases.jsonis untouched. tools/list changes only forauth_setup_service_accounton 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.renderaccountissuesandrenderproductissuesare reads (their output is "meant to be rendered and shown in third-party applications");merchantapi.accounts.developerRegistration.unregisterGcpandmerchantapi.accounts.homepage.unclaimare 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_configtools returned it that way, where Google's ownget_sdk_configdecodes it (adversarial review of gfirebase, F2). The new hand-writtenfirebase_get_sdk_configtakes a project and an app id (its platform decides which configuration is read) or aplatform, picks the first app of that platform when no id is given (web, then Android, then iOS otherwise), and answerssdk_configas the text ofgoogle-services.jsonorGoogleService-Info.plistwith 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 assdk_config_base64with a note saying so. - It matches Google's
get_sdk_config, so in thegoogletoolset it takes the place of the three generated per-platform tools. They stay inallandcurated, so nothing is lost there.
Added: the operation poller and the rules release lookup in the google toolset
firebase_operations_getandfirebaser_projects_releases_getjoin it (review F3): a create in this product returns a long-running Operation, and without the poller a caller had to reach forapi_call, which thegoogletoolset 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...
v2.9.0
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_courseworkmakes 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 asYYYY-MM-DDandHH:MMread in a time zone (Classroom keeps the pair in UTC), a schedule, individual students and the submission mode. It is a draft unlesspublishis true orscheduled_timeis 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_courseworkchanges only the fields you pass (they build Google'supdateMask), takes a field away withclear, and sets the students throughcourseWork.modifyAssignees(the adds and removes worked out from a read of the item). Both work their approval out inprepare, 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_patchandclassr_work_modify_assigneesin thegoogletoolset, which now holds 19 tools: those three took a rawCourseWorkbody or a rawupdateMask, with a description that had lost the field list and Google's project rule. Both tools match Google'screate_course_workandupdate_course_workin 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 forcourseWork.create,patchandmodifyAssignees, so no login's scopes change:gsm scopesfor 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.patchandcourseWorkMaterials.delete, and those tools have carried it whole since 1.29.1 raised the description limit;courseWorkMaterials.patchleaves it out, so its tool carries amethodNote(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.mdsaid the plugin has 119 tools, that the plugin optiongooglelists 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_createandclassroom_materials_patchkeep their generated form, so a material can still be made and changed with a raw body.tool-aliases.jsonis 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) andclassroom_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 whatnext_page_tokenis 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.createandclassroom.courses.teachers.create, which add a person to a course;classroom.courses.students.deleteand both invitation creates already ask twice, and an announcement that publishes does too (1.26.3). Raising the two creates means entries inconfig/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_linkuses the raw course id (F12, UNVERIFIED);checkRubricdoes 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 thepreparethat names the course);update_coursework(the mask from the fields passed,clear, themodifyAssigneesadd and remove, three refusals,destructiveWhen, and thepreparethat names the item); and the same-project text. tests/curated-contract.test.mjs: rows for both, againstcourseWork.create,courseWork.patchandcourseWork.modifyAssignees(160 curated tools). tests/curated.test.mjs and tests/toolset.test.mjs: the 16 curated tools and the 19-toolgooglelist.
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_listwants a raw readMask, a sort order and a page size from the caller.contacts_listsets the readMask (names, email addresses, phone numbers, organizations;fieldspicks 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 areadonlylogin 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.deleteContactshowedpeople/c123...and nothing else (review F5).contacts_deleteworks the read out inprepareinstead: 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
contactswrite scope.src/servers/cloud-http.tstakesDELETEfor 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 anddocs/USING.mdsaid 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'ssearchContactstext), 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 gcontactsgoogletoolset is still Google's three reads: the two new tools are not in it.tool-aliases.jsonis 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.*.rollUpanddailyRollUpare reads (1.26.3, F1); Health webhooks and Data Portability are optional parts, so a contacts login no longer asks forcloud-platformor 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.profileis preferred by every profile since 1.35.1, soprofile_mereturns 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].displayNameandemailAddresses[0].value. That issrc/core/target-preview.ts, a rule for every product's approvals, so it is not here. - Reported, not changed:
personSummarystill 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.batchDeleteContactsandpeople.contactGroups.deletekeep 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 forpeople/me, the readMask, the page size, the sort order, the page token, the total, the schema limits),contacts_delete(theprepareread and the names it shows, the DELETE alone, and the same request when called withoutprepare), 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 themeetmodule 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_moveandtasks_tasklists_insertjoin the list, which now holds 10 tools (adversarial review of gtasks, section C). Both already existed in thealltoolset: 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...
v2.5.0
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.runan empty description, so the generated tool said only that it calls the method, and thescriptIdtext 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 amethodNote(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) andappsscript_projects_versions_list(a read) join thegoogletoolset, which now holds 10 tools (review F8). Redeploying needs the update:deployments.createmakes a new deployment each time, with a new id and a new web-app URL, whiledeployments.updatekeeps the deployment id and its URL and points it at another version. Both tools already existed in thealltoolset and need no new scope (script.deploymentsandscript.projects.readonlyare already in the cover), sogsm scopesfor gapps is identical in every profile and toolset; the covered counts move (googlereadonly4 → 5 of 10,readwriteandfull8 → 10 of 10).
Fixed (docs): how to set up a script for scripts.run
docs/products/gapps.mdsaid the setupscripts.runneeds 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.jsonis untouched, and every other product is unchanged.gsm scopesfor 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
erroron the Operation, soisErroris 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 samerequestIdreasoning as Chat does not exist here).
Tests
- tests/method-notes.test.mjs: the
script.scripts.runnote 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_getandadmin_orgunit_getjoin thegoogletoolset, which now holds 12 tools (adversarial review of gadmin, section C). Both were already curated tools (Directory APIgroups.getandorgunits.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.readonlyandadmin.directory.orgunit.readonlywere already in thereadonlycover and in thereadwritepreference, sogsm scopesfor gadmin is identical in every profile and toolset; only the covered counts move (googlereadonly7 → 9 of 12,readwriteandfull10 → 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 underadmin.directory.groupand.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:groupscomes backnullwith 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.jsonuntouched).
Fixed: the four curated admin deletes show what they delete
admin_user_delete,admin_group_delete,admin_member_removeandadmin_orgunit_deletehad apreviewthat the gate never showed (onlypreparereaches the approval; learning of 2026-10-31), so the form showed the raw key you passed. Each now works the same read out inprepare, 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, andprepareonly reads.
Fixed (docs): a doubled period on eight capability pages
scripts/gen-capabilities.mjsadds a period after asourcethat is a sentence, and eight products' sources already end with one, so theirdocs/capabilities/<id>.mdread "…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_getand nothing else; the gapps, gchat and every other product's tool map,tools/listand scopes are byte-identical to 2.3.0.gsm scopesfor 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 insrc/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 doctorcan 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 thegooglelist gains. - tests/curated-contract.test.mjs: the four rows run
prepareinstead ofpreview(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_settingsandchat_update_notification_settingsreplace the generatedchat_spaces_space_notif_setting_getandchat_spaces_space_notif_setting_patchin thegoogletoolset, 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,updateMaskand body, and they return the setting. The update buildsupdateMaskfrom what the call passes, refuses a call with neither field before any request, and is awritethat asks once: it changes your own setting and can be changed back at once, so it is not destructive. Google marksupdate_notification_settingsidempotent and so does ours.FOR_YOUis 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'sget_notification_settingsasks for it and the Chat API has no read-only scope for it (spaceNotificationSetting.getlists only that scope), so areadonlylogin does not list the read.
Changed: a readonly Chat login asks for the read-state scope, so unread_only works
chat_search_messagestakesunread_only, which sendsis_unread(); Google's message-search page gives that filterchat.users.readstateor.readonly. Thegoogletoolset'sreadonlyprofile asked for neither, so the search was refused at Google. The tool now declareschat.users.readstate.readonlyas well, and gchat'sscopePolicy.prefernames it forreadonly, so areadonlylogin of thegoogleorcuratedtoolset asks for it. Readwrite is unchanged: the greedy cover still takeschat.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.botandchat.importnext to the user scopes, so areadwriteorfulllogin of the defaultalltoolset asked a person to grant an app's scope (gsm scopesprintedchat.botandchat.import). gchat'sscopePolicy.onlyInnow lists both with an empty profile list, as Gmail does forgmail.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 tochat.delete, the shortest scope it accepts. - An account that already holds
chat.botorchat.importkeeps them: both stay in the group's scope universe, so the stored-scope merge keeps them and its tools load. Only a login that ...
v2.2.0
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_policysent an emptyGetIamPolicyRequest, 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 sendsoptions.requestedPolicyVersion: 3, the field Discovery'sGetPolicyOptionsdocuments ("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
googletoolsetsourceURLs underdocs.cloud.google.comthat ended in/tools_listanswered 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(methodbigquery.jobs.query) is a plainwrite, so underconfirmation: destructive-onlyaDROP TABLE,DELETE,MERGEor script runs without a prompt: a write runs unasked in that mode and onlydestructiveasks (src/core/policy.ts,defaultDecision). The 12setIamPolicytools of this server already ask twice since 1.26.3, and the gateway'sapi_callasks 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 callsbigquery.jobs.insert, whose Discovery scopes arebigquery,cloud-platformanddevstorage.*only: areadonlylogin holdscloud-platform.read-only, which that method does not accept, whilebigquery.jobs.querydoes listcloud-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 tojobs.querywithdryRun, or change the tool's scopes; both change behaviour, so neither is here.- Google's
googletoolset parity: 21 official tools (5 Logging, 12 Cloud Billing, 4 IAM role) have no tool here and are reachable only throughapi_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 thegooglelist, 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 scopesare byte-identical, and the frozen files and goldens are untouched.
Tests
- tests/cloud-parity.test.mjs:
cloud_project_iam_policysends{ options: { requestedPolicyVersion: 3 } }toprojects/{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_filerenames a file (name), moves it (parent_id, oradd_parent_idandremove_parent_idone 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 thegoogletoolset. It sends Drive'sfiles.update, which is a PATCH: only the fields given change, and every other field keeps its value.parent_idreads 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 nomime_type, because Drive converts a Google file when that field changes (review of gdrive, G2).drive_untrash_filerestores a file from the trash, the inverse ofdrive_trash_file, with its folder and sharing kept. Both work their approval out inprepare, 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_textreads JSON, XML (SVG included), YAML, TOML, CSV and source-code types as text, as it readtext/*: the check isisTextMime, soapplication/jsonno 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 namesdrive_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 insheet_notewhen there is more than one. A newsheetargument reads a named sheet throughspreadsheets.values.getand 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
alltoolset carries Google Books (51 tools) and the Drive Labels API (25 tools and 25 gateway methods), so analllogin used to ask forbooks,drive.labelsanddrive.labels.readonly(review of gdrive, G8). They are now optional parts (scopePolicy.optionalin config/products.json), like Gmail'spostmaster: no profile asks for their scopes unless the login names them with--with books,labels(in the chat,auth_loginwith"with"). Anallreadwriteorfulllogin now asks fordrive,drive.activityanddrive.apps.readonly; areadonlyone fordrive.readonly,drive.activity.readonly,drive.apps.readonlyandforms.responses.readonly. - Named, a login asks exactly what it asked before:
gsm scopesfor 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. Thegoogleandcuratedtoolsets list no Books or Labels tool and resolve exactly as before. - The
googletoolset'ssourcewas 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_downloadalready 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 nosave_to_pathand 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):
isTextMimeand the CSV renderer;drive_update_file(a rename and a star in one PATCH with no read, a move that reads the folders then sendsaddParents/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_fileanddrive_trash_fileapprovals (preparereads, sizes and effects, and the same request as before);drive_read_textfor 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, theHeld 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
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 (configurationstoconfigs,accountstoaccts,permissionstoperms, …), then a resource that repeats the API prefix goes, then a resource is reduced to its head word (managedFolderstofolders, but not to a word that says nothing:smimeInfokeepssmime), 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:asyncBatchAnnotatemust not read likeannotate). 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.
gcloudmonitor_projects_metric_descri_listismonitor_metric_descriptors_list;gmailgmail_users_settin_send_as_smime_i_listisgmail_send_as_smime_info_list;gdrivedrivelabel_labe_revi_permi_batch_52b2isdrivelabel_revs_perms_batch_delete;gaidiscoverye_projec_locati_collec_engine_listisdiscoverye_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/callwith 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/listlists each tool once, under its new name; the old names are not listed.- A
policy.jsonrule 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 adenyon 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.
toolsetlists (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.annotateand its neighbour) both readvision_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. projectsandlocationsare dropped where the budget needs it, somonitoring.projects.alertPolicies.deleteismonitor_alert_policies_deletewhilemonitoring.projects.groups.deletekeeps itsprojects(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/listshows 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
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,generateKeywordHistoricalMetricsandsuggestKeywordThemes, and Vertex AIcountTokensin 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 aPOSTwith no read rule is a write. - What the user sees:
googleads_customers_generate_keyword_ideais listed with writes off (gads lists 133 tools instead of 132), and the six gateway methods no longer prompt throughapi_call.gsm scopesasks 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,suggestKeywordThemesandgenerateKeywordForecastMetrics, Google AdsgenerateKeywordForecastMetrics, Firebase MLcountTokensand Geminigenerativelanguage.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-
GETmethod 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", andcountTokensheld "token". Google AdsgenerateKeywordIdeasand Vertex AIcountTokenswere writes only through that accident (Q1 of the 2026-10-30 review). hasCredentialWord(methodWords+CREDENTIAL_WORDSin 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:generateKeywordIdeasis generate, keyword, ideas andcountTokensis count, tokens. The words aretoken,credential,secret,passwordandkey;authorizstays 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
POSTor aPATCH, and aPOSTis 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 AIcountTokensandcomputeTokens(16 bindings), Google Ads and Search Ads 360generateKeywordIdeas,generateKeywordHistoricalMetrics,suggestKeywordThemesandgenerateKeywordForecastMetrics, Identity ToolkitgetPublicKeysandgetSessionCookiePublicKeys, Cloud KMSgetAutokeyConfigandshowEffectiveAutokeyConfig, DataprocinjectCredentials, VMware EngineresetVcenterCredentialsandresetNsxCredentials, WorkstationspushCredentials, Tag Managerreauthorize, GamesretrieveTokensandgamesPlayerTokens,oauth2.tokeninfoandwebcontentpublisher.users.generatePlatformSiteTokens. - So no
writeentry was needed in config/tool-kinds.json, and none was added. Making the four methods the decision namesgenerateKeywordIdeas,generateKeywordHistoricalMetrics,suggestKeywordThemes(and the Search Ads 360 copies) and Vertex AIcountTokensreads needs a further decision: an exactreadentry in config/tool-kinds.json, or the names inREAD_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 asCLAUDE_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 readGSM_TOKEN_DIRonly, so with a customtoken_dirit readpolicy.jsonfrom the default folder while the server's gate read the custom one: adenyrule 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 asloadConfigdoes:GSM_TOKEN_DIR, elseCLAUDE_PLUGIN_OPTION_TOKEN_DIR, else~/.google-services-mcps. Both values go throughoptionValue, so an empty value and an unexpanded${user_config.token_dir}still mean unset (1.37.1), andGSM_TOKEN_DIRstill wins when both are set. The hook reads nothing else from that folder:policy.jsonis 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, anallowand anaskrule in a folder named only byCLAUDE_PLUGIN_OPTION_TOKEN_DIR, withGSM_TOKEN_DIRwinning 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 scopesand every request. A hook with no plugin option set resolves the folder it resolved before.
by FiredMosquito831
v1.41.1
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_deleteandsc_sitemap_deleteare 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'spreparereaches the approval, so the form showed the raw arguments (review of gsc, F6). The preview is now worked out inprepare, 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.tsis unchanged: the same gate pathgmail_sendandcalendar_delete_eventuse.
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_querytakes what Google'ssearchAnalytics.querytakes (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'smetadata.first_incomplete_datesays where it starts) orhourly_all("hourly breakdown", for thehourdimension;metadata.first_incomplete_hour).- the
hourdimension. aggregation_type:auto,byPage,byPropertyorbyNewsShowcasePanel, with Google's limits in its description.filters: a typed list of{ dimension, operator, expression }(dimensionsquery,page,country,device,searchAppearance; operatorsequals,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 untypeddimension_filter_groupsstill 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
metadataobject comes through in the answer.
Fixed: smaller Search Console gaps
sc_url_inspectsays 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, sohttps://Example.com/xbelongs tohttps://example.com/; a page whose host only starts with the property's (https://example.coagainsthttps://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 issc-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.freebusyandcalendar.events.readonly(https://developers.google.com/workspace/calendar/api/guides/configure-mcp-server, "paste the scopes for the Google Calendar MCP server"). Areadonlylogin withtoolset: googleasked forcalendar.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 itsreadwritelogin has asked forcalendar.events,calendar.calendarlist.readonlyandcalendar.events.freebusysince 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
readonlyprofile may ask for (VIEW_ONLY_SCOPES):calendar.events.freebusy("See the availability on Google calendars you have access to") andcalendar.freebusy("View your availability in your calendars"), quoted from https://developers.google.com/identity/protocols/oauth2/scopes. Their names do not end inreadonly, so before, noreadonlylogin could take them. - A token that holds
calendar.readonlykeeps every tool: each tool still accepts it.
Not changed
gsm scopesover all 207 plugin, profile and toolset cases: 206 identical; gcalendarreadonlygoogleasks forcalendar.calendarlist.readonly,calendar.events.freebusyandcalendar.events.readonlyinstead ofcalendar.readonly, with the same tools covered. Theallandcuratedtoolsets of gcalendar still ask forcalendar.readonly(andcalendar.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 intime_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_eventandcalendar_update_eventsend it as Calendar takes it:dateTimewithout an offset andtimeZone(Discovery, EventDateTime: "A time zone offset is required unless a time zone is explicitly specified in timeZone"). Withouttime_zone, the calendar's zone is read first (oneevents.listrequest for itstimeZonefield, a read with the scopes the tools already have);calendar_update_eventtakes the event's own zone when it has one.calendar_list_events,calendar_freebusyandcalendar_suggest_timeturn it into a UTC instant (Calendar takestimeMinandtimeMaxwith an offset only).calendar_freebusytakestime_zone(also the zone of its answer,FreeBusyRequest.timeZone);calendar_suggest_timeanswers 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_zonewhose offset at that moment differs, the answer has atime_note: Calendar keeps the instant the offset gives, so the event is not at that hour oftime_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_eventpatched the start alone, so moving an event later gave an empty range (refused by Google) or shortened it (F3). Now astartwithoutendreads 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 saysduration_kept. A date for a timed event (or a time for an all-day one) cannot keep a duration, and the error asks forendtoo. Withstartandendboth, the request is as before (one PATCH, no read). time_zonewithoutstartorendwas 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) andavailability(busy or free, Calendar's transparency) on both;attachmentson create andadd_attachments/remove_attachmentson update: links to files (for Drive, the file's link), at most 25 per event (Discovery, Event.attachments), sent withsupportsAttachments=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_typeon create:focusTime,outOfOfficeandworkingLocation, withauto_decline,decline_message,chat_statusandworking_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...
v1.38.3
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_adminfor 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 (toolsetCountwithout 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_serverfrom the hook input: "For an MCP tool, the input also carriesmcp_server, an object with the server'snameand asourcethat says where the server's definition came from. Thesourcevalues includeplugin,sdk, and configuration scopes such asuserandproject. ... Base trust decisions onsourcerather than onnameor themcp__<server>__tool-name prefix. Themcp_serverfield requires Claude Code v2.1.274 or later." (same page). Whensourceis a string other thanplugin, 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: whenmcp_serveror itssourceis missing or not a string (an older Claude Code), the hook decides by the tool name exactly as before. gsm doctorchecks 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.mjsexpects 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 withmcp_serverabsent,source: "plugin", nosource, a non-stringsourceor a non-objectmcp_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 whosesourceisuserorprojectthat 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.jsonnow hashomepage(the product's page,docs/products/<id>.mdon GitHub),repositoryandlicense: "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 asMITorApache-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 validateprints 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
categoryandtags("Free-form category for organizing the catalog", "Free-form tags for search", https://code.claude.com/docs/en/plugins/marketplace-reference), fromlistinginconfig/plugin-text.json.
Not changed
- tools/list, server instructions, tool maps and kinds, the hook.
claude plugin validate --strictpasses 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"]: truein tools/list when this server's gate would ask before it (confirmationevery-changeordestructive-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 inacceptEdits,auto, andbypassPermissionspermission 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. IndontAskmode, 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.
bypassPermissionsskips every prompt "except for the actions no mode auto-approves", which lists MCP tools markedrequiresUserInteractionand 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 anElicitationhook 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
askand the marker lead to the same permission prompt, then the server's form, as before. With confirmationoff, or a policyallowrule for the tool, there is no marker, so nothing new asks. Reads, writes,api_calland 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 confirmationoffand a policyallowrule 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 hasauth_setup_clientandauth_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: adescriptionwith the main use cases first and awhen_to_usewith trigger phrases and example requests (Claude Code: "Put the key use case first: the combineddescriptionandwhen_to_usetext 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-apikeyin a terminal for an API key, which is never pasted into the chat), the terminal fallback bynode "${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/...
v1.36.1
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_describeandapi_callread a method's full Discovery document (cached seven days) fromhttps://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 athttps://<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 undergoogleapis.comonly). 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_describeofmerchantapi.accounts.products.getand ofanalyticsadmin.accountSummaries.listfailed 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). Thefullprofile takes the broadest, shortest scope, so every--profile fullgapps login asked for the full Gmail scope only to run scripts;readwritetookuserinfo.emailfor the same tool.- gapps gets a scope policy in
config/products.json: the optional partmail(the full Gmail scope; as gyoutube'smonetary, 1.35.0) and the preferencefull: userinfo.email(as gmeet's, 1.33.0). Without the preference,fullwould have taken the next-shortest scope ofscripts.run, the legacy Contacts scopehttps://www.google.com/m8/feeds. Nowfullasks for whatreadwriteasks for;--with mail(in the chat:auth_loginwith"with": ["mail"]) adds the full Gmail scope, for a script that uses Gmail. readonlyandreadwriteask for the same scopes as before, with every toolset (tests compare them with the requirements without the policy).readwriteandfullgain aHeld 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_loginon gapps, which takeswith(mail).gsm scopesover all 207 cases against 1.35.5: 201 identical; the 3 gappsfullcases ask foruserinfo.emailinstead ofhttps://mail.google.com/with the same tools covered, and the 3 gappsreadwritecases only gain theHeld 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:
- Fact Check Tools
pages.create,.get,.list,.updateand.delete: "Requires the following OAuth scope: https://www.googleapis.com/auth/factchecktools" (https://developers.google.com/fact-check/tools/api/reference/rest/v1alpha1/pages/create and the other method pages). - Web Risk
projects.submissions.create: "Only allowlisted projects can use this method during Early Access." (https://docs.cloud.google.com/web-risk/docs/reference/rest/v1/projects.submissions/create); "We no longer accept new contracts or expansions for the Web Risk Submission API." (https://docs.cloud.google.com/web-risk/docs/submission-api), whose example sends an OAuth token. The fourprojects.operationstools (get, list, cancel, delete) follow a submission.
- Fact Check Tools
- 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 fromconfig/tool-kinds.json(which every tool of the API carries):Note: <API note> <method note>.gen-serverschecks each method id against the API's snapshot and copies the notes intoconfig/servers.jsonand the plugin'sservers.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_messagessentorderByascreate_time desc(orcreate_time ascwithorder: oldest). Google lists the directions in upper case: "Valid ordering operation values are as follows: -ASCfor ascending. -DESCfor descending. The default ordering iscreate_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 ascreateTime). It now sendscreate_time DESCandcreate_time ASC.- The field name stays
create_time, inorderByand in the time-windowfilter: 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 showscreateTimein the same sentences, because that page renders field names in their JSON form; it does not showcreate_timeas wrong.chat_search_messagesis unchanged: its request documentscreate_time descin lower case ("Only descending order (desc) is supported"). - tests/curated-contract.test.mjs rows can pin the query values a tool sends (
sends); the twochat_list_messagesrows 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_runstill 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'ssearchconsoleentry inconfig/products.jsonnow 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_querysends the search type astype. Google's reference markssearchType"Deprecated, use type instead" (https://developers.google.com/webmaster-tools/v1/searchanalytics/query). The argument was already calledtype, and its default is stillweb; the request body keeps its field order.- Descriptions stop advertising deprecated fields:
sc_sitemap_getno longer promises "indexed URL counts" (Google:WmxSitemapContent.indexed, "Deprecated; do not use.") and points tosc_url_inspectfor whether a page is indexed; thegoogletoolset notes ofsc_sitemaps_listandsc_url_inspectno longer list indexed counts and mobile usability (mobileUsabilityResultis 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_getandapi_methods(19 methods) change their descriptions; with writes off onlysc_sitemap_getandapi_methodschange.gsm scopesover all 207 cases: the same scopes everywhere; gscallcounts 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
v1orv1alphaversions." (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*_v1betaAPIs, and its 8 Reviews tools called Reviews v1beta, so thecuratedtoolset (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, ...