← Public packages
@playrunner/mcp
Connect Playrunner Cloud to Kody, then build and run Playwright test workflows from your agent.
src/index.ts
87 lines · 2.5 KB · TypeScriptimport { kody } from 'kody:runtime'
const SERVER_NAME = 'playrunner'
const SERVER_URL = 'https://playrunner.cloud/mcp'
type ConnectResult = {
name: string
state: string
toolCount: number
authUrl: string | null
alreadyPresent: boolean
nextStep: string
}
/**
* Connect this Kody account to Playrunner Cloud.
* Call this once, before anything else in the package: it registers the
* Playrunner MCP server if it is not already saved, and returns the
* authorisation link when the account still needs to approve access.
*
* Playrunner supports dynamic client registration, so no API token or manual
* configuration is needed — Kody registers itself and the user approves in the
* browser.
*
* @param input - Optional overrides. `url` targets a self-hosted Playrunner.
* @returns The saved server's state, its discovered tool count, and an
* `authUrl` the user must open when authorisation is outstanding.
*
* @example
* import connect from 'kody:@playrunner/mcp'
*
* const result = await connect()
* if (result.authUrl) {
* // Ask the user to open result.authUrl, then call status().
* }
*/
export default async function connect(
input: { url?: string } = {},
): Promise<ConnectResult> {
const url = input.url?.trim() || SERVER_URL
const existing = await findServer()
if (existing) {
return {
alreadyPresent: true,
authUrl: existing.authUrl ?? null,
name: existing.name,
nextStep: describe(existing),
state: existing.state,
toolCount: existing.toolCount ?? 0,
}
}
const added = await kody.mcpServerAdd({ name: SERVER_NAME, url })
return {
alreadyPresent: false,
authUrl: added.authUrl ?? null,
name: added.name,
nextStep: describe(added),
state: added.state,
toolCount: added.toolCount ?? 0,
}
}
type ServerRecord = {
authUrl?: string | null
name: string
state: string
toolCount?: number
tools?: string[]
}
export async function findServer(): Promise<ServerRecord | null> {
const listed = await kody.mcpServerList({})
const servers: ServerRecord[] = listed.servers ?? []
return servers.find((server) => server.name === SERVER_NAME) ?? null
}
export function describe(server: ServerRecord): string {
if (server.authUrl) {
return `Ask the user to open ${server.authUrl} and approve access, then call status().`
}
if (server.state === 'ready') {
return `Connected. Call kody.mcp["${SERVER_NAME}"].list_workflows({}) to see what this account can run.`
}
return `Server is ${server.state}. Call kody.mcpServerReconnect({ server: "${SERVER_NAME}" }) if it stays that way.`
}