@stabgan/openrouter-mcp-multimodal 1.0.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.
Files changed (32) hide show
  1. package/README.md +331 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +52 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/model-cache.d.ts +56 -0
  6. package/dist/model-cache.js +143 -0
  7. package/dist/model-cache.js.map +1 -0
  8. package/dist/openrouter-api.d.ts +26 -0
  9. package/dist/openrouter-api.js +119 -0
  10. package/dist/openrouter-api.js.map +1 -0
  11. package/dist/tool-handlers/analyze-image.d.ts +23 -0
  12. package/dist/tool-handlers/analyze-image.js +93 -0
  13. package/dist/tool-handlers/analyze-image.js.map +1 -0
  14. package/dist/tool-handlers/chat-completion.d.ts +24 -0
  15. package/dist/tool-handlers/chat-completion.js +111 -0
  16. package/dist/tool-handlers/chat-completion.js.map +1 -0
  17. package/dist/tool-handlers/get-model-info.d.ts +21 -0
  18. package/dist/tool-handlers/get-model-info.js +44 -0
  19. package/dist/tool-handlers/get-model-info.js.map +1 -0
  20. package/dist/tool-handlers/multi-image-analysis.d.ts +27 -0
  21. package/dist/tool-handlers/multi-image-analysis.js +136 -0
  22. package/dist/tool-handlers/multi-image-analysis.js.map +1 -0
  23. package/dist/tool-handlers/search-models.d.ts +34 -0
  24. package/dist/tool-handlers/search-models.js +44 -0
  25. package/dist/tool-handlers/search-models.js.map +1 -0
  26. package/dist/tool-handlers/validate-model.d.ts +21 -0
  27. package/dist/tool-handlers/validate-model.js +40 -0
  28. package/dist/tool-handlers/validate-model.js.map +1 -0
  29. package/dist/tool-handlers.d.ts +10 -0
  30. package/dist/tool-handlers.js +316 -0
  31. package/dist/tool-handlers.js.map +1 -0
  32. package/package.json +60 -0
