@index9/mcp 1.0.18 β 1.0.20
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/README.md +82 -31
- package/dist/client.d.ts +3 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -27
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +42 -85
- package/dist/schemas.d.ts +130 -50
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +165 -84
- package/dist/tools/find_models.d.ts +3 -0
- package/dist/tools/find_models.d.ts.map +1 -0
- package/dist/tools/find_models.js +4 -0
- package/dist/tools/test_model.d.ts.map +1 -1
- package/dist/tools/test_model.js +1 -1
- package/dist/types/api.d.ts +33 -49
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/models.d.ts +3 -7
- package/dist/types/models.d.ts.map +1 -1
- package/dist/types/models.js +1 -1
- package/dist/utils/rateLimiter.d.ts +1 -1
- package/dist/utils/rateLimiter.js +1 -1
- package/package.json +3 -3
- package/dist/tools/compare_models.d.ts +0 -3
- package/dist/tools/compare_models.d.ts.map +0 -1
- package/dist/tools/compare_models.js +0 -4
- package/dist/tools/get_capabilities.d.ts +0 -9
- package/dist/tools/get_capabilities.d.ts.map +0 -1
- package/dist/tools/get_capabilities.js +0 -19
- package/dist/tools/list_models.d.ts +0 -23
- package/dist/tools/list_models.d.ts.map +0 -1
- package/dist/tools/list_models.js +0 -25
- package/dist/tools/recommend_model.d.ts +0 -3
- package/dist/tools/recommend_model.d.ts.map +0 -1
- package/dist/tools/recommend_model.js +0 -4
- package/dist/tools/search_models.d.ts +0 -14
- package/dist/tools/search_models.d.ts.map +0 -1
- package/dist/tools/search_models.js +0 -5
package/README.md
CHANGED
|
@@ -3,24 +3,21 @@
|
|
|
3
3
|
[](https://badge.fury.io/js/@index9%2Fmcp)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
[
|
|
6
|
+
[Install](#quick-start) β’ [Issues](https://github.com/index9-org/mcp/issues)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
MCP server for searching and testing AI models. Data from [OpenRouter](https://openrouter.ai).
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Quick Start
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**Zero Config:** Search and Lookup features work immediately after installation. No API keys required.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- **Compare models** side-by-side with current pricing and context windows
|
|
16
|
-
- **Get recommendations** tailored to your use case, budget, and requirements
|
|
17
|
-
- **Test models** with real API calls to see latency and behavior before you commit
|
|
14
|
+
### Cursor
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
Open **Cursor Settings** β **MCP** β **Add new global MCP server**
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
[](https://cursor.com/en-US/install-mcp?name=index9&config=eyJjb21tYW5kIjoibnB4IC15IEBpbmRleDkvbWNwIn0%3D)
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
Or add manually:
|
|
24
21
|
|
|
25
22
|
```json
|
|
26
23
|
{
|
|
@@ -33,17 +30,32 @@ Open Cursor Settings β MCP β Add new global MCP server
|
|
|
33
30
|
}
|
|
34
31
|
```
|
|
35
32
|
|
|
36
|
-
[](https://cursor.com/en-US/install-mcp?name=index9&config=eyJjb21tYW5kIjoibnB4IC15IEBpbmRleDkvbWNwIn0%3D)
|
|
37
|
-
|
|
38
33
|
### VS Code
|
|
39
34
|
|
|
40
|
-
|
|
35
|
+
Add to your **MCP Servers** settings:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcp": {
|
|
40
|
+
"servers": {
|
|
41
|
+
"index9": {
|
|
42
|
+
"type": "stdio",
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "@index9/mcp"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Claude Desktop
|
|
52
|
+
|
|
53
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
41
54
|
|
|
42
55
|
```json
|
|
43
|
-
|
|
44
|
-
"
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
45
58
|
"index9": {
|
|
46
|
-
"type": "stdio",
|
|
47
59
|
"command": "npx",
|
|
48
60
|
"args": ["-y", "@index9/mcp"]
|
|
49
61
|
}
|
|
@@ -51,28 +63,67 @@ Open VS Code Settings β MCP Servers β Add Server
|
|
|
51
63
|
}
|
|
52
64
|
```
|
|
53
65
|
|
|
54
|
-
|
|
66
|
+
See [index9.dev](https://index9.dev/#installation) for Windsurf, Cline, and other clients.
|
|
55
67
|
|
|
56
|
-
|
|
68
|
+
## Configuration (Optional)
|
|
57
69
|
|
|
58
|
-
|
|
70
|
+
The **find_models** and **get_model** tools are free and require no configuration.
|
|
59
71
|
|
|
60
|
-
|
|
72
|
+
To use the **test_model** tool (for running live API calls), you must provide an OpenRouter API key.
|
|
61
73
|
|
|
62
|
-
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"index9": {
|
|
78
|
+
"command": "npx",
|
|
79
|
+
"args": ["-y", "@index9/mcp"],
|
|
80
|
+
"env": {
|
|
81
|
+
"OPENROUTER_API_KEY": "sk-..."
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
_Your key is never stored. It is only used to make ephemeral requests to OpenRouter for testing purposes._
|
|
63
89
|
|
|
64
|
-
|
|
90
|
+
### CLI Tools (Claude Code, etc.)
|
|
65
91
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- **`test_model`** - Live API testing with latency and cost estimates (requires API key)
|
|
92
|
+
For CLI-based MCP clients, set the environment variable before running:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
export OPENROUTER_API_KEY="sk-..."
|
|
96
|
+
```
|
|
72
97
|
|
|
73
|
-
|
|
98
|
+
Or add it to your shell profile (`~/.zshrc`, `~/.bashrc`) for persistence.
|
|
99
|
+
|
|
100
|
+
## Tools
|
|
101
|
+
|
|
102
|
+
| Tool | Description | Config Required |
|
|
103
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------- |
|
|
104
|
+
| `find_models` | Search and filter 300+ AI models. Use natural language ("fast coding model") or strict filters for price, context, and capabilities. | None |
|
|
105
|
+
| `get_model` | Get complete technical specifications. Returns pricing, context windows, max output tokens, and capabilities for any model. | None |
|
|
106
|
+
| `test_model` | Run live performance tests. Execute real API calls to multiple models simultaneously to compare latency, token usage, and costs. | `OPENROUTER_API_KEY` |
|
|
107
|
+
|
|
108
|
+
## Usage Examples
|
|
109
|
+
|
|
110
|
+
Ask your AI assistant natural questions to find models:
|
|
111
|
+
|
|
112
|
+
- "Find a cheap vision model with at least 128k context"
|
|
113
|
+
- "What are the best models for coding under $1 per million tokens?"
|
|
114
|
+
- "Compare the specs of gpt-4o and claude-3-5-sonnet"
|
|
115
|
+
- "Test the latency of haiku vs gemini-flash with a simple 'hello world' prompt"
|
|
116
|
+
|
|
117
|
+
## Tip: Add an Auto-Invoke Rule
|
|
118
|
+
|
|
119
|
+
For best results, add a rule so your AI assistant automatically uses index9 when answering model questions:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
When choosing AI models or comparing pricing/capabilities, use index9 MCP tools
|
|
123
|
+
to get current data instead of relying on training knowledge.
|
|
124
|
+
```
|
|
74
125
|
|
|
75
|
-
|
|
126
|
+
Add this to your client's rule system: Cursor Settings β Rules, `.windsurfrules`, `CLAUDE.md`, etc.
|
|
76
127
|
|
|
77
128
|
## License
|
|
78
129
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function
|
|
1
|
+
import type { GetModelResponse, FindModelsResponse, FindModelsRequest, TestModelResponse } from "./types/index.js";
|
|
2
|
+
export declare function findModels(params: FindModelsRequest): Promise<FindModelsResponse>;
|
|
3
3
|
export declare function getModel(modelId: string): Promise<GetModelResponse>;
|
|
4
|
-
export declare function
|
|
5
|
-
export declare function compareModels(modelIds: string[]): Promise<CompareModelsResponse>;
|
|
6
|
-
export declare function recommendModel(useCase: string, maxPrice?: number, minContext?: number, requiredCapabilities?: string[], limit?: number): Promise<RecommendModelResponse>;
|
|
7
|
-
export declare function testModel(modelIds: string[], testType?: "quick" | "code" | "reasoning" | "instruction" | "tool_calling", openRouterApiKey?: string | null): Promise<TestModelResponse>;
|
|
4
|
+
export declare function testModel(modelIds: string[], testType?: "quick" | "code" | "reasoning" | "instruction" | "tool_calling", openRouterApiKey?: string | null, prompt?: string, maxTokens?: number, temperature?: number, systemPrompt?: string): Promise<TestModelResponse>;
|
|
8
5
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,kBAAkB,CAAC;AA2B1B,wBAAsB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAGvF;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGzE;AAED,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,EAC1E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,EAChC,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAW5B"}
|
package/dist/client.js
CHANGED
|
@@ -17,43 +17,23 @@ const createAxiosClient = (timeout) => {
|
|
|
17
17
|
};
|
|
18
18
|
const client = createAxiosClient(API_TIMEOUT);
|
|
19
19
|
const testClient = createAxiosClient(TEST_MODEL_TIMEOUT); // test operations with longer timeout
|
|
20
|
-
export async function
|
|
21
|
-
const { data } = await client.
|
|
20
|
+
export async function findModels(params) {
|
|
21
|
+
const { data } = await client.post("/models/find", params);
|
|
22
22
|
return data;
|
|
23
23
|
}
|
|
24
24
|
export async function getModel(modelId) {
|
|
25
25
|
const { data } = await client.get(`/models/${encodeURIComponent(modelId)}`);
|
|
26
26
|
return data;
|
|
27
27
|
}
|
|
28
|
-
export async function
|
|
29
|
-
const { data } = await client.post("/search", {
|
|
30
|
-
query,
|
|
31
|
-
limit,
|
|
32
|
-
threshold,
|
|
33
|
-
});
|
|
34
|
-
return data;
|
|
35
|
-
}
|
|
36
|
-
export async function compareModels(modelIds) {
|
|
37
|
-
const { data } = await client.post("/models/compare", {
|
|
38
|
-
model_ids: modelIds,
|
|
39
|
-
});
|
|
40
|
-
return data;
|
|
41
|
-
}
|
|
42
|
-
export async function recommendModel(useCase, maxPrice, minContext, requiredCapabilities, limit) {
|
|
43
|
-
const { data } = await client.post("/models/recommend", {
|
|
44
|
-
use_case: useCase,
|
|
45
|
-
max_price_per_m: maxPrice,
|
|
46
|
-
min_context: minContext,
|
|
47
|
-
required_capabilities: requiredCapabilities,
|
|
48
|
-
limit,
|
|
49
|
-
});
|
|
50
|
-
return data;
|
|
51
|
-
}
|
|
52
|
-
export async function testModel(modelIds, testType, openRouterApiKey) {
|
|
28
|
+
export async function testModel(modelIds, testType, openRouterApiKey, prompt, maxTokens, temperature, systemPrompt) {
|
|
53
29
|
const { data } = await testClient.post("/test", {
|
|
54
30
|
model_ids: modelIds,
|
|
55
31
|
test_type: testType,
|
|
32
|
+
custom_prompt: prompt,
|
|
56
33
|
open_router_api_key: openRouterApiKey || undefined,
|
|
34
|
+
max_tokens: maxTokens,
|
|
35
|
+
temperature,
|
|
36
|
+
system_prompt: systemPrompt,
|
|
57
37
|
});
|
|
58
38
|
return data;
|
|
59
39
|
}
|
package/dist/mcp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0BpE,wBAAgB,eAAe,cAmI9B;AAED,wBAAsB,cAAc,kBAoBnC"}
|
package/dist/mcp.js
CHANGED
|
@@ -5,14 +5,11 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { logger } from "./logger.js";
|
|
7
7
|
import { checkRateLimit } from "./utils/rateLimiter.js";
|
|
8
|
-
import {
|
|
9
|
-
import { searchModelsTool } from "./tools/search_models.js";
|
|
8
|
+
import { findModelsTool } from "./tools/find_models.js";
|
|
10
9
|
import { getModelTool } from "./tools/get_model.js";
|
|
11
|
-
import { compareModelsTool } from "./tools/compare_models.js";
|
|
12
|
-
import { recommendModelTool } from "./tools/recommend_model.js";
|
|
13
10
|
import { testModelTool } from "./tools/test_model.js";
|
|
14
11
|
import { OPEN_ROUTER_API_KEY } from "./config.js";
|
|
15
|
-
import {
|
|
12
|
+
import { findModelsSchema, getModelSchema, testModelSchema, findModelsOutputSchema, getModelOutputSchema, testModelOutputSchema, } from "./schemas.js";
|
|
16
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
14
|
const __dirname = dirname(__filename);
|
|
18
15
|
const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
@@ -21,17 +18,31 @@ export function createMCPServer() {
|
|
|
21
18
|
name: "index9",
|
|
22
19
|
version: packageJson.version,
|
|
23
20
|
});
|
|
24
|
-
server.registerTool("
|
|
25
|
-
title: "
|
|
26
|
-
description:
|
|
27
|
-
|
|
21
|
+
server.registerTool("find_models", {
|
|
22
|
+
title: "Find AI Models",
|
|
23
|
+
description: `Search and filter 300+ AI models. Returns ranked results with pricing, context windows, and capabilities.
|
|
24
|
+
|
|
25
|
+
Call this tool first to discover model IDs, unless the user provides one (format: 'provider/model-name').
|
|
26
|
+
|
|
27
|
+
Parameters:
|
|
28
|
+
- query: Natural language search (e.g., 'fast cheap coding model')
|
|
29
|
+
- provider: Filter by provider(s). Comma-separated for multiple (e.g., 'openai,anthropic')
|
|
30
|
+
- min_context, max_context, max_price_per_m, capabilities: Exact filters
|
|
31
|
+
- sort_by: 'relevance' (default), 'price_asc', 'price_desc', 'date_desc', 'context_desc'
|
|
32
|
+
- limit, offset: Pagination
|
|
33
|
+
|
|
34
|
+
Scores: Results include a 'score' field (0-150+). Higher = more relevant. Combines semantic similarity, capability matching, and model quality signals. Use for relative ranking, not absolute measurement.
|
|
35
|
+
|
|
36
|
+
Use model IDs from results with get_model for full specs or test_model for live testing.`,
|
|
37
|
+
inputSchema: findModelsSchema,
|
|
38
|
+
outputSchema: findModelsOutputSchema,
|
|
28
39
|
}, async (input) => {
|
|
29
|
-
if (!checkRateLimit("
|
|
30
|
-
logger.warn({ tool: "
|
|
40
|
+
if (!checkRateLimit("find_models")) {
|
|
41
|
+
logger.warn({ tool: "find_models" }, "Rate limit exceeded");
|
|
31
42
|
throw new Error("Rate limit exceeded. Please try again later.");
|
|
32
43
|
}
|
|
33
44
|
try {
|
|
34
|
-
const result = await
|
|
45
|
+
const result = await findModelsTool(input);
|
|
35
46
|
return {
|
|
36
47
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
37
48
|
structuredContent: result,
|
|
@@ -39,36 +50,19 @@ export function createMCPServer() {
|
|
|
39
50
|
}
|
|
40
51
|
catch (error) {
|
|
41
52
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
42
|
-
logger.error({ tool: "
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
server.registerTool("search_models", {
|
|
47
|
-
title: "Search AI Models",
|
|
48
|
-
description: "Search 1200+ AI models using natural language (e.g., 'fast cheap coding model'). Uses semantic search and fuzzy matching. Returns ranked results with similarity scores.",
|
|
49
|
-
inputSchema: searchModelsSchema,
|
|
50
|
-
}, async (input) => {
|
|
51
|
-
if (!checkRateLimit("search_models")) {
|
|
52
|
-
logger.warn({ tool: "search_models" }, "Rate limit exceeded");
|
|
53
|
-
throw new Error("Rate limit exceeded. Please try again later.");
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
const result = await searchModelsTool(input);
|
|
57
|
-
return {
|
|
58
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
59
|
-
structuredContent: result,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64
|
-
logger.error({ tool: "search_models", error: errorMessage }, "Tool execution failed");
|
|
53
|
+
logger.error({ tool: "find_models", error: errorMessage }, "Tool execution failed");
|
|
65
54
|
throw error;
|
|
66
55
|
}
|
|
67
56
|
});
|
|
68
57
|
server.registerTool("get_model", {
|
|
69
58
|
title: "Get Model Details",
|
|
70
|
-
description:
|
|
59
|
+
description: `Get complete specs for a model by ID. Returns pricing, context window, capabilities, architecture, and per-request limits.
|
|
60
|
+
|
|
61
|
+
Call after find_models to get full details, or when the user provides a model ID (format: 'provider/model-name').
|
|
62
|
+
|
|
63
|
+
Returns 404 if model not found. Use find_models to discover valid IDs.`,
|
|
71
64
|
inputSchema: getModelSchema,
|
|
65
|
+
outputSchema: getModelOutputSchema,
|
|
72
66
|
}, async (input) => {
|
|
73
67
|
if (!checkRateLimit("get_model")) {
|
|
74
68
|
logger.warn({ tool: "get_model" }, "Rate limit exceeded");
|
|
@@ -87,58 +81,21 @@ export function createMCPServer() {
|
|
|
87
81
|
throw error;
|
|
88
82
|
}
|
|
89
83
|
});
|
|
90
|
-
server.registerTool("compare_models", {
|
|
91
|
-
title: "Compare AI Models",
|
|
92
|
-
description: "Compare 2-10 AI models side-by-side with unified pricing, context windows, and capabilities. Perfect for final selection decisions.",
|
|
93
|
-
inputSchema: compareModelsSchema,
|
|
94
|
-
}, async (input) => {
|
|
95
|
-
if (!checkRateLimit("compare_models")) {
|
|
96
|
-
logger.warn({ tool: "compare_models" }, "Rate limit exceeded");
|
|
97
|
-
throw new Error("Rate limit exceeded. Please try again later.");
|
|
98
|
-
}
|
|
99
|
-
const model_ids = Array.from(new Set(input.model_ids || []));
|
|
100
|
-
try {
|
|
101
|
-
if (model_ids.length < 2) {
|
|
102
|
-
throw new Error("At least 2 unique model IDs are required");
|
|
103
|
-
}
|
|
104
|
-
const result = await compareModelsTool({ model_ids });
|
|
105
|
-
return {
|
|
106
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
107
|
-
structuredContent: result,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
112
|
-
logger.error({ tool: "compare_models", error: errorMessage }, "Tool execution failed");
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
server.registerTool("recommend_model", {
|
|
117
|
-
title: "Get Model Recommendations",
|
|
118
|
-
description: "Get AI-powered model recommendations for your use case (e.g., 'coding assistant'). Optionally specify budget, context needs, and required capabilities. Returns ranked suggestions.",
|
|
119
|
-
inputSchema: recommendModelSchema,
|
|
120
|
-
}, async (input) => {
|
|
121
|
-
if (!checkRateLimit("recommend_model")) {
|
|
122
|
-
logger.warn({ tool: "recommend_model" }, "Rate limit exceeded");
|
|
123
|
-
throw new Error("Rate limit exceeded. Please try again later.");
|
|
124
|
-
}
|
|
125
|
-
try {
|
|
126
|
-
const result = await recommendModelTool(input);
|
|
127
|
-
return {
|
|
128
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
129
|
-
structuredContent: result,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
134
|
-
logger.error({ tool: "recommend_model", error: errorMessage }, "Tool execution failed");
|
|
135
|
-
throw error;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
84
|
server.registerTool("test_model", {
|
|
139
85
|
title: "Test AI Models",
|
|
140
|
-
description:
|
|
86
|
+
description: `Make live API calls to 1-5 models via OpenRouter. Returns output text, latency (ms), token usage, and cost estimates.
|
|
87
|
+
|
|
88
|
+
Requires OPENROUTER_API_KEY in MCP client configuration. Costs are billed to your OpenRouter account.
|
|
89
|
+
|
|
90
|
+
Parameters:
|
|
91
|
+
- model_ids: 1-5 model IDs to test (all receive identical prompts)
|
|
92
|
+
- test_type: 'quick' (math), 'code', 'reasoning', 'instruction', 'tool_calling'
|
|
93
|
+
- prompt: Custom prompt (overrides test_type)
|
|
94
|
+
- max_tokens: Response length limit (default 1000)
|
|
95
|
+
|
|
96
|
+
Use find_models or get_model first to identify model IDs.`,
|
|
141
97
|
inputSchema: testModelSchema,
|
|
98
|
+
outputSchema: testModelOutputSchema,
|
|
142
99
|
}, async (input) => {
|
|
143
100
|
if (!checkRateLimit("test_model")) {
|
|
144
101
|
logger.warn({ tool: "test_model" }, "Rate limit exceeded");
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1,38 +1,30 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Find Models Tool Schema
|
|
4
|
+
* Unified search and filter for AI models
|
|
5
5
|
*/
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const findModelsSchema: z.ZodObject<{
|
|
7
|
+
query: z.ZodOptional<z.ZodString>;
|
|
7
8
|
provider: z.ZodOptional<z.ZodString>;
|
|
8
|
-
owner: z.ZodOptional<z.ZodString>;
|
|
9
9
|
min_context: z.ZodOptional<z.ZodNumber>;
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
max_context: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
max_price_per_m: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
capabilities: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
12
13
|
vision: "vision";
|
|
13
|
-
|
|
14
|
+
audio: "audio";
|
|
14
15
|
video: "video";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
max_price_per_m: z.ZodOptional<z.ZodNumber>;
|
|
26
|
-
limit: z.ZodDefault<z.ZodNumber>;
|
|
27
|
-
}, z.core.$strip>;
|
|
28
|
-
/**
|
|
29
|
-
* Search Models Tool Schema
|
|
30
|
-
* Natural language semantic search across AI models
|
|
31
|
-
*/
|
|
32
|
-
export declare const searchModelsSchema: z.ZodObject<{
|
|
33
|
-
query: z.ZodString;
|
|
16
|
+
tool_calling: "tool_calling";
|
|
17
|
+
json_mode: "json_mode";
|
|
18
|
+
}>>>;
|
|
19
|
+
sort_by: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
|
|
20
|
+
relevance: "relevance";
|
|
21
|
+
price_asc: "price_asc";
|
|
22
|
+
price_desc: "price_desc";
|
|
23
|
+
date_desc: "date_desc";
|
|
24
|
+
context_desc: "context_desc";
|
|
25
|
+
}>>>;
|
|
34
26
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
35
|
-
|
|
27
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
36
28
|
}, z.core.$strip>;
|
|
37
29
|
/**
|
|
38
30
|
* Get Model Tool Schema
|
|
@@ -41,24 +33,6 @@ export declare const searchModelsSchema: z.ZodObject<{
|
|
|
41
33
|
export declare const getModelSchema: z.ZodObject<{
|
|
42
34
|
model_id: z.ZodString;
|
|
43
35
|
}, z.core.$strip>;
|
|
44
|
-
/**
|
|
45
|
-
* Compare Models Tool Schema
|
|
46
|
-
* Side-by-side comparison of multiple models
|
|
47
|
-
*/
|
|
48
|
-
export declare const compareModelsSchema: z.ZodObject<{
|
|
49
|
-
model_ids: z.ZodArray<z.ZodString>;
|
|
50
|
-
}, z.core.$strip>;
|
|
51
|
-
/**
|
|
52
|
-
* Recommend Model Tool Schema
|
|
53
|
-
* AI-powered model recommendations based on use case
|
|
54
|
-
*/
|
|
55
|
-
export declare const recommendModelSchema: z.ZodObject<{
|
|
56
|
-
use_case: z.ZodString;
|
|
57
|
-
max_price_per_m: z.ZodOptional<z.ZodNumber>;
|
|
58
|
-
min_context: z.ZodOptional<z.ZodNumber>;
|
|
59
|
-
required_capabilities: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
60
|
-
limit: z.ZodDefault<z.ZodNumber>;
|
|
61
|
-
}, z.core.$strip>;
|
|
62
36
|
/**
|
|
63
37
|
* Test Model Tool Schema
|
|
64
38
|
* Run live API tests against models via OpenRouter
|
|
@@ -66,17 +40,123 @@ export declare const recommendModelSchema: z.ZodObject<{
|
|
|
66
40
|
export declare const testModelSchema: z.ZodObject<{
|
|
67
41
|
model_ids: z.ZodArray<z.ZodString>;
|
|
68
42
|
test_type: z.ZodDefault<z.ZodEnum<{
|
|
69
|
-
tool_calling: "tool_calling";
|
|
70
43
|
quick: "quick";
|
|
71
44
|
code: "code";
|
|
72
45
|
reasoning: "reasoning";
|
|
73
46
|
instruction: "instruction";
|
|
47
|
+
tool_calling: "tool_calling";
|
|
74
48
|
}>>;
|
|
49
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
50
|
+
max_tokens: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
51
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
system_prompt: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
/**
|
|
55
|
+
* Output Schemas for Tool Results
|
|
56
|
+
* Define expected return structures for better LLM understanding
|
|
57
|
+
*/
|
|
58
|
+
export declare const findModelsOutputSchema: z.ZodObject<{
|
|
59
|
+
results: z.ZodArray<z.ZodObject<{
|
|
60
|
+
id: z.ZodString;
|
|
61
|
+
name: z.ZodString;
|
|
62
|
+
description: z.ZodNullable<z.ZodString>;
|
|
63
|
+
score: z.ZodNumber;
|
|
64
|
+
provider: z.ZodString;
|
|
65
|
+
context_window: z.ZodNullable<z.ZodNumber>;
|
|
66
|
+
pricing: z.ZodObject<{
|
|
67
|
+
input: z.ZodNullable<z.ZodNumber>;
|
|
68
|
+
output: z.ZodNullable<z.ZodNumber>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
capabilities: z.ZodObject<{
|
|
71
|
+
vision: z.ZodNullable<z.ZodBoolean>;
|
|
72
|
+
audio: z.ZodNullable<z.ZodBoolean>;
|
|
73
|
+
tool_calling: z.ZodNullable<z.ZodBoolean>;
|
|
74
|
+
json_mode: z.ZodNullable<z.ZodBoolean>;
|
|
75
|
+
video: z.ZodNullable<z.ZodBoolean>;
|
|
76
|
+
}, z.core.$strip>;
|
|
77
|
+
matched_features: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
78
|
+
hugging_face_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
79
|
+
release_date: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
80
|
+
}, z.core.$strip>>;
|
|
81
|
+
total: z.ZodOptional<z.ZodNumber>;
|
|
82
|
+
}, z.core.$strip>;
|
|
83
|
+
export declare const getModelOutputSchema: z.ZodObject<{
|
|
84
|
+
id: z.ZodString;
|
|
85
|
+
name: z.ZodString;
|
|
86
|
+
provider: z.ZodString;
|
|
87
|
+
description: z.ZodNullable<z.ZodString>;
|
|
88
|
+
family: z.ZodNullable<z.ZodString>;
|
|
89
|
+
version: z.ZodNullable<z.ZodString>;
|
|
90
|
+
release_date: z.ZodNullable<z.ZodString>;
|
|
91
|
+
limits: z.ZodObject<{
|
|
92
|
+
context_window: z.ZodNumber;
|
|
93
|
+
max_output_tokens: z.ZodNullable<z.ZodNumber>;
|
|
94
|
+
}, z.core.$strip>;
|
|
95
|
+
pricing: z.ZodObject<{
|
|
96
|
+
input: z.ZodNullable<z.ZodNumber>;
|
|
97
|
+
output: z.ZodNullable<z.ZodNumber>;
|
|
98
|
+
}, z.core.$strip>;
|
|
99
|
+
extended_pricing: z.ZodNullable<z.ZodObject<{
|
|
100
|
+
image: z.ZodNullable<z.ZodNumber>;
|
|
101
|
+
audio: z.ZodNullable<z.ZodNumber>;
|
|
102
|
+
web_search: z.ZodNullable<z.ZodNumber>;
|
|
103
|
+
cache_read: z.ZodNullable<z.ZodNumber>;
|
|
104
|
+
cache_write: z.ZodNullable<z.ZodNumber>;
|
|
105
|
+
discount: z.ZodNullable<z.ZodNumber>;
|
|
106
|
+
internal_reasoning: z.ZodNullable<z.ZodNumber>;
|
|
107
|
+
}, z.core.$strip>>;
|
|
108
|
+
capabilities: z.ZodObject<{
|
|
109
|
+
vision: z.ZodBoolean;
|
|
110
|
+
audio: z.ZodBoolean;
|
|
111
|
+
tool_calling: z.ZodBoolean;
|
|
112
|
+
json_mode: z.ZodBoolean;
|
|
113
|
+
video: z.ZodBoolean;
|
|
114
|
+
function_calling: z.ZodBoolean;
|
|
115
|
+
custom: z.ZodArray<z.ZodString>;
|
|
116
|
+
}, z.core.$strip>;
|
|
117
|
+
supported_parameters: z.ZodArray<z.ZodString>;
|
|
118
|
+
is_moderated: z.ZodBoolean;
|
|
119
|
+
input_modalities: z.ZodArray<z.ZodString>;
|
|
120
|
+
output_modalities: z.ZodArray<z.ZodString>;
|
|
121
|
+
architecture: z.ZodObject<{
|
|
122
|
+
tokenizer: z.ZodNullable<z.ZodString>;
|
|
123
|
+
instruct_type: z.ZodNullable<z.ZodString>;
|
|
124
|
+
}, z.core.$strip>;
|
|
125
|
+
per_request_limits: z.ZodNullable<z.ZodObject<{
|
|
126
|
+
prompt_tokens: z.ZodNullable<z.ZodNumber>;
|
|
127
|
+
completion_tokens: z.ZodNullable<z.ZodNumber>;
|
|
128
|
+
}, z.core.$strip>>;
|
|
129
|
+
}, z.core.$strip>;
|
|
130
|
+
export declare const testModelOutputSchema: z.ZodObject<{
|
|
131
|
+
test_type: z.ZodString;
|
|
132
|
+
prompt: z.ZodString;
|
|
133
|
+
results: z.ZodArray<z.ZodObject<{
|
|
134
|
+
model_id: z.ZodString;
|
|
135
|
+
model_name: z.ZodString;
|
|
136
|
+
latency_ms: z.ZodNumber;
|
|
137
|
+
output: z.ZodNullable<z.ZodString>;
|
|
138
|
+
tokens_used: z.ZodNullable<z.ZodObject<{
|
|
139
|
+
prompt_tokens: z.ZodNumber;
|
|
140
|
+
completion_tokens: z.ZodNumber;
|
|
141
|
+
total_tokens: z.ZodNumber;
|
|
142
|
+
}, z.core.$strip>>;
|
|
143
|
+
cost_estimate: z.ZodObject<{
|
|
144
|
+
input_cost: z.ZodNullable<z.ZodNumber>;
|
|
145
|
+
output_cost: z.ZodNullable<z.ZodNumber>;
|
|
146
|
+
total_cost: z.ZodNullable<z.ZodNumber>;
|
|
147
|
+
}, z.core.$strip>;
|
|
148
|
+
tool_calls_detected: z.ZodOptional<z.ZodBoolean>;
|
|
149
|
+
tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
150
|
+
name: z.ZodString;
|
|
151
|
+
arguments: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
152
|
+
}, z.core.$strip>>>;
|
|
153
|
+
error: z.ZodNullable<z.ZodString>;
|
|
154
|
+
}, z.core.$strip>>;
|
|
75
155
|
}, z.core.$strip>;
|
|
76
|
-
export type
|
|
77
|
-
export type SearchModelsInput = z.infer<typeof searchModelsSchema>;
|
|
156
|
+
export type FindModelsInput = z.infer<typeof findModelsSchema>;
|
|
78
157
|
export type GetModelInput = z.infer<typeof getModelSchema>;
|
|
79
|
-
export type CompareModelsInput = z.infer<typeof compareModelsSchema>;
|
|
80
|
-
export type RecommendModelInput = z.infer<typeof recommendModelSchema>;
|
|
81
158
|
export type TestModelInput = z.infer<typeof testModelSchema>;
|
|
159
|
+
export type FindModelsOutput = z.infer<typeof findModelsOutputSchema>;
|
|
160
|
+
export type GetModelOutput = z.infer<typeof getModelOutputSchema>;
|
|
161
|
+
export type TestModelOutput = z.infer<typeof testModelOutputSchema>;
|
|
82
162
|
//# sourceMappingURL=schemas.d.ts.map
|
package/dist/schemas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;iBA+D3B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc;;iBAOzB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;iBA4C1B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;iBA0BjC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkD/B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;iBAiChC,CAAC;AAGH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC/D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAC3D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC7D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|