import { 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 return { dryRun: false, executed: true, server, state: r.state, toolCount: r.toolCount, authUrl: r.authUrl ?? null, error: r.error ?? null, nextStep: r.nextStep } }