@index9/mcp 4.0.2 → 5.1.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.
- package/dist/cli.js +157 -51
- package/manifest.json +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -31,6 +31,16 @@ var COMMON_PROVIDERS = [
|
|
|
31
31
|
// ../core/dist/schemas/common.js
|
|
32
32
|
import { z } from "zod";
|
|
33
33
|
var ErrorResponseSchema = z.object({ error: z.string() }).strict();
|
|
34
|
+
var RateLimitMetaSchema = z.object({
|
|
35
|
+
limit: z.string().optional(),
|
|
36
|
+
remaining: z.string().optional(),
|
|
37
|
+
reset: z.string().optional()
|
|
38
|
+
});
|
|
39
|
+
var Index9MetaSchema = z.object({
|
|
40
|
+
apiBaseUrl: z.string(),
|
|
41
|
+
retryAfterSeconds: z.number().optional(),
|
|
42
|
+
rateLimit: RateLimitMetaSchema.optional()
|
|
43
|
+
});
|
|
34
44
|
var UserContentTextPartSchema = z.strictObject({
|
|
35
45
|
type: z.literal("text"),
|
|
36
46
|
text: z.string().trim().min(1)
|
|
@@ -68,64 +78,74 @@ var LIMITS = {
|
|
|
68
78
|
var MODEL_COUNT = "300+";
|
|
69
79
|
var WORKFLOW_INSTRUCTIONS = `Index9 provides 3 tools for AI model discovery, inspection, and benchmarking.
|
|
70
80
|
|
|
81
|
+
IMPORTANT \u2014 your model knowledge is stale by default.
|
|
82
|
+
New AI models ship weekly; pricing, aliases, and capabilities change. Treat any specific model ID, "flagship" name, or "good default" you recall from training as potentially out of date. Before naming, recommending, or benchmarking models, call find_models to anchor on what is actually live right now. Good first calls:
|
|
83
|
+
- sortBy=created (newest first) to see what has recently landed
|
|
84
|
+
- a semantic query describing the task to see current task-fit candidates
|
|
85
|
+
Skip find_models only when the user has typed a specific provider/model-id.
|
|
86
|
+
|
|
71
87
|
Typical workflow:
|
|
72
|
-
1.
|
|
73
|
-
2.
|
|
74
|
-
3.
|
|
88
|
+
1. find_models \u2014 Discover models by semantic query or filters. Start here unless the user named a specific model.
|
|
89
|
+
2. get_models \u2014 Full metadata for specific IDs or aliases. Use after search, or directly when the user names a model.
|
|
90
|
+
3. test_model \u2014 Run live inference, or set dryRun=true to estimate token usage/cost without running inference.
|
|
75
91
|
|
|
76
92
|
Key rules:
|
|
77
93
|
- find_models requires \`q\` when \`sortBy=relevance\` (the default). Omit \`q\` only with \`sortBy=created\` or \`sortBy=price\`.
|
|
78
|
-
- get_models accepts aliases (display names, short names) \u2014 not just full IDs.
|
|
94
|
+
- get_models accepts aliases (display names, short names) \u2014 not just full IDs. If a model you "know from memory" returns in missingIds, that is a signal to call find_models.
|
|
79
95
|
- Use test_model with \`dryRun=true\` to estimate cost before live testing.
|
|
80
96
|
- test_model with \`dryRun=false\` (default) requires OPENROUTER_API_KEY and incurs real usage costs.
|
|
97
|
+
- Reasoning-capable models (capabilities includes "reasoning") burn hidden reasoning tokens against \`maxTokens\` before emitting visible text. Leave \`maxTokens\` unset, or set it to at least 2000, when testing reasoning models \u2014 otherwise results may fail with finish_reason=length.
|
|
81
98
|
- Cursors are opaque and tied to query/sort/filters. Reuse the same query/sort/filters when paginating. \`limit\` may change between pages.`;
|
|
82
99
|
var TOOLS = {
|
|
83
100
|
find_models: {
|
|
84
101
|
name: "find_models",
|
|
102
|
+
title: "Search AI models",
|
|
85
103
|
summary: "Search and paginate AI models by semantic query or filters",
|
|
86
104
|
description: `Search and filter ${MODEL_COUNT} AI models. Returns ranked results with pricing, context windows, and capabilities.
|
|
87
105
|
|
|
88
|
-
Call this
|
|
106
|
+
Call this first unless the user named a specific model \u2014 your training-data list of "good" models is likely stale.
|
|
89
107
|
|
|
90
|
-
|
|
91
|
-
When the user mentions numeric or categorical constraints, you MUST map them to the structured filter parameters below instead of relying solely on \`q\`. The \`q\` parameter drives semantic ranking but does NOT enforce hard constraints.
|
|
108
|
+
Extract filters from user queries. \`q\` drives semantic ranking; numeric and categorical constraints MUST go in structured filters. Shorthand: 1K=1000, 1M=1000000. Prices are USD per million input tokens.
|
|
92
109
|
|
|
93
110
|
Examples:
|
|
94
|
-
- "
|
|
95
|
-
- "cheap vision model from openai" \u2192 q="cheap vision model", capabilitiesAll="vision", provider="openai"
|
|
96
|
-
- "function calling under $0.50 with 128K
|
|
97
|
-
- "best coding model" \u2192 q="best coding model"
|
|
111
|
+
- "1M context under $1" \u2192 q="model", minContext=1000000, maxPrice=1
|
|
112
|
+
- "cheap vision model from openai" \u2192 q="cheap vision model", capabilitiesAll=["vision"], provider="openai"
|
|
113
|
+
- "function calling under $0.50 with 128K" \u2192 q="function calling", capabilitiesAll=["function_calling"], maxPrice=0.5, minContext=128000
|
|
114
|
+
- "best coding model" \u2192 q="best coding model"
|
|
115
|
+
- "what's new" \u2192 sortBy="created" (no q needed)
|
|
98
116
|
|
|
99
|
-
|
|
117
|
+
Valid capabilities: ${CAPABILITIES.join(", ")}.
|
|
100
118
|
|
|
101
|
-
|
|
102
|
-
- q: Semantic search query \u2014 use for intent/quality ranking, not for numeric constraints
|
|
103
|
-
- provider: Filter by provider(s). Comma-separated for multiple (e.g., 'openai,anthropic')
|
|
104
|
-
- minPrice, maxPrice: Price bounds in USD per million input tokens
|
|
105
|
-
- minContext: Minimum context window in tokens
|
|
106
|
-
- capabilitiesAll: Capabilities the model MUST have (AND logic). Valid: ${CAPABILITIES.join(", ")}
|
|
107
|
-
- capabilitiesAny: Capabilities where at least one must be present (OR logic)
|
|
108
|
-
- sortBy: 'relevance' (default), 'created', 'price'
|
|
109
|
-
- limit: Page size
|
|
110
|
-
- cursor: Opaque pagination cursor
|
|
119
|
+
Each result: id, name, description, created (unix seconds), createdAt (ISO 8601), contextLength, maxOutputTokens, pricing.{promptPerMillion, completionPerMillion} (numbers, USD per million tokens), capabilities[], score.
|
|
111
120
|
|
|
112
|
-
|
|
121
|
+
\`score\` is 0-100: the best match per page scores 100; others scale proportionally. Combines semantic similarity and keyword matching. Null when sorting by price or date.
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
Pass result.id to get_models for full specs or to test_model for live testing.`,
|
|
115
124
|
requiresKey: false
|
|
116
125
|
},
|
|
117
126
|
get_models: {
|
|
118
127
|
name: "get_models",
|
|
128
|
+
title: "Inspect AI models",
|
|
119
129
|
summary: "Get full model metadata by IDs or aliases (batch, up to 100)",
|
|
120
|
-
description: `Get
|
|
130
|
+
description: `Get full specs for one or more models by id or alias. Accepts up to ${LIMITS.getModelsMax} ids per call \u2014 use this for batch comparison.
|
|
131
|
+
|
|
132
|
+
Call after find_models to inspect candidates, or directly when the user names a model (format: 'provider/model-name').
|
|
121
133
|
|
|
122
|
-
|
|
134
|
+
Response: { results: (Model | null)[], missingIds: string[], resolvedAliases?: Record<alias, canonicalId>, ambiguousAliases?: Record<alias, candidateIds[]> }. Each non-null result has:
|
|
135
|
+
- id, canonicalSlug, name, description
|
|
136
|
+
- created (unix seconds), createdAt (ISO 8601), knowledgeCutoff (ISO date or null)
|
|
137
|
+
- contextLength (tokens), maxOutputTokens, isModerated
|
|
138
|
+
- pricing: { promptPerMillion, completionPerMillion, requestUsd, imageUsd } \u2014 all USD, all numbers. Token prices are per million tokens; request/image are per unit.
|
|
139
|
+
- architecture: { inputModalities[], outputModalities[], tokenizer, instructType }
|
|
140
|
+
- capabilities[]: normalized capability flags (same values as find_models and capabilitiesAll/Any)
|
|
141
|
+
- supportedParameters[]: OpenRouter parameters the model accepts (e.g., "temperature", "tools", "response_format")
|
|
123
142
|
|
|
124
|
-
|
|
143
|
+
Entries in results are null when the id is unknown; those ids appear in missingIds. Ambiguous aliases appear in ambiguousAliases with candidate canonical ids \u2014 pass a canonical id to disambiguate.`,
|
|
125
144
|
requiresKey: false
|
|
126
145
|
},
|
|
127
146
|
test_model: {
|
|
128
147
|
name: "test_model",
|
|
148
|
+
title: "Test AI models live",
|
|
129
149
|
summary: "Run live inference or dry-run cost estimation across up to 10 models",
|
|
130
150
|
description: `Run model tests on 1-${LIMITS.testModelsMax} models. Use dryRun=true to estimate token usage/cost, or dryRun=false (default) to run live OpenRouter inference.
|
|
131
151
|
|
|
@@ -140,9 +160,9 @@ Parameters:
|
|
|
140
160
|
- prompt: Prompt text (required for dryRun; required for live unless userContent provided)
|
|
141
161
|
- dryRun: If true, return cost estimates only
|
|
142
162
|
- expectedCompletionTokens: Optional completion token estimate used by dryRun
|
|
143
|
-
-
|
|
163
|
+
- maxTokens, systemPrompt, temperature, topP, seed, responseFormat, enforceJson, retries: Live-testing controls (ignored when dryRun=true)
|
|
144
164
|
|
|
145
|
-
Use find_models or get_models first to identify model
|
|
165
|
+
Results (live): each result carries modelId (the id you passed), resolvedModelId (canonical id, present when the input was an alias), ok, response, latencyMs, tokens { prompt, completion }, cost (USD; live from OpenRouter when available, else estimated from cached pricing), and truncated=true when finish_reason is "length". Use find_models or get_models first to identify model ids.`,
|
|
146
166
|
requiresKey: true
|
|
147
167
|
}
|
|
148
168
|
};
|
|
@@ -150,15 +170,17 @@ var PARAM_DESCRIPTIONS = {
|
|
|
150
170
|
q: "Natural language search query describing desired model characteristics (e.g., 'fast cheap coding model'). Uses semantic search with fuzzy matching. Optional - omit to use filters only.",
|
|
151
171
|
sortBy: `Sort order for results. Options: 'relevance' (best semantic match, default), 'created' (newest models), 'price' (cheapest/most expensive, with sortOrder). Defaults to 'relevance'.`,
|
|
152
172
|
cursor: `Opaque pagination cursor from a previous response's \`nextCursor\` field. IMPORTANT: cursors are bound to the exact query text, filters, and sort order that produced them. Reuse the same query+filters+sort when paginating. \`limit\` may change between pages. To start a new search, omit the cursor.`,
|
|
153
|
-
capabilitiesAll: `
|
|
154
|
-
capabilitiesAny: `
|
|
155
|
-
modality: `Required output modality. Filters on the model's output modalities, not input capabilities. For example,
|
|
173
|
+
capabilitiesAll: `Array of capabilities that must ALL be present on the model (AND logic). Valid values: ${CAPABILITIES.join(", ")}. Example: ["function_calling","vision"].`,
|
|
174
|
+
capabilitiesAny: `Array of capabilities where at least ONE must be present (OR logic). Valid values: ${CAPABILITIES.join(", ")}. Example: ["vision","audio_input"].`,
|
|
175
|
+
modality: `Required output modality. Filters on the model's output modalities, not input capabilities. For example, "image" finds image-generation models, while capabilitiesAll=["vision"] finds models that accept image input. Valid values: ${OUTPUT_MODALITIES.join(", ")}.`,
|
|
156
176
|
provider: `Provider prefix filter. Matches model IDs starting with this prefix (e.g., 'openai' matches 'openai/gpt-4o'). Common providers: ${COMMON_PROVIDERS.join(", ")}.`,
|
|
157
177
|
expectedCompletionTokens: `Expected number of completion tokens for cost estimation (default: 256). Typical ranges: 100-500 for quick tests, 1000-2000 for code generation, 4000+ for long-form content. This is a heuristic \u2014 actual billed tokens may differ.`
|
|
158
178
|
};
|
|
159
179
|
var SITE = {
|
|
160
180
|
nav: {
|
|
161
181
|
brand: "index9",
|
|
182
|
+
tools: "Tools",
|
|
183
|
+
howItWorks: "How it works",
|
|
162
184
|
install: "Install",
|
|
163
185
|
faq: "FAQ",
|
|
164
186
|
github: "GitHub",
|
|
@@ -168,19 +190,47 @@ var SITE = {
|
|
|
168
190
|
titleLine1: "Test AI models on your actual prompts, ",
|
|
169
191
|
titleLine2: "not generic benchmarks",
|
|
170
192
|
subtitle: "Compare quality, speed, and cost across 300+ models \u2014 in Cursor, VS Code, or Claude Code.",
|
|
171
|
-
|
|
193
|
+
identity: "index9 is an MCP server that lets your AI coding assistant search, compare, and live-test models from inside your editor.",
|
|
194
|
+
audiencePrefix: "Built for",
|
|
195
|
+
audience: ["AI engineers", "Indie developers", "Teams standardizing on models"],
|
|
196
|
+
pricingNote: "Free. You only pay OpenRouter for live model calls.",
|
|
197
|
+
getStarted: "Add to your editor",
|
|
172
198
|
seeHowItWorks: "See an example",
|
|
173
|
-
updatedBadge: "
|
|
199
|
+
updatedBadge: "Model pricing & specs from OpenRouter \u2014 refreshed "
|
|
200
|
+
},
|
|
201
|
+
howItWorks: {
|
|
202
|
+
label: "How it works",
|
|
203
|
+
heading: "Your assistant picks the right model, automatically",
|
|
204
|
+
subtitle: "index9 runs as an MCP (Model Context Protocol) server. Your editor already speaks MCP \u2014 index9 just plugs in as three extra tools your assistant can call.",
|
|
205
|
+
steps: [
|
|
206
|
+
{
|
|
207
|
+
number: "1",
|
|
208
|
+
title: "You ask your assistant",
|
|
209
|
+
body: '"Pick the cheapest model that can summarize this document well." You chat normally \u2014 no new UI to learn.'
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
number: "2",
|
|
213
|
+
title: "Your assistant calls index9",
|
|
214
|
+
body: "It runs find_models, get_models, and test_model against live OpenRouter data. Results come back with latency, tokens, and cost for your prompt."
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
number: "3",
|
|
218
|
+
title: "You get a measured recommendation",
|
|
219
|
+
body: "The assistant compares real outputs on your real prompt, then recommends the model that fits your constraints. Evidence, not guesswork."
|
|
220
|
+
}
|
|
221
|
+
]
|
|
174
222
|
},
|
|
175
223
|
toolsSection: {
|
|
176
224
|
label: "Tools",
|
|
177
|
-
heading: "Search,
|
|
225
|
+
heading: "Search, inspect, and run live tests",
|
|
226
|
+
subheading: "Three MCP tools your assistant can call. Each maps to one clear job your assistant can do without leaving the chat.",
|
|
178
227
|
openRouterKey: "OpenRouter API key (live tests only)",
|
|
179
228
|
noKeyRequired: "No API key required",
|
|
180
229
|
requiresLabel: "Requires ",
|
|
181
230
|
cards: [
|
|
182
231
|
{
|
|
183
232
|
name: "find_models",
|
|
233
|
+
action: "Search",
|
|
184
234
|
displayName: "find_models",
|
|
185
235
|
fullName: null,
|
|
186
236
|
description: `Search ${MODEL_COUNT} models by what you need \u2014 price, speed, context window, or capabilities like vision and function calling.`,
|
|
@@ -189,14 +239,16 @@ var SITE = {
|
|
|
189
239
|
},
|
|
190
240
|
{
|
|
191
241
|
name: "get_models",
|
|
242
|
+
action: "Inspect",
|
|
192
243
|
displayName: "get_models",
|
|
193
244
|
fullName: null,
|
|
194
|
-
description: "Get current pricing, limits, and capabilities for any model.
|
|
245
|
+
description: "Get current pricing, limits, and capabilities for any model. Synced from OpenRouter every 30 minutes.",
|
|
195
246
|
badge: null,
|
|
196
247
|
requiresKey: false
|
|
197
248
|
},
|
|
198
249
|
{
|
|
199
250
|
name: "test_model",
|
|
251
|
+
action: "Run live tests",
|
|
200
252
|
displayName: "test_model",
|
|
201
253
|
fullName: null,
|
|
202
254
|
description: "Send your prompt to multiple models. Compare outputs, latency, and cost \u2014 measured, not estimated.",
|
|
@@ -234,7 +286,7 @@ var SITE = {
|
|
|
234
286
|
},
|
|
235
287
|
{
|
|
236
288
|
question: "What's the project status?",
|
|
237
|
-
answer: "index9 is
|
|
289
|
+
answer: "index9 is live and used daily. Core tools are stable. Improvements ship through changesets on GitHub; issues and feedback are welcome there.",
|
|
238
290
|
link: null
|
|
239
291
|
},
|
|
240
292
|
{
|
|
@@ -246,7 +298,8 @@ var SITE = {
|
|
|
246
298
|
},
|
|
247
299
|
install: {
|
|
248
300
|
label: "Setup",
|
|
249
|
-
heading: "Add to your
|
|
301
|
+
heading: "Add index9 to your editor",
|
|
302
|
+
subheading: "One line of config for Cursor, VS Code, or Claude Code. Your assistant can start using it immediately.",
|
|
250
303
|
configs: [
|
|
251
304
|
{
|
|
252
305
|
id: "cursor-vscode",
|
|
@@ -288,6 +341,7 @@ var SITE = {
|
|
|
288
341
|
comparison: {
|
|
289
342
|
label: "Comparison",
|
|
290
343
|
heading: "Evidence over intuition",
|
|
344
|
+
subheading: "Benchmark on your real prompts \u2014 not someone else's.",
|
|
291
345
|
withoutLabel: "Without index9",
|
|
292
346
|
withLabel: "With index9",
|
|
293
347
|
withoutItems: [
|
|
@@ -439,16 +493,16 @@ var SearchQuerySchema = z2.object({
|
|
|
439
493
|
minPrice: z2.number().min(0).optional(),
|
|
440
494
|
maxPrice: z2.number().min(0).optional(),
|
|
441
495
|
minContext: z2.number().int().min(1).optional(),
|
|
442
|
-
capabilitiesAll: z2.array(z2.
|
|
443
|
-
capabilitiesAny: z2.array(z2.
|
|
444
|
-
modality: z2.
|
|
496
|
+
capabilitiesAll: z2.array(z2.enum(CAPABILITIES)).optional(),
|
|
497
|
+
capabilitiesAny: z2.array(z2.enum(CAPABILITIES)).optional(),
|
|
498
|
+
modality: z2.enum(OUTPUT_MODALITIES).optional(),
|
|
445
499
|
provider: z2.string().min(1).optional()
|
|
446
500
|
}).strict();
|
|
447
501
|
var SearchResultSchema = z2.object({
|
|
448
|
-
|
|
502
|
+
id: z2.string(),
|
|
449
503
|
name: z2.string(),
|
|
450
504
|
description: z2.string(),
|
|
451
|
-
|
|
505
|
+
created: z2.number().nullable(),
|
|
452
506
|
createdAt: z2.string().nullable(),
|
|
453
507
|
contextLength: z2.number().nullable(),
|
|
454
508
|
maxOutputTokens: z2.number().nullable(),
|
|
@@ -473,6 +527,9 @@ var SearchResponseSchema = z2.object({
|
|
|
473
527
|
ranking: z2.literal("hybrid_rrf")
|
|
474
528
|
})
|
|
475
529
|
});
|
|
530
|
+
var FindModelsToolResultSchema = SearchResponseSchema.extend({
|
|
531
|
+
_index9: Index9MetaSchema
|
|
532
|
+
});
|
|
476
533
|
|
|
477
534
|
// ../core/dist/schemas/model.js
|
|
478
535
|
import { z as z3 } from "zod";
|
|
@@ -480,13 +537,47 @@ var BatchModelLookupRequestSchema = z3.object({
|
|
|
480
537
|
ids: z3.array(z3.string().min(1)).min(1, "ids are required").max(LIMITS.getModelsMax, `ids must contain between 1 and ${LIMITS.getModelsMax} model IDs`),
|
|
481
538
|
maxDescriptionChars: z3.number().int().min(0).max(2e3).optional()
|
|
482
539
|
}).strict();
|
|
483
|
-
var
|
|
540
|
+
var ModelPricingSchema = z3.object({
|
|
541
|
+
promptPerMillion: z3.number().nullable(),
|
|
542
|
+
completionPerMillion: z3.number().nullable(),
|
|
543
|
+
requestUsd: z3.number().nullable(),
|
|
544
|
+
imageUsd: z3.number().nullable()
|
|
545
|
+
});
|
|
546
|
+
var ModelArchitectureSchema = z3.object({
|
|
547
|
+
inputModalities: z3.array(z3.string()),
|
|
548
|
+
outputModalities: z3.array(z3.string()),
|
|
549
|
+
tokenizer: z3.string().nullable(),
|
|
550
|
+
instructType: z3.string().nullable()
|
|
551
|
+
});
|
|
552
|
+
var ModelResponseSchema = z3.object({
|
|
553
|
+
id: z3.string(),
|
|
554
|
+
canonicalSlug: z3.string().nullable(),
|
|
555
|
+
name: z3.string(),
|
|
556
|
+
description: z3.string(),
|
|
557
|
+
created: z3.number().nullable(),
|
|
558
|
+
createdAt: z3.string().nullable(),
|
|
559
|
+
knowledgeCutoff: z3.string().nullable(),
|
|
560
|
+
contextLength: z3.number().nullable(),
|
|
561
|
+
maxOutputTokens: z3.number().nullable(),
|
|
562
|
+
isModerated: z3.boolean().nullable(),
|
|
563
|
+
pricing: ModelPricingSchema,
|
|
564
|
+
architecture: ModelArchitectureSchema,
|
|
565
|
+
capabilities: z3.array(z3.string()),
|
|
566
|
+
supportedParameters: z3.array(z3.string())
|
|
567
|
+
});
|
|
484
568
|
var BatchModelLookupResponseSchema = z3.object({
|
|
485
569
|
results: z3.array(ModelResponseSchema.nullable()),
|
|
486
570
|
missingIds: z3.array(z3.string()),
|
|
487
571
|
resolvedAliases: z3.record(z3.string(), z3.string()).optional(),
|
|
488
572
|
ambiguousAliases: z3.record(z3.string(), z3.array(z3.string())).optional()
|
|
489
573
|
}).strict();
|
|
574
|
+
var GetModelsToolResultSchema = z3.object({
|
|
575
|
+
results: z3.array(ModelResponseSchema.nullable()),
|
|
576
|
+
missingIds: z3.array(z3.string()),
|
|
577
|
+
resolvedAliases: z3.record(z3.string(), z3.string()).optional(),
|
|
578
|
+
ambiguousAliases: z3.record(z3.string(), z3.array(z3.string())).optional(),
|
|
579
|
+
_index9: Index9MetaSchema
|
|
580
|
+
});
|
|
490
581
|
|
|
491
582
|
// ../core/dist/schemas/test.js
|
|
492
583
|
import { z as z4 } from "zod";
|
|
@@ -540,7 +631,7 @@ var TestPricingUsedSchema = z4.object({
|
|
|
540
631
|
var TestModelMetadataSchema = z4.object({
|
|
541
632
|
id: z4.string(),
|
|
542
633
|
name: z4.string(),
|
|
543
|
-
|
|
634
|
+
created: z4.number().nullable().optional(),
|
|
544
635
|
createdAt: z4.string().nullable().optional(),
|
|
545
636
|
pricingUsed: TestPricingUsedSchema.optional()
|
|
546
637
|
});
|
|
@@ -552,7 +643,8 @@ var TestResultSuccessSchema = z4.object({
|
|
|
552
643
|
response: z4.string(),
|
|
553
644
|
latencyMs: z4.number().min(0),
|
|
554
645
|
tokens: UsageTokensSchema,
|
|
555
|
-
cost: z4.number().nullable().optional()
|
|
646
|
+
cost: z4.number().nullable().optional(),
|
|
647
|
+
truncated: z4.boolean().optional()
|
|
556
648
|
});
|
|
557
649
|
var TestResultFailureSchema = z4.object({
|
|
558
650
|
modelId: z4.string(),
|
|
@@ -683,10 +775,14 @@ function baseHeaders(ctx) {
|
|
|
683
775
|
return h;
|
|
684
776
|
}
|
|
685
777
|
function toResponse(payload, isError = false) {
|
|
686
|
-
|
|
778
|
+
const response = {
|
|
687
779
|
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
688
780
|
isError: isError || void 0
|
|
689
781
|
};
|
|
782
|
+
if (!isError && typeof payload === "object" && payload !== null && !Array.isArray(payload)) {
|
|
783
|
+
response.structuredContent = payload;
|
|
784
|
+
}
|
|
785
|
+
return response;
|
|
690
786
|
}
|
|
691
787
|
function parseRetryAfterSeconds(value) {
|
|
692
788
|
if (!value) return void 0;
|
|
@@ -818,6 +914,7 @@ async function createServer() {
|
|
|
818
914
|
server.registerTool(
|
|
819
915
|
"find_models",
|
|
820
916
|
{
|
|
917
|
+
title: TOOLS.find_models.title,
|
|
821
918
|
description: TOOLS.find_models.description,
|
|
822
919
|
inputSchema: {
|
|
823
920
|
q: z5.string().min(1).optional().describe(PARAM_DESCRIPTIONS.q),
|
|
@@ -830,11 +927,12 @@ async function createServer() {
|
|
|
830
927
|
minPrice: z5.number().min(0).optional().describe("Minimum prompt price in USD per million tokens."),
|
|
831
928
|
maxPrice: z5.number().min(0).optional().describe("Maximum prompt price in USD per million tokens."),
|
|
832
929
|
minContext: z5.number().int().min(1).optional().describe("Minimum context window in tokens."),
|
|
833
|
-
capabilitiesAll: z5.array(z5.
|
|
834
|
-
capabilitiesAny: z5.array(z5.
|
|
835
|
-
modality: z5.
|
|
930
|
+
capabilitiesAll: z5.array(z5.enum(CAPABILITIES)).optional().describe(PARAM_DESCRIPTIONS.capabilitiesAll),
|
|
931
|
+
capabilitiesAny: z5.array(z5.enum(CAPABILITIES)).optional().describe(PARAM_DESCRIPTIONS.capabilitiesAny),
|
|
932
|
+
modality: z5.enum(OUTPUT_MODALITIES).optional().describe(PARAM_DESCRIPTIONS.modality),
|
|
836
933
|
provider: z5.string().min(1).optional().describe(PARAM_DESCRIPTIONS.provider)
|
|
837
934
|
},
|
|
935
|
+
outputSchema: FindModelsToolResultSchema.shape,
|
|
838
936
|
annotations: { readOnlyHint: true }
|
|
839
937
|
},
|
|
840
938
|
async (args) => handleSearchModels(ctx, args)
|
|
@@ -842,11 +940,13 @@ async function createServer() {
|
|
|
842
940
|
server.registerTool(
|
|
843
941
|
"get_models",
|
|
844
942
|
{
|
|
943
|
+
title: TOOLS.get_models.title,
|
|
845
944
|
description: TOOLS.get_models.description,
|
|
846
945
|
inputSchema: {
|
|
847
946
|
ids: z5.array(z5.string().min(1)).min(1).max(100).describe("Model identifiers or aliases. Up to 100."),
|
|
848
947
|
maxDescriptionChars: z5.number().int().min(0).max(2e3).optional().describe("Truncate descriptions to this many characters.")
|
|
849
948
|
},
|
|
949
|
+
outputSchema: GetModelsToolResultSchema.shape,
|
|
850
950
|
annotations: { readOnlyHint: true }
|
|
851
951
|
},
|
|
852
952
|
async (args) => handleGetModels(ctx, args)
|
|
@@ -854,6 +954,7 @@ async function createServer() {
|
|
|
854
954
|
server.registerTool(
|
|
855
955
|
"test_model",
|
|
856
956
|
{
|
|
957
|
+
title: TOOLS.test_model.title,
|
|
857
958
|
description: TOOLS.test_model.description,
|
|
858
959
|
inputSchema: {
|
|
859
960
|
prompt: z5.string().min(1).optional().describe("Prompt sent to each model."),
|
|
@@ -864,7 +965,9 @@ async function createServer() {
|
|
|
864
965
|
expectedCompletionTokens: z5.number().int().min(1).optional().describe(PARAM_DESCRIPTIONS.expectedCompletionTokens),
|
|
865
966
|
models: z5.array(z5.string().min(1)).min(1).max(LIMITS.testModelsMax).describe(`Model IDs to evaluate (1-${LIMITS.testModelsMax}).`),
|
|
866
967
|
timeoutMs: z5.number().int().min(1).optional().describe("Per-model timeout in ms (default 15000, max 60000)."),
|
|
867
|
-
maxTokens: z5.number().int().min(1).optional().describe(
|
|
968
|
+
maxTokens: z5.number().int().min(1).optional().describe(
|
|
969
|
+
"Completion token cap. For reasoning-capable models, set \u2265 2000 (or omit) \u2014 reasoning tokens count against this before visible output, and too-low caps cause finish_reason=length."
|
|
970
|
+
),
|
|
868
971
|
systemPrompt: z5.string().min(1).optional().describe("System instruction prepended to prompt."),
|
|
869
972
|
temperature: z5.number().min(0).max(2).optional().describe("Sampling temperature (0-2)."),
|
|
870
973
|
topP: z5.number().gt(0).max(1).optional().describe("Nucleus sampling (0-1]."),
|
|
@@ -875,6 +978,9 @@ async function createServer() {
|
|
|
875
978
|
enforceJson: z5.boolean().optional().describe("When true, output must parse as JSON."),
|
|
876
979
|
retries: z5.number().int().min(0).max(3).optional().describe("Retries for transient failures.")
|
|
877
980
|
},
|
|
981
|
+
// No outputSchema: test_model returns a z.union of dry-run and live shapes.
|
|
982
|
+
// The SDK supports only ZodRawShape | AnySchema for outputSchema; a discriminated-union
|
|
983
|
+
// output is represented accurately in the tool description instead.
|
|
878
984
|
annotations: { readOnlyHint: false }
|
|
879
985
|
},
|
|
880
986
|
async (args) => handleTestModels(ctx, args)
|
package/manifest.json
CHANGED