← Public packages
@charlesmatte/granola
Search and read Granola meeting notes, summaries and transcripts from any agent; manage webhooks and legal holds safely.
src/mcp/connect.ts
46 lines · 2.5 KB · TypeScriptimport { kody } from 'kody:runtime'
import { echo, mutationMode } from '../lib/guard.ts'
import { DEFAULT_MCP_SERVER, findMcpServer, GRANOLA_MCP_URL, MCP_SERVER_PATTERN } from '../lib/mcp.ts'
import { mutationSpec, parseInput } from '../lib/validate.ts'
/**
* Connect Granola's official MCP server (https://mcp.granola.ai/mcp) to this Kody account so the
* ./mcp/* exports can use it. Granola MCP uses browser OAuth: the result carries an `authUrl` the
* Kody account owner must open to sign in to Granola (no API key; works on every Granola plan).
* Same as adding the server by hand at https://kody.codes/account/mcp-servers (name `granola`,
* URL https://mcp.granola.ai/mcp). Changes Kody account settings, so it previews unless `confirm: true`. Does nothing if a server
* with that name already exists.
*
* @param input.server - Kody MCP server name to create (default `granola`).
* @param input.dryRun - Preview only. @param input.confirm - `true` to add the server.
* @returns Preview, `{ alreadyExists: true, state }`, or `{ executed: true, state, authUrl, nextStep }`
*
* @example
* import connect from 'kody:@charlesmatte/granola/mcp/connect'
*
* const r = await connect({ confirm: true }) // then open r.authUrl in a browser
*/
export default async function connectGranolaMcp(input: unknown) {
const p = parseInput<{ server?: string; dryRun?: boolean; confirm?: boolean }>(
input,
{ server: { type: 'string', pattern: MCP_SERVER_PATTERN }, ...mutationSpec },
'mcp/connect',
)
const server = p.server ?? DEFAULT_MCP_SERVER
const existing = await findMcpServer(server)
if (existing) return { server, alreadyExists: true, url: existing.url, state: existing.state ?? existing.status, authUrl: existing.authUrl ?? null }
const mode = mutationMode(p)
const acct = { account: '(kody mcp)', secretName: '(oauth, stored by Kody)' }
if (!mode.execute) {
return {
dryRun: true,
executed: false,
echo: echo(acct, 'mcp/connect', `Kody MCP server "${server}" → ${GRANOLA_MCP_URL}`, mode),
reason: mode.reason,
request: { capability: 'mcpServerAdd', name: server, url: GRANOLA_MCP_URL },
next: 'Nothing was changed. Re-run with confirm: true to add the server, then open the returned authUrl to sign in to Granola.',
}
}
const r = (await kody.mcpServerAdd({ name: server, url: GRANOLA_MCP_URL })) as Record<string, unknown>
return { dryRun: false, executed: true, server, state: r.state, toolCount: r.toolCount, authUrl: r.authUrl ?? null, error: r.error ?? null, nextStep: r.nextStep }
}