@@ -0,0 +1,34 @@
1
+ import { ModelCache } from '../model-cache.js';
2
+ import { OpenRouterAPIClient } from '../openrouter-api.js';
3
+ export interface SearchModelsToolRequest {
4
+ query?: string;
5
+ provider?: string;
6
+ minContextLength?: number | string;
7
+ maxContextLength?: number | string;
8
+ maxPromptPrice?: number | string;
9
+ maxCompletionPrice?: number | string;
10
+ capabilities?: {
11
+ functions?: boolean;
12
+ tools?: boolean;
13
+ vision?: boolean;
14
+ json_mode?: boolean;
15
+ };
16
+ limit?: number | string;
17
+ }
18
+ export declare function handleSearchModels(request: {
19
+ params: {
20
+ arguments: SearchModelsToolRequest;
21
+ };
22
+ }, apiClient: OpenRouterAPIClient, modelCache: ModelCache): Promise<{
23
+ content: {
24
+ type: string;
25
+ text: string;
26
+ }[];
27
+ isError?: undefined;
28
+ } | {
29
+ content: {
30
+ type: string;
31
+ text: string;
32
+ }[];
33
+ isError: boolean;
34
+ }>;
@@ -0,0 +1,44 @@
1
+ export async function handleSearchModels(request, apiClient, modelCache) {
2
+ const args = request.params.arguments;
3
+ try {
4
+ // Refresh the cache if needed
5
+ if (!modelCache.isCacheValid()) {
6
+ const models = await apiClient.getModels();
7
+ modelCache.setModels(models);
8
+ }
9
+ // Search models based on criteria
10
+ const results = modelCache.searchModels({
11
+ query: args.query,
12
+ provider: args.provider,
13
+ minContextLength: args.minContextLength,
14
+ maxContextLength: args.maxContextLength,
15
+ maxPromptPrice: args.maxPromptPrice,
16
+ maxCompletionPrice: args.maxCompletionPrice,
17
+ capabilities: args.capabilities,
18
+ limit: args.limit || 10,
19
+ });
20
+ return {
21
+ content: [
22
+ {
23
+ type: 'text',
24
+ text: JSON.stringify(results, null, 2),
25
+ },
26
+ ],
27
+ };
28
+ }
29
+ catch (error) {
30
+ if (error instanceof Error) {
31
+ return {
32
+ content: [
33
+ {
34
+ type: 'text',
35
+ text: `Error searching models: ${error.message}`,
36
+ },
37
+ ],
38
+ isError: true,
39
+ };
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+ //# sourceMappingURL=search-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-models.js","sourceRoot":"","sources":["../../src/tool-handlers/search-models.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAA2D,EAC3D,SAA8B,EAC9B,UAAsB;IAEtB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;IAEtC,IAAI,CAAC;QACH,8BAA8B;QAC9B,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,CAAC;YAC3C,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;QAED,kCAAkC;QAClC,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,CAAC;YACtC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;SACxB,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;iBACvC;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,2BAA2B,KAAK,CAAC,OAAO,EAAE;qBACjD;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { ModelCache } from '../model-cache.js';
2
+ export interface ValidateModelToolRequest {
3
+ model: string;
4
+ }
5
+ export declare function handleValidateModel(request: {
6
+ params: {
7
+ arguments: ValidateModelToolRequest;
8
+ };
9
+ }, modelCache: ModelCache): Promise<{
10
+ content: {
11
+ type: string;
12
+ text: string;
13
+ }[];
14
+ isError: boolean;
15
+ } | {
16
+ content: {
17
+ type: string;
18
+ text: string;
19
+ }[];
20
+ isError?: undefined;
21
+ }>;
@@ -0,0 +1,40 @@
1
+ export async function handleValidateModel(request, modelCache) {
2
+ const args = request.params.arguments;
3
+ try {
4
+ if (!modelCache.isCacheValid()) {
5
+ return {
6
+ content: [
7
+ {
8
+ type: 'text',
9
+ text: 'Model cache is empty or expired. Please call search_models first to populate the cache.',
10
+ },
11
+ ],
12
+ isError: true,
13
+ };
14
+ }
15
+ const isValid = modelCache.hasModel(args.model);
16
+ return {
17
+ content: [
18
+ {
19
+ type: 'text',
20
+ text: JSON.stringify({ valid: isValid }),
21
+ },
22
+ ],
23
+ };
24
+ }
25
+ catch (error) {
26
+ if (error instanceof Error) {
27
+ return {
28
+ content: [
29
+ {
30
+ type: 'text',
31
+ text: `Error validating model: ${error.message}`,
32
+ },
33
+ ],
34
+ isError: true,
35
+ };
36
+ }
37
+ throw error;
38
+ }
39
+ }
40
+ //# sourceMappingURL=validate-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-model.js","sourceRoot":"","sources":["../../src/tool-handlers/validate-model.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA4D,EAC5D,UAAsB;IAEtB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;IAEtC,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,EAAE,CAAC;YAC/B,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,yFAAyF;qBAChG;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhD,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;iBACzC;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,2BAA2B,KAAK,CAAC,OAAO,EAAE;qBACjD;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ export declare class ToolHandlers {
3
+ private server;
4
+ private openai;
5
+ private modelCache;
6
+ private apiClient;
7
+ private defaultModel?;
8
+ constructor(server: Server, apiKey: string, defaultModel?: string);
9
+ private setupToolHandlers;
10
+ }
@@ -0,0 +1,316 @@
1
+ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
2
+ import OpenAI from 'openai';
3
+ import { ModelCache } from './model-cache.js';
4
+ import { OpenRouterAPIClient } from './openrouter-api.js';
5
+ // Import tool handlers
6
+ import { handleChatCompletion } from './tool-handlers/chat-completion.js';
7
+ import { handleSearchModels } from './tool-handlers/search-models.js';
8
+ import { handleGetModelInfo } from './tool-handlers/get-model-info.js';
9
+ import { handleValidateModel } from './tool-handlers/validate-model.js';
10
+ import { handleAnalyzeImage } from './tool-handlers/analyze-image.js';
11
+ import { handleMultiImageAnalysis } from './tool-handlers/multi-image-analysis.js';
12
+ export class ToolHandlers {
13
+ server;
14
+ openai;
15
+ modelCache;
16
+ apiClient;
17
+ defaultModel;
18
+ constructor(server, apiKey, defaultModel) {
19
+ this.server = server;
20
+ this.modelCache = ModelCache.getInstance();
21
+ this.apiClient = new OpenRouterAPIClient(apiKey);
22
+ this.defaultModel = defaultModel;
23
+ this.openai = new OpenAI({
24
+ apiKey: apiKey,
25
+ baseURL: 'https://openrouter.ai/api/v1',
26
+ defaultHeaders: {
27
+ 'HTTP-Referer': 'https://github.com/stabgan/openrouter-mcp-multimodal',
28
+ 'X-Title': 'OpenRouter MCP Multimodal Server',
29
+ },
30
+ });
31
+ this.setupToolHandlers();
32
+ }
33
+ setupToolHandlers() {
34
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
35
+ tools: [
36
+ // Chat Completion Tool
37
+ {
38
+ name: 'chat_completion',
39
+ description: 'Send a message to OpenRouter.ai and get a response',
40
+ inputSchema: {
41
+ type: 'object',
42
+ properties: {
43
+ model: {
44
+ type: 'string',
45
+ description: 'The model to use (e.g., "google/gemini-2.5-pro-exp-03-25:free", "undi95/toppy-m-7b:free"). If not provided, uses the default model if set.',
46
+ },
47
+ messages: {
48
+ type: 'array',
49
+ description: 'An array of conversation messages with roles and content',
50
+ minItems: 1,
51
+ maxItems: 100,
52
+ items: {
53
+ type: 'object',
54
+ properties: {
55
+ role: {
56
+ type: 'string',
57
+ enum: ['system', 'user', 'assistant'],
58
+ description: 'The role of the message sender',
59
+ },
60
+ content: {
61
+ oneOf: [
62
+ {
63
+ type: 'string',
64
+ description: 'The text content of the message',
65
+ },
66
+ {
67
+ type: 'array',
68
+ description: 'Array of content parts for multimodal messages (text and images)',
69
+ items: {
70
+ type: 'object',
71
+ properties: {
72
+ type: {
73
+ type: 'string',
74
+ enum: ['text', 'image_url'],
75
+ description: 'The type of content (text or image)',
76
+ },
77
+ text: {
78
+ type: 'string',
79
+ description: 'The text content (for text type)',
80
+ },
81
+ image_url: {
82
+ type: 'object',
83
+ description: 'The image URL object (for image_url type)',
84
+ properties: {
85
+ url: {
86
+ type: 'string',
87
+ description: 'URL of the image (can be a data URL with base64)',
88
+ },
89
+ },
90
+ required: ['url'],
91
+ },
92
+ },
93
+ required: ['type'],
94
+ },
95
+ },
96
+ ],
97
+ },
98
+ },
99
+ required: ['role', 'content'],
100
+ },
101
+ },
102
+ temperature: {
103
+ type: 'number',
104
+ description: 'Sampling temperature (0-2)',
105
+ minimum: 0,
106
+ maximum: 2,
107
+ },
108
+ },
109
+ required: ['messages'],
110
+ },
111
+ maxContextTokens: 200000
112
+ },
113
+ // Image Analysis Tool
114
+ {
115
+ name: 'analyze_image',
116
+ description: 'Analyze an image using OpenRouter vision models',
117
+ inputSchema: {
118
+ type: 'object',
119
+ properties: {
120
+ image_path: {
121
+ type: 'string',
122
+ description: 'Path to the image file to analyze (must be an absolute path)',
123
+ },
124
+ question: {
125
+ type: 'string',
126
+ description: 'Question to ask about the image',
127
+ },
128
+ model: {
129
+ type: 'string',
130
+ description: 'OpenRouter model to use (e.g., "anthropic/claude-3.5-sonnet")',
131
+ },
132
+ },
133
+ required: ['image_path'],
134
+ },
135
+ },
136
+ // Multi-Image Analysis Tool
137
+ {
138
+ name: 'multi_image_analysis',
139
+ description: 'Analyze multiple images at once with a single prompt and receive detailed responses',
140
+ inputSchema: {
141
+ type: 'object',
142
+ properties: {
143
+ images: {
144
+ type: 'array',
145
+ description: 'Array of image objects to analyze',
146
+ items: {
147
+ type: 'object',
148
+ properties: {
149
+ url: {
150
+ type: 'string',
151
+ description: 'URL or data URL of the image (can be a file:// URL to read from local filesystem)',
152
+ },
153
+ alt: {
154
+ type: 'string',
155
+ description: 'Optional alt text or description of the image',
156
+ },
157
+ },
158
+ required: ['url'],
159
+ },
160
+ },
161
+ prompt: {
162
+ type: 'string',
163
+ description: 'Prompt for analyzing the images',
164
+ },
165
+ markdown_response: {
166
+ type: 'boolean',
167
+ description: 'Whether to format the response in Markdown (default: true)',
168
+ default: true,
169
+ },
170
+ model: {
171
+ type: 'string',
172
+ description: 'OpenRouter model to use (defaults to claude-3.5-sonnet if not specified)',
173
+ },
174
+ },
175
+ required: ['images', 'prompt'],
176
+ },
177
+ },
178
+ // Search Models Tool
179
+ {
180
+ name: 'search_models',
181
+ description: 'Search and filter OpenRouter.ai models based on various criteria',
182
+ inputSchema: {
183
+ type: 'object',
184
+ properties: {
185
+ query: {
186
+ type: 'string',
187
+ description: 'Optional search query to filter by name, description, or provider',
188
+ },
189
+ provider: {
190
+ type: 'string',
191
+ description: 'Filter by specific provider (e.g., "anthropic", "openai", "cohere")',
192
+ },
193
+ minContextLength: {
194
+ type: 'number',
195
+ description: 'Minimum context length in tokens',
196
+ },
197
+ maxContextLength: {
198
+ type: 'number',
199
+ description: 'Maximum context length in tokens',
200
+ },
201
+ maxPromptPrice: {
202
+ type: 'number',
203
+ description: 'Maximum price per 1K tokens for prompts',
204
+ },
205
+ maxCompletionPrice: {
206
+ type: 'number',
207
+ description: 'Maximum price per 1K tokens for completions',
208
+ },
209
+ capabilities: {
210
+ type: 'object',
211
+ description: 'Filter by model capabilities',
212
+ properties: {
213
+ functions: {
214
+ type: 'boolean',
215
+ description: 'Requires function calling capability',
216
+ },
217
+ tools: {
218
+ type: 'boolean',
219
+ description: 'Requires tools capability',
220
+ },
221
+ vision: {
222
+ type: 'boolean',
223
+ description: 'Requires vision capability',
224
+ },
225
+ json_mode: {
226
+ type: 'boolean',
227
+ description: 'Requires JSON mode capability',
228
+ }
229
+ }
230
+ },
231
+ limit: {
232
+ type: 'number',
233
+ description: 'Maximum number of results to return (default: 10)',
234
+ minimum: 1,
235
+ maximum: 50
236
+ }
237
+ }
238
+ },
239
+ },
240
+ // Get Model Info Tool
241
+ {
242
+ name: 'get_model_info',
243
+ description: 'Get detailed information about a specific model',
244
+ inputSchema: {
245
+ type: 'object',
246
+ properties: {
247
+ model: {
248
+ type: 'string',
249
+ description: 'The model ID to get information for',
250
+ },
251
+ },
252
+ required: ['model'],
253
+ },
254
+ },
255
+ // Validate Model Tool
256
+ {
257
+ name: 'validate_model',
258
+ description: 'Check if a model ID is valid',
259
+ inputSchema: {
260
+ type: 'object',
261
+ properties: {
262
+ model: {
263
+ type: 'string',
264
+ description: 'The model ID to validate',
265
+ },
266
+ },
267
+ required: ['model'],
268
+ },
269
+ },
270
+ ],
271
+ }));
272
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
273
+ switch (request.params.name) {
274
+ case 'chat_completion':
275
+ return handleChatCompletion({
276
+ params: {
277
+ arguments: request.params.arguments
278
+ }
279
+ }, this.openai, this.defaultModel);
280
+ case 'analyze_image':
281
+ return handleAnalyzeImage({
282
+ params: {
283
+ arguments: request.params.arguments
284
+ }
285
+ }, this.openai, this.defaultModel);
286
+ case 'multi_image_analysis':
287
+ return handleMultiImageAnalysis({
288
+ params: {
289
+ arguments: request.params.arguments
290
+ }
291
+ }, this.openai, this.defaultModel);
292
+ case 'search_models':
293
+ return handleSearchModels({
294
+ params: {
295
+ arguments: request.params.arguments
296
+ }
297
+ }, this.apiClient, this.modelCache);
298
+ case 'get_model_info':
299
+ return handleGetModelInfo({
300
+ params: {
301
+ arguments: request.params.arguments
302
+ }
303
+ }, this.modelCache);
304
+ case 'validate_model':
305
+ return handleValidateModel({
306
+ params: {
307
+ arguments: request.params.arguments
308
+ }
309
+ }, this.modelCache);
310
+ default:
311
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
312
+ }
313
+ });
314
+ }
315
+ }
316
+ //# sourceMappingURL=tool-handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-handlers.js","sourceRoot":"","sources":["../src/tool-handlers.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@stabgan/openrouter-mcp-multimodal",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for OpenRouter providing text chat and image analysis tools",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "openrouter-multimodal": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc && shx chmod +x dist/*.js",
17
+ "prepare": "npm run build",
18
+ "start": "node dist/index.js",
19
+ "watch": "tsc --watch"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "openrouter",
24
+ "ai",
25
+ "llm",
26
+ "vision",
27
+ "image-analysis",
28
+ "modelcontextprotocol"
29
+ ],
30
+ "author": "stabgan",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/stabgan/openrouter-mcp-multimodal.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/stabgan/openrouter-mcp-multimodal/issues"
38
+ },
39
+ "homepage": "https://github.com/stabgan/openrouter-mcp-multimodal#readme",
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.4.1",
45
+ "axios": "^1.7.9",
46
+ "node-fetch": "^3.3.2",
47
+ "openai": "^4.83.0",
48
+ "sharp": "^0.33.3"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^22.13.1",
52
+ "@types/sharp": "^0.32.0",
53
+ "shx": "^0.3.4",
54
+ "typescript": "^5.7.3"
55
+ },
56
+ "overrides": {
57
+ "uri-js": "npm:uri-js-replace",
58
+ "whatwg-url": "^14.1.0"
59
+ }
60
+ }