parse-teams-url
Convert any Microsoft Teams meeting URL format (short, full, or recap) into a standard joinWebUrl for consistent access.
Instructions
Converts any Teams meeting URL format (short /meet/, full /meetup-join/, or recap ?threadId=) into a standard joinWebUrl. Use this before list-online-meetings when the user provides a recap or short URL.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Teams meeting URL in any format |
Implementation Reference
- src/graph-tools.ts:152-169 (handler)The execute handler for parse-teams-url that validates the url parameter, calls parseTeamsUrl(), and returns the joinWebUrl or an error.
execute: async (params) => { const url = params.url; if (typeof url !== 'string') { return { content: [{ type: 'text', text: JSON.stringify({ error: 'url is required.' }) }], isError: true, }; } try { const joinWebUrl = parseTeamsUrl(url); return { content: [{ type: 'text', text: joinWebUrl }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ error: (error as Error).message }) }], isError: true, }; } }, - src/lib/teams-url-parser.ts:10-38 (helper)The core parsing function that converts any Teams meeting URL format (short /meet/, full /meetup-join/, or recap ?threadId=) into a standard joinWebUrl.
export function parseTeamsUrl(url: string): string { // Format 1 & 2: Already a joinWebUrl or short /meet/ URL — pass through if (url.includes('/meet/') || url.includes('/meetup-join/')) { return url; } // Format 3: Recap URL — extract params and reconstruct joinWebUrl if (url.toLowerCase().includes('meetingrecap')) { const params = Object.fromEntries( [...url.matchAll(/([a-zA-Z]+)=([^]+)/g)].map((m) => [m[1], m[2]]) ); const threadId = decodeURIComponent(params.threadId || ''); const tenantId = params.tenantId || ''; const organizerId = params.organizerId || ''; if (!threadId || !tenantId || !organizerId) { throw new Error('Invalid recap URL: missing threadId, tenantId, or organizerId parameter'); } const threadEnc = encodeURIComponent(threadId).replace(/%3A/gi, '%3a').replace(/%40/gi, '%40'); const ctx = JSON.stringify({ Tid: tenantId, Oid: organizerId }); const ctxEnc = encodeURIComponent(ctx); return `https://teams.microsoft.com/l/meetup-join/${threadEnc}/0?context=${ctxEnc}`; } // Unknown format — return as-is return url; } - src/graph-tools.ts:149-151 (schema)The Zod schema for parse-teams-url: expects a single 'url' string parameter.
buildSchema: () => ({ url: z.string().describe('Teams meeting URL in any format'), }), - src/graph-tools.ts:247-263 (registration)The registerUtilityToolWithMcp function that calls server.tool() to register utility tools (including parse-teams-url) with the MCP server.
function registerUtilityToolWithMcp( server: McpServer, utility: UtilityTool, ctx: UtilityToolContext ): void { server.tool( utility.name, utility.description, utility.buildSchema(ctx), { title: utility.name, readOnlyHint: utility.readOnlyHint ?? true, openWorldHint: utility.openWorldHint ?? true, }, async (params) => utility.execute(params, ctx) ); } - src/graph-tools.ts:140-146 (registration)The UTILITY_TOOLS array registration entry listing parse-teams-url with its name, method, path, description, schema, and execute handler.
export const UTILITY_TOOLS: readonly UtilityTool[] = [ { name: 'parse-teams-url', method: 'POST', path: 'tool:parse-teams-url', description: 'Converts any Teams meeting URL format (short /meet/, full /meetup-join/, or recap ?threadId=) into a standard joinWebUrl. Use this before list-online-meetings when the user provides a recap or short URL.',