import { parseInput } from '../lib/validate.ts' import { DEFAULT_MCP_SERVER, findMcpServer, GRANOLA_MCP_TOOLS, GRANOLA_MCP_URL, KODY_MCP_PAGE, MCP_SERVER_PATTERN, toolNamesOf } from '../lib/mcp.ts' /** * Status of the optional MCP lane: whether Granola's official MCP server (https://mcp.granola.ai/mcp) * is connected to this Kody account, its OAuth state, and the tools it exposes. Read-only; no * Granola request. The MCP lane works on every Granola plan (Basic: last 30 days of notes) and * adds `query_granola_meetings` (ask questions across meetings), which the REST API does not have. * * @param input.server - Kody MCP server name (default `granola`). * @returns `{ server, connected, state, authUrl, tools, documentedTools, next }` * * @example * import mcpTools from 'kody:@charlesmatte/granola/mcp/tools' * * const status = await mcpTools({}) */ export default async function granolaMcpTools(input: unknown) { const p = parseInput<{ server?: string }>(input, { server: { type: 'string', pattern: MCP_SERVER_PATTERN } }, 'mcp/tools') const server = p.server ?? DEFAULT_MCP_SERVER const info = await findMcpServer(server) if (!info) { return { server, connected: false, documentedTools: GRANOLA_MCP_TOOLS, next: `Not connected. One-time setup: open ${KODY_MCP_PAGE}, add a server named "${server}" with URL ${GRANOLA_MCP_URL}, then open the authorization link and sign in to Granola. Or run ./mcp/connect({ confirm: true }) and open the returned authUrl.` } } const tools = toolNamesOf(info) const state = String(info.state ?? info.status ?? 'unknown') return { server, connected: tools.length > 0, url: info.url, state, authUrl: info.authUrl ?? null, error: info.error ?? null, tools, documentedTools: GRANOLA_MCP_TOOLS, next: tools.length ? 'Ready: ask questions with ./mcp/query({ question }), or call a tool with ./mcp/call({ tool, args }).' : info.authUrl ? `Open authUrl to finish the Granola sign-in: ${info.authUrl}` : 'Server saved but no tools discovered yet; reconnect with ./mcp/connect.', } }