Skip to content

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

Package listing

@kody/atlassian-mcp

src/mcp.ts

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

export const ATLASSIAN_MCP_NAME = 'atlassian'
export const ATLASSIAN_MCP_URL = 'https://mcp.atlassian.com/v1/mcp/authv2'

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

export function getAtlassianMcp(): McpServer | null {
	const server = kody.mcp?.[ATLASSIAN_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 isAtlassianMcpConnected(): boolean {
	return getAtlassianMcp() !== null
}

export async function callAtlassianMcp(
	candidates: Array<string>,
	args: Record<string, unknown> = {},
): Promise<{ tool: string; result: unknown } | null> {
	const server = getAtlassianMcp()
	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 atlassianMcpSetupMessage(): string {
	return [
		'Add the official Atlassian MCP server, then authorize it:',
		`kody.mcp_server_add({ name: "${ATLASSIAN_MCP_NAME}", url: "${ATLASSIAN_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
}