@index9/mcp 5.0.0 → 5.2.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 +64 -27
- 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,56 +78,58 @@ 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.
|
|
83
|
+
|
|
84
|
+
When a user asks you to recommend or pick specific models, you MUST call find_models at least once with \`sortBy=created\` (newest first, no q) before committing to a shortlist. Sorting purely by price or using a semantic q alone returns the cheapest-ever cache entries \u2014 which are often superseded by newer cheap models you should have considered. A good pattern:
|
|
85
|
+
1. find_models sortBy=created, limit=10 \u2014 see what has landed recently (last weeks/months).
|
|
86
|
+
2. Optional second call: find_models with the task query or price filter to surface established options.
|
|
87
|
+
3. Cross-reference and pick 2-4 candidates that span recent + established.
|
|
88
|
+
|
|
89
|
+
Skip the anchor call only when the user has typed a specific provider/model-id.
|
|
90
|
+
|
|
71
91
|
Typical workflow:
|
|
72
|
-
1.
|
|
73
|
-
2.
|
|
74
|
-
3.
|
|
92
|
+
1. find_models \u2014 Discover models by semantic query or filters. Start here unless the user named a specific model.
|
|
93
|
+
2. get_models \u2014 Full metadata for specific IDs or aliases. Use after search, or directly when the user names a model.
|
|
94
|
+
3. test_model \u2014 Run live inference, or set dryRun=true to estimate token usage/cost without running inference.
|
|
75
95
|
|
|
76
96
|
Key rules:
|
|
77
97
|
- 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.
|
|
98
|
+
- 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
99
|
- Use test_model with \`dryRun=true\` to estimate cost before live testing.
|
|
80
100
|
- test_model with \`dryRun=false\` (default) requires OPENROUTER_API_KEY and incurs real usage costs.
|
|
101
|
+
- 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
102
|
- Cursors are opaque and tied to query/sort/filters. Reuse the same query/sort/filters when paginating. \`limit\` may change between pages.`;
|
|
82
103
|
var TOOLS = {
|
|
83
104
|
find_models: {
|
|
84
105
|
name: "find_models",
|
|
106
|
+
title: "Search AI models",
|
|
85
107
|
summary: "Search and paginate AI models by semantic query or filters",
|
|
86
108
|
description: `Search and filter ${MODEL_COUNT} AI models. Returns ranked results with pricing, context windows, and capabilities.
|
|
87
109
|
|
|
88
|
-
Call this
|
|
110
|
+
Call this first unless the user named a specific model \u2014 your training-data list of "good" models is likely stale. When recommending models to the user, always include one call with sortBy=created (no q) to see what has shipped recently; sorting purely by price surfaces old tiny models and misses this month's cheap frontier.
|
|
89
111
|
|
|
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.
|
|
112
|
+
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
113
|
|
|
93
114
|
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"
|
|
98
|
-
|
|
99
|
-
Convert shorthand: 1K=1000, 1M=1000000, 128K=128000. Prices are in USD per million input tokens.
|
|
115
|
+
- "1M context under $1" \u2192 q="model", minContext=1000000, maxPrice=1
|
|
116
|
+
- "cheap vision model from openai" \u2192 q="cheap vision model", capabilitiesAll=["vision"], provider="openai"
|
|
117
|
+
- "function calling under $0.50 with 128K" \u2192 q="function calling", capabilitiesAll=["function_calling"], maxPrice=0.5, minContext=128000
|
|
118
|
+
- "best coding model" \u2192 q="best coding model"
|
|
119
|
+
- "what's new" \u2192 sortBy="created" (no q needed)
|
|
100
120
|
|
|
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
|
|
121
|
+
Valid capabilities: ${CAPABILITIES.join(", ")}.
|
|
111
122
|
|
|
112
|
-
Each result
|
|
123
|
+
Each result: id, name, description, created (unix seconds), createdAt (ISO 8601), contextLength, maxOutputTokens, pricing.{promptPerMillion, completionPerMillion} (numbers, USD per million tokens), capabilities[], score.
|
|
113
124
|
|
|
114
|
-
|
|
125
|
+
\`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.
|
|
115
126
|
|
|
116
127
|
Pass result.id to get_models for full specs or to test_model for live testing.`,
|
|
117
128
|
requiresKey: false
|
|
118
129
|
},
|
|
119
130
|
get_models: {
|
|
120
131
|
name: "get_models",
|
|
132
|
+
title: "Inspect AI models",
|
|
121
133
|
summary: "Get full model metadata by IDs or aliases (batch, up to 100)",
|
|
122
134
|
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.
|
|
123
135
|
|
|
@@ -137,6 +149,7 @@ Entries in results are null when the id is unknown; those ids appear in missingI
|
|
|
137
149
|
},
|
|
138
150
|
test_model: {
|
|
139
151
|
name: "test_model",
|
|
152
|
+
title: "Test AI models live",
|
|
140
153
|
summary: "Run live inference or dry-run cost estimation across up to 10 models",
|
|
141
154
|
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.
|
|
142
155
|
|
|
@@ -518,6 +531,9 @@ var SearchResponseSchema = z2.object({
|
|
|
518
531
|
ranking: z2.literal("hybrid_rrf")
|
|
519
532
|
})
|
|
520
533
|
});
|
|
534
|
+
var FindModelsToolResultSchema = SearchResponseSchema.extend({
|
|
535
|
+
_index9: Index9MetaSchema
|
|
536
|
+
});
|
|
521
537
|
|
|
522
538
|
// ../core/dist/schemas/model.js
|
|
523
539
|
import { z as z3 } from "zod";
|
|
@@ -559,6 +575,13 @@ var BatchModelLookupResponseSchema = z3.object({
|
|
|
559
575
|
resolvedAliases: z3.record(z3.string(), z3.string()).optional(),
|
|
560
576
|
ambiguousAliases: z3.record(z3.string(), z3.array(z3.string())).optional()
|
|
561
577
|
}).strict();
|
|
578
|
+
var GetModelsToolResultSchema = z3.object({
|
|
579
|
+
results: z3.array(ModelResponseSchema.nullable()),
|
|
580
|
+
missingIds: z3.array(z3.string()),
|
|
581
|
+
resolvedAliases: z3.record(z3.string(), z3.string()).optional(),
|
|
582
|
+
ambiguousAliases: z3.record(z3.string(), z3.array(z3.string())).optional(),
|
|
583
|
+
_index9: Index9MetaSchema
|
|
584
|
+
});
|
|
562
585
|
|
|
563
586
|
// ../core/dist/schemas/test.js
|
|
564
587
|
import { z as z4 } from "zod";
|
|
@@ -756,10 +779,14 @@ function baseHeaders(ctx) {
|
|
|
756
779
|
return h;
|
|
757
780
|
}
|
|
758
781
|
function toResponse(payload, isError = false) {
|
|
759
|
-
|
|
782
|
+
const response = {
|
|
760
783
|
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
761
784
|
isError: isError || void 0
|
|
762
785
|
};
|
|
786
|
+
if (!isError && typeof payload === "object" && payload !== null && !Array.isArray(payload)) {
|
|
787
|
+
response.structuredContent = payload;
|
|
788
|
+
}
|
|
789
|
+
return response;
|
|
763
790
|
}
|
|
764
791
|
function parseRetryAfterSeconds(value) {
|
|
765
792
|
if (!value) return void 0;
|
|
@@ -891,6 +918,7 @@ async function createServer() {
|
|
|
891
918
|
server.registerTool(
|
|
892
919
|
"find_models",
|
|
893
920
|
{
|
|
921
|
+
title: TOOLS.find_models.title,
|
|
894
922
|
description: TOOLS.find_models.description,
|
|
895
923
|
inputSchema: {
|
|
896
924
|
q: z5.string().min(1).optional().describe(PARAM_DESCRIPTIONS.q),
|
|
@@ -908,6 +936,7 @@ async function createServer() {
|
|
|
908
936
|
modality: z5.enum(OUTPUT_MODALITIES).optional().describe(PARAM_DESCRIPTIONS.modality),
|
|
909
937
|
provider: z5.string().min(1).optional().describe(PARAM_DESCRIPTIONS.provider)
|
|
910
938
|
},
|
|
939
|
+
outputSchema: FindModelsToolResultSchema.shape,
|
|
911
940
|
annotations: { readOnlyHint: true }
|
|
912
941
|
},
|
|
913
942
|
async (args) => handleSearchModels(ctx, args)
|
|
@@ -915,11 +944,13 @@ async function createServer() {
|
|
|
915
944
|
server.registerTool(
|
|
916
945
|
"get_models",
|
|
917
946
|
{
|
|
947
|
+
title: TOOLS.get_models.title,
|
|
918
948
|
description: TOOLS.get_models.description,
|
|
919
949
|
inputSchema: {
|
|
920
950
|
ids: z5.array(z5.string().min(1)).min(1).max(100).describe("Model identifiers or aliases. Up to 100."),
|
|
921
951
|
maxDescriptionChars: z5.number().int().min(0).max(2e3).optional().describe("Truncate descriptions to this many characters.")
|
|
922
952
|
},
|
|
953
|
+
outputSchema: GetModelsToolResultSchema.shape,
|
|
923
954
|
annotations: { readOnlyHint: true }
|
|
924
955
|
},
|
|
925
956
|
async (args) => handleGetModels(ctx, args)
|
|
@@ -927,6 +958,7 @@ async function createServer() {
|
|
|
927
958
|
server.registerTool(
|
|
928
959
|
"test_model",
|
|
929
960
|
{
|
|
961
|
+
title: TOOLS.test_model.title,
|
|
930
962
|
description: TOOLS.test_model.description,
|
|
931
963
|
inputSchema: {
|
|
932
964
|
prompt: z5.string().min(1).optional().describe("Prompt sent to each model."),
|
|
@@ -937,7 +969,9 @@ async function createServer() {
|
|
|
937
969
|
expectedCompletionTokens: z5.number().int().min(1).optional().describe(PARAM_DESCRIPTIONS.expectedCompletionTokens),
|
|
938
970
|
models: z5.array(z5.string().min(1)).min(1).max(LIMITS.testModelsMax).describe(`Model IDs to evaluate (1-${LIMITS.testModelsMax}).`),
|
|
939
971
|
timeoutMs: z5.number().int().min(1).optional().describe("Per-model timeout in ms (default 15000, max 60000)."),
|
|
940
|
-
maxTokens: z5.number().int().min(1).optional().describe(
|
|
972
|
+
maxTokens: z5.number().int().min(1).optional().describe(
|
|
973
|
+
"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."
|
|
974
|
+
),
|
|
941
975
|
systemPrompt: z5.string().min(1).optional().describe("System instruction prepended to prompt."),
|
|
942
976
|
temperature: z5.number().min(0).max(2).optional().describe("Sampling temperature (0-2)."),
|
|
943
977
|
topP: z5.number().gt(0).max(1).optional().describe("Nucleus sampling (0-1]."),
|
|
@@ -948,6 +982,9 @@ async function createServer() {
|
|
|
948
982
|
enforceJson: z5.boolean().optional().describe("When true, output must parse as JSON."),
|
|
949
983
|
retries: z5.number().int().min(0).max(3).optional().describe("Retries for transient failures.")
|
|
950
984
|
},
|
|
985
|
+
// No outputSchema: test_model returns a z.union of dry-run and live shapes.
|
|
986
|
+
// The SDK supports only ZodRawShape | AnySchema for outputSchema; a discriminated-union
|
|
987
|
+
// output is represented accurately in the tool description instead.
|
|
951
988
|
annotations: { readOnlyHint: false }
|
|
952
989
|
},
|
|
953
990
|
async (args) => handleTestModels(ctx, args)
|
package/manifest.json
CHANGED