#!/usr/bin/env node /** * kosha-discovery — MCP server (stdio transport). * * Exposes the local kosha registry as MCP tools so AI agents can query * model pricing, routing, and health without HTTP. * * Protocol: JSON-RPC 2.0 over newline-delimited stdio. The server speaks * every MCP revision in {@link MCP_PROTOCOL_VERSIONS} and echoes the * client's requested revision back when it is one of them (otherwise it * answers with the newest it supports, per the MCP negotiation rule). * * Tools: * kosha_query_models — list / filter models * kosha_cheapest_model — cheapest model meeting requirements * kosha_ranked_routes — strategy-ranked routes (cheapest / fastest / reliable / balanced) * kosha_model_detail — full detail for one model * kosha_model_routes — all provider routes for a model * kosha_resolve_alias — alias → canonical ID * kosha_provider_health — provider auth + error status * kosha_context_strategy — context-management advice for a long conversation * * The JSON-RPC handler ({@link handleJsonRpc}) is exported and pure over an * injected registry loader so it can be unit-tested; the stdio loop only * starts when this file is the process entry point. * @module */ import { ModelRegistry } from "./registry.js"; /** Package version, read from package.json so `serverInfo.version` never drifts from the release. */ export declare const KOSHA_MCP_VERSION: string; /** MCP protocol revisions this server implements, newest first. */ export declare const MCP_PROTOCOL_VERSIONS: readonly string[]; /** * Pick the protocol revision to answer an `initialize` with: the client's * own when we support it, otherwise our newest (the client then decides * whether to proceed). */ export declare function negotiateProtocolVersion(requested: unknown): string; export interface JsonRpcMessage { jsonrpc: "2.0"; id?: string | number | null; method?: string; params?: unknown; result?: unknown; error?: { code: number; message: string; }; } export declare const TOOLS: readonly [{ readonly name: "kosha_query_models"; readonly description: "List AI models from the local kosha registry. Optionally filter by provider, mode, or capability tag. Returns id, provider, name, mode, context window, capabilities, and pricing."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly provider: { readonly type: "string"; readonly description: "Provider ID (e.g. anthropic, openai, groq, openrouter)"; }; readonly mode: { readonly type: "string"; readonly enum: readonly ["chat", "embedding", "image", "video", "audio", "moderation", "rerank", "judgment"]; readonly description: "Primary model mode"; }; readonly capability: { readonly type: "string"; readonly description: "Capability tag (e.g. vision, tool_use, code, reasoning)"; }; readonly limit: { readonly type: "number"; readonly description: "Max results to return (default 20)"; }; }; }; }, { readonly name: "kosha_cheapest_model"; readonly description: "Find the cheapest AI model that meets your requirements. Returns ranked matches with per-million token pricing. Use this before routing a request to pick the most cost-effective option."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly capability: { readonly type: "string"; readonly description: "Required capability (e.g. tool_use, vision, code, reasoning)"; }; readonly min_context_k: { readonly type: "number"; readonly description: "Minimum context window in thousands of tokens (e.g. 128 means 128k)"; }; readonly provider: { readonly type: "string"; readonly description: "Pin to a specific provider"; }; readonly limit: { readonly type: "number"; readonly description: "Number of ranked results (default 5)"; }; }; }; }, { readonly name: "kosha_ranked_routes"; readonly description: "Rank chat-model routes by strategy: cheapest (price only), fastest (observed p95 latency), reliable (circuit-breaker state plus timeout / auth-error history), or balanced (weighted blend of all three). Providers whose breaker is open always sort last, so the result doubles as a failover order. Accepts the same filters as kosha_cheapest_model."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly strategy: { readonly type: "string"; readonly enum: readonly ["cheapest", "fastest", "reliable", "balanced"]; readonly description: "Ranking strategy"; }; readonly capability: { readonly type: "string"; readonly description: "Required capability tag (e.g. tool_use, vision)"; }; readonly min_context_k: { readonly type: "number"; readonly description: "Minimum context window in thousands of tokens"; }; readonly provider: { readonly type: "string"; readonly description: "Pin to a specific provider"; }; readonly limit: { readonly type: "number"; readonly description: "Number of ranked results (default 5)"; }; }; readonly required: readonly ["strategy"]; }; }, { readonly name: "kosha_model_detail"; readonly description: "Get full details for a specific model — pricing, capabilities, context window, tool dialect, structured output modes, status, and deprecation info."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly model: { readonly type: "string"; readonly description: "Model ID or alias (e.g. sonnet, claude-sonnet-5, gpt-4o, deepseek-v3)"; }; }; readonly required: readonly ["model"]; }; }, { readonly name: "kosha_model_routes"; readonly description: "List all serving-layer routes for a model (direct provider, OpenRouter, Bedrock, Vertex, etc.) with pricing per route. Useful for finding the cheapest or most available path to a specific model."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly model: { readonly type: "string"; readonly description: "Model ID or alias"; }; }; readonly required: readonly ["model"]; }; }, { readonly name: "kosha_resolve_alias"; readonly description: "Resolve a model alias or short name to its canonical ID and provider."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly alias: { readonly type: "string"; readonly description: "Short name or alias (e.g. sonnet, opus, haiku, gpt-4o-mini, gemini-flash)"; }; }; readonly required: readonly ["alias"]; }; }, { readonly name: "kosha_provider_health"; readonly description: "Get authentication and health status for all discovered providers. Shows which providers are active, which need credentials, and any recent discovery errors."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly provider: { readonly type: "string"; readonly description: "Filter to a specific provider ID"; }; }; }; }, { readonly name: "kosha_context_strategy"; readonly description: "Advise on context management for a long-running conversation. Given a model and current token usage, returns ranked options (continue, enable prompt cache, compact + continue, switch to long-context tier, switch model, batch offload) with rough cost-per-turn math. Useful before deciding whether to summarize, swap models, or just keep going."; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly model: { readonly type: "string"; readonly description: "Model ID or alias the caller is currently using"; }; readonly current_tokens: { readonly type: "number"; readonly description: "Approximate token count of the conversation so far"; }; readonly expected_output_tokens: { readonly type: "number"; readonly description: "Tokens the next reply is expected to produce (default 1024)"; }; readonly expected_remaining_turns: { readonly type: "number"; readonly description: "How many more turns the caller plans (default 5)"; }; }; readonly required: readonly ["model", "current_tokens"]; }; }]; /** Dependencies the JSON-RPC handler needs; injected so tests can supply a fixture registry. */ export interface McpDeps { registry: () => Promise; } export declare function callTool(name: string, args: Record, deps?: McpDeps): Promise; /** * Handle one JSON-RPC request and return the response, or `null` for * notifications (which carry no id and expect no reply). * * Tool *execution* failures come back as a successful `tools/call` result * with `isError: true`, per the MCP spec, so the model can read the message * and recover; only protocol-level problems (unknown method, unknown tool, * malformed params) surface as JSON-RPC errors. */ export declare function handleJsonRpc(msg: JsonRpcMessage, deps?: McpDeps): Promise; /** Start the newline-delimited JSON-RPC loop over stdio. */ export declare function runStdioServer(deps?: McpDeps): void; //# sourceMappingURL=mcp-server.d.ts.map