🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@llmintel/mcp

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@llmintel/mcp - npm Package Compare versions

Comparing version
0.1.1
to
0.2.0
+12
-6
dist/cli.js

@@ -242,3 +242,4 @@ #!/usr/bin/env node

var SERVER_NAME = "llmintel";
var SERVER_VERSION = "0.1.0";
var SERVER_VERSION = "0.2.0";
var READ_ONLY = { readOnlyHint: true, openWorldHint: true };
function text(body) {

@@ -263,3 +264,4 @@ return { content: [{ type: "text", text: body }] };

model: z.string().min(1).describe("Model id or alias exactly as it appears in code, e.g. 'gpt-4o'.")
}
},
annotations: READ_ONLY
},

@@ -288,3 +290,4 @@ async ({ model }) => {

provider: z.enum(PROVIDERS).optional().describe("Restrict to one provider. Omit for all providers.")
}
},
annotations: READ_ONLY
},

@@ -319,3 +322,4 @@ async ({ withinDays, provider }) => {

model: z.string().min(1).describe("Model id or alias to find a replacement for.")
}
},
annotations: READ_ONLY
},

@@ -381,3 +385,4 @@ async ({ model }) => {

limit: z.number().int().positive().max(200).default(50).describe("Maximum results.")
}
},
annotations: READ_ONLY
},

@@ -401,3 +406,4 @@ async ({ provider, state, limit }) => {

provider: z.enum(PROVIDERS).optional().describe("Restrict to one provider.")
}
},
annotations: READ_ONLY
},

