You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Comparison table: three columns moved again, and the sweep cell for taylorwilsdon changed.npm run table-sources
reported taylorwilsdon, aaronsb and klodr ahead of the recorded revisions; each was brought forward by reading the
diff, with the repository-wide claims re-checked in a fresh checkout. taylorwilsdon (78973045, v2.1.0, 170 commits
on) gained an apply action on its filter tool that translates a filter's criteria into a Gmail search, pages messages.list and relabels the matches through batchModify — the first query-driven bulk path on that column, so the
cell no longer says explicit ids alone. It is labels only, and the ids are never re-checked against live labels, which
the cell and the paragraph under the table now say. aaronsb (14c25e66, v4.6.0) added listDrafts, deleteDraft and createLabel, with the permanent draft deletion added to its no-delete policy — no cell moves; the same round
corrected a count of ours in docs/comparison-sources.json (the 8 September note said fifteen Gmail operations and
listed sixteen; it was sixteen, and is nineteen now). klodr (ddb9da01) moved only its version string. The table
marker stays at 3 September, the Google column's date.
Comparison table: three columns moved at once, and one cell changed.npm run table-sources
reported klodr, a-bonus and taylorwilsdon all ahead of the recorded revision; each was brought
forward by reading the diff and the repository-wide claims re-checked in a fresh checkout. klodr
(2fa333bd) moved for the first time since July and grew a download_all_attachments tool that
carries an output schema of its own, so the structured-outputs cell now says two tools rather than
one — the only cell to change. The same round corrected a sentence of ours: the 3 September note
claimed no occurrence of dmarc or spf in that repository, and src/prompts.ts has carried
"DMARC/SPF failure hints" in a phishing-triage prompt all along — a guess from a header mismatch,
not a read of Authentication-Results, so the cell stays a dash, but the note's zero was wrong and
is now corrected in place. a-bonus (2e40593d) touched no Gmail file: credential-loading error
text, a deferred Google client so the MCP handshake succeeds without credentials, and a Drive
save-path guard. taylorwilsdon (ed70fb90, v1.29.0, 84 commits on) adds a headers-only format
and a label visibility value inside existing Gmail tools, and its two scope files widen the Sheets
and Apps Script levels while the Gmail level table stays as read on 7 September — the second
instance of a level named for one service reaching into another API. Its new schema middleware
rewrites input schemas for Gemini and is not an output schema; output_schema still has no
occurrence there. The README's table note now describes this bring-forward practice instead of
the 18 September state it had frozen at.
Comparison table: the taylorwilsdon column brought forward once more (8475cecf, v1.28.0,
33 commits on), and this time the Gmail file itself moved: gmail/gmail_tools.py +116/-21, with
no tool added or removed. A label update no longer resets the two visibility settings to their
create defaults, an unresolvable thread_id on a draft is now an error instead of a silently
orphaned draft, and emails wrapped inside an email (message/rfc822) are rendered by the read
tools, capped in count and depth. That renderer labels the wrapped headers as claimed by the
attachment and unverified — the closest the repository comes to the subject of the
sender-authentication cell, and it still verifies none, so the cell stands. The four files the
least-privilege and token-encryption cells rest on are absent from the diff; the one
permissions-named test file that grew carries file-limit validation, as on 18 September. The
repository-wide claims were checked at the HEAD in a full checkout: no output_schema, no snooze, no Authentication-Results, no dmarc, GMAIL_METADATA_HEADERS still ends at List-Id, fourteen @server.tool decorators counted again. The other four columns are unmoved
upstream and keep their verified dates — settled on 22 September as the rule for this file: the
date is the day the cells were read, and an unchanged HEAD is not a reading.
get_thread says that full: false keeps authentication — it always did, and the
description never said so. It listed what the sparse fetch drops (bodies, attachment metadata)
and elsewhere that every message carries authentication; that both hold at once was left to be
discovered. A mailbox session discovered it and now relies on it, because it makes an authenticity
check cost no body. A test pins it, so what was an observation about the current build is a
promise the next one has to keep — and the way it could break is specific: the sparse path strips
fields by name, so the risk is a name added to that list, not a change to authentication itself.
Comparison table: the taylorwilsdon column brought forward again (d80ddd92, v1.27.1, 11
commits on), two days after the last round, and this time the diff is not empty where it counts: auth/permissions.py and auth/scopes.py both moved, which are the two files the least-privilege
cell rests on. The change is confined to the chat service — a new chat.memberships.readonly
scope and contacts.readonly added to chat's readonly level and to the read-only scope map —
while the gmail entry in the level table is unchanged and core/tool_registry.py does not
appear in the diff at all. No cell moves. Worth recording anyway, because it is the same caveat
our cell already carries, now visible in his code: a level named readonly pulls in a scope of a
different API, so the level names the intent of the service, not the reach of the grant. gmail/
is absent from the diff; the repository-wide claims were checked at the HEAD in a full checkout,
because a diff cannot carry them — no output_schema, no snooze, no Authentication-Results,
no dmarc, GMAIL_METADATA_HEADERS still ends at List-Id, and the fourteen @server.tool
decorators counted again at this revision rather than carried forward from the correction two
days ago. The other four columns are unmoved upstream, and their verified dates deliberately
stay where they are: a HEAD comparison shows that nothing changed, which is not the same as
having read anything.
Comparison table: the taylorwilsdon column is current again (e844d805, v1.27.0, 16
commits on), brought forward by diff. No cell moves, and this round the Gmail half of the diff is
empty in the strongest sense: gmail/ does not appear in the changed-file list at all, and
neither do auth/permissions.py, auth/scopes.py, core/tool_registry.py or auth/credential_store.py. The weight of the round is Google Docs — a plain-text export path,
document links, markdown — which is outside this table. The one auth file that moved drops the
mirroring of GOOGLE_* into FastMCP's provider environment: bootstrap, not a scope map, despite
the scope-sounding name of the test that shrank with it. The two repository-wide claims were
checked at the HEAD instead of through the diff, because a diff cannot carry them: output_schema
still has no occurrence anywhere, and neither do snooze, Authentication-Results or dmarc.
Said plainly what 0.22.0's call-time scope check does and does not do: it explains a refusal,
it does not prevent one. The request goes to Google and comes back rejected; what changed is that
the answer then names the gap instead of listing every scope that could be missing. A gate that
blocked the call up front would need each method's required scopes, not the tier's — a different
and heavier feature. Prompted by csitte.at, who also corrected a claim we made about aaronsb/google-workspace-mcp when reporting this release: we implied his call-time check reads
the scopes from Google while ours reads the token. It does not — accountAccess in src/factory/safety.ts takes them from readCredential(ctx.account), written once at consent,
and tokeninfo appears nowhere in his repository. Our own docs/comparison-sources.json has
said "read from the credential file" since 8 September; the claim contradicted a check this
project had already done and written down. So the remaining difference is order, not source: his
check blocks before the request, ours explains after it, and a right revoked at Google surfaces
as a 403 for both. 📌 The notes exist so a claim can be looked up instead of reconstructed —
reconstructing one anyway is how a checked fact turns back into a guess.
Fixed
A tool count of ours was wrong for eighteen days:docs/comparison-sources.json recorded
sixteen Gmail tools for taylorwilsdon/google_workspace_mcp from 31 August on, most recently as
“the count of sixteen stands” on 17 September. It is fourteen, and it was fourteen at every
revision we had recorded — counted at cce49e11, 54b1c56 and fb89c818, not inferred from
today's. The miscount therefore sits in the single round that read the file end to end, and the
three diff rounds after it carried the number forward unexamined, because a diff can only say
that a number did not change. No cell moves: the table never named a count, which is why nothing
caught it. The note states the correction where the wrong number stood rather than quietly
replacing it.
The npm wait added for the registry race was itself too short, and asked the wrong question.
It fired for the first time on 0.22.0 and failed the run: npm publish succeeded at 20:37:35,
the thirty 10-second attempts ran out at 20:42:44, and npm records the version as published at
20:43:42 — just over six minutes, against a five-minute budget. For 0.21.0 the same wait
would have cleared in 30 seconds, so the delay is npm's queue and not a constant; the budget is
now ten minutes and still no guarantee. The second half matters more: at 20:43:58 the two npm
views disagreed — /mailwarden/0.22.0 answered 200 while the package document did not list the
version and dist-tags.latest still said 0.21.0, catching up only by 20:45:39. npm install
reads the package document, so a wait that checks the version endpoint alone can go green while
the version is still uninstallable. Both are checked now and must agree, which also makes a
re-run dispatched on a superseded tag wait rather than register it. Parsed with node instead
of jq so the loop can be run where the repository is developed: this step only fires on a tag,
so the main-branch CI never exercises it, and a step only CI can run is a step only CI can debug.
All three cases were run against the live registry before committing.
📌 A retry budget is a measurement, not a guess — and the first thing to check about a wait is
whether it is waiting for the right signal.
Security
Four advisories in the runtime tree closed by moving @modelcontextprotocol/sdk 1.30.0 to 1.32.1.
Dependabot flagged two of them on the 10 October push and npm audit --omit=dev showed four, all
reached through the SDK: proxy-addr 2.0.7 (critical, IP spoofing through an IPv4-mapped IPv6 trust
subnet, GHSA-jqcg-44mw-7w3h), the SDK itself at 1.12.0 to 1.30.1 (high, its OAuth client could be
steered to send credentials to an authorization server the MCP server names, GHSA-6qxp-vccf-f47h), fast-uri 3.1.7 (moderate, host case normalisation, GHSA-hrr3-gc8f-f4qj) and ip-address 10.4.0
(moderate, four subnet and link-local findings, GHSA-2vr4-cq9g-pvrc and others). npm audit fix
resolved all of them inside the declared ^1.30.0 range, so only the lockfile moves: the SDK to
1.32.1, proxy-addr to 2.0.8, fast-uri to 3.1.8, ip-address to 10.7.3 and source-map-js to
1.2.2. Two of the findings are worth placing: mailwarden is an MCP server and never instantiates
the SDK's OAuth client, so the high one had no path here; and proxy-addr is Express's
trust-proxy resolver, which only acts once Express is told to trust a proxy, and --http never
sets that. Build, the full test suite and npm run smoke pass on the new tree; at the time of this
entry the runtime dependency tree carries no known advisory. As before: an audit result is a date,
not a property.