Files
OmniRoute/open-sse/mcp-server/schemas/tools.ts

846 lines
25 KiB
TypeScript

/**
* MCP Tool Schemas — Contracts for all 16 OmniRoute MCP tools.
*
* Defines input/output Zod schemas, descriptions, scopes, and audit levels
* for both essential (Phase 1) and advanced (Phase 3) MCP tools.
*
* Each tool wraps existing OmniRoute API endpoints and exposes them through
* the Model Context Protocol, enabling AI agents in IDEs (VS Code, Cursor,
* Copilot, Claude Desktop) to intelligently query gateway state.
*/
import { z } from "zod";
// ============ Shared Types ============
export type AuditLevel = "none" | "basic" | "full";
export interface McpToolDefinition<TInput extends z.ZodTypeAny, TOutput extends z.ZodTypeAny> {
/** Tool name (MCP identifier) */
name: string;
/** Human-readable description for AI agents */
description: string;
/** Zod schema for input validation */
inputSchema: TInput;
/** Zod schema for output validation */
outputSchema: TOutput;
/** Required API key scopes */
scopes: readonly string[];
/** Audit logging level */
auditLevel: AuditLevel;
/** Phase: 1 = essential, 2 = advanced */
phase: 1 | 2;
/** Source endpoints on OmniRoute that this tool wraps */
sourceEndpoints: readonly string[];
}
// ============ Phase 1: Essential Tools (8) ============
// --- Tool 1: omniroute_get_health ---
export const getHealthInput = z.object({}).describe("No parameters required");
export const getHealthOutput = z.object({
uptime: z.string(),
version: z.string(),
memoryUsage: z.object({
heapUsed: z.number(),
heapTotal: z.number(),
}),
circuitBreakers: z.array(
z.object({
provider: z.string(),
state: z.enum(["CLOSED", "OPEN", "HALF_OPEN"]),
failureCount: z.number(),
lastFailure: z.string().nullable(),
})
),
rateLimits: z.array(
z.object({
provider: z.string(),
rpm: z.number(),
currentUsage: z.number(),
isLimited: z.boolean(),
})
),
cacheStats: z
.object({
hits: z.number(),
misses: z.number(),
hitRate: z.number(),
})
.optional(),
});
export const getHealthTool: McpToolDefinition<typeof getHealthInput, typeof getHealthOutput> = {
name: "omniroute_get_health",
description:
"Returns the current health status of OmniRoute including uptime, memory usage, circuit breaker states for all providers, rate limit status, and cache statistics.",
inputSchema: getHealthInput,
outputSchema: getHealthOutput,
scopes: ["read:health"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/monitoring/health", "/api/resilience", "/api/rate-limits"],
};
// --- Tool 2: omniroute_list_combos ---
export const listCombosInput = z.object({
includeMetrics: z
.boolean()
.optional()
.describe("Include request count, success rate, latency, and cost metrics per combo"),
});
export const listCombosOutput = z.object({
combos: z.array(
z.object({
id: z.string(),
name: z.string(),
models: z.array(
z.object({
provider: z.string(),
model: z.string(),
priority: z.number(),
})
),
strategy: z.enum([
"priority",
"weighted",
"round-robin",
"strict-random",
"random",
"least-used",
"cost-optimized",
"auto",
]),
enabled: z.boolean(),
metrics: z
.object({
requestCount: z.number(),
successRate: z.number(),
avgLatencyMs: z.number(),
totalCost: z.number(),
})
.optional(),
})
),
});
export const listCombosTool: McpToolDefinition<typeof listCombosInput, typeof listCombosOutput> = {
name: "omniroute_list_combos",
description:
"Lists all configured combos (model chains) with their strategies and optionally includes performance metrics. Combos define how requests are routed across multiple providers.",
inputSchema: listCombosInput,
outputSchema: listCombosOutput,
scopes: ["read:combos"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/combos", "/api/combos/metrics"],
};
// --- Tool 3: omniroute_get_combo_metrics ---
export const getComboMetricsInput = z.object({
comboId: z.string().describe("ID of the combo to get metrics for"),
});
export const getComboMetricsOutput = z.object({
requests: z.number(),
successRate: z.number(),
avgLatency: z.number(),
costTotal: z.number(),
fallbackCount: z.number(),
byProvider: z.array(
z.object({
provider: z.string(),
requests: z.number(),
successRate: z.number(),
avgLatency: z.number(),
})
),
});
export const getComboMetricsTool: McpToolDefinition<
typeof getComboMetricsInput,
typeof getComboMetricsOutput
> = {
name: "omniroute_get_combo_metrics",
description:
"Returns detailed performance metrics for a specific combo including request count, success rate, average latency, total cost, and per-provider breakdowns.",
inputSchema: getComboMetricsInput,
outputSchema: getComboMetricsOutput,
scopes: ["read:combos"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/combos/metrics"],
};
// --- Tool 4: omniroute_switch_combo ---
export const switchComboInput = z.object({
comboId: z.string().describe("ID of the combo to activate/deactivate"),
active: z.boolean().describe("Whether to enable or disable the combo"),
});
export const switchComboOutput = z.object({
success: z.boolean(),
combo: z.object({
id: z.string(),
name: z.string(),
enabled: z.boolean(),
}),
});
export const switchComboTool: McpToolDefinition<typeof switchComboInput, typeof switchComboOutput> =
{
name: "omniroute_switch_combo",
description:
"Activates or deactivates a combo. When deactivated, requests will not be routed through this combo. Use to toggle between different routing strategies.",
inputSchema: switchComboInput,
outputSchema: switchComboOutput,
scopes: ["write:combos"],
auditLevel: "full",
phase: 1,
sourceEndpoints: ["/api/combos"],
};
// --- Tool 5: omniroute_check_quota ---
export const checkQuotaInput = z.object({
provider: z
.string()
.optional()
.describe(
"Filter by provider name (e.g., 'claude', 'gemini'). If omitted, returns all providers."
),
connectionId: z.string().optional().describe("Filter by specific connection ID"),
});
export const checkQuotaOutput = z.object({
providers: z.array(
z.object({
name: z.string(),
provider: z.string(),
connectionId: z.string(),
quotaUsed: z.number(),
quotaTotal: z.number().nullable(),
percentRemaining: z.number(),
resetAt: z.string().nullable(),
tokenStatus: z.enum(["valid", "expiring", "expired", "refreshing"]),
})
),
meta: z
.object({
generatedAt: z.string(),
filters: z.object({
provider: z.string().nullable(),
connectionId: z.string().nullable(),
}),
totalProviders: z.number(),
})
.optional(),
});
export const checkQuotaTool: McpToolDefinition<typeof checkQuotaInput, typeof checkQuotaOutput> = {
name: "omniroute_check_quota",
description:
"Checks the remaining API quota for one or all providers. Returns quota used/total, percentage remaining, reset time, and token health status.",
inputSchema: checkQuotaInput,
outputSchema: checkQuotaOutput,
scopes: ["read:quota"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/usage/quota", "/api/token-health", "/api/rate-limits"],
};
// --- Tool 6: omniroute_route_request ---
export const routeRequestInput = z.object({
model: z.string().describe("Model identifier (e.g., 'claude-sonnet-4', 'gpt-4o')"),
messages: z
.array(
z.object({
role: z.string(),
content: z.string(),
})
)
.describe("Chat messages in OpenAI format"),
combo: z.string().optional().describe("Specific combo to route through"),
budget: z.number().optional().describe("Maximum cost in USD for this request"),
role: z
.enum(["coding", "review", "planning", "analysis"])
.optional()
.describe("Task role hint for intelligent routing"),
stream: z.boolean().optional().default(false).describe("Whether to stream the response"),
});
export const routeRequestOutput = z.object({
response: z.object({
content: z.string(),
model: z.string(),
tokens: z.object({
prompt: z.number(),
completion: z.number(),
}),
}),
routing: z.object({
provider: z.string(),
combo: z.string().nullable(),
fallbacksTriggered: z.number(),
cost: z.number(),
latencyMs: z.number(),
routingExplanation: z.string(),
}),
});
export const routeRequestTool: McpToolDefinition<
typeof routeRequestInput,
typeof routeRequestOutput
> = {
name: "omniroute_route_request",
description:
"Sends a chat completion request through OmniRoute's intelligent routing pipeline. Supports combo selection, budget limits, and task role hints for optimal provider matching.",
inputSchema: routeRequestInput,
outputSchema: routeRequestOutput,
scopes: ["execute:completions"],
auditLevel: "full",
phase: 1,
sourceEndpoints: ["/v1/chat/completions", "/v1/responses"],
};
// --- Tool 7: omniroute_cost_report ---
export const costReportInput = z.object({
period: z
.enum(["session", "day", "week", "month"])
.optional()
.default("session")
.describe("Time period for the cost report"),
});
export const costReportOutput = z.object({
period: z.string(),
totalCost: z.number(),
requestCount: z.number(),
tokenCount: z.object({
prompt: z.number(),
completion: z.number(),
}),
byProvider: z.array(
z.object({
name: z.string(),
cost: z.number(),
requests: z.number(),
})
),
byModel: z.array(
z.object({
model: z.string(),
cost: z.number(),
requests: z.number(),
})
),
budget: z.object({
limit: z.number().nullable(),
remaining: z.number().nullable(),
}),
});
export const costReportTool: McpToolDefinition<typeof costReportInput, typeof costReportOutput> = {
name: "omniroute_cost_report",
description:
"Generates a cost report for the specified period showing total cost, request count, token usage, and breakdowns by provider and model. Also shows budget status if configured.",
inputSchema: costReportInput,
outputSchema: costReportOutput,
scopes: ["read:usage"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/usage/analytics", "/api/usage/budget"],
};
// --- Tool 8: omniroute_list_models_catalog ---
export const listModelsCatalogInput = z.object({
provider: z.string().optional().describe("Filter by provider name"),
capability: z
.enum(["chat", "embedding", "image", "audio", "video", "rerank", "moderation"])
.optional()
.describe("Filter by model capability"),
});
export const listModelsCatalogOutput = z.object({
models: z.array(
z.object({
id: z.string(),
provider: z.string(),
capabilities: z.array(z.string()),
status: z.enum(["available", "degraded", "unavailable"]),
pricing: z
.object({
inputPerMillion: z.number().nullable(),
outputPerMillion: z.number().nullable(),
})
.optional(),
})
),
});
export const listModelsCatalogTool: McpToolDefinition<
typeof listModelsCatalogInput,
typeof listModelsCatalogOutput
> = {
name: "omniroute_list_models_catalog",
description:
"Lists all available AI models across all providers with their capabilities, current status, and pricing information.",
inputSchema: listModelsCatalogInput,
outputSchema: listModelsCatalogOutput,
scopes: ["read:models"],
auditLevel: "none",
phase: 1,
sourceEndpoints: ["/api/models/catalog", "/v1/models"],
};
// ============ Phase 2: Advanced Tools (8) ============
// --- Tool 9: omniroute_simulate_route ---
export const simulateRouteInput = z.object({
model: z.string().describe("Target model for simulation"),
promptTokenEstimate: z.number().describe("Estimated prompt token count"),
combo: z.string().optional().describe("Specific combo to simulate (default: active combo)"),
});
export const simulateRouteOutput = z.object({
simulatedPath: z.array(
z.object({
provider: z.string(),
model: z.string(),
probability: z.number(),
estimatedCost: z.number(),
healthStatus: z.enum(["CLOSED", "OPEN", "HALF_OPEN"]),
quotaAvailable: z.number(),
})
),
fallbackTree: z.object({
primary: z.string(),
fallbacks: z.array(z.string()),
worstCaseCost: z.number(),
bestCaseCost: z.number(),
}),
});
export const simulateRouteTool: McpToolDefinition<
typeof simulateRouteInput,
typeof simulateRouteOutput
> = {
name: "omniroute_simulate_route",
description:
"Simulates (dry-run) the routing path a request would take without actually executing it. Shows the fallback tree, provider probabilities, estimated costs, and health status.",
inputSchema: simulateRouteInput,
outputSchema: simulateRouteOutput,
scopes: ["read:health", "read:combos"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: ["/api/combos", "/api/monitoring/health", "/api/resilience"],
};
// --- Tool 10: omniroute_set_budget_guard ---
export const setBudgetGuardInput = z.object({
maxCost: z.number().describe("Maximum cost in USD for this session"),
action: z.enum(["degrade", "block", "alert"]).describe("Action when budget is exceeded"),
degradeToTier: z
.enum(["cheap", "free"])
.optional()
.describe("If action=degrade, which tier to fall back to"),
});
export const setBudgetGuardOutput = z.object({
sessionId: z.string(),
budgetTotal: z.number(),
budgetSpent: z.number(),
budgetRemaining: z.number(),
action: z.string(),
status: z.enum(["active", "warning", "exceeded"]),
});
export const setBudgetGuardTool: McpToolDefinition<
typeof setBudgetGuardInput,
typeof setBudgetGuardOutput
> = {
name: "omniroute_set_budget_guard",
description:
"Sets a budget guard that limits spending for the current session. When the budget is reached, it can degrade to cheaper models, block requests, or send alerts.",
inputSchema: setBudgetGuardInput,
outputSchema: setBudgetGuardOutput,
scopes: ["write:budget"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/usage/budget"],
};
// --- Tool 11: omniroute_set_routing_strategy ---
export const setRoutingStrategyInput = z.object({
comboId: z.string().describe("Combo ID or name to update"),
strategy: z
.enum([
"priority",
"weighted",
"round-robin",
"strict-random",
"random",
"least-used",
"cost-optimized",
"auto",
])
.describe("Routing strategy to apply"),
autoRoutingStrategy: z
.enum(["rules", "cost", "eco", "latency", "fast"])
.optional()
.describe("Optional strategy used by auto mode (only used when strategy='auto')"),
});
export const setRoutingStrategyOutput = z.object({
success: z.boolean(),
combo: z.object({
id: z.string(),
name: z.string(),
strategy: z.string(),
autoRoutingStrategy: z.string().nullable(),
}),
});
export const setRoutingStrategyTool: McpToolDefinition<
typeof setRoutingStrategyInput,
typeof setRoutingStrategyOutput
> = {
name: "omniroute_set_routing_strategy",
description:
"Updates a combo routing strategy (priority/weighted/auto/etc.) at runtime. Supports selecting the sub-strategy used by auto mode (rules/cost/latency).",
inputSchema: setRoutingStrategyInput,
outputSchema: setRoutingStrategyOutput,
scopes: ["write:combos"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/combos", "/api/combos/{id}"],
};
// --- Tool 12: omniroute_set_resilience_profile ---
export const setResilienceProfileInput = z.object({
profile: z
.enum(["aggressive", "balanced", "conservative"])
.describe("Resilience profile to apply"),
});
export const setResilienceProfileOutput = z.object({
applied: z.boolean(),
settings: z.object({
circuitBreakerThreshold: z.number(),
retryCount: z.number(),
timeoutMs: z.number(),
fallbackDepth: z.number(),
}),
});
export const setResilienceProfileTool: McpToolDefinition<
typeof setResilienceProfileInput,
typeof setResilienceProfileOutput
> = {
name: "omniroute_set_resilience_profile",
description:
"Applies a resilience profile that adjusts circuit breaker thresholds, retry counts, timeouts, and fallback depth. 'aggressive' = fast fail, 'conservative' = max retries.",
inputSchema: setResilienceProfileInput,
outputSchema: setResilienceProfileOutput,
scopes: ["write:resilience"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/resilience"],
};
// --- Tool 13: omniroute_test_combo ---
export const testComboInput = z.object({
comboId: z.string().describe("ID of the combo to test"),
testPrompt: z.string().max(500).describe("Short test prompt (max 500 chars)"),
});
export const testComboOutput = z.object({
results: z.array(
z.object({
provider: z.string(),
model: z.string(),
success: z.boolean(),
latencyMs: z.number(),
cost: z.number(),
tokenCount: z.number(),
error: z.string().optional(),
})
),
summary: z.object({
totalProviders: z.number(),
successful: z.number(),
fastestProvider: z.string(),
cheapestProvider: z.string(),
}),
});
export const testComboTool: McpToolDefinition<typeof testComboInput, typeof testComboOutput> = {
name: "omniroute_test_combo",
description:
"Tests a combo by sending a short test prompt to each provider in the combo and reporting individual results including latency, cost, and success status.",
inputSchema: testComboInput,
outputSchema: testComboOutput,
scopes: ["execute:completions", "read:combos"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/combos/test", "/v1/chat/completions"],
};
// --- Tool 14: omniroute_get_provider_metrics ---
export const getProviderMetricsInput = z.object({
provider: z.string().describe("Provider name (e.g., 'claude', 'gemini-cli', 'codex')"),
});
export const getProviderMetricsOutput = z.object({
provider: z.string(),
successRate: z.number(),
requestCount: z.number(),
avgLatencyMs: z.number(),
p50LatencyMs: z.number(),
p95LatencyMs: z.number(),
p99LatencyMs: z.number(),
errorRate: z.number(),
lastError: z
.object({
message: z.string(),
timestamp: z.string(),
})
.nullable(),
circuitBreakerState: z.enum(["CLOSED", "OPEN", "HALF_OPEN"]),
quotaInfo: z.object({
used: z.number(),
total: z.number().nullable(),
resetAt: z.string().nullable(),
}),
});
export const getProviderMetricsTool: McpToolDefinition<
typeof getProviderMetricsInput,
typeof getProviderMetricsOutput
> = {
name: "omniroute_get_provider_metrics",
description:
"Returns detailed performance metrics for a specific provider including success/error rates, latency percentiles (p50/p95/p99), circuit breaker state, and quota information.",
inputSchema: getProviderMetricsInput,
outputSchema: getProviderMetricsOutput,
scopes: ["read:health"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: ["/api/provider-metrics", "/api/resilience"],
};
// --- Tool 15: omniroute_best_combo_for_task ---
export const bestComboForTaskInput = z.object({
taskType: z
.enum(["coding", "review", "planning", "analysis", "debugging", "documentation"])
.describe("Type of task to find the best combo for"),
budgetConstraint: z.number().optional().describe("Maximum cost in USD"),
latencyConstraint: z.number().optional().describe("Maximum acceptable latency in ms"),
});
export const bestComboForTaskOutput = z.object({
recommendedCombo: z.object({
id: z.string(),
name: z.string(),
reason: z.string(),
}),
alternatives: z.array(
z.object({
id: z.string(),
name: z.string(),
tradeoff: z.string(),
})
),
freeAlternative: z
.object({
id: z.string(),
name: z.string(),
})
.nullable(),
});
export const bestComboForTaskTool: McpToolDefinition<
typeof bestComboForTaskInput,
typeof bestComboForTaskOutput
> = {
name: "omniroute_best_combo_for_task",
description:
"Recommends the best combo for a given task type (coding, review, planning, etc.) considering budget and latency constraints. Also suggests alternatives and free options.",
inputSchema: bestComboForTaskInput,
outputSchema: bestComboForTaskOutput,
scopes: ["read:combos", "read:health"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: ["/api/combos", "/api/combos/metrics", "/api/monitoring/health"],
};
// --- Tool 16: omniroute_explain_route ---
export const explainRouteInput = z.object({
requestId: z.string().describe("Request ID from the X-Request-Id header"),
});
export const explainRouteOutput = z.object({
requestId: z.string(),
decision: z.object({
comboUsed: z.string(),
providerSelected: z.string(),
modelUsed: z.string(),
score: z.number(),
factors: z.array(
z.object({
name: z.string(),
value: z.number(),
weight: z.number(),
contribution: z.number(),
})
),
fallbacksTriggered: z.array(
z.object({
provider: z.string(),
reason: z.string(),
})
),
costActual: z.number(),
latencyActual: z.number(),
}),
});
export const explainRouteTool: McpToolDefinition<
typeof explainRouteInput,
typeof explainRouteOutput
> = {
name: "omniroute_explain_route",
description:
"Explains why a specific request was routed to a particular provider. Shows the scoring factors, weights, fallbacks triggered, actual cost, and latency.",
inputSchema: explainRouteInput,
outputSchema: explainRouteOutput,
scopes: ["read:health", "read:usage"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: [],
};
// --- Tool 17: omniroute_get_session_snapshot ---
export const getSessionSnapshotInput = z.object({}).describe("No parameters required");
export const getSessionSnapshotOutput = z.object({
sessionStart: z.string(),
duration: z.string(),
requestCount: z.number(),
costTotal: z.number(),
tokenCount: z.object({
prompt: z.number(),
completion: z.number(),
}),
topModels: z.array(
z.object({
model: z.string(),
count: z.number(),
})
),
topProviders: z.array(
z.object({
provider: z.string(),
count: z.number(),
})
),
errors: z.number(),
fallbacks: z.number(),
budgetGuard: z
.object({
active: z.boolean(),
remaining: z.number(),
})
.nullable(),
});
export const getSessionSnapshotTool: McpToolDefinition<
typeof getSessionSnapshotInput,
typeof getSessionSnapshotOutput
> = {
name: "omniroute_get_session_snapshot",
description:
"Returns a snapshot of the current working session including duration, request count, total cost, top models/providers used, error count, and budget guard status.",
inputSchema: getSessionSnapshotInput,
outputSchema: getSessionSnapshotOutput,
scopes: ["read:usage"],
auditLevel: "none",
phase: 2,
sourceEndpoints: ["/api/usage/analytics", "/api/telemetry/summary"],
};
// --- Tool 18: omniroute_sync_pricing ---
export const syncPricingInput = z.object({
sources: z
.array(z.string())
.optional()
.describe("External pricing sources to sync from (default: ['litellm'])"),
dryRun: z
.boolean()
.optional()
.describe("If true, preview sync results without saving to database"),
});
export const syncPricingOutput = z.object({
success: z.boolean(),
modelCount: z.number(),
providerCount: z.number(),
source: z.string(),
dryRun: z.boolean(),
error: z.string().optional(),
warnings: z.array(z.string()).optional(),
data: z.record(z.string(), z.record(z.string(), z.unknown())).optional(),
});
export const syncPricingTool: McpToolDefinition<typeof syncPricingInput, typeof syncPricingOutput> =
{
name: "omniroute_sync_pricing",
description:
"Syncs pricing data from external sources (LiteLLM) into OmniRoute. Synced pricing fills gaps not covered by hardcoded defaults without overwriting user-set prices. Use dryRun=true to preview.",
inputSchema: syncPricingInput,
outputSchema: syncPricingOutput,
scopes: ["pricing:write"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/pricing/sync"],
};
// ============ Tool Registry ============
/** All MCP tool definitions, ordered by phase then name */
export const MCP_TOOLS = [
// Phase 1: Essential
getHealthTool,
listCombosTool,
getComboMetricsTool,
switchComboTool,
checkQuotaTool,
routeRequestTool,
costReportTool,
listModelsCatalogTool,
// Phase 2: Advanced
simulateRouteTool,
setBudgetGuardTool,
setRoutingStrategyTool,
setResilienceProfileTool,
testComboTool,
getProviderMetricsTool,
bestComboForTaskTool,
explainRouteTool,
getSessionSnapshotTool,
syncPricingTool,
] as const;
/** Essential tools only (Phase 1) */
export const MCP_ESSENTIAL_TOOLS = MCP_TOOLS.filter((t) => t.phase === 1);
/** Advanced tools only (Phase 2) */
export const MCP_ADVANCED_TOOLS = MCP_TOOLS.filter((t) => t.phase === 2);
/** Map of tool name → tool definition */
export const MCP_TOOL_MAP = Object.fromEntries(MCP_TOOLS.map((t) => [t.name, t])) as Record<
string,
(typeof MCP_TOOLS)[number]
>;