# Index9 (npm · @index9/mcp)

Discover, shortlist, compare, cost-model, and live-test 300+ AI models from your editor

- Trust score: 65/100 (medium)
- Change this week: +39
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-04

## Components

- npm · `@index9/mcp`: 65/100 (this document), [markdown](https://verifymcp.io/servers/index9-org-mcp/index9-mcp.md), [page](https://verifymcp.io/servers/index9-org-mcp/index9-mcp)

## Channel facts

- Registry: `npm`
- Package: `@index9/mcp`
- Version: `6.5.2`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-04.

- **Supply Chain Security**: 83/100
  - No malware found by supply-chain analysis.
  - CVE check failed: a known medium-severity CVE affects hono 4.12.33, reached via @modelcontextprotocol/sdk > hono. A fixed version is available.
  - No install/post-install scripts declared.
  - Only part of the dependency tree could be resolved (94 of 98), so this covers what we could see, not the whole tree.
- **Provenance & Transparency**: 45/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 69 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 58/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 5167 tokens (~1033/item across 5 items; 5 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 30/100
  - Stability observed for 9 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (80% of tools); any adoption earns full credit.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add index9-org-mcp -- npx -y @index9/mcp
```

### Codex

```bash
codex mcp add index9-org-mcp -- npx -y @index9/mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "index9-org-mcp": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "@index9/mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add index9-org-mcp --command npx --arg -y --arg @index9/mcp
```

### Hermes

```yaml
mcp_servers:
  index9-org-mcp:
    command: "npx"
    args: ["-y", "@index9/mcp"]
```

### Other

```json
{
  "mcpServers": {
    "index9-org-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@index9/mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-04 (score 65, 0)

- [security regression] CVE-2026-69207 affects this package: medium
- [security regression] Known CVEs: partial → fail

### 2026-08-02 (score 65, +25)

- [security regression] Install scripts: pass → unverified
- [security regression] Provenance: fail → unverified
- [security improvement] Known CVEs: unverified → partial
- [security improvement] Malware scan: unverified → pass
- [functional regression] Maintenance: pass → unverified
- [functional regression] License: pass → unverified
- [functional improvement] Dependency health: unverified → partial
- [functional improvement] Stability: unverified → 0.23
- [functional] Licence: MIT

### 2026-08-01 (score 40, +27)

- [security] Stability: Stability not yet verified: not enough scan history yet (needs a 30-day window).
- [functional improvement] MCP protocol: unverified → pass
- [functional improvement] Tool coverage: unverified → 100

### 2026-07-31 (score 13, −2)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 15, −60)

- [security regression] Known CVEs: partial → unverified
- [security regression] Malware scan: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional regression] Dependency health: partial → unverified

### 2026-07-29 (score 75, +49)

- [security regression] Provenance: unverified → fail
- [security improvement] Known CVEs: unverified → partial
- [security improvement] Install scripts: unverified → pass
- [functional improvement] Maintenance: unverified → pass
- [functional improvement] License: unverified → pass
- [functional improvement] Tool coverage: unverified → 100
- [functional improvement] Schema quality: unverified → excellent
- [functional] Licence: MIT

### 2026-07-28 (score 26, −14)

- [functional regression] Tool coverage: 100 → unverified
- [functional improvement] Dependency health: unverified → partial
- [functional] First check of Schema quality: unverified

### 2026-07-27 (score 40)

First indexed and scored.

## MCP tools (5)

### `find_models` (~1532 tokens)

Search AI models

Filter 300+ AI models by structured constraints (capabilities, price, context, modality, provider). The semantic `q` is a soft tiebreaker on top of filters — trust filters first; weak `q`-only queries surface as `meta.confidence: "low"` with a hint to drop `q` and use `sortBy=created` or `sortBy=price` instead.

Call this after list_facets (or directly when you already know the filters). Always include one call with sortBy=created (no q) when recommending models to the user — your training-data list of "good" models is likely stale, and sorting purely by price surfaces old tiny models and misses this month's cheap frontier.

Extract filters from user queries. Numeric and categorical constraints MUST go in structured filters; `q` is for semantic flavor. Shorthand: 1K=1000, 1M=1000000. Prices are USD per million input tokens.

Examples:
\- "1M context under $1" → q="model", minContext=1000000, maxPrice=1
\- "cheap vision model from openai" → q="cheap vision model", capabilitiesAll=["vision"], provider="openai"
\- "function calling under $0.50 with 128K" → q="function calling", capabilitiesAll=["function_calling"], maxPrice=0.5, minContext=128000
\- "cheapest paid model" → sortBy="price", sortOrder="asc", excludeFree=true
\- "best coding model" → q="best coding model"
\- "what's new" → sortBy="created" (no q needed)

Valid capabilities: function_calling, structured_output, reasoning, web_search, vision, audio_input, file_input, image_generation, audio_output.

Each result: id, name, description, created (unix seconds), createdAt (ISO 8601), contextLength, maxOutputTokens, pricing.{promptPerMillion, completionPerMillion} (rounded display $/M), pricing.{promptPerToken, completionPerToken, requestUsd} (exact, use for cost math), inputModalities[] / outputModalities[], capabilities[], score. With sortBy=price, results also expose pricing.effectivePromptPerMillion and pageInfo.priceSortBasis — sort order may diverge from displayed promptPerMillion for models with per-request fee…

Input parameters:

- `capabilitiesAll` (array): Array of capabilities that must ALL be present on the model (AND logic). Valid values: function_calling, structured_output, reasoning, web_search, vision, audio_input, file_input, image_generation, a…
- `capabilitiesAny` (array): Array of capabilities where at least ONE must be present (OR logic). Valid values: function_calling, structured_output, reasoning, web_search, vision, audio_input, file_input, image_generation, audio…
- `createdAfter` (string): Lower bound for model created timestamp.
- `createdBefore` (string): Upper bound for model created timestamp.
- `cursor` (string): Opaque pagination cursor from a previous response's `nextCursor` field. IMPORTANT: cursors are bound to the exact query text, filters, and sort order that produced them. Reuse the same query+filters+…
- `excludeFree` (boolean): When true, exclude models with id ending in ':free'. Useful for sortBy=price (which would otherwise be dominated by free-tier preview models) and when you want a paid SLA. Default false.
- `limit` (integer): Page size (1-100, default 20).
- `maxPrice` (number): Maximum effective prompt price in USD per million tokens. Matches the basis exposed in `pricing.effectivePromptPerMillion` and `pageInfo.priceSortBasis` — token price plus per-request fees scaled to…
- `minContext` (integer): Minimum context window in tokens.
- `minPrice` (number): Minimum effective prompt price in USD per million tokens. Matches the basis exposed in `pricing.effectivePromptPerMillion` and `pageInfo.priceSortBasis` — token price plus per-request fees scaled to…
- `modality` (string): Required output modality. Filters on the model's output modalities, not input capabilities. For example, "image" finds image-generation models, while capabilitiesAll=["vision"] finds models that acce…
- `provider` (array): Provider prefix filter. Array of provider slugs — a model matches if its ID starts with any of them (e.g., ['openai'] matches 'openai/gpt-4o'; ['openai','anthropic'] matches both). Pass a single-elem…
- `q` (string): Natural language search query describing desired model characteristics (e.g., 'fast cheap coding model'). Uses semantic search with fuzzy matching. Must be at least 2 characters when provided. Option…
- `requireKeywordMatch` (boolean): When true, suppress weak vector-only results from semantic queries. If no candidate has a BM25 keyword hit, returns an empty page with meta.confidence='low' and meta.lowConfidenceReason — instead of…
- `sortBy` (string): Sort order for results. Options: 'relevance' (best semantic match, default), 'created' (newest models), 'price' (cheapest/most expensive, with sortOrder). Defaults to 'relevance'.
- `sortOrder` (string): Sort order. Defaults by sortBy.

Output parameters:

- `_index9` (object)
- `meta` (object)
- `nextCursor`
- `pageInfo` (object)
- `results` (array)

### `get_models` (~527 tokens)

Inspect AI models

Get full specs for one or more models by id or alias. Accepts up to 100 ids per call — use this for batch comparison.

Call after find_models to inspect candidates, or directly when the user names a model (format: 'provider/model-name').

Response: { results: (Model | null)[], missingIds: string[], resolvedAliases?: Record<alias, canonicalId>, ambiguousAliases?: Record<alias, candidateIds[]>, suggestions?: Record<unknownId, Array<{id, name, created}>> }. Each non-null result has:
\- id, canonicalSlug, name, description
\- created (unix seconds), createdAt (ISO 8601), knowledgeCutoff (ISO date or null)
\- contextLength (tokens), maxOutputTokens, isModerated
\- pricing: { promptPerMillion, completionPerMillion, promptPerToken, completionPerToken, requestUsd, imageUsd } — *PerMillion is rounded display, *PerToken is exact (use for cost math). request/image are flat per-unit fees.
\- architecture: { inputModalities[], outputModalities[], tokenizer, instructType }
\- capabilities[]: normalized capability flags (same values as find_models and capabilitiesAll/Any)
\- supportedParameters[]: OpenRouter parameters the model accepts (e.g., "temperature", "tools", "response_format")

Entries in results are null when the id is unknown; those ids appear in missingIds. Ambiguous aliases appear in ambiguousAliases with candidate canonical ids — pass a canonical id to disambiguate. Unknown ids that partially match (e.g. "sonnet" → all Claude Sonnet variants) appear in `suggestions` as up to 5 `{id, name, created}` entries **sorted newest-first** — pick `suggestions[id][0].id` for the most current replacement without a second lookup. When token-overlap finds nothing but the id is shaped like `provider/<unknown>` and the provider exists, suggestions falls back to the 5 newest models from that provider (real created timestamps, no hardcoded "popular" list).

\`missingDiagnostics` (when present) gives a machine-readable reason per missing id: `unknown_provider` (the prefix before / isn't in th…

Input parameters:

- `ids` (array, required): Model identifiers or aliases. Up to 100.
- `maxDescriptionChars` (integer): Truncate descriptions to this many characters.

Output parameters:

- `_index9` (object)
- `ambiguousAliases` (object)
- `missingDiagnostics` (object)
- `missingIds` (array)
- `resolvedAliases` (object)
- `results` (array)
- `suggestions` (object)

### `compare_models` (~558 tokens)

Compare AI models side-by-side

Compare 2-10 models side-by-side. Returns each model's full metadata plus a diff matrix highlighting which fields are equal and which differ.

Use this when the user asks "which is cheaper / has more context / supports X" across multiple specific models. Faster than calling get_models and diffing yourself.

Response: { models: ModelResponse[], diff: { contextLength, maxOutputTokens, promptPricePerMillion, completionPricePerMillion, tokenizer, inputModalities, outputModalities, capabilities, supportedParameters }, cheapestForPromptPerMillion, largestContext, missingIds, resolvedAliases?, ambiguousAliases?, suggestions?: Record<unknownId, Array<{id, name, created}>> (newest-first), missingDiagnostics? }.

Each numeric/string diff field has { allEqual: boolean, values: Record<id, value|null> }. Capability/parameter diffs have { commonAll: string[], uniquePerModel: Record<id, string[]> }. cheapestForPromptPerMillion / largestContext are convenience picks across the supplied models — null when the field is missing on every model.

Optional: pass `expectedPromptTokens` AND `expectedCompletionTokens` to also receive `workloadCosts` and `cheapestForRealisticWorkload` — the actual cheapest given the user's expected token mix. Each `workloadCosts[i]` carries `tokenCostUsd` (token-only), `requestCostUsd` (per-request fee), `totalCostUsd` (sum, includes request fees), and `pricingBasis` ("exact_per_token" | "rounded_per_million" | "unavailable"). This matters when prompt:completion price ratios diverge across models, or when a model has a per-request fee.

Accepts the same alias formats as get_models. Unknown ids are returned in missingIds (with `suggestions[id]` as newest-first `{id, name, created}` entries when partial matches exist, plus `missingDiagnostics` carrying a machine-readable reason per id). When fewer than 2 ids resolve, this returns 400 with the diagnostics so you can retry with `suggestions[id][0].id` for each missing id.

Input parameters:

- `expectedCompletionTokens` (integer): Optional. Pair with expectedPromptTokens to surface workloadCosts and cheapestForRealisticWorkload. Both must be set to enable workload costing.
- `expectedPromptTokens` (integer): Optional. When set with expectedCompletionTokens, computes total per-call cost for each model and picks cheapestForRealisticWorkload — closes the gap where promptPerMillion alone misleads when prompt…
- `ids` (array, required): Model identifiers or aliases to compare (2-10). Same alias formats as get_models.

Output parameters:

- `_index9` (object)
- `ambiguousAliases` (object)
- `cheapestForPromptPerMillion`
- `cheapestForRealisticWorkload`
- `diff` (object)
- `largestContext`
- `missingDiagnostics` (object)
- `missingIds` (array)
- `models` (array)
- `resolvedAliases` (object)
- `suggestions` (object)
- `workloadCosts` (array)

### `list_facets` (~128 tokens)

List filter vocabulary

Return the live vocabulary derived from the current model cache: providers (id-prefixes with model counts), capability flags (with counts), input/output modalities, and tokenizers.

Use this once at the start of a session to learn what filter values find_models will accept, instead of trial-and-error against find_models.

Response: { providers: { id, modelCount }[], capabilities: { id, modelCount }[], modalities: { input: string[], output: string[] }, tokenizers: string[], totalModels: number, updatedAt: string (ISO 8601) }. No inputs.

Output parameters:

- `_index9` (object)
- `capabilities` (array)
- `modalities` (object)
- `providers` (array)
- `tokenizers` (array)
- `totalModels` (integer)
- `updatedAt` (string)

### `test_model` (~1433 tokens)

Test AI models live

Run model tests on 1-10 models. Use dryRun=true to estimate token usage/cost, or dryRun=false (default) to run live OpenRouter inference.

When dryRun=true:
\- No OpenRouter API key required
\- No inference call is made
\- Either `prompt` OR `expectedPromptTokens` is required (use the latter for capacity planning at sizes you don't want to paste in full)
\- expectedCompletionTokens defaults to 256 when omitted

Parameters:
\- models: 1-10 model IDs to test (all receive identical prompts)
\- prompt: Prompt text (required for dryRun unless expectedPromptTokens is set; required for live unless userContent provided)
\- dryRun: If true, return cost estimates only
\- expectedPromptTokens: Estimated prompt-token count for dryRun cost estimation; overrides the prompt-string heuristic. Use to model "what would N-token requests cost?" without pasting N tokens.
\- expectedCompletionTokens: Optional completion token estimate used by dryRun
\- maxTokens, systemPrompt, temperature, topP, seed, responseFormat, enforceJson, retries: Live-testing controls (ignored when dryRun=true)
\- stream: Use OpenRouter's SSE streaming so capacity/refusal errors surface in ~1s instead of waiting the full per-model timeout for an empty 200. Defaults to false.
\- firstTokenTimeoutMs: Streaming-only deadline for the first delta. Defaults to 10s. If the upstream sends no token within this window, the request aborts and returns failureReason="timeout". Ignored when stream=false.
\- providerSort: "throughput" | "price" | "latency" — opt-in OpenRouter provider routing. Defaults to OpenRouter's load-balanced choice.
\- providerOrder: ordered list of provider slugs (up to 8). Try these providers first before falling back. Useful for steering around an overloaded provider for a single model.
\- fallbackModels: ordered list of model ids (up to 5). OpenRouter automatically retries the request against the next id when the primary is unavailable. Use sparingly — a benchmark should usually test the model you asked for, not…

Input parameters:

- `debug` (boolean): When true, include upstream finish_reason, provider, error, refusal, and usage.
- `dryRun` (boolean): When true, returns estimated token usage and cost without calling OpenRouter (no API key required).
- `enforceJson` (boolean): When true, output must parse as JSON.
- `expectedCompletionTokens` (integer): Expected number of completion tokens for cost estimation (default: 256). Typical ranges: 100-500 for quick tests, 1000-2000 for code generation, 4000+ for long-form content. This is a heuristic — act…
- `expectedPromptTokens` (integer): Expected number of prompt tokens for dryRun cost estimation. When set, overrides the heuristic that counts characters from the literal `prompt` string — use this for capacity planning ("what would 60…
- `fallbackModels` (array): Fallback model IDs OpenRouter may try if the primary is unavailable. Up to 5.
- `firstTokenTimeoutMs` (integer): Streaming-only first-token deadline in ms. Defaults to 10000.
- `maxTokens` (integer): Completion token cap. For reasoning-capable models, set ≥ 2000 (or omit) — reasoning tokens count against this before visible output, and too-low caps cause finish_reason=length.
- `models` (array, required): Model IDs to evaluate (1-10).
- `prompt` (string): Prompt sent to each model.
- `providerOrder` (array): Provider slugs to try first, in order. Up to 8.
- `providerSort` (string): OpenRouter provider routing sort: "throughput", "price", or "latency".
- `responseFormat` (object): Structured output shape request forwarded to OpenRouter (e.g., { type: 'json_object' }).
- `retries` (integer): Retries for transient failures.
- `seed` (integer): Seed for repeatable outputs.
- `stream` (boolean): Use OpenRouter SSE streaming so capacity/refusal errors surface quickly. Defaults to false.
- `systemPrompt` (string): System instruction prepended to prompt.
- `temperature` (number): Sampling temperature (0-2).
- `timeoutMs` (integer): Per-model timeout in ms (default 15000, max 60000).
- `topP` (number): Nucleus sampling (0-1].
- `userContent` (array): Multimodal user content. At least one of prompt or userContent required.

## Diagnostics

Captured diagnostic sections: Provenance, Vulnerabilities, Dependencies. The full working is on the page: https://verifymcp.io/servers/index9-org-mcp/index9-mcp#diagnostics

## Score history

- 2026-08-04: 65
- 2026-08-03: 65
- 2026-08-02: 65
- 2026-08-01: 40
- 2026-07-31: 13
- 2026-07-30: 15
- 2026-07-29: 75
- 2026-07-28: 26
- 2026-07-27: 40

## Links

- npm package: https://www.npmjs.com/package/@index9/mcp
- Socket report: https://socket.dev/npm/package/@index9/mcp
- Repository: https://github.com/index9-org/mcp
- Changelog RSS feed: https://verifymcp.io/servers/index9-org-mcp/index9-mcp/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/index9-org-mcp/index9-mcp/changelog.json
- HTML version of this page: https://verifymcp.io/servers/index9-org-mcp/index9-mcp
