Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/canva-mcp

src/mcp.ts

62 lines · 1.7 KB · TypeScript
import { kody } from 'kody:runtime'

export const CANVA_MCP_NAME = 'canva'
export const CANVA_MCP_URL = 'https://mcp.canva.com/mcp'

type McpServer = Record<string, (args?: Record<string, unknown>) => Promise<unknown>>

export function getCanvaMcp(): McpServer | null {
	const server = kody.mcp?.[CANVA_MCP_NAME]
	if (!server || typeof server !== 'object') return null
	const tools = Object.entries(server).filter(([, value]) => typeof value === 'function')
	if (tools.length === 0) return null
	return server as McpServer
}

export function isCanvaMcpConnected(): boolean {
	return getCanvaMcp() !== null
}

export async function callCanvaMcp(
	candidates: Array<string>,
	args: Record<string, unknown> = {},
): Promise<{ tool: string; result: unknown } | null> {
	const server = getCanvaMcp()
	if (!server) return null
	for (const name of candidates) {
		const fn = server[name]
		if (typeof fn === 'function') {
			return { tool: name, result: await fn(args) }
		}
	}
	return null
}

export function canvaMcpSetupMessage(): string {
	return [
		'Add the official Canva MCP server, then authorize it:',
		`kody.mcp_server_add({ name: "${CANVA_MCP_NAME}", url: "${CANVA_MCP_URL}" })`,
		'Open the returned authUrl. Do not register an OAuth app for the one-click path.',
	].join(' ')
}

export function firstArray(value: unknown): Array<unknown> | null {
	if (Array.isArray(value)) return value
	if (!value || typeof value !== 'object') return null
	const record = value as Record<string, unknown>
	for (const key of [
		'results',
		'items',
		'data',
		'issues',
		'pages',
		'customers',
		'organizations',
		'designs',
		'values',
		'nodes',
	]) {
		if (Array.isArray(record[key])) return record[key] as Array<unknown>
	}
	return null
}