@@ -404,0 +410,0 @@ async ({ sinceDays, provider }) => {

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/client.ts","../src/format.ts","../src/server.ts","../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Minimal client for the public LLMIntel catalog API.\n *\n * The catalog endpoints require no API key, which is the whole point of this server: an agent can\n * answer \"is this model deprecated?\" with zero setup. A key is accepted anyway (via\n * `LLMINTEL_API_KEY`) purely to raise the rate-limit budget for heavy users.\n */\n\nexport const DEFAULT_BASE_URL = \"https://llmintel.ai\";\n\n/** Canonical lifecycle states, ordered from earliest to latest in a model's life. */\nexport const LIFECYCLE_STATES = [\n \"announced\",\n \"active\",\n \"legacy\",\n \"deprecated\",\n \"retiring\",\n \"retired\",\n] as const;\n\nexport type LifecycleState = (typeof LIFECYCLE_STATES)[number];\n\nexport const PROVIDERS = [\n \"openai\",\n \"anthropic\",\n \"azure\",\n \"bedrock\",\n \"google\",\n \"cohere\",\n \"mistral\",\n] as const;\n\nexport type Provider = (typeof PROVIDERS)[number];\n\nexport interface ModelSummary {\n id: string;\n provider: string;\n displayName: string;\n aliases?: string[];\n lifecycleState: LifecycleState;\n announcedDate: string | null;\n deprecatedDate: string | null;\n retirementDate: string | null;\n sourceUrl: string | null;\n sourceTerm?: string | null;\n}\n\nexport interface ModelSpec {\n inputUsdPerMillion?: number | null;\n outputUsdPerMillion?: number | null;\n contextWindow?: number | null;\n maxOutputTokens?: number | null;\n}\n\nexport interface ModelDetail extends ModelSummary {\n spec?: ModelSpec | null;\n migration?: {\n recommendedReplacementIds?: string[];\n resolvedReplacements?: Record<string, string>;\n breakingNotes?: string | null;\n confidence?: string | null;\n } | null;\n events?: Array<{\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n }>;\n}\n\nexport interface LifecycleEvent {\n modelId: string;\n provider: string;\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n sourceUrl?: string | null;\n}\n\n/** Thrown for any non-2xx catalog response, carrying the HTTP status for the caller to interpret. */\nexport class CatalogError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"CatalogError\";\n this.status = status;\n }\n}\n\nexport interface CatalogClientOptions {\n baseUrl?: string;\n /** Optional — only raises the rate-limit budget. The catalog itself is public. */\n apiKey?: string;\n fetchImpl?: typeof fetch;\n /** Abort a hung request so a stalled network never wedges the agent's tool call. */\n timeoutMs?: number;\n}\n\nexport class CatalogClient {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: CatalogClientOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.fetchImpl = options.fetchImpl ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? 10_000;\n }\n\n private async get<T>(path: string, params: Record<string, string | number | undefined> = {}) {\n const url = new URL(`${this.baseUrl}${path}`);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n\n const headers: Record<string, string> = { accept: \"application/json\" };\n if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;\n\n const signal = AbortSignal.timeout(this.timeoutMs);\n const response = await this.fetchImpl(url.toString(), { headers, signal });\n\n if (!response.ok) {\n const body = (await response.text().catch(() => \"\")).slice(0, 300);\n throw new CatalogError(response.status, body || response.statusText);\n }\n return (await response.json()) as T;\n }\n\n /**\n * Look up one model by canonical id *or* alias — `gpt-4o` works as well as\n * `openai/gpt-4o-2024-05-13`. Returns null when nothing matches, so callers can distinguish\n * \"we don't track this\" from a transport failure.\n */\n async getModel(ref: string): Promise<ModelDetail | null> {\n // The id may contain slashes; encode each segment so the catch-all route reassembles it.\n const encoded = ref\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n try {\n const body = await this.get<{ data: ModelDetail }>(`/v1/models/${encoded}`);\n return body.data;\n } catch (error) {\n if (error instanceof CatalogError && error.status === 404) return null;\n throw error;\n }\n }\n\n async listModels(\n params: { provider?: string; state?: string; limit?: number; offset?: number } = {},\n ): Promise<ModelSummary[]> {\n const body = await this.get<{ data: ModelSummary[] }>(\"/v1/models\", params);\n return body.data ?? [];\n }\n\n async listEvents(\n params: { provider?: string; state?: string; since?: string; limit?: number } = {},\n ): Promise<LifecycleEvent[]> {\n const body = await this.get<{ data: LifecycleEvent[] }>(\"/v1/events\", params);\n return body.data ?? [];\n }\n}\n","/**\n * Pure presentation logic for the MCP tools.\n *\n * These functions produce the *text an LLM reads*, so they are written for a machine consumer that\n * will act on the answer: lead with the verdict, state the deadline in days (a model cannot reason\n * reliably about whether 2026-10-14 is soon), and always name the replacement and the source.\n */\n\nimport type { LifecycleEvent, LifecycleState, ModelDetail, ModelSummary } from \"./client\";\n\n/** How much attention a model's lifecycle state demands right now. */\nexport type Risk = \"broken\" | \"urgent\" | \"plan\" | \"watch\" | \"safe\";\n\n/** Anything retiring within this window is treated as urgent rather than merely scheduled. */\nexport const URGENT_WINDOW_DAYS = 90;\n\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Whole days from `now` until an ISO date, or null when the date is absent/unparseable.\n * Negative means the date has passed. Both sides are truncated to UTC midnight so the result is a\n * stable calendar-day count rather than depending on the time of day the tool is called.\n */\nexport function daysUntil(date: string | null | undefined, now: Date): number | null {\n if (!date) return null;\n const target = Date.parse(`${date.slice(0, 10)}T00:00:00Z`);\n if (Number.isNaN(target)) return null;\n const today = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());\n return Math.round((target - today) / MS_PER_DAY);\n}\n\n/**\n * Classify a model's urgency. Lifecycle state is authoritative for what *has* happened; the\n * retirement date refines how soon it matters.\n */\nexport function assessRisk(model: ModelSummary, now: Date): Risk {\n const days = daysUntil(model.retirementDate, now);\n\n // Retired means calls already fail — nothing else outranks that.\n if (model.lifecycleState === \"retired\") return \"broken\";\n if (days !== null && days < 0) return \"broken\";\n if (days !== null && days <= URGENT_WINDOW_DAYS) return \"urgent\";\n\n switch (model.lifecycleState) {\n case \"retiring\":\n return \"urgent\";\n case \"deprecated\":\n case \"legacy\":\n return \"plan\";\n case \"announced\":\n return \"watch\";\n default:\n return \"safe\";\n }\n}\n\nconst RISK_VERDICT: Record<Risk, string> = {\n broken: \"DO NOT USE — this model is retired; API calls to it fail.\",\n urgent: \"ACT NOW — this model is retiring imminently.\",\n plan: \"PLAN A MIGRATION — this model is deprecated and will be retired.\",\n watch: \"NOT YET GENERALLY AVAILABLE — this model is pre-GA and may change or be withdrawn.\",\n safe: \"OK — this model is active with no announced retirement.\",\n};\n\nconst STATE_MEANING: Record<LifecycleState, string> = {\n announced: \"announced but not generally available\",\n active: \"generally available\",\n legacy: \"superseded but still callable\",\n deprecated: \"closed to new use; existing calls still work\",\n retiring: \"retirement scheduled\",\n retired: \"retired; calls fail\",\n};\n\nfunction formatDeadline(days: number | null, date: string | null | undefined): string | null {\n if (!date) return null;\n if (days === null) return date;\n if (days < 0) return `${date} (${Math.abs(days)} days ago)`;\n if (days === 0) return `${date} (today)`;\n return `${date} (in ${days} days)`;\n}\n\n/** Replacement ids for a model, canonicalised where the catalog could resolve them. */\nexport function replacementIds(model: ModelDetail): string[] {\n const raw = model.migration?.recommendedReplacementIds ?? [];\n const resolved = model.migration?.resolvedReplacements ?? {};\n return raw.map((id) => resolved[id] ?? id);\n}\n\n/**\n * The full answer to \"can I use this model?\". Deliberately verbose about *why*, because the agent\n * relays this reasoning to the developer rather than just the verdict.\n */\nexport function formatModelReport(model: ModelDetail, now: Date, query: string): string {\n const risk = assessRisk(model, now);\n const lines: string[] = [RISK_VERDICT[risk], \"\"];\n\n if (query.toLowerCase() !== model.id.toLowerCase()) {\n lines.push(`\"${query}\" resolves to the tracked model ${model.id}.`);\n }\n\n lines.push(\n `Model: ${model.displayName} (${model.id})`,\n `Provider: ${model.provider}`,\n `Lifecycle state: ${model.lifecycleState} — ${STATE_MEANING[model.lifecycleState]}`,\n );\n\n const retirement = formatDeadline(daysUntil(model.retirementDate, now), model.retirementDate);\n const deprecation = formatDeadline(daysUntil(model.deprecatedDate, now), model.deprecatedDate);\n if (deprecation) lines.push(`Deprecated: ${deprecation}`);\n if (retirement) lines.push(`Retirement: ${retirement}`);\n if (!retirement && risk !== \"safe\") lines.push(\"Retirement: no date published yet.\");\n\n const replacements = replacementIds(model);\n if (replacements.length > 0) {\n lines.push(\"\", `Recommended replacement(s): ${replacements.join(\", \")}`);\n } else if (risk === \"broken\" || risk === \"urgent\" || risk === \"plan\") {\n // Say so explicitly — silence would read as \"no migration needed\".\n lines.push(\"\", \"The provider has not named a replacement. Use suggest_replacement for options.\");\n }\n\n if (model.migration?.breakingNotes) {\n lines.push(`Breaking changes: ${model.migration.breakingNotes}`);\n }\n\n const spec = model.spec;\n if (spec?.inputUsdPerMillion != null || spec?.outputUsdPerMillion != null) {\n const input = spec.inputUsdPerMillion != null ? `$${spec.inputUsdPerMillion}/1M in` : null;\n const output = spec.outputUsdPerMillion != null ? `$${spec.outputUsdPerMillion}/1M out` : null;\n const context = spec.contextWindow != null ? `${spec.contextWindow} ctx` : null;\n lines.push(`Pricing/limits: ${[input, output, context].filter(Boolean).join(\" · \")}`);\n }\n\n if (model.sourceUrl) {\n lines.push(\"\", `Source: ${model.sourceUrl}`);\n if (model.sourceTerm) lines.push(`Provider's own term: \"${model.sourceTerm}\"`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Sort key: soonest real deadline first, undated entries last. */\nfunction retirementRank(model: ModelSummary, now: Date): number {\n const days = daysUntil(model.retirementDate, now);\n return days ?? Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Render a retirement window, splitting deadlines that have already passed from those still ahead.\n *\n * The split matters: a model whose retirement date is in the past is already broken, and burying it\n * in a list headed \"retiring soon\" invites an agent to treat it as future work. Past-due entries\n * are listed first and named for what they are.\n */\nexport function formatRetiringList(models: ModelSummary[], now: Date, withinDays: number): string {\n if (models.length === 0) {\n return `No tracked models are scheduled to retire within ${withinDays} days.`;\n }\n\n const sorted = [...models].sort((a, b) => retirementRank(a, now) - retirementRank(b, now));\n const overdue = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) < 0);\n const upcoming = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) >= 0);\n\n const lines: string[] = [];\n\n if (overdue.length > 0) {\n lines.push(\n `${overdue.length} model(s) are PAST their retirement date — calls to these should be ` +\n `assumed to fail. Migrate immediately:`,\n \"\",\n );\n for (const model of overdue) {\n const days = Math.abs(daysUntil(model.retirementDate, now) ?? 0);\n lines.push(\n `- ${model.id} (${model.provider}) — retirement date passed ${days} days ago ` +\n `(${model.retirementDate})`,\n );\n }\n lines.push(\"\");\n }\n\n if (upcoming.length > 0) {\n lines.push(`${upcoming.length} model(s) retiring within ${withinDays} days, soonest first:`, \"\");\n for (const model of upcoming) {\n const days = daysUntil(model.retirementDate, now);\n const when = days === 0 ? \"today\" : `in ${days} days`;\n lines.push(\n `- ${model.id} (${model.provider}) — ${when} (${model.retirementDate}) ` +\n `[${model.lifecycleState}]`,\n );\n }\n } else {\n lines.push(`No further retirements are scheduled within ${withinDays} days.`);\n }\n\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatEvents(events: LifecycleEvent[], since: string | undefined): string {\n if (events.length === 0) {\n return since\n ? `No lifecycle changes recorded since ${since}.`\n : \"No lifecycle changes recorded.\";\n }\n\n const lines = [`${events.length} lifecycle change(s), newest first:`, \"\"];\n for (const event of events) {\n const from = event.fromState ?? \"new\";\n lines.push(\n `- ${event.detectedAt.slice(0, 10)} ${event.modelId}: ${from} -> ${event.toState}`,\n );\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatModelList(models: ModelSummary[], now: Date): string {\n if (models.length === 0) return \"No models matched.\";\n\n const lines = [`${models.length} model(s):`, \"\"];\n for (const model of models) {\n const risk = assessRisk(model, now);\n const days = daysUntil(model.retirementDate, now);\n const suffix = days !== null && days >= 0 ? `, retires in ${days} days` : \"\";\n lines.push(`- ${model.id} — ${model.lifecycleState}${suffix} [${risk}]`);\n }\n return lines.join(\"\\n\");\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { LIFECYCLE_STATES, PROVIDERS, type CatalogClient, type ModelSummary } from \"./client\";\nimport {\n assessRisk,\n daysUntil,\n formatEvents,\n formatModelList,\n formatModelReport,\n formatRetiringList,\n replacementIds,\n} from \"./format\";\n\nexport const SERVER_NAME = \"llmintel\";\nexport const SERVER_VERSION = \"0.1.0\";\n\n/** Wrap tool output in the MCP content envelope. */\nfunction text(body: string) {\n return { content: [{ type: \"text\" as const, text: body }] };\n}\n\n/**\n * A tool failure must not look like a factual answer — an agent that reads \"not found\" as \"safe to\n * use\" would happily ship a retired model id. Errors are flagged with `isError` so the host\n * surfaces them as failures.\n */\nfunction failure(body: string) {\n return { content: [{ type: \"text\" as const, text: body }], isError: true as const };\n}\n\nfunction describeError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `Could not reach the LLMIntel catalog: ${message}. Do not infer a model's lifecycle state from this failure — the lookup did not complete.`;\n}\n\nexport interface BuildServerOptions {\n client: CatalogClient;\n /** Injectable clock so \"days until retirement\" is deterministic in tests. */\n now?: () => Date;\n}\n\n/**\n * Build the MCP server exposing the LLMIntel model-lifecycle catalog.\n *\n * The tool surface is intentionally small and answers questions an agent actually has while writing\n * code that names a model: is this id safe, what replaces it, what's about to break, and what\n * changed recently.\n */\nexport function buildServer({ client, now = () => new Date() }: BuildServerOptions): McpServer {\n const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });\n\n server.registerTool(\n \"check_model\",\n {\n title: \"Check a model's lifecycle status\",\n description:\n \"Check whether an LLM model id is safe to use, deprecated, or retired, and what to \" +\n \"migrate to. Accepts the exact string used in code (e.g. 'gpt-4o', \" +\n \"'claude-sonnet-4-5-20250929', 'anthropic/claude-opus-4-1'). Call this before writing or \" +\n \"changing any hardcoded model id.\",\n inputSchema: {\n model: z\n .string()\n .min(1)\n .describe(\"Model id or alias exactly as it appears in code, e.g. 'gpt-4o'.\"),\n },\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(\n `\"${model}\" is not in the LLMIntel catalog. That is not a safety verdict: it may be a ` +\n `very new model, a fine-tune, a self-hosted model, or a typo. Verify against the ` +\n `provider's own documentation before relying on it.`,\n );\n }\n return text(formatModelReport(detail, now(), model));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"list_retiring_models\",\n {\n title: \"List models retiring soon\",\n description:\n \"List tracked models scheduled to retire within a time window, soonest first. Use this to \" +\n \"audit a codebase or plan migration work.\",\n inputSchema: {\n withinDays: z\n .number()\n .int()\n .positive()\n .max(1095)\n .default(180)\n .describe(\"Only include models retiring within this many days. Defaults to 180.\"),\n provider: z\n .enum(PROVIDERS)\n .optional()\n .describe(\"Restrict to one provider. Omit for all providers.\"),\n },\n },\n async ({ withinDays, provider }) => {\n try {\n // The catalog has no server-side \"retiring within N days\" filter, so pull the dated states\n // and window them here. Both states can carry a retirement date.\n const [retiring, deprecated] = await Promise.all([\n client.listModels({ provider, state: \"retiring\", limit: 500 }),\n client.listModels({ provider, state: \"deprecated\", limit: 500 }),\n ]);\n\n const at = now();\n const seen = new Set<string>();\n const due: ModelSummary[] = [];\n for (const model of [...retiring, ...deprecated]) {\n if (seen.has(model.id)) continue;\n seen.add(model.id);\n const days = daysUntil(model.retirementDate, at);\n if (days !== null && days <= withinDays) due.push(model);\n }\n\n return text(formatRetiringList(due, at, withinDays));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"suggest_replacement\",\n {\n title: \"Suggest a replacement for a model\",\n description:\n \"Given a deprecated or retiring model, return the provider's recommended replacement(s) \" +\n \"and, when none is published, active models from the same provider to consider.\",\n inputSchema: {\n model: z.string().min(1).describe(\"Model id or alias to find a replacement for.\"),\n },\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(`\"${model}\" is not in the LLMIntel catalog, so no replacement is known.`);\n }\n\n const at = now();\n const risk = assessRisk(detail, at);\n const recommended = replacementIds(detail);\n\n if (recommended.length > 0) {\n const lines = [\n `Provider-recommended replacement(s) for ${detail.id}: ${recommended.join(\", \")}`,\n \"\",\n \"These come from the provider's own deprecation notice, not our editorial judgement.\",\n ];\n if (detail.migration?.breakingNotes) {\n lines.push(\"\", `Breaking changes to expect: ${detail.migration.breakingNotes}`);\n }\n if (detail.sourceUrl) lines.push(\"\", `Source: ${detail.sourceUrl}`);\n return text(lines.join(\"\\n\"));\n }\n\n if (risk === \"safe\") {\n return text(\n `${detail.id} is active with no announced retirement, so no replacement is needed.`,\n );\n }\n\n // No provider-stated replacement: fall back to that provider's active models, and label the\n // list as editorial so the agent does not present it as a vendor recommendation.\n const active = await client.listModels({\n provider: detail.provider,\n state: \"active\",\n limit: 25,\n });\n if (active.length === 0) {\n return text(\n `${detail.provider} published no replacement for ${detail.id}, and we track no active ` +\n `${detail.provider} models to suggest. Check the provider's documentation.`,\n );\n }\n return text(\n [\n `${detail.provider} has not published a replacement for ${detail.id} ` +\n `(state: ${detail.lifecycleState}).`,\n \"\",\n \"Active models from the same provider — candidates to evaluate, not a vendor recommendation:\",\n \"\",\n formatModelList(active, at),\n ].join(\"\\n\"),\n );\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"search_models\",\n {\n title: \"Search the model catalog\",\n description:\n \"List tracked models, optionally filtered by provider and lifecycle state. Use this to \" +\n \"discover what is currently available from a provider.\",\n inputSchema: {\n provider: z.enum(PROVIDERS).optional().describe(\"Filter by provider.\"),\n state: z\n .enum(LIFECYCLE_STATES)\n .optional()\n .describe(\"Filter by canonical lifecycle state, e.g. 'active' or 'deprecated'.\"),\n limit: z.number().int().positive().max(200).default(50).describe(\"Maximum results.\"),\n },\n },\n async ({ provider, state, limit }) => {\n try {\n const models = await client.listModels({ provider, state, limit });\n return text(formatModelList(models, now()));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"recent_lifecycle_changes\",\n {\n title: \"Recent lifecycle changes\",\n description:\n \"Lifecycle state changes across all tracked providers, newest first. Use this to answer \" +\n \"'what model deprecations happened recently?'.\",\n inputSchema: {\n sinceDays: z\n .number()\n .int()\n .positive()\n .max(365)\n .default(30)\n .describe(\"Look back this many days. Defaults to 30.\"),\n provider: z.enum(PROVIDERS).optional().describe(\"Restrict to one provider.\"),\n },\n },\n async ({ sinceDays, provider }) => {\n try {\n const since = new Date(now().getTime() - sinceDays * 86_400_000).toISOString();\n const events = await client.listEvents({ provider, since, limit: 100 });\n return text(formatEvents(events, since.slice(0, 10)));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n return server;\n}\n","/**\n * stdio entry point. MCP hosts (Cursor, Claude Desktop/Code, Windsurf, …) launch this as a child\n * process and speak JSON-RPC over stdin/stdout.\n *\n * Nothing may be written to stdout except protocol frames — a stray console.log corrupts the\n * stream — so all diagnostics go to stderr.\n */\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { CatalogClient, DEFAULT_BASE_URL } from \"./client\";\nimport { buildServer } from \"./server\";\n\nasync function main(): Promise<void> {\n const client = new CatalogClient({\n baseUrl: process.env.LLMINTEL_BASE_URL ?? DEFAULT_BASE_URL,\n // Optional: the catalog is public, a key only raises the rate-limit budget.\n apiKey: process.env.LLMINTEL_API_KEY,\n });\n\n const server = buildServer({ client });\n await server.connect(new StdioServerTransport());\n}\n\nmain().catch((error: unknown) => {\n console.error(\"[llmintel-mcp] fatal:\", error);\n process.exit(1);\n});\n"]}
{"version":3,"sources":["../src/client.ts","../src/format.ts","../src/server.ts","../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Minimal client for the public LLMIntel catalog API.\n *\n * The catalog endpoints require no API key, which is the whole point of this server: an agent can\n * answer \"is this model deprecated?\" with zero setup. A key is accepted anyway (via\n * `LLMINTEL_API_KEY`) purely to raise the rate-limit budget for heavy users.\n */\n\nexport const DEFAULT_BASE_URL = \"https://llmintel.ai\";\n\n/** Canonical lifecycle states, ordered from earliest to latest in a model's life. */\nexport const LIFECYCLE_STATES = [\n \"announced\",\n \"active\",\n \"legacy\",\n \"deprecated\",\n \"retiring\",\n \"retired\",\n] as const;\n\nexport type LifecycleState = (typeof LIFECYCLE_STATES)[number];\n\nexport const PROVIDERS = [\n \"openai\",\n \"anthropic\",\n \"azure\",\n \"bedrock\",\n \"google\",\n \"cohere\",\n \"mistral\",\n] as const;\n\nexport type Provider = (typeof PROVIDERS)[number];\n\nexport interface ModelSummary {\n id: string;\n provider: string;\n displayName: string;\n aliases?: string[];\n lifecycleState: LifecycleState;\n announcedDate: string | null;\n deprecatedDate: string | null;\n retirementDate: string | null;\n sourceUrl: string | null;\n sourceTerm?: string | null;\n}\n\nexport interface ModelSpec {\n inputUsdPerMillion?: number | null;\n outputUsdPerMillion?: number | null;\n contextWindow?: number | null;\n maxOutputTokens?: number | null;\n}\n\nexport interface ModelDetail extends ModelSummary {\n spec?: ModelSpec | null;\n migration?: {\n recommendedReplacementIds?: string[];\n resolvedReplacements?: Record<string, string>;\n breakingNotes?: string | null;\n confidence?: string | null;\n } | null;\n events?: Array<{\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n }>;\n}\n\nexport interface LifecycleEvent {\n modelId: string;\n provider: string;\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n sourceUrl?: string | null;\n}\n\n/** Thrown for any non-2xx catalog response, carrying the HTTP status for the caller to interpret. */\nexport class CatalogError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"CatalogError\";\n this.status = status;\n }\n}\n\n/**\n * The catalog reads the MCP tools depend on.\n *\n * `CatalogClient` is the implementation that talks to the public REST API, and it is what the npm\n * package ships. Keeping the tools on a structural interface lets llmintel.ai serve the same tools\n * over Streamable HTTP while reading its own database directly, instead of the deployment issuing\n * HTTP calls to itself and burning its own anonymous per-IP rate limit on behalf of every caller.\n */\nexport interface CatalogSource {\n getModel(ref: string): Promise<ModelDetail | null>;\n listModels(params?: {\n provider?: string;\n state?: string;\n limit?: number;\n offset?: number;\n }): Promise<ModelSummary[]>;\n listEvents(params?: {\n provider?: string;\n state?: string;\n since?: string;\n limit?: number;\n }): Promise<LifecycleEvent[]>;\n}\n\nexport interface CatalogClientOptions {\n baseUrl?: string;\n /** Optional — only raises the rate-limit budget. The catalog itself is public. */\n apiKey?: string;\n fetchImpl?: typeof fetch;\n /** Abort a hung request so a stalled network never wedges the agent's tool call. */\n timeoutMs?: number;\n}\n\nexport class CatalogClient implements CatalogSource {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: CatalogClientOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.fetchImpl = options.fetchImpl ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? 10_000;\n }\n\n private async get<T>(path: string, params: Record<string, string | number | undefined> = {}) {\n const url = new URL(`${this.baseUrl}${path}`);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n\n const headers: Record<string, string> = { accept: \"application/json\" };\n if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;\n\n const signal = AbortSignal.timeout(this.timeoutMs);\n const response = await this.fetchImpl(url.toString(), { headers, signal });\n\n if (!response.ok) {\n const body = (await response.text().catch(() => \"\")).slice(0, 300);\n throw new CatalogError(response.status, body || response.statusText);\n }\n return (await response.json()) as T;\n }\n\n /**\n * Look up one model by canonical id *or* alias — `gpt-4o` works as well as\n * `openai/gpt-4o-2024-05-13`. Returns null when nothing matches, so callers can distinguish\n * \"we don't track this\" from a transport failure.\n */\n async getModel(ref: string): Promise<ModelDetail | null> {\n // The id may contain slashes; encode each segment so the catch-all route reassembles it.\n const encoded = ref\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n try {\n const body = await this.get<{ data: ModelDetail }>(`/v1/models/${encoded}`);\n return body.data;\n } catch (error) {\n if (error instanceof CatalogError && error.status === 404) return null;\n throw error;\n }\n }\n\n async listModels(\n params: { provider?: string; state?: string; limit?: number; offset?: number } = {},\n ): Promise<ModelSummary[]> {\n const body = await this.get<{ data: ModelSummary[] }>(\"/v1/models\", params);\n return body.data ?? [];\n }\n\n async listEvents(\n params: { provider?: string; state?: string; since?: string; limit?: number } = {},\n ): Promise<LifecycleEvent[]> {\n const body = await this.get<{ data: LifecycleEvent[] }>(\"/v1/events\", params);\n return body.data ?? [];\n }\n}\n","/**\n * Pure presentation logic for the MCP tools.\n *\n * These functions produce the *text an LLM reads*, so they are written for a machine consumer that\n * will act on the answer: lead with the verdict, state the deadline in days (a model cannot reason\n * reliably about whether 2026-10-14 is soon), and always name the replacement and the source.\n */\n\nimport type { LifecycleEvent, LifecycleState, ModelDetail, ModelSummary } from \"./client\";\n\n/** How much attention a model's lifecycle state demands right now. */\nexport type Risk = \"broken\" | \"urgent\" | \"plan\" | \"watch\" | \"safe\";\n\n/** Anything retiring within this window is treated as urgent rather than merely scheduled. */\nexport const URGENT_WINDOW_DAYS = 90;\n\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Whole days from `now` until an ISO date, or null when the date is absent/unparseable.\n * Negative means the date has passed. Both sides are truncated to UTC midnight so the result is a\n * stable calendar-day count rather than depending on the time of day the tool is called.\n */\nexport function daysUntil(date: string | null | undefined, now: Date): number | null {\n if (!date) return null;\n const target = Date.parse(`${date.slice(0, 10)}T00:00:00Z`);\n if (Number.isNaN(target)) return null;\n const today = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());\n return Math.round((target - today) / MS_PER_DAY);\n}\n\n/**\n * Classify a model's urgency. Lifecycle state is authoritative for what *has* happened; the\n * retirement date refines how soon it matters.\n */\nexport function assessRisk(model: ModelSummary, now: Date): Risk {\n const days = daysUntil(model.retirementDate, now);\n\n // Retired means calls already fail — nothing else outranks that.\n if (model.lifecycleState === \"retired\") return \"broken\";\n if (days !== null && days < 0) return \"broken\";\n if (days !== null && days <= URGENT_WINDOW_DAYS) return \"urgent\";\n\n switch (model.lifecycleState) {\n case \"retiring\":\n return \"urgent\";\n case \"deprecated\":\n case \"legacy\":\n return \"plan\";\n case \"announced\":\n return \"watch\";\n default:\n return \"safe\";\n }\n}\n\nconst RISK_VERDICT: Record<Risk, string> = {\n broken: \"DO NOT USE — this model is retired; API calls to it fail.\",\n urgent: \"ACT NOW — this model is retiring imminently.\",\n plan: \"PLAN A MIGRATION — this model is deprecated and will be retired.\",\n watch: \"NOT YET GENERALLY AVAILABLE — this model is pre-GA and may change or be withdrawn.\",\n safe: \"OK — this model is active with no announced retirement.\",\n};\n\nconst STATE_MEANING: Record<LifecycleState, string> = {\n announced: \"announced but not generally available\",\n active: \"generally available\",\n legacy: \"superseded but still callable\",\n deprecated: \"closed to new use; existing calls still work\",\n retiring: \"retirement scheduled\",\n retired: \"retired; calls fail\",\n};\n\nfunction formatDeadline(days: number | null, date: string | null | undefined): string | null {\n if (!date) return null;\n if (days === null) return date;\n if (days < 0) return `${date} (${Math.abs(days)} days ago)`;\n if (days === 0) return `${date} (today)`;\n return `${date} (in ${days} days)`;\n}\n\n/** Replacement ids for a model, canonicalised where the catalog could resolve them. */\nexport function replacementIds(model: ModelDetail): string[] {\n const raw = model.migration?.recommendedReplacementIds ?? [];\n const resolved = model.migration?.resolvedReplacements ?? {};\n return raw.map((id) => resolved[id] ?? id);\n}\n\n/**\n * The full answer to \"can I use this model?\". Deliberately verbose about *why*, because the agent\n * relays this reasoning to the developer rather than just the verdict.\n */\nexport function formatModelReport(model: ModelDetail, now: Date, query: string): string {\n const risk = assessRisk(model, now);\n const lines: string[] = [RISK_VERDICT[risk], \"\"];\n\n if (query.toLowerCase() !== model.id.toLowerCase()) {\n lines.push(`\"${query}\" resolves to the tracked model ${model.id}.`);\n }\n\n lines.push(\n `Model: ${model.displayName} (${model.id})`,\n `Provider: ${model.provider}`,\n `Lifecycle state: ${model.lifecycleState} — ${STATE_MEANING[model.lifecycleState]}`,\n );\n\n const retirement = formatDeadline(daysUntil(model.retirementDate, now), model.retirementDate);\n const deprecation = formatDeadline(daysUntil(model.deprecatedDate, now), model.deprecatedDate);\n if (deprecation) lines.push(`Deprecated: ${deprecation}`);\n if (retirement) lines.push(`Retirement: ${retirement}`);\n if (!retirement && risk !== \"safe\") lines.push(\"Retirement: no date published yet.\");\n\n const replacements = replacementIds(model);\n if (replacements.length > 0) {\n lines.push(\"\", `Recommended replacement(s): ${replacements.join(\", \")}`);\n } else if (risk === \"broken\" || risk === \"urgent\" || risk === \"plan\") {\n // Say so explicitly — silence would read as \"no migration needed\".\n lines.push(\"\", \"The provider has not named a replacement. Use suggest_replacement for options.\");\n }\n\n if (model.migration?.breakingNotes) {\n lines.push(`Breaking changes: ${model.migration.breakingNotes}`);\n }\n\n const spec = model.spec;\n if (spec?.inputUsdPerMillion != null || spec?.outputUsdPerMillion != null) {\n const input = spec.inputUsdPerMillion != null ? `$${spec.inputUsdPerMillion}/1M in` : null;\n const output = spec.outputUsdPerMillion != null ? `$${spec.outputUsdPerMillion}/1M out` : null;\n const context = spec.contextWindow != null ? `${spec.contextWindow} ctx` : null;\n lines.push(`Pricing/limits: ${[input, output, context].filter(Boolean).join(\" · \")}`);\n }\n\n if (model.sourceUrl) {\n lines.push(\"\", `Source: ${model.sourceUrl}`);\n if (model.sourceTerm) lines.push(`Provider's own term: \"${model.sourceTerm}\"`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Sort key: soonest real deadline first, undated entries last. */\nfunction retirementRank(model: ModelSummary, now: Date): number {\n const days = daysUntil(model.retirementDate, now);\n return days ?? Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Render a retirement window, splitting deadlines that have already passed from those still ahead.\n *\n * The split matters: a model whose retirement date is in the past is already broken, and burying it\n * in a list headed \"retiring soon\" invites an agent to treat it as future work. Past-due entries\n * are listed first and named for what they are.\n */\nexport function formatRetiringList(models: ModelSummary[], now: Date, withinDays: number): string {\n if (models.length === 0) {\n return `No tracked models are scheduled to retire within ${withinDays} days.`;\n }\n\n const sorted = [...models].sort((a, b) => retirementRank(a, now) - retirementRank(b, now));\n const overdue = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) < 0);\n const upcoming = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) >= 0);\n\n const lines: string[] = [];\n\n if (overdue.length > 0) {\n lines.push(\n `${overdue.length} model(s) are PAST their retirement date — calls to these should be ` +\n `assumed to fail. Migrate immediately:`,\n \"\",\n );\n for (const model of overdue) {\n const days = Math.abs(daysUntil(model.retirementDate, now) ?? 0);\n lines.push(\n `- ${model.id} (${model.provider}) — retirement date passed ${days} days ago ` +\n `(${model.retirementDate})`,\n );\n }\n lines.push(\"\");\n }\n\n if (upcoming.length > 0) {\n lines.push(`${upcoming.length} model(s) retiring within ${withinDays} days, soonest first:`, \"\");\n for (const model of upcoming) {\n const days = daysUntil(model.retirementDate, now);\n const when = days === 0 ? \"today\" : `in ${days} days`;\n lines.push(\n `- ${model.id} (${model.provider}) — ${when} (${model.retirementDate}) ` +\n `[${model.lifecycleState}]`,\n );\n }\n } else {\n lines.push(`No further retirements are scheduled within ${withinDays} days.`);\n }\n\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatEvents(events: LifecycleEvent[], since: string | undefined): string {\n if (events.length === 0) {\n return since\n ? `No lifecycle changes recorded since ${since}.`\n : \"No lifecycle changes recorded.\";\n }\n\n const lines = [`${events.length} lifecycle change(s), newest first:`, \"\"];\n for (const event of events) {\n const from = event.fromState ?? \"new\";\n lines.push(\n `- ${event.detectedAt.slice(0, 10)} ${event.modelId}: ${from} -> ${event.toState}`,\n );\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatModelList(models: ModelSummary[], now: Date): string {\n if (models.length === 0) return \"No models matched.\";\n\n const lines = [`${models.length} model(s):`, \"\"];\n for (const model of models) {\n const risk = assessRisk(model, now);\n const days = daysUntil(model.retirementDate, now);\n const suffix = days !== null && days >= 0 ? `, retires in ${days} days` : \"\";\n lines.push(`- ${model.id} — ${model.lifecycleState}${suffix} [${risk}]`);\n }\n return lines.join(\"\\n\");\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { LIFECYCLE_STATES, PROVIDERS, type CatalogSource, type ModelSummary } from \"./client\";\nimport {\n assessRisk,\n daysUntil,\n formatEvents,\n formatModelList,\n formatModelReport,\n formatRetiringList,\n replacementIds,\n} from \"./format\";\n\nexport const SERVER_NAME = \"llmintel\";\nexport const SERVER_VERSION = \"0.2.0\";\n\n/**\n * Every tool here only reads the catalog, and the catalog is a service outside this process. Hosts\n * use `readOnlyHint` to decide what can run without a confirmation prompt, and Anthropic's directory\n * review requires the hint be present, so state it on all five rather than relying on a default.\n */\nconst READ_ONLY = { readOnlyHint: true, openWorldHint: true } as const;\n\n/** Wrap tool output in the MCP content envelope. */\nfunction text(body: string) {\n return { content: [{ type: \"text\" as const, text: body }] };\n}\n\n/**\n * A tool failure must not look like a factual answer — an agent that reads \"not found\" as \"safe to\n * use\" would happily ship a retired model id. Errors are flagged with `isError` so the host\n * surfaces them as failures.\n */\nfunction failure(body: string) {\n return { content: [{ type: \"text\" as const, text: body }], isError: true as const };\n}\n\nfunction describeError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `Could not reach the LLMIntel catalog: ${message}. Do not infer a model's lifecycle state from this failure — the lookup did not complete.`;\n}\n\nexport interface BuildServerOptions {\n client: CatalogSource;\n /** Injectable clock so \"days until retirement\" is deterministic in tests. */\n now?: () => Date;\n}\n\n/**\n * Build the MCP server exposing the LLMIntel model-lifecycle catalog.\n *\n * The tool surface is intentionally small and answers questions an agent actually has while writing\n * code that names a model: is this id safe, what replaces it, what's about to break, and what\n * changed recently.\n */\nexport function buildServer({ client, now = () => new Date() }: BuildServerOptions): McpServer {\n const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });\n\n server.registerTool(\n \"check_model\",\n {\n title: \"Check a model's lifecycle status\",\n description:\n \"Check whether an LLM model id is safe to use, deprecated, or retired, and what to \" +\n \"migrate to. Accepts the exact string used in code (e.g. 'gpt-4o', \" +\n \"'claude-sonnet-4-5-20250929', 'anthropic/claude-opus-4-1'). Call this before writing or \" +\n \"changing any hardcoded model id.\",\n inputSchema: {\n model: z\n .string()\n .min(1)\n .describe(\"Model id or alias exactly as it appears in code, e.g. 'gpt-4o'.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(\n `\"${model}\" is not in the LLMIntel catalog. That is not a safety verdict: it may be a ` +\n `very new model, a fine-tune, a self-hosted model, or a typo. Verify against the ` +\n `provider's own documentation before relying on it.`,\n );\n }\n return text(formatModelReport(detail, now(), model));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"list_retiring_models\",\n {\n title: \"List models retiring soon\",\n description:\n \"List tracked models scheduled to retire within a time window, soonest first. Use this to \" +\n \"audit a codebase or plan migration work.\",\n inputSchema: {\n withinDays: z\n .number()\n .int()\n .positive()\n .max(1095)\n .default(180)\n .describe(\"Only include models retiring within this many days. Defaults to 180.\"),\n provider: z\n .enum(PROVIDERS)\n .optional()\n .describe(\"Restrict to one provider. Omit for all providers.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ withinDays, provider }) => {\n try {\n // The catalog has no server-side \"retiring within N days\" filter, so pull the dated states\n // and window them here. Both states can carry a retirement date.\n const [retiring, deprecated] = await Promise.all([\n client.listModels({ provider, state: \"retiring\", limit: 500 }),\n client.listModels({ provider, state: \"deprecated\", limit: 500 }),\n ]);\n\n const at = now();\n const seen = new Set<string>();\n const due: ModelSummary[] = [];\n for (const model of [...retiring, ...deprecated]) {\n if (seen.has(model.id)) continue;\n seen.add(model.id);\n const days = daysUntil(model.retirementDate, at);\n if (days !== null && days <= withinDays) due.push(model);\n }\n\n return text(formatRetiringList(due, at, withinDays));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"suggest_replacement\",\n {\n title: \"Suggest a replacement for a model\",\n description:\n \"Given a deprecated or retiring model, return the provider's recommended replacement(s) \" +\n \"and, when none is published, active models from the same provider to consider.\",\n inputSchema: {\n model: z.string().min(1).describe(\"Model id or alias to find a replacement for.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(`\"${model}\" is not in the LLMIntel catalog, so no replacement is known.`);\n }\n\n const at = now();\n const risk = assessRisk(detail, at);\n const recommended = replacementIds(detail);\n\n if (recommended.length > 0) {\n const lines = [\n `Provider-recommended replacement(s) for ${detail.id}: ${recommended.join(\", \")}`,\n \"\",\n \"These come from the provider's own deprecation notice, not our editorial judgement.\",\n ];\n if (detail.migration?.breakingNotes) {\n lines.push(\"\", `Breaking changes to expect: ${detail.migration.breakingNotes}`);\n }\n if (detail.sourceUrl) lines.push(\"\", `Source: ${detail.sourceUrl}`);\n return text(lines.join(\"\\n\"));\n }\n\n if (risk === \"safe\") {\n return text(\n `${detail.id} is active with no announced retirement, so no replacement is needed.`,\n );\n }\n\n // No provider-stated replacement: fall back to that provider's active models, and label the\n // list as editorial so the agent does not present it as a vendor recommendation.\n const active = await client.listModels({\n provider: detail.provider,\n state: \"active\",\n limit: 25,\n });\n if (active.length === 0) {\n return text(\n `${detail.provider} published no replacement for ${detail.id}, and we track no active ` +\n `${detail.provider} models to suggest. Check the provider's documentation.`,\n );\n }\n return text(\n [\n `${detail.provider} has not published a replacement for ${detail.id} ` +\n `(state: ${detail.lifecycleState}).`,\n \"\",\n \"Active models from the same provider — candidates to evaluate, not a vendor recommendation:\",\n \"\",\n formatModelList(active, at),\n ].join(\"\\n\"),\n );\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"search_models\",\n {\n title: \"Search the model catalog\",\n description:\n \"List tracked models, optionally filtered by provider and lifecycle state. Use this to \" +\n \"discover what is currently available from a provider.\",\n inputSchema: {\n provider: z.enum(PROVIDERS).optional().describe(\"Filter by provider.\"),\n state: z\n .enum(LIFECYCLE_STATES)\n .optional()\n .describe(\"Filter by canonical lifecycle state, e.g. 'active' or 'deprecated'.\"),\n limit: z.number().int().positive().max(200).default(50).describe(\"Maximum results.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ provider, state, limit }) => {\n try {\n const models = await client.listModels({ provider, state, limit });\n return text(formatModelList(models, now()));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"recent_lifecycle_changes\",\n {\n title: \"Recent lifecycle changes\",\n description:\n \"Lifecycle state changes across all tracked providers, newest first. Use this to answer \" +\n \"'what model deprecations happened recently?'.\",\n inputSchema: {\n sinceDays: z\n .number()\n .int()\n .positive()\n .max(365)\n .default(30)\n .describe(\"Look back this many days. Defaults to 30.\"),\n provider: z.enum(PROVIDERS).optional().describe(\"Restrict to one provider.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ sinceDays, provider }) => {\n try {\n const since = new Date(now().getTime() - sinceDays * 86_400_000).toISOString();\n const events = await client.listEvents({ provider, since, limit: 100 });\n return text(formatEvents(events, since.slice(0, 10)));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n return server;\n}\n","/**\n * stdio entry point. MCP hosts (Cursor, Claude Desktop/Code, Windsurf, …) launch this as a child\n * process and speak JSON-RPC over stdin/stdout.\n *\n * Nothing may be written to stdout except protocol frames — a stray console.log corrupts the\n * stream — so all diagnostics go to stderr.\n */\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { CatalogClient, DEFAULT_BASE_URL } from \"./client\";\nimport { buildServer } from \"./server\";\n\nasync function main(): Promise<void> {\n const client = new CatalogClient({\n baseUrl: process.env.LLMINTEL_BASE_URL ?? DEFAULT_BASE_URL,\n // Optional: the catalog is public, a key only raises the rate-limit budget.\n apiKey: process.env.LLMINTEL_API_KEY,\n });\n\n const server = buildServer({ client });\n await server.connect(new StdioServerTransport());\n}\n\nmain().catch((error: unknown) => {\n console.error(\"[llmintel-mcp] fatal:\", error);\n process.exit(1);\n});\n"]}

