BEARER TOKEN
MEETING NOTES
Meeting notes, summaries, and action items. Your team's call history lives in Granola. Your agent can pull notes, surface decisions, and retrieve past context, scoped to the user who recorded them.
import { ScalekitClient } from "@scalekit-sdk/node";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { z } from "zod";
const sk = new ScalekitClient(envUrl, clientId, clientSecret);
const { tools } = await sk.tools.listScopedTools("user_123", {
filter: { connectionNames: ["granola"], toolNames: ["granola_notes_list", "granola_note_get", "granola_note_summary_get"] },
pageSize: 100,
});
const lcTools = tools.map((t) => new DynamicStructuredTool({
name: t.tool.definition.name,
description: t.tool.definition.description,
schema: z.object({}).passthrough(),
func: async (args) => {
const { data } = await sk.tools.executeTool({
toolName: t.tool.definition.name,
identifier: "user_123",
params: args,
});
return JSON.stringify(data);
},
}));
const agent = createReactAgent({ llm, tools: lcTools });import { ScalekitClient } from "@scalekit-sdk/node";
import OpenAI from "openai";
const sk = new ScalekitClient(envUrl, clientId, clientSecret);
const openai = new OpenAI();
const { tools } = await sk.tools.listScopedTools("user_123", {
filter: { connectionNames: ["granola"], toolNames: ["granola_notes_list", "granola_note_get", "granola_note_summary_get"] },
pageSize: 100,
});
const llmTools = tools.map((t) => ({
type: "function",
function: {
name: t.tool.definition.name,
description: t.tool.definition.description,
parameters: t.tool.definition.input_schema,
},
}));
const resp = await openai.responses.create({
model: "gpt-4o", input: prompt, tools: llmTools,
});import { ScalekitClient } from "@scalekit-sdk/node";
import Anthropic from "@anthropic-ai/sdk";
const sk = new ScalekitClient(envUrl, clientId, clientSecret);
const anthropic = new Anthropic();
const { tools } = await sk.tools.listScopedTools("user_123", {
filter: { connectionNames: ["granola"], toolNames: ["granola_notes_list", "granola_note_get", "granola_note_summary_get"] },
pageSize: 100,
});
const llmTools = tools.map((t) => ({
name: t.tool.definition.name,
description: t.tool.definition.description,
input_schema: t.tool.definition.input_schema,
}));
const msg = await anthropic.messages.create({
model: "claude-sonnet-4-6", max_tokens: 1024,
tools: llmTools,
messages: [{ role: "user", content: prompt }],
});import { Agent } from "@google/adk/agents";
import {
MCPToolset, StreamableHTTPConnectionParams,
} from "@google/adk/tools/mcp";
const toolset = new MCPToolset({
connectionParams: new StreamableHTTPConnectionParams({
url: "https://mcp.scalekit.com/granola",
headers: { Authorization: `Bearer ${userScopedToken}` },
}),
});
const agent = new Agent({
name: "agent", model: "gemini-2.0-flash",
tools: await toolset.getTools(),
});// shared token
audit → bot_service_account
user_filter → broken
// scalekit
audit → user_abc
scope → enforced ✓Does the agent access Granola as the user or as a shared key?
As the user. Each workspace member authorizes once and Scalekit resolves their credential at request time. Audit logs attribute every action to that user, not a shared service account.
Where is the Granola bearer token stored?
In Scalekit's managed AES-256 token vault, namespaced per tenant. Refresh is automatic. Revocation is a single dashboard action. Tokens never appear in prompts, logs, or LLM context.
Can I limit what the agent is allowed to do in Granola?
Yes. Pass a tool name filter to listScopedTools so the meeting notes agent only sees the subset you authorize. Pre-API-call scope checks block out-of-policy actions before the request reaches Granola.
What happens when a user revokes Granola access?
The connection is invalidated on the next tool call. Subsequent requests for that user fail closed with a clear error. Other users in the tenant remain unaffected. The event is logged for audit.
Which meeting notes can the agent fetch?
Only notes accessible to the authorizing user. Shared workspace notes, personal notes, and any meeting the user attended. Cross-user notes stay private unless explicitly shared in Granola.
What other MCP connectors does Scalekit support?
Scalekit runs the Jiminny MCP server, Diarize MCP server, and Granola MCP server on the same per-user auth, token vault, and audit trail. Browse 500+ connectors in the MCP connector directory.
How do I build a Granola agent?
Follow a step-by-step tutorial: Build a Sales Call Prep Agent: Granola, Attio & Calendar; Build a Meeting Notes Agent with Mastra, Granola, Scalekit. Each one covers per-user auth, tool scoping, and working agent code for Granola.