@tronsfey/ucli 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/lib/server-client.ts","../src/commands/configure.ts","../src/lib/cache.ts","../src/lib/oas-runner.ts","../src/commands/services.ts","../src/commands/run.ts","../src/commands/refresh.ts","../src/commands/help-cmd.ts","../src/lib/mcp-runner.ts","../src/commands/mcp.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { createRequire } from 'node:module'\nimport { registerConfigure } from './commands/configure.js'\nimport { registerServices } from './commands/services.js'\nimport { registerRun } from './commands/run.js'\nimport { registerRefresh } from './commands/refresh.js'\nimport { registerHelp } from './commands/help-cmd.js'\nimport { registerMcp } from './commands/mcp.js'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('../package.json') as { version: string; description: string }\n\nconst program = new Command()\n\nprogram\n .name('ucli')\n .description(pkg.description)\n .version(pkg.version, '-v, --version')\n .addHelpCommand(false) // we provide our own help command\n\nregisterConfigure(program)\nregisterServices(program)\nregisterRun(program)\nregisterRefresh(program)\nregisterMcp(program)\nregisterHelp(program)\n\nprogram.parse(process.argv)\n","import Conf from 'conf'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport interface CLIConfig {\n serverUrl: string\n token: string\n}\n\nconst conf = new Conf<CLIConfig>({\n projectName: 'ucli',\n schema: {\n serverUrl: { type: 'string' },\n token: { type: 'string' },\n },\n})\n\nexport const cacheDir = join(homedir(), '.cache', 'ucli')\n\nexport function getConfig(): CLIConfig {\n const serverUrl = conf.get('serverUrl')\n const token = conf.get('token')\n\n if (!serverUrl || !token) {\n console.error('ucli is not configured. Run: ucli configure --server <url> --token <jwt>')\n process.exit(1)\n }\n\n return { serverUrl, token }\n}\n\nexport function saveConfig(cfg: CLIConfig): void {\n conf.set('serverUrl', cfg.serverUrl)\n conf.set('token', cfg.token)\n}\n\nexport function isConfigured(): boolean {\n return Boolean(conf.get('serverUrl') && conf.get('token'))\n}\n","/**\n * HTTP client for the ucli-server API.\n * Attaches group JWT and handles common error cases.\n */\nimport axios, { type AxiosInstance } from 'axios'\nimport type { CLIConfig } from '../config.js'\n\nexport interface OASEntryPublic {\n id: string\n name: string\n description: string\n remoteUrl: string\n baseEndpoint: string | null\n authType: 'bearer' | 'api_key' | 'basic' | 'oauth2_cc' | 'none'\n authConfig: Record<string, unknown>\n cacheTtl: number\n}\n\nexport type McpAuthConfig =\n | { type: 'none' }\n | { type: 'http_headers'; headers: Record<string, string> }\n | { type: 'env'; env: Record<string, string> }\n\nexport interface McpEntryPublic {\n id: string\n groupId: string\n name: string\n description: string\n transport: 'http' | 'stdio'\n serverUrl: string | null\n command: string | null\n authConfig: McpAuthConfig\n enabled: boolean\n}\n\nexport class ServerClient {\n private http: AxiosInstance\n\n constructor(cfg: CLIConfig) {\n this.http = axios.create({\n baseURL: cfg.serverUrl.replace(/\\/$/, ''),\n headers: {\n Authorization: `Bearer ${cfg.token}`,\n 'Content-Type': 'application/json',\n },\n timeout: 15_000,\n })\n\n this.http.interceptors.response.use(\n (r) => r,\n (err: unknown) => {\n if (axios.isAxiosError(err)) {\n const status = err.response?.status\n const message = (err.response?.data as { message?: string })?.message ?? err.message\n\n if (status === 401) {\n console.error('Authentication failed. Run: ucli configure --server <url> --token <jwt>')\n process.exit(1)\n }\n\n throw new Error(`Server error ${status ?? 'unknown'}: ${message}`)\n }\n throw err\n },\n )\n }\n\n async listOAS(): Promise<OASEntryPublic[]> {\n const { data } = await this.http.get<OASEntryPublic[]>('/api/v1/oas')\n return data\n }\n\n async getOAS(name: string): Promise<OASEntryPublic> {\n const { data } = await this.http.get<OASEntryPublic>(`/api/v1/oas/${encodeURIComponent(name)}`)\n return data\n }\n\n async listMCP(): Promise<McpEntryPublic[]> {\n const { data } = await this.http.get<McpEntryPublic[]>('/api/v1/mcp')\n return data\n }\n\n async getMCP(name: string): Promise<McpEntryPublic> {\n const { data } = await this.http.get<McpEntryPublic>(`/api/v1/mcp/${encodeURIComponent(name)}`)\n return data\n }\n}\n","import type { Command } from 'commander'\nimport { saveConfig, isConfigured } from '../config.js'\nimport { ServerClient } from '../lib/server-client.js'\n\nexport function registerConfigure(program: Command): void {\n program\n .command('configure')\n .description('Configure the OAS Gateway server URL and authentication token')\n .requiredOption('--server <url>', 'OAS Gateway server URL (e.g. https://oas.example.com)')\n .requiredOption('--token <jwt>', 'Group JWT token issued by the server admin')\n .action(async (opts: { server: string; token: string }) => {\n const serverUrl = opts.server.replace(/\\/$/, '')\n const token = opts.token\n\n // Validate connectivity before saving\n console.log(`Connecting to ${serverUrl}...`)\n const client = new ServerClient({ serverUrl, token })\n\n try {\n await client.listOAS()\n saveConfig({ serverUrl, token })\n console.log('✓ Configuration saved successfully.')\n console.log(` Server: ${serverUrl}`)\n console.log(` Token: ${token.slice(0, 20)}...`)\n } catch (err) {\n console.error('Connection failed:', (err as Error).message)\n console.error('Please check the server URL and token.')\n process.exit(1)\n }\n })\n}\n","/**\n * Local file cache for OAS entries.\n * Stored at ~/.cache/oas-cli/<name>.json with TTL metadata.\n */\nimport { readFile, writeFile, mkdir } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { cacheDir } from '../config.js'\nimport type { OASEntryPublic } from './server-client.js'\n\ninterface CacheFile {\n entries: OASEntryPublic[]\n fetchedAt: number // ms timestamp\n ttlSec: number // cache duration\n}\n\nconst LIST_CACHE_FILE = join(cacheDir, 'oas-list.json')\n\nasync function ensureCacheDir(): Promise<void> {\n await mkdir(cacheDir, { recursive: true })\n}\n\nexport async function readOASListCache(): Promise<OASEntryPublic[] | null> {\n try {\n const raw = await readFile(LIST_CACHE_FILE, 'utf8')\n const cached: CacheFile = JSON.parse(raw)\n const age = (Date.now() - cached.fetchedAt) / 1000\n if (cached.ttlSec === 0 || age > cached.ttlSec) return null // expired\n return cached.entries\n } catch {\n return null // not found or parse error\n }\n}\n\nexport async function writeOASListCache(entries: OASEntryPublic[], ttlSec: number): Promise<void> {\n await ensureCacheDir()\n const cached: CacheFile = { entries, fetchedAt: Date.now(), ttlSec }\n await writeFile(LIST_CACHE_FILE, JSON.stringify(cached, null, 2), 'utf8')\n}\n\nexport async function clearOASListCache(): Promise<void> {\n try {\n await writeFile(LIST_CACHE_FILE, '{}', 'utf8')\n } catch {\n // ignore if not found\n }\n}\n","/**\n * Bridge between oas-cli and @tronsfey/openapi2cli run mode.\n *\n * Spawns openapi2cli as a child process, injecting auth config\n * as environment variables (never exposed to the agent's shell).\n */\nimport { spawn } from 'node:child_process'\nimport { createRequire } from 'node:module'\nimport { fileURLToPath } from 'node:url'\nimport { join, dirname } from 'node:path'\nimport type { OASEntryPublic } from './server-client.js'\n\nconst require = createRequire(import.meta.url)\n\nfunction resolveOpenapi2CliBin(): string {\n try {\n const pkgPath = require.resolve('@tronsfey/openapi2cli/package.json')\n const pkgDir = dirname(pkgPath)\n // @tronsfey/openapi2cli exposes its binary; find it\n const pkg = require('@tronsfey/openapi2cli/package.json') as { bin?: Record<string, string> }\n const binEntry = pkg.bin?.['openapi2cli'] ?? 'bin/openapi2cli.js'\n return join(pkgDir, binEntry)\n } catch {\n throw new Error(\n '@tronsfey/openapi2cli is not installed. Run: pnpm add @tronsfey/openapi2cli in packages/cli',\n )\n }\n}\n\nexport interface RunOptions {\n entry: OASEntryPublic\n /** Operation command args (e.g. ['listPets', '--limit', '10']) */\n operationArgs: string[]\n format?: 'json' | 'table' | 'yaml'\n query?: string\n}\n\n/**\n * Build auth environment variables for injection into child process.\n * The calling shell (and thus the AI agent) never sees these values.\n */\nfunction buildAuthEnv(entry: OASEntryPublic): Record<string, string> {\n const cfg = entry.authConfig\n const prefix = entry.name.toUpperCase().replace(/[^A-Z0-9]/g, '_')\n\n switch (cfg['type']) {\n case 'bearer':\n return { [`${prefix}_TOKEN`]: cfg['token'] as string }\n\n case 'api_key':\n return { [`${prefix}_API_KEY`]: cfg['key'] as string }\n\n case 'basic':\n return { [`${prefix}_CREDENTIALS`]: `${cfg['username']}:${cfg['password']}` }\n\n case 'oauth2_cc':\n return {\n [`${prefix}_CLIENT_ID`]: cfg['clientId'] as string,\n [`${prefix}_CLIENT_SECRET`]: cfg['clientSecret'] as string,\n [`${prefix}_SCOPES`]: (cfg['scopes'] as string[]).join(' '),\n }\n\n default:\n return {}\n }\n}\n\nexport async function runOperation(opts: RunOptions): Promise<void> {\n const bin = resolveOpenapi2CliBin()\n const { entry, operationArgs, format, query } = opts\n\n const args = [\n 'run',\n '--oas', entry.remoteUrl,\n '--cache-ttl', String(entry.cacheTtl),\n ...(entry.baseEndpoint ? ['--endpoint', entry.baseEndpoint] : []),\n ...(format ? ['--format', format] : []),\n ...(query ? ['--query', query] : []),\n ...operationArgs,\n ]\n\n const authEnv = buildAuthEnv(entry)\n\n await new Promise<void>((resolve, reject) => {\n const child = spawn(process.execPath, [bin, ...args], {\n stdio: 'inherit',\n env: {\n ...process.env,\n ...authEnv, // inject auth — not visible to parent shell\n },\n })\n\n child.on('close', (code) => {\n if (code === 0) resolve()\n else reject(new Error(`openapi2cli exited with code ${code}`))\n })\n child.on('error', reject)\n })\n}\n\n/**\n * Get list of available operations for a service by running `--help`.\n * Returns the raw help text from openapi2cli.\n */\nexport async function getServiceHelp(entry: OASEntryPublic): Promise<string> {\n const bin = resolveOpenapi2CliBin()\n const args = [\n 'run',\n '--oas', entry.remoteUrl,\n '--cache-ttl', String(entry.cacheTtl),\n '--help',\n ]\n\n return new Promise<string>((resolve, reject) => {\n let output = ''\n const child = spawn(process.execPath, [bin, ...args], {\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n child.stdout?.on('data', (d: Buffer) => { output += d.toString() })\n child.stderr?.on('data', (d: Buffer) => { output += d.toString() })\n child.on('close', () => resolve(output))\n child.on('error', reject)\n })\n}\n","import type { Command } from 'commander'\nimport { getConfig } from '../config.js'\nimport { ServerClient } from '../lib/server-client.js'\nimport { readOASListCache, writeOASListCache } from '../lib/cache.js'\nimport { getServiceHelp } from '../lib/oas-runner.js'\n\nexport function registerServices(program: Command): void {\n const services = program\n .command('services')\n .description('Manage and inspect available OAS services')\n\n // services list\n services\n .command('list')\n .description('List all OAS services available in the current group')\n .option('--no-cache', 'Bypass local cache and fetch fresh from server')\n .action(async (opts: { cache: boolean }) => {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n\n let entries = opts.cache ? await readOASListCache() : null\n\n if (!entries) {\n entries = await client.listOAS()\n if (entries.length > 0) {\n const maxTtl = Math.min(...entries.map((e) => e.cacheTtl))\n await writeOASListCache(entries, maxTtl)\n }\n }\n\n if (entries.length === 0) {\n console.log('No services registered in this group.')\n return\n }\n\n const nameWidth = Math.max(10, ...entries.map((e) => e.name.length))\n console.log(`\\n${'SERVICE'.padEnd(nameWidth)} AUTH DESCRIPTION`)\n console.log(`${'-'.repeat(nameWidth)} -------- ${'-'.repeat(40)}`)\n for (const e of entries) {\n const auth = e.authType.padEnd(8)\n const desc = e.description.length > 60 ? e.description.slice(0, 57) + '...' : e.description\n console.log(`${e.name.padEnd(nameWidth)} ${auth} ${desc}`)\n }\n console.log()\n })\n\n // services info <name>\n services\n .command('info <name>')\n .description('Show detailed information and available operations for a service')\n .action(async (name: string) => {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n\n let entry\n try {\n entry = await client.getOAS(name)\n } catch (err) {\n console.error(`Service not found: ${name}`)\n console.error('Run `ucli services list` to see available services.')\n process.exit(1)\n }\n\n console.log(`\\nService: ${entry.name}`)\n console.log(`Description: ${entry.description || '(none)'}`)\n console.log(`OAS URL: ${entry.remoteUrl}`)\n if (entry.baseEndpoint) console.log(`Base endpoint: ${entry.baseEndpoint}`)\n console.log(`Auth type: ${entry.authType}`)\n console.log(`Cache TTL: ${entry.cacheTtl}s`)\n\n console.log('\\nAvailable operations:')\n console.log('─'.repeat(60))\n\n const help = await getServiceHelp(entry)\n console.log(help)\n })\n}\n","import type { Command } from 'commander'\nimport { getConfig } from '../config.js'\nimport { ServerClient } from '../lib/server-client.js'\nimport { runOperation } from '../lib/oas-runner.js'\n\nexport function registerRun(program: Command): void {\n program\n .command('run <service> [args...]')\n .description('Execute an operation on a service')\n .option('--format <fmt>', 'Output format: json | table | yaml', 'json')\n .option('--query <jmespath>', 'Filter response with JMESPath expression')\n .option('--data <json>', 'Request body (JSON string or @filename)')\n .allowUnknownOption(true)\n .action(async (\n service: string,\n args: string[],\n opts: { format?: string; query?: string; data?: string; args?: string[] },\n ) => {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n\n let entry\n try {\n entry = await client.getOAS(service)\n } catch {\n console.error(`Unknown service: ${service}`)\n console.error('Run `ucli services list` to see available services.')\n process.exit(1)\n }\n\n // Collect extra args (pass-through to openapi2cli)\n const extraArgs = opts.args ?? []\n const operationArgs = [\n ...args,\n ...extraArgs,\n ...(opts.data ? ['--data', opts.data] : []),\n ]\n\n const format = opts.format as 'json' | 'table' | 'yaml' | undefined\n const query = opts.query as string | undefined\n\n try {\n await runOperation({\n entry,\n operationArgs,\n ...(format !== undefined ? { format } : {}),\n ...(query !== undefined ? { query } : {}),\n })\n } catch (err) {\n console.error('Operation failed:', (err as Error).message)\n process.exit(1)\n }\n })\n}\n","import type { Command } from 'commander'\nimport { getConfig } from '../config.js'\nimport { ServerClient } from '../lib/server-client.js'\nimport { writeOASListCache, clearOASListCache } from '../lib/cache.js'\n\nexport function registerRefresh(program: Command): void {\n program\n .command('refresh')\n .description('Force-refresh the local OAS cache from the server')\n .action(async () => {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n\n console.log('Refreshing OAS list from server...')\n await clearOASListCache()\n\n const entries = await client.listOAS()\n if (entries.length > 0) {\n const maxTtl = Math.min(...entries.map((e) => e.cacheTtl))\n await writeOASListCache(entries, maxTtl)\n }\n\n console.log(`✓ Refreshed ${entries.length} service(s).`)\n })\n}\n","import type { Command } from 'commander'\nimport { getConfig, isConfigured } from '../config.js'\nimport { ServerClient } from '../lib/server-client.js'\nimport { readOASListCache, writeOASListCache } from '../lib/cache.js'\nimport { getServiceHelp } from '../lib/oas-runner.js'\n\nexport function registerHelp(program: Command): void {\n program\n .command('help [service]')\n .description('Show usage guide. Pass a service name for service-specific operations.')\n .action(async (service?: string) => {\n if (!service) {\n printGeneralHelp()\n if (isConfigured()) {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n let entries = await readOASListCache()\n if (!entries) {\n entries = await client.listOAS()\n if (entries.length > 0) {\n const maxTtl = Math.min(...entries.map((e) => e.cacheTtl))\n await writeOASListCache(entries, maxTtl)\n }\n }\n if (entries.length > 0) {\n console.log('\\nAvailable services:')\n for (const e of entries) {\n console.log(` ${e.name.padEnd(20)} ${e.description}`)\n }\n console.log('\\nTip: Run `ucli help <service>` for service-specific operations.')\n }\n } else {\n console.log('\\nRun `ucli configure --server <url> --token <jwt>` to get started.')\n }\n return\n }\n\n // Service-specific help\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n\n let entry\n try {\n entry = await client.getOAS(service)\n } catch {\n console.error(`Unknown service: ${service}`)\n console.error('Run `ucli services list` to see available services.')\n process.exit(1)\n }\n\n console.log(`\\n=== ${entry.name} ===`)\n console.log(`${entry.description}`)\n console.log(`\\nOAS spec: ${entry.remoteUrl}`)\n console.log('\\nOperations:')\n console.log('─'.repeat(60))\n\n const help = await getServiceHelp(entry)\n console.log(help)\n\n console.log('\\nExamples:')\n console.log(` ucli run ${entry.name} <operation>`)\n console.log(` ucli run ${entry.name} <operation> --format table`)\n console.log(` ucli run ${entry.name} <operation> --query \"results[*].id\"`)\n console.log(` ucli run ${entry.name} <operation> --data '{\"key\":\"value\"}'`)\n })\n}\n\nfunction printGeneralHelp(): void {\n console.log(`\nucli — OpenAPI & MCP Gateway for AI Agents\n════════════════════════════════════════\n\nSETUP\n ucli configure --server <url> --token <jwt>\n Configure server connection and authentication.\n\nDISCOVERY\n ucli services list\n List all OAS services available in your group.\n\n ucli services info <service>\n Show detailed service info and all available operations.\n\n ucli help [service]\n Show this guide, or service-specific operations.\n\nEXECUTION\n ucli run <service> <operation> [options]\n Execute a service operation.\n\n Options:\n --format json|table|yaml Output format (default: json)\n --query <jmespath> Filter response with JMESPath\n --data <json|@file> Request body for POST/PUT/PATCH\n\nMAINTENANCE\n ucli refresh\n Force-refresh the local OAS cache from the server.\n\nERRORS\n 401 Unauthorized → Run: ucli configure --server <url> --token <jwt>\n 404 Not Found → Check service name: ucli services list\n 4xx Client Error → Check operation args: ucli services info <service>\n 5xx Server Error → Retry or run: ucli refresh\n`)\n}\n","/**\n * MCP tool runner using @tronsfey/mcp2cli programmatic API.\n *\n * Auth credentials are injected via McpServerConfig (headers or env) —\n * never passed as CLI arguments (which would be visible in `ps`).\n */\nimport type { McpEntryPublic } from './server-client.js'\n\n// Dynamic imports to avoid top-level await in ESM\nasync function getMcp2cli() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const clientMod = await import('@tronsfey/mcp2cli/dist/client/index.js') as any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const runnerMod = await import('@tronsfey/mcp2cli/dist/runner/index.js') as any\n return { createMcpClient: clientMod.createMcpClient, getTools: runnerMod.getTools, runTool: runnerMod.runTool }\n}\n\nfunction buildMcpConfig(entry: McpEntryPublic): Record<string, unknown> {\n const base: Record<string, unknown> = { type: entry.transport }\n if (entry.transport === 'http') {\n base.url = entry.serverUrl\n } else {\n base.command = entry.command\n }\n const auth = entry.authConfig\n if (auth.type === 'http_headers') {\n base.headers = auth.headers\n } else if (auth.type === 'env') {\n base.env = auth.env\n }\n return base\n}\n\nexport async function listMcpTools(entry: McpEntryPublic): Promise<{ name: string; description?: string }[]> {\n const { createMcpClient, getTools } = await getMcp2cli()\n const config = buildMcpConfig(entry)\n const client = await createMcpClient(config)\n const tools = await getTools(client, config, { noCache: true })\n return tools\n}\n\nexport async function runMcpTool(entry: McpEntryPublic, toolName: string, rawArgs: string[]): Promise<void> {\n const { createMcpClient, getTools, runTool } = await getMcp2cli()\n const config = buildMcpConfig(entry)\n const client = await createMcpClient(config)\n const tools = await getTools(client, config, { noCache: false, cacheTtl: 3600 })\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const tool = tools.find((t: any) => t.name === toolName)\n if (!tool) throw new Error(`Tool \"${toolName}\" not found on MCP server \"${entry.name}\"`)\n await runTool(client, tool, rawArgs, {})\n}\n","import type { Command } from 'commander'\nimport { getConfig } from '../config.js'\nimport { ServerClient } from '../lib/server-client.js'\nimport { listMcpTools, runMcpTool } from '../lib/mcp-runner.js'\n\nexport function registerMcp(program: Command): void {\n const mcp = program\n .command('mcp')\n .description('Interact with MCP servers registered in your group')\n\n // mcp list\n mcp\n .command('list')\n .description('List all MCP servers available in the current group')\n .action(async () => {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n const entries = await client.listMCP()\n\n if (entries.length === 0) {\n console.log('No MCP servers registered in this group.')\n return\n }\n\n const nameWidth = Math.max(10, ...entries.map(e => e.name.length))\n console.log(`\\n${'SERVER'.padEnd(nameWidth)} TRANSPORT DESCRIPTION`)\n console.log(`${'-'.repeat(nameWidth)} --------- ${'-'.repeat(40)}`)\n for (const e of entries) {\n const desc = e.description.length > 60 ? e.description.slice(0, 57) + '...' : e.description\n console.log(`${e.name.padEnd(nameWidth)} ${e.transport.padEnd(9)} ${desc}`)\n }\n console.log()\n })\n\n // mcp tools <server>\n mcp\n .command('tools <server>')\n .description('List tools available on a MCP server')\n .action(async (serverName: string) => {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n\n let entry\n try {\n entry = await client.getMCP(serverName)\n } catch {\n console.error(`Unknown MCP server: ${serverName}`)\n console.error('Run `ucli mcp list` to see available servers.')\n process.exit(1)\n }\n\n let tools\n try {\n tools = await listMcpTools(entry)\n } catch (err) {\n console.error('Failed to fetch tools:', (err as Error).message)\n process.exit(1)\n }\n\n if (tools.length === 0) {\n console.log(`No tools found on MCP server \"${serverName}\".`)\n return\n }\n\n console.log(`\\nTools on \"${serverName}\":`)\n console.log('─'.repeat(60))\n for (const t of tools) {\n console.log(` ${t.name}`)\n if (t.description) console.log(` ${t.description}`)\n }\n console.log()\n })\n\n // mcp run <server> <tool> [args...]\n mcp\n .command('run <server> <tool> [args...]')\n .description('Call a tool on a MCP server')\n .action(async (serverName: string, toolName: string, args: string[]) => {\n const cfg = getConfig()\n const client = new ServerClient(cfg)\n\n let entry\n try {\n entry = await client.getMCP(serverName)\n } catch {\n console.error(`Unknown MCP server: ${serverName}`)\n console.error('Run `ucli mcp list` to see available servers.')\n process.exit(1)\n }\n\n try {\n await runMcpTool(entry, toolName, args)\n } catch (err) {\n console.error('Tool execution failed:', (err as Error).message)\n process.exit(1)\n }\n })\n}\n"],"mappings":"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","names":["createRequire","program","join","join","join","require","pkg","program","program","program","program","cfg","client","program","require","createRequire"]}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@tronsfey/ucli",
3
+ "version": "0.3.0",
4
+ "description": "ucli — proxy OpenAPI and MCP services for AI agents",
5
+ "keywords": ["openapi", "oas", "cli", "ai-agent", "api-client"],
6
+ "license": "MIT",
7
+ "engines": { "node": ">=18" },
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "files": [
12
+ "dist/**",
13
+ "assets/**",
14
+ "skill.md",
15
+ "README.md",
16
+ "README.zh.md"
17
+ ],
18
+ "type": "module",
19
+ "bin": {
20
+ "ucli": "./dist/index.js"
21
+ },
22
+ "scripts": {
23
+ "dev": "tsx watch src/index.ts",
24
+ "build": "tsup && chmod +x dist/index.js",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "lint": "tsc --noEmit",
28
+ "clean": "rm -rf dist"
29
+ },
30
+ "dependencies": {
31
+ "@tronsfey/mcp2cli": "^1.0.0",
32
+ "@tronsfey/openapi2cli": "^1.0.12",
33
+ "axios": "^1.8.4",
34
+ "commander": "^12.1.0",
35
+ "conf": "^13.1.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^22.14.0",
39
+ "tsx": "^4.19.3",
40
+ "tsup": "^8.4.0",
41
+ "vitest": "^3.1.1",
42
+ "typescript": "^5.7.3"
43
+ }
44
+ }
package/skill.md ADDED
@@ -0,0 +1,223 @@
1
+ # ucli Skill
2
+
3
+ ## Overview
4
+
5
+ Use `ucli` whenever you need to call any external business API or MCP server tool. This tool:
6
+ - Proxies registered OpenAPI services on your behalf
7
+ - Handles authentication automatically (credentials are never exposed to you)
8
+ - Returns structured JSON output suitable for further processing
9
+
10
+ **When to use:** Any time you need to interact with external services (business APIs, data sources, microservices). Always check available services first with `ucli services list`.
11
+
12
+ ---
13
+
14
+ ## Step 1 — Discover Available Services
15
+
16
+ ```bash
17
+ ucli services list
18
+ ```
19
+
20
+ Returns a table of service names, auth type, and descriptions. Run this first to see what's available.
21
+
22
+ **Example output:**
23
+ ```
24
+ SERVICE AUTH DESCRIPTION
25
+ ---------- -------- ------------------------------------------
26
+ payments bearer Payment processing service
27
+ inventory api_key Product inventory management
28
+ crm oauth2_cc Customer relationship management
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Step 2 — Inspect a Service's Operations
34
+
35
+ ```bash
36
+ ucli services info <service-name>
37
+ ```
38
+
39
+ Shows all available operations, their parameters, and expected inputs.
40
+
41
+ **Example:**
42
+ ```bash
43
+ ucli services info payments
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Step 3 — Execute an Operation
49
+
50
+ ```bash
51
+ ucli run <service> <operation> [options]
52
+ ```
53
+
54
+ ### Options
55
+
56
+ | Flag | Description | Example |
57
+ |------|-------------|---------|
58
+ | `--format json\|table\|yaml` | Output format (default: json) | `--format table` |
59
+ | `--query <jmespath>` | Filter response with JMESPath | `--query "items[*].id"` |
60
+ | `--data <json\|@file>` | Request body for POST/PUT/PATCH | `--data '{"amount":100}'` |
61
+
62
+ ### Examples
63
+
64
+ **List resources (GET):**
65
+ ```bash
66
+ ucli run payments listTransactions --format json
67
+ ```
68
+
69
+ **Filter response:**
70
+ ```bash
71
+ ucli run inventory listProducts --query "items[?stock > \`0\`].name"
72
+ ```
73
+
74
+ **Create a resource (POST):**
75
+ ```bash
76
+ ucli run payments createCharge --data '{"amount": 5000, "currency": "USD", "customerId": "cus_123"}'
77
+ ```
78
+
79
+ **Update a resource (PUT/PATCH):**
80
+ ```bash
81
+ ucli run crm updateContact --data '{"email": "new@example.com"}' --contactId abc123
82
+ ```
83
+
84
+ **Get a specific resource:**
85
+ ```bash
86
+ ucli run inventory getProduct --productId SKU-001
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Step 4 — Process the Output
92
+
93
+ By default, `ucli run` returns JSON. You can:
94
+ - Parse it directly as structured data
95
+ - Use `--query` to extract specific fields (JMESPath syntax)
96
+ - Use `--format table` for human-readable display
97
+
98
+ **JMESPath examples:**
99
+ ```bash
100
+ # Extract all IDs
101
+ --query "results[*].id"
102
+
103
+ # Filter by field value
104
+ --query "items[?status == 'active']"
105
+
106
+ # Get nested field
107
+ --query "data.user.email"
108
+
109
+ # Count results
110
+ --query "length(items)"
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Complete Workflow Example
116
+
117
+ ```bash
118
+ # 1. Discover services
119
+ ucli services list
120
+
121
+ # 2. Check what operations are available on "payments"
122
+ ucli services info payments
123
+
124
+ # 3. List recent transactions
125
+ ucli run payments listTransactions --query "transactions[*].{id:id,amount:amount,status:status}"
126
+
127
+ # 4. Get a specific transaction
128
+ ucli run payments getTransaction --transactionId txn_abc123
129
+
130
+ # 5. Create a new charge
131
+ ucli run payments createCharge --data '{
132
+ "amount": 9900,
133
+ "currency": "USD",
134
+ "customerId": "cus_xyz789",
135
+ "description": "Monthly subscription"
136
+ }'
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Error Handling
142
+
143
+ | Error | Cause | Resolution |
144
+ |-------|-------|------------|
145
+ | `Authentication failed` | Token expired or invalid | Run `ucli configure --server <url> --token <jwt>` |
146
+ | `Unknown service: <name>` | Service not registered | Run `ucli services list` to see valid names |
147
+ | `400 Bad Request` | Invalid parameters | Check operation signature with `ucli services info <service>` |
148
+ | `404 Not Found` | Resource doesn't exist | Verify the resource ID |
149
+ | `429 Too Many Requests` | Rate limit exceeded | Wait and retry |
150
+ | `5xx Server Error` | Upstream service error | Retry once; if persistent, report to the service owner |
151
+
152
+ **On persistent errors:**
153
+ ```bash
154
+ # Refresh the local OAS cache (may resolve stale spec issues)
155
+ ucli refresh
156
+
157
+ # Then retry the operation
158
+ ucli run <service> <operation>
159
+ ```
160
+
161
+ ---
162
+
163
+ ## MCP Server Tools
164
+
165
+ In addition to OpenAPI services, ucli can interact with MCP (Model Context Protocol) servers. Auth credentials (`http_headers` or `env`) are injected programmatically — they are never passed as CLI arguments (which would be visible in `ps`).
166
+
167
+ ### Workflow
168
+
169
+ ```bash
170
+ # Step 1: Discover available MCP servers
171
+ ucli mcp list
172
+
173
+ # Step 2: Inspect a server's available tools
174
+ ucli mcp tools <server-name>
175
+
176
+ # Step 3: Run a tool (args as key=value pairs)
177
+ ucli mcp run <server-name> <tool-name> [key=value ...]
178
+ ```
179
+
180
+ ### Commands
181
+
182
+ | Command | Description |
183
+ |---------|-------------|
184
+ | `ucli mcp list` | List all MCP servers available to your group |
185
+ | `ucli mcp tools <server>` | List tools available on the server |
186
+ | `ucli mcp run <server> <tool> [args...]` | Execute a tool on the server |
187
+
188
+ ### Examples
189
+
190
+ ```bash
191
+ # List available MCP servers
192
+ ucli mcp list
193
+
194
+ # See what tools are available on "weather" server
195
+ ucli mcp tools weather
196
+
197
+ # Call the get_forecast tool with arguments
198
+ ucli mcp run weather get_forecast location="New York" units=metric
199
+
200
+ # Call a search tool
201
+ ucli mcp run search-server web_search query="ucli documentation" limit=5
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Tips for AI Agents
207
+
208
+ 1. **Always discover first.** Don't guess service or operation names — run `ucli services list` then `ucli services info <name>`.
209
+
210
+ 2. **Use JSON output.** Default `--format json` gives you machine-parseable data. Only switch to `table` when presenting to humans.
211
+
212
+ 3. **Use `--query` to extract.** Instead of parsing the entire response, use JMESPath to extract exactly what you need.
213
+
214
+ 4. **Chain operations.** Use the output of one operation as input to the next:
215
+ ```bash
216
+ # Get customer ID, then create a charge
217
+ CUSTOMER_ID=$(ucli run crm findCustomer --email user@example.com --query "id" | tr -d '"')
218
+ ucli run payments createCharge --data "{\"customerId\": \"$CUSTOMER_ID\", \"amount\": 1000}"
219
+ ```
220
+
221
+ 5. **Check pagination.** Large result sets may be paginated. Look for `nextPage`, `cursor`, or `Link` headers in the response.
222
+
223
+ 6. **Validate before mutating.** For destructive operations (DELETE, large updates), confirm the resource exists and is correct before proceeding.