Repository navigation
Meeting transcripts were unreachable end to end. Two independent defects compounded, so a transcript that exists in Teams was reported as one that does not.
Breaking change
graph_get_meeting_transcript_content → graph_get_transcript_content.
The old name is 36 characters, which is 65 with the mcp__plugin_graph-mcp_graph__ prefix a plugin install adds — one over the 64-character limit on a prefixed tool name. The client rewrites an over-length name to a truncated hashed alias that does not route, so the only tool returning transcript text answered No such tool available. Standalone installs, prefixed with only mcp__graph__, were unaffected, which is why it survived.
Standalone MCP installs must update. No alias is kept: a second registration at 65 characters would still be unreachable in plugin installs, so it would only mislead.
Fixed
- Every join-URL meeting lookup was broken.
graph_list_online_meetingsembedded the join URL asencodeURIComponent(join_url)inside its OData literal, and the HTTP layer percent-encoded the query string again, so Graph comparedJoinWebUrlagainst a doubly encoded string that can never match. Every lookup failed with404 3004: Specified meeting is not found— an error that reads as "no such meeting" rather than "the client built the filter wrong". The value now goes in verbatim, with only transport encoding. The''apostrophe escaping that keeps a hostile join URL inside one OData literal is unchanged. graph_list_online_meetingsno longer claims an emptyjoin_url"returns recent meetings". Graph has no unfiltered listing and answers400: One of the required parameters to lookup meeting by QueryOptions is null or empty, so a missing or ambiguous lookup is now reported without spending a request.
Added
graph_get_meeting_idresolves the ID the six meeting tools require, from a calendar event, a Teams join URL, or a meeting chat thread. It prefers the join-URL lookup Graph documents and, when that finds nothing, derivesbase64("1*<organizer object ID>*0**<thread ID>")from the join URL's path segment andcontext.Oid. That composite is what Graph reports asonlineMeeting.id; it previously had to be assembled by hand outside the tool surface from two unrelated calls plus a shellbase64. Single- and double-encoded join URLs both parse.join_meeting_idongraph_list_online_meetings— the numeric meeting ID printed in every invite, spaces tolerated. The only lookup that works for shortteams.microsoft.com/meet/<code>links, which carry no thread ID.- A contract test fails if any tool name exceeds the prefixed 64-character limit, so the next long name breaks the build instead of silently vanishing at runtime. Next longest is
graph_get_channel_message_repliesat 62.
Tool count
126 → 127.
Verification
npm run verify passes on a pristine checkout of the release commit: 1672 tests across 31 files, plus lint, typecheck, build, and the version, package, and lockfile validators. Both installed plugins expose exactly 127 tools.
Confirmed against live Microsoft Graph: the verbatim filter returns the meeting while the previous filter returns 404 3004; the failure reproduced on a meeting organized by the signed-in user, so it was never specific to Microsoft Bookings or shared mailboxes; a hand-derived composite ID is byte-identical to the ID the API reports; and the built bundle resolves a calendar event to that ID, lists its transcripts, and returns VTT.
Full details in CHANGELOG.md and #26.