Skip to content
Scalekit Docs
Talk to an Engineer Dashboard

Connect AI agents to the Granola MCP server

Vendor MCP
Open markdown

The Granola MCP connector routes your AI agent's tool calls to Granola's own MCP server through Scalekit. Each user signs in to Granola once, and Scalekit stores and refreshes their tokens, so your agent never handles credentials. It comes with 18 tools.

Tools
18
What they doRead · write · destructive
10 · 7 · 110 read7 write1 destructive
Users sign in with
OAuth app
Scalekit's or your own

What you can do

  • Ask about meetings: answer plain-language questions on discussions, decisions, and action items, with links to source notes
  • List meetings: find meeting notes by time range, folder, or whether the user took part
  • Read meeting notes: fetch private notes, AI summaries, attendees, and details for specific meetings
  • Get transcripts: retrieve the verbatim transcript of a meeting for exact quotes and wording
  • Browse folders: list meeting folders with their descriptions and note counts

Setup

  1. Install the SDK

    Terminal window
    npm install @scalekit-sdk/node dotenv
  2. Set your credentials

    Add your Scalekit credentials to your .env file. Find values in app.scalekit.com > Developers > API Credentials.

    .env
    SCALEKIT_ENVIRONMENT_URL=<your-environment-url>
    SCALEKIT_CLIENT_ID=<your-client-id>
    SCALEKIT_CLIENT_SECRET=<your-client-secret>
  3. Create the Granola MCP connection

    In AgentKit > Connections, create a Granola MCP connection. The name you give it is the connection_name your code passes. See Configure connections.

    Scalekit credentials are available for Granola MCP server, so you don't need to register an OAuth app.

  4. Authorize a user and make your first call

    quickstart.mts
    import { ScalekitClient } from '@scalekit-sdk/node'
    import 'dotenv/config'
    import { createInterface } from 'node:readline/promises'
    const scalekit = new ScalekitClient(
    process.env.SCALEKIT_ENVIRONMENT_URL,
    process.env.SCALEKIT_CLIENT_ID,
    process.env.SCALEKIT_CLIENT_SECRET,
    )
    const actions = scalekit.actions
    const connector = 'granolamcp'
    const identifier = 'user_123'
    // Generate an authorization link for the user
    const { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })
    console.log('Authorize Granola MCP:', link)
    const rl = createInterface({ input: process.stdin, output: process.stdout })
    await rl.question('Press Enter after authorizing...')
    rl.close()
    // Make your first call
    const result = await actions.executeTool({
    connector,
    identifier,
    toolName: 'granolamcp_get_account_info',
    toolInput: {},
    })
    console.log(result)
    Terminal window
    npx tsx quickstart.mts

    Each user signs in once. See Authorize a user for the full flow and statuses.

Tools