@@ -61,2 +61,25 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

}
/**
* The catalog reads the MCP tools depend on.
*
* `CatalogClient` is the implementation that talks to the public REST API, and it is what the npm
* package ships. Keeping the tools on a structural interface lets llmintel.ai serve the same tools
* over Streamable HTTP while reading its own database directly, instead of the deployment issuing
* HTTP calls to itself and burning its own anonymous per-IP rate limit on behalf of every caller.
*/
interface CatalogSource {
getModel(ref: string): Promise<ModelDetail | null>;
listModels(params?: {
provider?: string;
state?: string;
limit?: number;
offset?: number;
}): Promise<ModelSummary[]>;
listEvents(params?: {
provider?: string;
state?: string;
since?: string;
limit?: number;
}): Promise<LifecycleEvent[]>;
}
interface CatalogClientOptions {

@@ -70,3 +93,3 @@ baseUrl?: string;

}
declare class CatalogClient {
declare class CatalogClient implements CatalogSource {
private readonly baseUrl;

@@ -140,5 +163,5 @@ private readonly apiKey;

declare const SERVER_NAME = "llmintel";
declare const SERVER_VERSION = "0.1.0";
declare const SERVER_VERSION = "0.2.0";
interface BuildServerOptions {
client: CatalogClient;
client: CatalogSource;
/** Injectable clock so "days until retirement" is deterministic in tests. */

@@ -156,2 +179,2 @@ now?: () => Date;

export { type BuildServerOptions, CatalogClient, type CatalogClientOptions, CatalogError, DEFAULT_BASE_URL, LIFECYCLE_STATES, type LifecycleEvent, type LifecycleState, type ModelDetail, type ModelSpec, type ModelSummary, PROVIDERS, type Provider, type Risk, SERVER_NAME, SERVER_VERSION, URGENT_WINDOW_DAYS, assessRisk, buildServer, daysUntil, formatEvents, formatModelList, formatModelReport, formatRetiringList, replacementIds };
export { type BuildServerOptions, CatalogClient, type CatalogClientOptions, CatalogError, type CatalogSource, DEFAULT_BASE_URL, LIFECYCLE_STATES, type LifecycleEvent, type LifecycleState, type ModelDetail, type ModelSpec, type ModelSummary, PROVIDERS, type Provider, type Risk, SERVER_NAME, SERVER_VERSION, URGENT_WINDOW_DAYS, assessRisk, buildServer, daysUntil, formatEvents, formatModelList, formatModelReport, formatRetiringList, replacementIds };

@@ -238,3 +238,4 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

var SERVER_NAME = "llmintel";
var SERVER_VERSION = "0.1.0";
var SERVER_VERSION = "0.2.0";
var READ_ONLY = { readOnlyHint: true, openWorldHint: true };
function text(body) {

@@ -259,3 +260,4 @@ return { content: [{ type: "text", text: body }] };

model: z.string().min(1).describe("Model id or alias exactly as it appears in code, e.g. 'gpt-4o'.")
}
},
annotations: READ_ONLY
},

@@ -284,3 +286,4 @@ async ({ model }) => {

provider: z.enum(PROVIDERS).optional().describe("Restrict to one provider. Omit for all providers.")
}
},
annotations: READ_ONLY
},

