Skip to main content
Glama
Vivek-k3

Models PLUS

by Vivek-k3
index.ts10.8 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; // Type definitions type Model = { id: string; provider: string; name?: string; release_date?: string; last_updated?: string; attachment?: boolean; reasoning?: boolean; temperature?: boolean; tool_call?: boolean; open_weights?: boolean; knowledge?: string; cost?: { input?: number; output?: number; cache_read?: number; cache_write?: number; }; limit?: { context?: number; output?: number; }; modalities?: { input?: string[]; output?: string[]; }; [key: string]: unknown; }; type Provider = { id: string; name: string; env: string[]; npm?: string; api?: string; doc?: string; [key: string]: unknown; }; // Constants for magic numbers const API_TIMEOUT_MS = 10_000; const DEFAULT_SEARCH_LIMIT = 50; const DEFAULT_PROVIDERS_LIMIT = 20; // API Client for internal use class ModelsAPI { private async fetchFromAPI( endpoint: string, params?: Record<string, string | boolean | number> ): Promise<unknown> { const url = new URL(`${'https://modelsplus.quivr.tech'}${endpoint}`); if (params) { for (const [key, value] of Object.entries(params)) { if (value !== undefined && value !== null) { url.searchParams.set(key, String(value)); } } } const response = await fetch(url.toString(), { headers: { Accept: 'application/json', 'User-Agent': 'modelsplus-mcp/0.1.0', }, signal: AbortSignal.timeout(API_TIMEOUT_MS), }); if (!response.ok) { throw new Error( `API request failed: ${response.status} ${response.statusText}` ); } return response.json(); } async searchModels(options: { q?: string; provider?: string; tool_call?: boolean; reasoning?: boolean; limit?: number; offset?: number; }): Promise<Model[]> { const params: Record<string, string | boolean | number> = {}; if (options.q) { params.q = options.q; } if (options.provider) { params.provider = options.provider; } if (options.tool_call !== undefined) { params.tool_call = options.tool_call; } if (options.reasoning !== undefined) { params.reasoning = options.reasoning; } if (options.limit !== undefined) { params.limit = options.limit; } if (options.offset !== undefined) { params.offset = options.offset; } const data = await this.fetchFromAPI('/v1/models', params); return data as Model[]; } async getModel(id: string): Promise<Model | null> { try { const data = await this.fetchFromAPI(`/v1/models/${id}`); return data as Model | null; } catch (error) { if (error instanceof Error && error.message.includes('404')) { return null; } throw error; } } async searchProviders(options: { q?: string; env?: string; limit?: number; offset?: number; }): Promise<Provider[]> { const params: Record<string, string | boolean | number> = {}; if (options.q) { params.q = options.q; } if (options.env) { params.env = options.env; } if (options.limit !== undefined) { params.limit = options.limit; } if (options.offset !== undefined) { params.offset = options.offset; } const data = await this.fetchFromAPI('/v1/providers', params); return data as Provider[]; } async getProviders(): Promise<Provider[]> { const data = await this.fetchFromAPI('/v1/providers'); return data as Provider[]; } async getProvider(id: string): Promise<Provider | null> { try { const providers = await this.getProviders(); return providers.find((p: Provider) => p.id === id) || null; } catch (_error) { return null; } } } // Configuration schema for the ModelsPlus API export const configSchema = z.object({ apiTimeout: z .number() .default(API_TIMEOUT_MS) .describe('API request timeout in milliseconds'), debug: z.boolean().default(false).describe('Enable debug logging'), }); export default function createServer() { const api = new ModelsAPI(); const server = new McpServer({ name: 'modelsplus', version: '0.1.0', }); // Tool: Search Models server.registerTool( 'search_models', { title: 'Search Models', description: 'Search for AI models by name, provider, or capabilities', inputSchema: { q: z .string() .optional() .describe('Search query (model name, provider, etc.)'), provider: z .string() .optional() .describe('Filter by provider (e.g., openai, anthropic)'), tool_call: z .boolean() .optional() .describe('Filter by tool calling support'), reasoning: z .boolean() .optional() .describe('Filter by reasoning capabilities'), limit: z .number() .default(DEFAULT_SEARCH_LIMIT) .describe('Maximum number of results'), }, }, async (args: { q?: string; provider?: string; tool_call?: boolean; reasoning?: boolean; limit?: number; }) => { const { q, provider, tool_call, reasoning, limit = DEFAULT_SEARCH_LIMIT, } = args; const searchOptions: Parameters<ModelsAPI['searchModels']>[0] = {}; if (q !== undefined) { searchOptions.q = q; } if (provider !== undefined) { searchOptions.provider = provider; } if (tool_call !== undefined) { searchOptions.tool_call = tool_call; } if (reasoning !== undefined) { searchOptions.reasoning = reasoning; } if (limit !== undefined) { searchOptions.limit = limit; } try { const models = await api.searchModels(searchOptions); return { content: [ { type: 'text', text: `Found ${models.length} AI models matching your criteria:\n\n${JSON.stringify( models, null, 2 )}`, }, ], }; } catch (error) { throw new Error( `Failed to search models: ${error instanceof Error ? error.message : String(error)}` ); } } ); // Tool: Get Model server.registerTool( 'get_model', { title: 'Get Model', description: 'Get detailed information about a specific AI model', inputSchema: { id: z.string().describe('Model ID (e.g., gpt-4, claude-3-sonnet)'), }, }, async (args) => { const { id } = args as { id: string }; try { const model = await api.getModel(id); if (!model) { throw new Error(`AI model with ID '${id}' not found`); } return { content: [ { type: 'text', text: `AI model details for ${model.id}:\n\n${JSON.stringify(model, null, 2)}`, }, ], }; } catch (error) { throw new Error( `Failed to get model '${id}': ${error instanceof Error ? error.message : String(error)}` ); } } ); // Tool: Search Providers server.registerTool( 'search_providers', { title: 'Search Providers', description: 'Search for AI model providers by name or environment variables', inputSchema: { q: z.string().optional().describe('Search query (provider name)'), env: z .string() .optional() .describe('Filter by required environment variable'), limit: z .number() .default(DEFAULT_PROVIDERS_LIMIT) .describe('Maximum number of results'), }, }, async (args: { q?: string; env?: string; limit?: number }) => { const { q, env, limit = DEFAULT_PROVIDERS_LIMIT } = args; const searchOptions: Parameters<ModelsAPI['searchProviders']>[0] = {}; if (q !== undefined) { searchOptions.q = q; } if (env !== undefined) { searchOptions.env = env; } if (limit !== undefined) { searchOptions.limit = limit; } try { const providers = await api.searchProviders(searchOptions); return { content: [ { type: 'text', text: `Found ${providers.length} AI model providers matching your criteria:\n\n${JSON.stringify( providers, null, 2 )}`, }, ], }; } catch (error) { throw new Error( `Failed to search providers: ${error instanceof Error ? error.message : String(error)}` ); } } ); // Tool: Get Provider server.registerTool( 'get_provider', { title: 'Get Provider', description: 'Get detailed information about a specific AI model provider', inputSchema: { id: z.string().describe('Provider ID'), }, }, async (args) => { const { id } = args as { id: string }; try { const provider = await api.getProvider(id); if (!provider) { throw new Error(`AI model provider with ID '${id}' not found`); } return { content: [ { type: 'text', text: `AI model provider details for ${provider.id}:\n\n${JSON.stringify(provider, null, 2)}`, }, ], }; } catch (error) { throw new Error( `Failed to get provider '${id}': ${error instanceof Error ? error.message : String(error)}` ); } } ); // Resource: ModelsPlus API Info server.registerResource( 'modelsplus-api-info', 'info://modelsplus-api', { title: 'ModelsPlus API Information', description: 'Information about the ModelsPlus API and data sources', }, async (uri) => ({ contents: [ { uri: uri.href, text: `ModelsPlus MCP Server v0.1.1 Data Source: https://modelsplus.quivr.tech API Documentation: https://github.com/vivek-k3/modelsplus This server provides real-time access to AI model specifications and provider information from the Models.dev database. Available Tools: - search_models: Search AI models by various criteria - get_model: Get detailed information about a specific model - search_providers: Search AI model providers - get_provider: Get detailed information about a specific provider `, mimeType: 'text/plain', }, ], }) ); return server.server; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Vivek-k3/modelsplus'

If you have feedback or need assistance with the MCP directory API, please join our Discord server