Pass the exact name to execute_tool
Try in PlaygroundRequest a tool
  • granolamcp_get_account_infoGet the email, active workspace, and effective note-access scopes for the Granola account currently connected to this MCP session.Read-only

    Granola: Get Account Info

    Get the email, active workspace, and effective note-access scopes for the Granola account currently connected to this MCP session. When to use: - User asks 'who am I signed in as?', 'which Granola account is this?', or 'what's my email?' - User suspects they connected the wrong Granola account - Meeting results may be incomplete or empty because of the user's Granola plan or workspace MCP access controls - Before performing actions, to confirm identity if the user references a specific account When scope-based access controls are active, mcp_note_access.scopes contains the note categories this connection can search: - personal: notes the connected user owns, notes shared directly with them, and notes accessible through private folders - public: notes accessible through workspace-visible Team Space folders - Both scopes means both categories can be searched. These scopes describe access, not who captured or participated in a meeting.

    Inputs

    This tool takes no inputs.

  • granolamcp_get_meeting_attachmentGet up to 5 meeting attachments, such as screenshots of shared screens, as images in request order.Read-only

    Get Meeting Attachment

    Get up to 5 meeting attachments, such as screenshots of shared screens, as images in request order. Provide attachment_ids for a batch or attachment_id for one image. Each image is followed by its metadata; failed attachments return an error with their ID without discarding successful images. A response holds about 6 MB of images, so a batch of large screenshots may leave some out; each one left out returns an error with its ID, so request it again in a separate call. Attachment IDs come from the <attachments> section of get_meetings results. Use this when the description alone does not answer the user's question, for example to read a slide, chart, or code on screen.

    Inputs

    attachment_idstring
    Single attachment ID. Omit both attachment_id and attachment_ids to browse by meeting ID. If both are provided, they must refer to the same attachment.
    attachment_idsarray
    Attachment IDs from the <attachment id="..."> tags in get_meetings results, up to 5 per call; request more in further calls. Omit both attachment_id and attachment_ids to browse by meeting ID. If both are provided, they must refer to the same attachment.
    limitinteger
    Attachments to attempt per page (default/max 5). Only valid when attachment IDs are omitted. Images may be deferred by the response size limit.
    meeting_idstring
    Meeting UUID or public note ID (not_…) that owns the attachments. Required unless note_id is provided, including when attachment_id or attachment_ids is set.
    note_idstring
    Alias for meeting_id. If both are provided, they must refer to the same note (UUID and public note ID may differ).
    offsetinteger
    Starting position in the viewable attachment list (default 0). Use pagination.next_offset to continue. Only valid when attachment IDs are omitted.
  • granolamcp_get_meeting_transcriptGet the full transcript for a specific Granola meeting by ID.Read-only

    Granola: Get Meeting Transcript

    Get the full transcript for a specific Granola meeting by ID. Returns only the verbatim transcript content, not summaries or notes. Use this when the user needs exact quotes, specific wording, or wants to review what was literally said in a meeting. For summarized content or action items, use query_granola_meetings or list_meetings/get_meetings instead.

    Inputs

    meeting_idstringrequired
    Meeting UUID or public note ID (not_…).
    chunk_idsarray
    Read up to ten finalized transcript chunks instead of the full transcript. Use chunk IDs from search_transcripts, or [0] to browse from the beginning. IDs past the last chunk are skipped and listed in ignored_chunk_ids; if none of the IDs exist the status is out_of_range. Returns one verbatim passage per speaker turn with its speaker label (absent for preformatted transcripts) and start time (null when unknown), plus total_chunks and previous/next chunk IDs.
    include_timestampsboolean
    Prefix each reliably timed block with [m:ss], minutes:seconds since the transcript's earliest timed block, not clock time; that block can predate the meeting when recording started early. Applies to every page; chunk_ids reads ignore it. Adds about 7 characters per block, and offset, next_offset and total_chars count the text as rendered with it, so keep the same value when continuing from next_offset. When no block has timing, no prefixes are added and timestamps_unavailable says so.
    max_charsinteger
    Maximum size of the transcript field as sent (integer, at least 1,000), cut at the last utterance that fits; a page holds fewer transcript characters when the text needs JSON escaping. Defaults to 40000; larger requests are capped at 80000. Use next_offset to continue. Lower it if responses exceed your output limit.
    meeting_idsarray
    Read up to 10 transcripts in one call instead of meeting_id. offset and max_chars apply to each meeting; use offsets to start meetings at different positions. A meeting that cannot be read gets an error entry and the others are still returned. If meeting_id or note_id is also provided, they must all refer to the same note.
    note_idstring
    Alias for meeting_id. If both are provided, they must refer to the same note (UUID and public note ID may differ).
    offsetinteger
    Character offset; pass next_offset to continue, with the same include_timestamps as that page.
    offsetsobject
    With meeting_ids only: character offset per meeting, keyed by meeting ID, e.g. {"<id>": 8000}. Pass each truncated meeting's next_offset to continue several transcripts in one call. Meetings not listed start at offset. Omit or pass {} when not needed.
    transcript_versionstring
    With chunk_ids, reuse the version from search or a previous chunk read. A changed status returns no passages: search again or restart browsing without the old version. Omit chunk_ids and transcript_version for the existing full transcript read.
  • granolamcp_get_meetingsGet detailed meeting information for one or more Granola meetings by ID.Read-only

    Granola: Get Meetings

    Get detailed meeting information for one or more Granola meetings by ID. Returns private notes, AI-generated summary, attendees, and metadata. Use this when you already have specific meeting IDs (e.g. from list_meetings results). For open-ended questions about meeting content, use query_granola_meetings instead.

    Inputs

    meeting_idsarrayrequired
    Meeting UUIDs or public note IDs (max 10). Provide at least one ID in meeting_ids or note_ids; empty arrays are ignored.
    attachmentsstring
    Omit or pass "list" to list each meeting's viewable attachments with their IDs; when several meetings are returned, only the first 20 per meeting are listed and the attachments element says how many were left out. Pass "count" to get only an attachment_count attribute on each meeting that has attachments. Pass "none" to leave attachments out.one of listcountnone
    max_participantsinteger
    Maximum attendees to list per meeting, besides the note creator. Omit to list everyone. Set a small value (e.g. 10) for broad ranges or large meetings to keep responses small. When attendees are left out, known_participants has total and omitted attributes, e.g. <known_participants total="250" omitted="240">.
    note_idsarray
    Alias for meeting_ids. Empty arrays are ignored. If both are nonempty, they must refer to the same set of notes; order, duplicates, and UUID/public ID format may differ.
  • granolamcp_list_meeting_foldersList the user's Granola meeting folders.Read-only

    Granola: List Meeting Folders

    List the user's Granola meeting folders. Returns folder ID, title, description, and note count including nested folders. When to use: - User asks about their folders or wants to browse meetings by folder - User wants to narrow down meeting searches to a specific folder Use the returned folder IDs with list_meetings (folder_id parameter) to list meetings within a specific folder.

    Inputs

    limitinteger
    Maximum folders to return. Defaults to 100.
    offsetinteger
    Number of folders to skip. Use next_offset from a previous truncated response. Defaults to 0.
  • granolamcp_list_meetingsList the user's Granola meeting notes within a time range.Read-only

    Granola: List Meetings

    List the user's Granola meeting notes within a time range. Returns meeting titles and metadata. IMPORTANT: For short-term questions about recent meeting details, prefer using query_granola_meetings instead. When to use: - User asks to list their meetings - User asks about action items, decisions, or summaries from meetings over a longer or specific date range - User asks about content from their meeting transcripts - User references 'Granola notes' or 'meeting notes' or 'transcripts' When NOT to use: - User is asking about upcoming calendar events or scheduling - User wants to create/modify calendar invites Filtering: - Omit workspace_only and involvement to return every meeting the user is allowed to access - For 'my meetings' or meetings the user was involved in, set both involvement conditions to true; true conditions combine using OR - Set captured_by_me to true for meetings whose Granola notes the user captured, or false to exclude them - Set listed_as_participant to true for meetings where the user is a known participant, or false to exclude them - False involvement conditions are exclusions and combine with the positive conditions using AND; omit a condition to ignore it - For Team Space or public workspace meetings, set workspace_only to true - workspace_only and involvement combine using AND Use get_meetings to retrieve detailed meeting content after identifying relevant meetings. Use list_meeting_folders to discover folder IDs, then pass a folder_id to list meetings within a specific folder.

    Inputs

    cursorstring
    Opaque next_cursor from the previous response. Keep the same filters; omit or pass an empty string for the first page.
    folder_idstring
    Optional folder ID to list meetings from a specific folder. Use list_meeting_folders to discover folder IDs.
    from_datestring
    ISO date for custom range start (required if time_range is 'custom'). Prefer YYYY-MM-DD for whole-day requests; dates and times without an offset use the user's stored timezone (UTC if unavailable). An explicit Z means UTC; explicit offsets are respected. Do not append Z to a local time. For a day in another timezone, give both bounds as times with that timezone's offset.
    involvementobject
    Optional involvement filter. Conditions set to true form an OR inclusion group. Conditions set to false are exclusions applied using AND. Omitted conditions are ignored.
    limitinteger
    Requested meetings per page (positive integer). Defaults to and is capped at 200 on paid plans and 100 on free plans. Larger requests use the plan's cap; use next_cursor to continue.
    max_participantsinteger
    Maximum attendees to list per meeting, besides the note creator. Omit to list everyone. Set a small value (e.g. 10) for broad ranges or large meetings to keep responses small. When attendees are left out, known_participants has total and omitted attributes, e.g. <known_participants total="250" omitted="240">.
    time_rangestring
    Time range to query meetings from. Custom bounds imply 'custom' when time_range is omitted; otherwise defaults to the last 7 days, starting at midnight in the user's timezone. Weeks start on Monday at midnight in the user's timezone: this_week runs from this Monday to now, and last_week from the previous Monday up to, but not including, this Monday.one of last_7_daysthis_weeklast_weeklast_30_dayscustom
    to_datestring
    ISO date for custom range end (required if time_range is 'custom'). Prefer YYYY-MM-DD to include the whole final day in the user's stored timezone (UTC if unavailable). Times without an offset use that timezone; an explicit Z means UTC and explicit offsets are respected. Do not append Z to a local time. For a day in another timezone, give both bounds as times with that timezone's offset.
    updated_afterstring
    Only notes whose summary or content changed after this ISO date or time; matching rows then show updated_at. Use it to pick up changes since a previous call. Without a time_range or custom bounds it covers all accessible meeting history (the last 30 days on the free plan) instead of the last 7 days; a range narrows it further by meeting date. Offsetless values use the user's timezone (UTC if unavailable).
    workspace_onlyboolean
    Set to true only when the user explicitly asks for Team Space, public workspace, or workspace-visible meetings. Omit or set to false to search every meeting the user is allowed to access.
  • granolamcp_list_templatesList the note templates available for generating a meeting summary: Granola's built-in templates, the user's own, and those shared with their company, each with id, title, description, source (granola, yours or shared) and section headings.Read-only

    List Templates

    List the note templates available for generating a meeting summary: Granola's built-in templates, the user's own, and those shared with their company, each with id, title, description, source (granola, yours or shared) and section headings. Pass a template's id as template_id to generate_summary; match the user's wording by title and description, and ask if more than one could fit.

    Inputs

    This tool takes no inputs.

  • granolamcp_query_granola_meetingsQuery Granola about the user's meetings using natural language.Read-only

    Granola: Query Meetings

    Query Granola about the user's meetings using natural language. Returns a tailored response with inline citation links in mark (e.g. [[0]](url)) that reference source meeting notes. IMPORTANT: The response includes numbered citation links to specific Granola meeting notes. These citations MUST be preserved in your response to the user — they provide transparency and allow the user to verify information by clicking through to the original notes. When to use: - User asks about what was discussed, decided, or action-items from meetings - User asks about follow-ups, todos, or commitments from recent meetings - User references 'Granola notes' or 'meeting notes' When NOT to use: - User is asking about calendar scheduling or upcoming events - User explicitly asks for a specific meeting by ID (use get_meetings instead) Prioritize using query_granola_meetings over list_meetings/get_meetings for open-ended or natural language queries about meeting content.

    Inputs

    querystringrequired
    The query to run on Granola meeting notes
    document_idsarray
    Optional meeting UUIDs or public note IDs to limit context to (max 10).
    note_idsarray
    Alias for document_ids (max 10). If both are provided, they must refer to the same set of notes; order, duplicates, and UUID/public ID format may differ.

Workflows

Tool calling

Use this connector when you want an agent to work with Granola meeting content, including summaries, notes, attendees, and transcripts.

  • Use granolamcp_query_granola_meetings for natural-language questions such as decisions, action items, or follow-ups from past meetings.
  • Use granolamcp_list_meetings to find meetings in a time window before drilling into specific meeting IDs.
  • Use granolamcp_get_meetings when you already know the Granola meeting IDs and need richer metadata or notes.
  • Use granolamcp_get_meeting_transcript when exact wording matters and you need the verbatim transcript instead of summarized notes.
examples/granolamcp_query_meetings.py
tool_response = actions.execute_tool(
connection_name='granolamcp',
identifier='user_123',
tool_name="granolamcp_query_granola_meetings",
tool_input={
"query": "What decisions and follow-ups came out of last week's customer calls?"
},
)
print("Granola response:", tool_response)