@@ -315,3 +318,4 @@ async ({ withinDays, provider }) => {

model: z.string().min(1).describe("Model id or alias to find a replacement for.")
}
},
annotations: READ_ONLY
},

@@ -377,3 +381,4 @@ async ({ model }) => {

limit: z.number().int().positive().max(200).default(50).describe("Maximum results.")
}
},
annotations: READ_ONLY
},

@@ -397,3 +402,4 @@ async ({ provider, state, limit }) => {

provider: z.enum(PROVIDERS).optional().describe("Restrict to one provider.")
}
},
annotations: READ_ONLY
},

@@ -400,0 +406,0 @@ async ({ sinceDays, provider }) => {

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/client.ts","../src/format.ts","../src/server.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Minimal client for the public LLMIntel catalog API.\n *\n * The catalog endpoints require no API key, which is the whole point of this server: an agent can\n * answer \"is this model deprecated?\" with zero setup. A key is accepted anyway (via\n * `LLMINTEL_API_KEY`) purely to raise the rate-limit budget for heavy users.\n */\n\nexport const DEFAULT_BASE_URL = \"https://llmintel.ai\";\n\n/** Canonical lifecycle states, ordered from earliest to latest in a model's life. */\nexport const LIFECYCLE_STATES = [\n \"announced\",\n \"active\",\n \"legacy\",\n \"deprecated\",\n \"retiring\",\n \"retired\",\n] as const;\n\nexport type LifecycleState = (typeof LIFECYCLE_STATES)[number];\n\nexport const PROVIDERS = [\n \"openai\",\n \"anthropic\",\n \"azure\",\n \"bedrock\",\n \"google\",\n \"cohere\",\n \"mistral\",\n] as const;\n\nexport type Provider = (typeof PROVIDERS)[number];\n\nexport interface ModelSummary {\n id: string;\n provider: string;\n displayName: string;\n aliases?: string[];\n lifecycleState: LifecycleState;\n announcedDate: string | null;\n deprecatedDate: string | null;\n retirementDate: string | null;\n sourceUrl: string | null;\n sourceTerm?: string | null;\n}\n\nexport interface ModelSpec {\n inputUsdPerMillion?: number | null;\n outputUsdPerMillion?: number | null;\n contextWindow?: number | null;\n maxOutputTokens?: number | null;\n}\n\nexport interface ModelDetail extends ModelSummary {\n spec?: ModelSpec | null;\n migration?: {\n recommendedReplacementIds?: string[];\n resolvedReplacements?: Record<string, string>;\n breakingNotes?: string | null;\n confidence?: string | null;\n } | null;\n events?: Array<{\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n }>;\n}\n\nexport interface LifecycleEvent {\n modelId: string;\n provider: string;\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n sourceUrl?: string | null;\n}\n\n/** Thrown for any non-2xx catalog response, carrying the HTTP status for the caller to interpret. */\nexport class CatalogError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"CatalogError\";\n this.status = status;\n }\n}\n\nexport interface CatalogClientOptions {\n baseUrl?: string;\n /** Optional — only raises the rate-limit budget. The catalog itself is public. */\n apiKey?: string;\n fetchImpl?: typeof fetch;\n /** Abort a hung request so a stalled network never wedges the agent's tool call. */\n timeoutMs?: number;\n}\n\nexport class CatalogClient {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: CatalogClientOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.fetchImpl = options.fetchImpl ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? 10_000;\n }\n\n private async get<T>(path: string, params: Record<string, string | number | undefined> = {}) {\n const url = new URL(`${this.baseUrl}${path}`);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n\n const headers: Record<string, string> = { accept: \"application/json\" };\n if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;\n\n const signal = AbortSignal.timeout(this.timeoutMs);\n const response = await this.fetchImpl(url.toString(), { headers, signal });\n\n if (!response.ok) {\n const body = (await response.text().catch(() => \"\")).slice(0, 300);\n throw new CatalogError(response.status, body || response.statusText);\n }\n return (await response.json()) as T;\n }\n\n /**\n * Look up one model by canonical id *or* alias — `gpt-4o` works as well as\n * `openai/gpt-4o-2024-05-13`. Returns null when nothing matches, so callers can distinguish\n * \"we don't track this\" from a transport failure.\n */\n async getModel(ref: string): Promise<ModelDetail | null> {\n // The id may contain slashes; encode each segment so the catch-all route reassembles it.\n const encoded = ref\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n try {\n const body = await this.get<{ data: ModelDetail }>(`/v1/models/${encoded}`);\n return body.data;\n } catch (error) {\n if (error instanceof CatalogError && error.status === 404) return null;\n throw error;\n }\n }\n\n async listModels(\n params: { provider?: string; state?: string; limit?: number; offset?: number } = {},\n ): Promise<ModelSummary[]> {\n const body = await this.get<{ data: ModelSummary[] }>(\"/v1/models\", params);\n return body.data ?? [];\n }\n\n async listEvents(\n params: { provider?: string; state?: string; since?: string; limit?: number } = {},\n ): Promise<LifecycleEvent[]> {\n const body = await this.get<{ data: LifecycleEvent[] }>(\"/v1/events\", params);\n return body.data ?? [];\n }\n}\n","/**\n * Pure presentation logic for the MCP tools.\n *\n * These functions produce the *text an LLM reads*, so they are written for a machine consumer that\n * will act on the answer: lead with the verdict, state the deadline in days (a model cannot reason\n * reliably about whether 2026-10-14 is soon), and always name the replacement and the source.\n */\n\nimport type { LifecycleEvent, LifecycleState, ModelDetail, ModelSummary } from \"./client\";\n\n/** How much attention a model's lifecycle state demands right now. */\nexport type Risk = \"broken\" | \"urgent\" | \"plan\" | \"watch\" | \"safe\";\n\n/** Anything retiring within this window is treated as urgent rather than merely scheduled. */\nexport const URGENT_WINDOW_DAYS = 90;\n\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Whole days from `now` until an ISO date, or null when the date is absent/unparseable.\n * Negative means the date has passed. Both sides are truncated to UTC midnight so the result is a\n * stable calendar-day count rather than depending on the time of day the tool is called.\n */\nexport function daysUntil(date: string | null | undefined, now: Date): number | null {\n if (!date) return null;\n const target = Date.parse(`${date.slice(0, 10)}T00:00:00Z`);\n if (Number.isNaN(target)) return null;\n const today = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());\n return Math.round((target - today) / MS_PER_DAY);\n}\n\n/**\n * Classify a model's urgency. Lifecycle state is authoritative for what *has* happened; the\n * retirement date refines how soon it matters.\n */\nexport function assessRisk(model: ModelSummary, now: Date): Risk {\n const days = daysUntil(model.retirementDate, now);\n\n // Retired means calls already fail — nothing else outranks that.\n if (model.lifecycleState === \"retired\") return \"broken\";\n if (days !== null && days < 0) return \"broken\";\n if (days !== null && days <= URGENT_WINDOW_DAYS) return \"urgent\";\n\n switch (model.lifecycleState) {\n case \"retiring\":\n return \"urgent\";\n case \"deprecated\":\n case \"legacy\":\n return \"plan\";\n case \"announced\":\n return \"watch\";\n default:\n return \"safe\";\n }\n}\n\nconst RISK_VERDICT: Record<Risk, string> = {\n broken: \"DO NOT USE — this model is retired; API calls to it fail.\",\n urgent: \"ACT NOW — this model is retiring imminently.\",\n plan: \"PLAN A MIGRATION — this model is deprecated and will be retired.\",\n watch: \"NOT YET GENERALLY AVAILABLE — this model is pre-GA and may change or be withdrawn.\",\n safe: \"OK — this model is active with no announced retirement.\",\n};\n\nconst STATE_MEANING: Record<LifecycleState, string> = {\n announced: \"announced but not generally available\",\n active: \"generally available\",\n legacy: \"superseded but still callable\",\n deprecated: \"closed to new use; existing calls still work\",\n retiring: \"retirement scheduled\",\n retired: \"retired; calls fail\",\n};\n\nfunction formatDeadline(days: number | null, date: string | null | undefined): string | null {\n if (!date) return null;\n if (days === null) return date;\n if (days < 0) return `${date} (${Math.abs(days)} days ago)`;\n if (days === 0) return `${date} (today)`;\n return `${date} (in ${days} days)`;\n}\n\n/** Replacement ids for a model, canonicalised where the catalog could resolve them. */\nexport function replacementIds(model: ModelDetail): string[] {\n const raw = model.migration?.recommendedReplacementIds ?? [];\n const resolved = model.migration?.resolvedReplacements ?? {};\n return raw.map((id) => resolved[id] ?? id);\n}\n\n/**\n * The full answer to \"can I use this model?\". Deliberately verbose about *why*, because the agent\n * relays this reasoning to the developer rather than just the verdict.\n */\nexport function formatModelReport(model: ModelDetail, now: Date, query: string): string {\n const risk = assessRisk(model, now);\n const lines: string[] = [RISK_VERDICT[risk], \"\"];\n\n if (query.toLowerCase() !== model.id.toLowerCase()) {\n lines.push(`\"${query}\" resolves to the tracked model ${model.id}.`);\n }\n\n lines.push(\n `Model: ${model.displayName} (${model.id})`,\n `Provider: ${model.provider}`,\n `Lifecycle state: ${model.lifecycleState} — ${STATE_MEANING[model.lifecycleState]}`,\n );\n\n const retirement = formatDeadline(daysUntil(model.retirementDate, now), model.retirementDate);\n const deprecation = formatDeadline(daysUntil(model.deprecatedDate, now), model.deprecatedDate);\n if (deprecation) lines.push(`Deprecated: ${deprecation}`);\n if (retirement) lines.push(`Retirement: ${retirement}`);\n if (!retirement && risk !== \"safe\") lines.push(\"Retirement: no date published yet.\");\n\n const replacements = replacementIds(model);\n if (replacements.length > 0) {\n lines.push(\"\", `Recommended replacement(s): ${replacements.join(\", \")}`);\n } else if (risk === \"broken\" || risk === \"urgent\" || risk === \"plan\") {\n // Say so explicitly — silence would read as \"no migration needed\".\n lines.push(\"\", \"The provider has not named a replacement. Use suggest_replacement for options.\");\n }\n\n if (model.migration?.breakingNotes) {\n lines.push(`Breaking changes: ${model.migration.breakingNotes}`);\n }\n\n const spec = model.spec;\n if (spec?.inputUsdPerMillion != null || spec?.outputUsdPerMillion != null) {\n const input = spec.inputUsdPerMillion != null ? `$${spec.inputUsdPerMillion}/1M in` : null;\n const output = spec.outputUsdPerMillion != null ? `$${spec.outputUsdPerMillion}/1M out` : null;\n const context = spec.contextWindow != null ? `${spec.contextWindow} ctx` : null;\n lines.push(`Pricing/limits: ${[input, output, context].filter(Boolean).join(\" · \")}`);\n }\n\n if (model.sourceUrl) {\n lines.push(\"\", `Source: ${model.sourceUrl}`);\n if (model.sourceTerm) lines.push(`Provider's own term: \"${model.sourceTerm}\"`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Sort key: soonest real deadline first, undated entries last. */\nfunction retirementRank(model: ModelSummary, now: Date): number {\n const days = daysUntil(model.retirementDate, now);\n return days ?? Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Render a retirement window, splitting deadlines that have already passed from those still ahead.\n *\n * The split matters: a model whose retirement date is in the past is already broken, and burying it\n * in a list headed \"retiring soon\" invites an agent to treat it as future work. Past-due entries\n * are listed first and named for what they are.\n */\nexport function formatRetiringList(models: ModelSummary[], now: Date, withinDays: number): string {\n if (models.length === 0) {\n return `No tracked models are scheduled to retire within ${withinDays} days.`;\n }\n\n const sorted = [...models].sort((a, b) => retirementRank(a, now) - retirementRank(b, now));\n const overdue = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) < 0);\n const upcoming = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) >= 0);\n\n const lines: string[] = [];\n\n if (overdue.length > 0) {\n lines.push(\n `${overdue.length} model(s) are PAST their retirement date — calls to these should be ` +\n `assumed to fail. Migrate immediately:`,\n \"\",\n );\n for (const model of overdue) {\n const days = Math.abs(daysUntil(model.retirementDate, now) ?? 0);\n lines.push(\n `- ${model.id} (${model.provider}) — retirement date passed ${days} days ago ` +\n `(${model.retirementDate})`,\n );\n }\n lines.push(\"\");\n }\n\n if (upcoming.length > 0) {\n lines.push(`${upcoming.length} model(s) retiring within ${withinDays} days, soonest first:`, \"\");\n for (const model of upcoming) {\n const days = daysUntil(model.retirementDate, now);\n const when = days === 0 ? \"today\" : `in ${days} days`;\n lines.push(\n `- ${model.id} (${model.provider}) — ${when} (${model.retirementDate}) ` +\n `[${model.lifecycleState}]`,\n );\n }\n } else {\n lines.push(`No further retirements are scheduled within ${withinDays} days.`);\n }\n\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatEvents(events: LifecycleEvent[], since: string | undefined): string {\n if (events.length === 0) {\n return since\n ? `No lifecycle changes recorded since ${since}.`\n : \"No lifecycle changes recorded.\";\n }\n\n const lines = [`${events.length} lifecycle change(s), newest first:`, \"\"];\n for (const event of events) {\n const from = event.fromState ?? \"new\";\n lines.push(\n `- ${event.detectedAt.slice(0, 10)} ${event.modelId}: ${from} -> ${event.toState}`,\n );\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatModelList(models: ModelSummary[], now: Date): string {\n if (models.length === 0) return \"No models matched.\";\n\n const lines = [`${models.length} model(s):`, \"\"];\n for (const model of models) {\n const risk = assessRisk(model, now);\n const days = daysUntil(model.retirementDate, now);\n const suffix = days !== null && days >= 0 ? `, retires in ${days} days` : \"\";\n lines.push(`- ${model.id} — ${model.lifecycleState}${suffix} [${risk}]`);\n }\n return lines.join(\"\\n\");\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { LIFECYCLE_STATES, PROVIDERS, type CatalogClient, type ModelSummary } from \"./client\";\nimport {\n assessRisk,\n daysUntil,\n formatEvents,\n formatModelList,\n formatModelReport,\n formatRetiringList,\n replacementIds,\n} from \"./format\";\n\nexport const SERVER_NAME = \"llmintel\";\nexport const SERVER_VERSION = \"0.1.0\";\n\n/** Wrap tool output in the MCP content envelope. */\nfunction text(body: string) {\n return { content: [{ type: \"text\" as const, text: body }] };\n}\n\n/**\n * A tool failure must not look like a factual answer — an agent that reads \"not found\" as \"safe to\n * use\" would happily ship a retired model id. Errors are flagged with `isError` so the host\n * surfaces them as failures.\n */\nfunction failure(body: string) {\n return { content: [{ type: \"text\" as const, text: body }], isError: true as const };\n}\n\nfunction describeError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `Could not reach the LLMIntel catalog: ${message}. Do not infer a model's lifecycle state from this failure — the lookup did not complete.`;\n}\n\nexport interface BuildServerOptions {\n client: CatalogClient;\n /** Injectable clock so \"days until retirement\" is deterministic in tests. */\n now?: () => Date;\n}\n\n/**\n * Build the MCP server exposing the LLMIntel model-lifecycle catalog.\n *\n * The tool surface is intentionally small and answers questions an agent actually has while writing\n * code that names a model: is this id safe, what replaces it, what's about to break, and what\n * changed recently.\n */\nexport function buildServer({ client, now = () => new Date() }: BuildServerOptions): McpServer {\n const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });\n\n server.registerTool(\n \"check_model\",\n {\n title: \"Check a model's lifecycle status\",\n description:\n \"Check whether an LLM model id is safe to use, deprecated, or retired, and what to \" +\n \"migrate to. Accepts the exact string used in code (e.g. 'gpt-4o', \" +\n \"'claude-sonnet-4-5-20250929', 'anthropic/claude-opus-4-1'). Call this before writing or \" +\n \"changing any hardcoded model id.\",\n inputSchema: {\n model: z\n .string()\n .min(1)\n .describe(\"Model id or alias exactly as it appears in code, e.g. 'gpt-4o'.\"),\n },\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(\n `\"${model}\" is not in the LLMIntel catalog. That is not a safety verdict: it may be a ` +\n `very new model, a fine-tune, a self-hosted model, or a typo. Verify against the ` +\n `provider's own documentation before relying on it.`,\n );\n }\n return text(formatModelReport(detail, now(), model));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"list_retiring_models\",\n {\n title: \"List models retiring soon\",\n description:\n \"List tracked models scheduled to retire within a time window, soonest first. Use this to \" +\n \"audit a codebase or plan migration work.\",\n inputSchema: {\n withinDays: z\n .number()\n .int()\n .positive()\n .max(1095)\n .default(180)\n .describe(\"Only include models retiring within this many days. Defaults to 180.\"),\n provider: z\n .enum(PROVIDERS)\n .optional()\n .describe(\"Restrict to one provider. Omit for all providers.\"),\n },\n },\n async ({ withinDays, provider }) => {\n try {\n // The catalog has no server-side \"retiring within N days\" filter, so pull the dated states\n // and window them here. Both states can carry a retirement date.\n const [retiring, deprecated] = await Promise.all([\n client.listModels({ provider, state: \"retiring\", limit: 500 }),\n client.listModels({ provider, state: \"deprecated\", limit: 500 }),\n ]);\n\n const at = now();\n const seen = new Set<string>();\n const due: ModelSummary[] = [];\n for (const model of [...retiring, ...deprecated]) {\n if (seen.has(model.id)) continue;\n seen.add(model.id);\n const days = daysUntil(model.retirementDate, at);\n if (days !== null && days <= withinDays) due.push(model);\n }\n\n return text(formatRetiringList(due, at, withinDays));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"suggest_replacement\",\n {\n title: \"Suggest a replacement for a model\",\n description:\n \"Given a deprecated or retiring model, return the provider's recommended replacement(s) \" +\n \"and, when none is published, active models from the same provider to consider.\",\n inputSchema: {\n model: z.string().min(1).describe(\"Model id or alias to find a replacement for.\"),\n },\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(`\"${model}\" is not in the LLMIntel catalog, so no replacement is known.`);\n }\n\n const at = now();\n const risk = assessRisk(detail, at);\n const recommended = replacementIds(detail);\n\n if (recommended.length > 0) {\n const lines = [\n `Provider-recommended replacement(s) for ${detail.id}: ${recommended.join(\", \")}`,\n \"\",\n \"These come from the provider's own deprecation notice, not our editorial judgement.\",\n ];\n if (detail.migration?.breakingNotes) {\n lines.push(\"\", `Breaking changes to expect: ${detail.migration.breakingNotes}`);\n }\n if (detail.sourceUrl) lines.push(\"\", `Source: ${detail.sourceUrl}`);\n return text(lines.join(\"\\n\"));\n }\n\n if (risk === \"safe\") {\n return text(\n `${detail.id} is active with no announced retirement, so no replacement is needed.`,\n );\n }\n\n // No provider-stated replacement: fall back to that provider's active models, and label the\n // list as editorial so the agent does not present it as a vendor recommendation.\n const active = await client.listModels({\n provider: detail.provider,\n state: \"active\",\n limit: 25,\n });\n if (active.length === 0) {\n return text(\n `${detail.provider} published no replacement for ${detail.id}, and we track no active ` +\n `${detail.provider} models to suggest. Check the provider's documentation.`,\n );\n }\n return text(\n [\n `${detail.provider} has not published a replacement for ${detail.id} ` +\n `(state: ${detail.lifecycleState}).`,\n \"\",\n \"Active models from the same provider — candidates to evaluate, not a vendor recommendation:\",\n \"\",\n formatModelList(active, at),\n ].join(\"\\n\"),\n );\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"search_models\",\n {\n title: \"Search the model catalog\",\n description:\n \"List tracked models, optionally filtered by provider and lifecycle state. Use this to \" +\n \"discover what is currently available from a provider.\",\n inputSchema: {\n provider: z.enum(PROVIDERS).optional().describe(\"Filter by provider.\"),\n state: z\n .enum(LIFECYCLE_STATES)\n .optional()\n .describe(\"Filter by canonical lifecycle state, e.g. 'active' or 'deprecated'.\"),\n limit: z.number().int().positive().max(200).default(50).describe(\"Maximum results.\"),\n },\n },\n async ({ provider, state, limit }) => {\n try {\n const models = await client.listModels({ provider, state, limit });\n return text(formatModelList(models, now()));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"recent_lifecycle_changes\",\n {\n title: \"Recent lifecycle changes\",\n description:\n \"Lifecycle state changes across all tracked providers, newest first. Use this to answer \" +\n \"'what model deprecations happened recently?'.\",\n inputSchema: {\n sinceDays: z\n .number()\n .int()\n .positive()\n .max(365)\n .default(30)\n .describe(\"Look back this many days. Defaults to 30.\"),\n provider: z.enum(PROVIDERS).optional().describe(\"Restrict to one provider.\"),\n },\n },\n async ({ sinceDays, provider }) => {\n try {\n const since = new Date(now().getTime() - sinceDays * 86_400_000).toISOString();\n const events = await client.listEvents({ provider, since, limit: 100 });\n return text(formatEvents(events, since.slice(0, 10)));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n return server;\n}\n"]}
{"version":3,"sources":["../src/client.ts","../src/format.ts","../src/server.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Minimal client for the public LLMIntel catalog API.\n *\n * The catalog endpoints require no API key, which is the whole point of this server: an agent can\n * answer \"is this model deprecated?\" with zero setup. A key is accepted anyway (via\n * `LLMINTEL_API_KEY`) purely to raise the rate-limit budget for heavy users.\n */\n\nexport const DEFAULT_BASE_URL = \"https://llmintel.ai\";\n\n/** Canonical lifecycle states, ordered from earliest to latest in a model's life. */\nexport const LIFECYCLE_STATES = [\n \"announced\",\n \"active\",\n \"legacy\",\n \"deprecated\",\n \"retiring\",\n \"retired\",\n] as const;\n\nexport type LifecycleState = (typeof LIFECYCLE_STATES)[number];\n\nexport const PROVIDERS = [\n \"openai\",\n \"anthropic\",\n \"azure\",\n \"bedrock\",\n \"google\",\n \"cohere\",\n \"mistral\",\n] as const;\n\nexport type Provider = (typeof PROVIDERS)[number];\n\nexport interface ModelSummary {\n id: string;\n provider: string;\n displayName: string;\n aliases?: string[];\n lifecycleState: LifecycleState;\n announcedDate: string | null;\n deprecatedDate: string | null;\n retirementDate: string | null;\n sourceUrl: string | null;\n sourceTerm?: string | null;\n}\n\nexport interface ModelSpec {\n inputUsdPerMillion?: number | null;\n outputUsdPerMillion?: number | null;\n contextWindow?: number | null;\n maxOutputTokens?: number | null;\n}\n\nexport interface ModelDetail extends ModelSummary {\n spec?: ModelSpec | null;\n migration?: {\n recommendedReplacementIds?: string[];\n resolvedReplacements?: Record<string, string>;\n breakingNotes?: string | null;\n confidence?: string | null;\n } | null;\n events?: Array<{\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n }>;\n}\n\nexport interface LifecycleEvent {\n modelId: string;\n provider: string;\n fromState: LifecycleState | null;\n toState: LifecycleState;\n detectedAt: string;\n sourceUrl?: string | null;\n}\n\n/** Thrown for any non-2xx catalog response, carrying the HTTP status for the caller to interpret. */\nexport class CatalogError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"CatalogError\";\n this.status = status;\n }\n}\n\n/**\n * The catalog reads the MCP tools depend on.\n *\n * `CatalogClient` is the implementation that talks to the public REST API, and it is what the npm\n * package ships. Keeping the tools on a structural interface lets llmintel.ai serve the same tools\n * over Streamable HTTP while reading its own database directly, instead of the deployment issuing\n * HTTP calls to itself and burning its own anonymous per-IP rate limit on behalf of every caller.\n */\nexport interface CatalogSource {\n getModel(ref: string): Promise<ModelDetail | null>;\n listModels(params?: {\n provider?: string;\n state?: string;\n limit?: number;\n offset?: number;\n }): Promise<ModelSummary[]>;\n listEvents(params?: {\n provider?: string;\n state?: string;\n since?: string;\n limit?: number;\n }): Promise<LifecycleEvent[]>;\n}\n\nexport interface CatalogClientOptions {\n baseUrl?: string;\n /** Optional — only raises the rate-limit budget. The catalog itself is public. */\n apiKey?: string;\n fetchImpl?: typeof fetch;\n /** Abort a hung request so a stalled network never wedges the agent's tool call. */\n timeoutMs?: number;\n}\n\nexport class CatalogClient implements CatalogSource {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: CatalogClientOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.fetchImpl = options.fetchImpl ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? 10_000;\n }\n\n private async get<T>(path: string, params: Record<string, string | number | undefined> = {}) {\n const url = new URL(`${this.baseUrl}${path}`);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n\n const headers: Record<string, string> = { accept: \"application/json\" };\n if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;\n\n const signal = AbortSignal.timeout(this.timeoutMs);\n const response = await this.fetchImpl(url.toString(), { headers, signal });\n\n if (!response.ok) {\n const body = (await response.text().catch(() => \"\")).slice(0, 300);\n throw new CatalogError(response.status, body || response.statusText);\n }\n return (await response.json()) as T;\n }\n\n /**\n * Look up one model by canonical id *or* alias — `gpt-4o` works as well as\n * `openai/gpt-4o-2024-05-13`. Returns null when nothing matches, so callers can distinguish\n * \"we don't track this\" from a transport failure.\n */\n async getModel(ref: string): Promise<ModelDetail | null> {\n // The id may contain slashes; encode each segment so the catch-all route reassembles it.\n const encoded = ref\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n try {\n const body = await this.get<{ data: ModelDetail }>(`/v1/models/${encoded}`);\n return body.data;\n } catch (error) {\n if (error instanceof CatalogError && error.status === 404) return null;\n throw error;\n }\n }\n\n async listModels(\n params: { provider?: string; state?: string; limit?: number; offset?: number } = {},\n ): Promise<ModelSummary[]> {\n const body = await this.get<{ data: ModelSummary[] }>(\"/v1/models\", params);\n return body.data ?? [];\n }\n\n async listEvents(\n params: { provider?: string; state?: string; since?: string; limit?: number } = {},\n ): Promise<LifecycleEvent[]> {\n const body = await this.get<{ data: LifecycleEvent[] }>(\"/v1/events\", params);\n return body.data ?? [];\n }\n}\n","/**\n * Pure presentation logic for the MCP tools.\n *\n * These functions produce the *text an LLM reads*, so they are written for a machine consumer that\n * will act on the answer: lead with the verdict, state the deadline in days (a model cannot reason\n * reliably about whether 2026-10-14 is soon), and always name the replacement and the source.\n */\n\nimport type { LifecycleEvent, LifecycleState, ModelDetail, ModelSummary } from \"./client\";\n\n/** How much attention a model's lifecycle state demands right now. */\nexport type Risk = \"broken\" | \"urgent\" | \"plan\" | \"watch\" | \"safe\";\n\n/** Anything retiring within this window is treated as urgent rather than merely scheduled. */\nexport const URGENT_WINDOW_DAYS = 90;\n\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Whole days from `now` until an ISO date, or null when the date is absent/unparseable.\n * Negative means the date has passed. Both sides are truncated to UTC midnight so the result is a\n * stable calendar-day count rather than depending on the time of day the tool is called.\n */\nexport function daysUntil(date: string | null | undefined, now: Date): number | null {\n if (!date) return null;\n const target = Date.parse(`${date.slice(0, 10)}T00:00:00Z`);\n if (Number.isNaN(target)) return null;\n const today = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());\n return Math.round((target - today) / MS_PER_DAY);\n}\n\n/**\n * Classify a model's urgency. Lifecycle state is authoritative for what *has* happened; the\n * retirement date refines how soon it matters.\n */\nexport function assessRisk(model: ModelSummary, now: Date): Risk {\n const days = daysUntil(model.retirementDate, now);\n\n // Retired means calls already fail — nothing else outranks that.\n if (model.lifecycleState === \"retired\") return \"broken\";\n if (days !== null && days < 0) return \"broken\";\n if (days !== null && days <= URGENT_WINDOW_DAYS) return \"urgent\";\n\n switch (model.lifecycleState) {\n case \"retiring\":\n return \"urgent\";\n case \"deprecated\":\n case \"legacy\":\n return \"plan\";\n case \"announced\":\n return \"watch\";\n default:\n return \"safe\";\n }\n}\n\nconst RISK_VERDICT: Record<Risk, string> = {\n broken: \"DO NOT USE — this model is retired; API calls to it fail.\",\n urgent: \"ACT NOW — this model is retiring imminently.\",\n plan: \"PLAN A MIGRATION — this model is deprecated and will be retired.\",\n watch: \"NOT YET GENERALLY AVAILABLE — this model is pre-GA and may change or be withdrawn.\",\n safe: \"OK — this model is active with no announced retirement.\",\n};\n\nconst STATE_MEANING: Record<LifecycleState, string> = {\n announced: \"announced but not generally available\",\n active: \"generally available\",\n legacy: \"superseded but still callable\",\n deprecated: \"closed to new use; existing calls still work\",\n retiring: \"retirement scheduled\",\n retired: \"retired; calls fail\",\n};\n\nfunction formatDeadline(days: number | null, date: string | null | undefined): string | null {\n if (!date) return null;\n if (days === null) return date;\n if (days < 0) return `${date} (${Math.abs(days)} days ago)`;\n if (days === 0) return `${date} (today)`;\n return `${date} (in ${days} days)`;\n}\n\n/** Replacement ids for a model, canonicalised where the catalog could resolve them. */\nexport function replacementIds(model: ModelDetail): string[] {\n const raw = model.migration?.recommendedReplacementIds ?? [];\n const resolved = model.migration?.resolvedReplacements ?? {};\n return raw.map((id) => resolved[id] ?? id);\n}\n\n/**\n * The full answer to \"can I use this model?\". Deliberately verbose about *why*, because the agent\n * relays this reasoning to the developer rather than just the verdict.\n */\nexport function formatModelReport(model: ModelDetail, now: Date, query: string): string {\n const risk = assessRisk(model, now);\n const lines: string[] = [RISK_VERDICT[risk], \"\"];\n\n if (query.toLowerCase() !== model.id.toLowerCase()) {\n lines.push(`\"${query}\" resolves to the tracked model ${model.id}.`);\n }\n\n lines.push(\n `Model: ${model.displayName} (${model.id})`,\n `Provider: ${model.provider}`,\n `Lifecycle state: ${model.lifecycleState} — ${STATE_MEANING[model.lifecycleState]}`,\n );\n\n const retirement = formatDeadline(daysUntil(model.retirementDate, now), model.retirementDate);\n const deprecation = formatDeadline(daysUntil(model.deprecatedDate, now), model.deprecatedDate);\n if (deprecation) lines.push(`Deprecated: ${deprecation}`);\n if (retirement) lines.push(`Retirement: ${retirement}`);\n if (!retirement && risk !== \"safe\") lines.push(\"Retirement: no date published yet.\");\n\n const replacements = replacementIds(model);\n if (replacements.length > 0) {\n lines.push(\"\", `Recommended replacement(s): ${replacements.join(\", \")}`);\n } else if (risk === \"broken\" || risk === \"urgent\" || risk === \"plan\") {\n // Say so explicitly — silence would read as \"no migration needed\".\n lines.push(\"\", \"The provider has not named a replacement. Use suggest_replacement for options.\");\n }\n\n if (model.migration?.breakingNotes) {\n lines.push(`Breaking changes: ${model.migration.breakingNotes}`);\n }\n\n const spec = model.spec;\n if (spec?.inputUsdPerMillion != null || spec?.outputUsdPerMillion != null) {\n const input = spec.inputUsdPerMillion != null ? `$${spec.inputUsdPerMillion}/1M in` : null;\n const output = spec.outputUsdPerMillion != null ? `$${spec.outputUsdPerMillion}/1M out` : null;\n const context = spec.contextWindow != null ? `${spec.contextWindow} ctx` : null;\n lines.push(`Pricing/limits: ${[input, output, context].filter(Boolean).join(\" · \")}`);\n }\n\n if (model.sourceUrl) {\n lines.push(\"\", `Source: ${model.sourceUrl}`);\n if (model.sourceTerm) lines.push(`Provider's own term: \"${model.sourceTerm}\"`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Sort key: soonest real deadline first, undated entries last. */\nfunction retirementRank(model: ModelSummary, now: Date): number {\n const days = daysUntil(model.retirementDate, now);\n return days ?? Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Render a retirement window, splitting deadlines that have already passed from those still ahead.\n *\n * The split matters: a model whose retirement date is in the past is already broken, and burying it\n * in a list headed \"retiring soon\" invites an agent to treat it as future work. Past-due entries\n * are listed first and named for what they are.\n */\nexport function formatRetiringList(models: ModelSummary[], now: Date, withinDays: number): string {\n if (models.length === 0) {\n return `No tracked models are scheduled to retire within ${withinDays} days.`;\n }\n\n const sorted = [...models].sort((a, b) => retirementRank(a, now) - retirementRank(b, now));\n const overdue = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) < 0);\n const upcoming = sorted.filter((m) => (daysUntil(m.retirementDate, now) ?? 0) >= 0);\n\n const lines: string[] = [];\n\n if (overdue.length > 0) {\n lines.push(\n `${overdue.length} model(s) are PAST their retirement date — calls to these should be ` +\n `assumed to fail. Migrate immediately:`,\n \"\",\n );\n for (const model of overdue) {\n const days = Math.abs(daysUntil(model.retirementDate, now) ?? 0);\n lines.push(\n `- ${model.id} (${model.provider}) — retirement date passed ${days} days ago ` +\n `(${model.retirementDate})`,\n );\n }\n lines.push(\"\");\n }\n\n if (upcoming.length > 0) {\n lines.push(`${upcoming.length} model(s) retiring within ${withinDays} days, soonest first:`, \"\");\n for (const model of upcoming) {\n const days = daysUntil(model.retirementDate, now);\n const when = days === 0 ? \"today\" : `in ${days} days`;\n lines.push(\n `- ${model.id} (${model.provider}) — ${when} (${model.retirementDate}) ` +\n `[${model.lifecycleState}]`,\n );\n }\n } else {\n lines.push(`No further retirements are scheduled within ${withinDays} days.`);\n }\n\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatEvents(events: LifecycleEvent[], since: string | undefined): string {\n if (events.length === 0) {\n return since\n ? `No lifecycle changes recorded since ${since}.`\n : \"No lifecycle changes recorded.\";\n }\n\n const lines = [`${events.length} lifecycle change(s), newest first:`, \"\"];\n for (const event of events) {\n const from = event.fromState ?? \"new\";\n lines.push(\n `- ${event.detectedAt.slice(0, 10)} ${event.modelId}: ${from} -> ${event.toState}`,\n );\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatModelList(models: ModelSummary[], now: Date): string {\n if (models.length === 0) return \"No models matched.\";\n\n const lines = [`${models.length} model(s):`, \"\"];\n for (const model of models) {\n const risk = assessRisk(model, now);\n const days = daysUntil(model.retirementDate, now);\n const suffix = days !== null && days >= 0 ? `, retires in ${days} days` : \"\";\n lines.push(`- ${model.id} — ${model.lifecycleState}${suffix} [${risk}]`);\n }\n return lines.join(\"\\n\");\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { LIFECYCLE_STATES, PROVIDERS, type CatalogSource, type ModelSummary } from \"./client\";\nimport {\n assessRisk,\n daysUntil,\n formatEvents,\n formatModelList,\n formatModelReport,\n formatRetiringList,\n replacementIds,\n} from \"./format\";\n\nexport const SERVER_NAME = \"llmintel\";\nexport const SERVER_VERSION = \"0.2.0\";\n\n/**\n * Every tool here only reads the catalog, and the catalog is a service outside this process. Hosts\n * use `readOnlyHint` to decide what can run without a confirmation prompt, and Anthropic's directory\n * review requires the hint be present, so state it on all five rather than relying on a default.\n */\nconst READ_ONLY = { readOnlyHint: true, openWorldHint: true } as const;\n\n/** Wrap tool output in the MCP content envelope. */\nfunction text(body: string) {\n return { content: [{ type: \"text\" as const, text: body }] };\n}\n\n/**\n * A tool failure must not look like a factual answer — an agent that reads \"not found\" as \"safe to\n * use\" would happily ship a retired model id. Errors are flagged with `isError` so the host\n * surfaces them as failures.\n */\nfunction failure(body: string) {\n return { content: [{ type: \"text\" as const, text: body }], isError: true as const };\n}\n\nfunction describeError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `Could not reach the LLMIntel catalog: ${message}. Do not infer a model's lifecycle state from this failure — the lookup did not complete.`;\n}\n\nexport interface BuildServerOptions {\n client: CatalogSource;\n /** Injectable clock so \"days until retirement\" is deterministic in tests. */\n now?: () => Date;\n}\n\n/**\n * Build the MCP server exposing the LLMIntel model-lifecycle catalog.\n *\n * The tool surface is intentionally small and answers questions an agent actually has while writing\n * code that names a model: is this id safe, what replaces it, what's about to break, and what\n * changed recently.\n */\nexport function buildServer({ client, now = () => new Date() }: BuildServerOptions): McpServer {\n const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });\n\n server.registerTool(\n \"check_model\",\n {\n title: \"Check a model's lifecycle status\",\n description:\n \"Check whether an LLM model id is safe to use, deprecated, or retired, and what to \" +\n \"migrate to. Accepts the exact string used in code (e.g. 'gpt-4o', \" +\n \"'claude-sonnet-4-5-20250929', 'anthropic/claude-opus-4-1'). Call this before writing or \" +\n \"changing any hardcoded model id.\",\n inputSchema: {\n model: z\n .string()\n .min(1)\n .describe(\"Model id or alias exactly as it appears in code, e.g. 'gpt-4o'.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(\n `\"${model}\" is not in the LLMIntel catalog. That is not a safety verdict: it may be a ` +\n `very new model, a fine-tune, a self-hosted model, or a typo. Verify against the ` +\n `provider's own documentation before relying on it.`,\n );\n }\n return text(formatModelReport(detail, now(), model));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"list_retiring_models\",\n {\n title: \"List models retiring soon\",\n description:\n \"List tracked models scheduled to retire within a time window, soonest first. Use this to \" +\n \"audit a codebase or plan migration work.\",\n inputSchema: {\n withinDays: z\n .number()\n .int()\n .positive()\n .max(1095)\n .default(180)\n .describe(\"Only include models retiring within this many days. Defaults to 180.\"),\n provider: z\n .enum(PROVIDERS)\n .optional()\n .describe(\"Restrict to one provider. Omit for all providers.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ withinDays, provider }) => {\n try {\n // The catalog has no server-side \"retiring within N days\" filter, so pull the dated states\n // and window them here. Both states can carry a retirement date.\n const [retiring, deprecated] = await Promise.all([\n client.listModels({ provider, state: \"retiring\", limit: 500 }),\n client.listModels({ provider, state: \"deprecated\", limit: 500 }),\n ]);\n\n const at = now();\n const seen = new Set<string>();\n const due: ModelSummary[] = [];\n for (const model of [...retiring, ...deprecated]) {\n if (seen.has(model.id)) continue;\n seen.add(model.id);\n const days = daysUntil(model.retirementDate, at);\n if (days !== null && days <= withinDays) due.push(model);\n }\n\n return text(formatRetiringList(due, at, withinDays));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"suggest_replacement\",\n {\n title: \"Suggest a replacement for a model\",\n description:\n \"Given a deprecated or retiring model, return the provider's recommended replacement(s) \" +\n \"and, when none is published, active models from the same provider to consider.\",\n inputSchema: {\n model: z.string().min(1).describe(\"Model id or alias to find a replacement for.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ model }) => {\n try {\n const detail = await client.getModel(model);\n if (!detail) {\n return text(`\"${model}\" is not in the LLMIntel catalog, so no replacement is known.`);\n }\n\n const at = now();\n const risk = assessRisk(detail, at);\n const recommended = replacementIds(detail);\n\n if (recommended.length > 0) {\n const lines = [\n `Provider-recommended replacement(s) for ${detail.id}: ${recommended.join(\", \")}`,\n \"\",\n \"These come from the provider's own deprecation notice, not our editorial judgement.\",\n ];\n if (detail.migration?.breakingNotes) {\n lines.push(\"\", `Breaking changes to expect: ${detail.migration.breakingNotes}`);\n }\n if (detail.sourceUrl) lines.push(\"\", `Source: ${detail.sourceUrl}`);\n return text(lines.join(\"\\n\"));\n }\n\n if (risk === \"safe\") {\n return text(\n `${detail.id} is active with no announced retirement, so no replacement is needed.`,\n );\n }\n\n // No provider-stated replacement: fall back to that provider's active models, and label the\n // list as editorial so the agent does not present it as a vendor recommendation.\n const active = await client.listModels({\n provider: detail.provider,\n state: \"active\",\n limit: 25,\n });\n if (active.length === 0) {\n return text(\n `${detail.provider} published no replacement for ${detail.id}, and we track no active ` +\n `${detail.provider} models to suggest. Check the provider's documentation.`,\n );\n }\n return text(\n [\n `${detail.provider} has not published a replacement for ${detail.id} ` +\n `(state: ${detail.lifecycleState}).`,\n \"\",\n \"Active models from the same provider — candidates to evaluate, not a vendor recommendation:\",\n \"\",\n formatModelList(active, at),\n ].join(\"\\n\"),\n );\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"search_models\",\n {\n title: \"Search the model catalog\",\n description:\n \"List tracked models, optionally filtered by provider and lifecycle state. Use this to \" +\n \"discover what is currently available from a provider.\",\n inputSchema: {\n provider: z.enum(PROVIDERS).optional().describe(\"Filter by provider.\"),\n state: z\n .enum(LIFECYCLE_STATES)\n .optional()\n .describe(\"Filter by canonical lifecycle state, e.g. 'active' or 'deprecated'.\"),\n limit: z.number().int().positive().max(200).default(50).describe(\"Maximum results.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ provider, state, limit }) => {\n try {\n const models = await client.listModels({ provider, state, limit });\n return text(formatModelList(models, now()));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n server.registerTool(\n \"recent_lifecycle_changes\",\n {\n title: \"Recent lifecycle changes\",\n description:\n \"Lifecycle state changes across all tracked providers, newest first. Use this to answer \" +\n \"'what model deprecations happened recently?'.\",\n inputSchema: {\n sinceDays: z\n .number()\n .int()\n .positive()\n .max(365)\n .default(30)\n .describe(\"Look back this many days. Defaults to 30.\"),\n provider: z.enum(PROVIDERS).optional().describe(\"Restrict to one provider.\"),\n },\n annotations: READ_ONLY,\n },\n async ({ sinceDays, provider }) => {\n try {\n const since = new Date(now().getTime() - sinceDays * 86_400_000).toISOString();\n const events = await client.listEvents({ provider, since, limit: 100 });\n return text(formatEvents(events, since.slice(0, 10)));\n } catch (error) {\n return failure(describeError(error));\n }\n },\n );\n\n return server;\n}\n"]}
{
"name": "@llmintel/mcp",
"version": "0.1.1",
"mcpName": "ai.llmintel/llmintel",
"version": "0.2.0",
"mcpName": "ai.llmintel/model-lifecycle",
"description": "MCP server for AI model lifecycle data — check whether a model id is deprecated or retiring, and what to migrate to, across OpenAI, Anthropic, Azure, AWS Bedrock, Google, and Cohere.",

@@ -6,0 +6,0 @@ "keywords": [

@@ -14,2 +14,5 @@ # @llmintel/mcp

[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=llmintel&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsbG1pbnRlbC9tY3AiXX0%3D)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522llmintel%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522%2540llmintel%252Fmcp%2522%255D%257D)
## Install

@@ -44,2 +47,19 @@

### Hosted endpoint (no install)
The same five tools are served over Streamable HTTP at `https://llmintel.ai/v1/mcp`. Hosts that take
a URL need no Node and no package:
```json
{
"mcpServers": {
"llmintel": {
"url": "https://llmintel.ai/v1/mcp"
}
}
}
```
The endpoint is stateless and read-only. It answers from the same catalog the npm package queries.
## Tools

@@ -46,0 +66,0 @@

{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "ai.llmintel/llmintel",
"name": "ai.llmintel/model-lifecycle",
"title": "LLMIntel Model Lifecycle",
"description": "Check whether an LLM model id is deprecated, retiring, or retired, and what to migrate to.",
"version": "0.1.1",
"version": "0.2.0",
"websiteUrl": "https://llmintel.ai",

@@ -11,2 +12,20 @@ "repository": {

},
"icons": [
{
"src": "https://llmintel.ai/logo.svg",
"mimeType": "image/svg+xml",
"sizes": ["any"]
},
{
"src": "https://llmintel.ai/logo.png",
"mimeType": "image/png",
"sizes": ["400x400"]
}
],
"remotes": [
{
"type": "streamable-http",
"url": "https://llmintel.ai/v1/mcp"
}
],
"packages": [

@@ -17,3 +36,3 @@ {

"identifier": "@llmintel/mcp",
"version": "0.1.1",
"version": "0.2.0",
"transport": { "type": "stdio" },

@@ -20,0 +39,0 @@ "environmentVariables": [