npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@will-cppa/pinecone-read-only-mcp

v0.1.6

Published

A Model Context Protocol (MCP) server that provides semantic search over Pinecone vector databases using hybrid search (dense + sparse) with reranking.

Readme

Pinecone Read-Only MCP (TypeScript)

npm version Node.js Version License: BSL-1.0 CI

A Model Context Protocol (MCP) server that provides semantic search over Pinecone vector databases using hybrid search (dense + sparse) with reranking.

Features

  • Hybrid Search: Combines dense and sparse embeddings for superior recall
  • Semantic Reranking: Uses BGE reranker model for improved precision
  • Dynamic Namespace Discovery: Automatically discovers available namespaces in your Pinecone index
  • Metadata Filtering: Supports optional metadata filters for refined searches
  • Fast & Optimized: Lazy initialization, connection pooling, and efficient result merging
  • Production Ready: Input validation, error handling, and configurable logging
  • TypeScript Support: Full TypeScript support with type definitions

Installation

As a Package

npm install @will-cppa/pinecone-read-only-mcp

Or using yarn:

yarn add @will-cppa/pinecone-read-only-mcp

Or using pnpm:

pnpm add @will-cppa/pinecone-read-only-mcp

Global Installation

npm install -g @will-cppa/pinecone-read-only-mcp

From Source

git clone https://github.com/CppDigest/pinecone-read-only-mcp-typescript.git
cd pinecone-read-only-mcp-typescript
npm install
npm run build

Configuration

The server requires a Pinecone API key and supports the following configuration options:

Environment Variables

| Variable | Required | Default | Description | | ---------------------------------- | -------- | ---------------------- | ------------------------------------------------ | | PINECONE_API_KEY | Yes | - | Your Pinecone API key | | PINECONE_INDEX_NAME | No | rag-hybrid | Pinecone index name (dense + sparse for hybrid) | | PINECONE_RERANK_MODEL | No | bge-reranker-v2-m3 | Reranking model | | PINECONE_READ_ONLY_MCP_LOG_LEVEL | No | INFO | Logging level |

Claude Desktop Configuration

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "pinecone-search": {
      "command": "npx",
      "args": ["-y", "@will-cppa/pinecone-read-only-mcp"],
      "env": {
        "PINECONE_API_KEY": "your-api-key-here"
      }
    }
  }
}

Or with explicit options:

{
  "mcpServers": {
    "pinecone-search": {
      "command": "npx",
      "args": [
        "-y",
        "@will-cppa/pinecone-read-only-mcp",
        "--api-key",
        "your-api-key-here",
        "--index-name",
        "your-index-name",
        "--rerank-model",
        "bge-reranker-v2-m3"
      ]
    }
  }
}

For a global installation:

{
  "mcpServers": {
    "pinecone-search": {
      "command": "pinecone-read-only-mcp",
      "args": ["--api-key", "your-api-key-here"]
    }
  }
}

Usage

Command Line

Run the server using npx (no installation required):

npx @will-cppa/pinecone-read-only-mcp --api-key YOUR_API_KEY

Or if installed globally:

pinecone-read-only-mcp --api-key YOUR_API_KEY

Or if installed locally in your project:

node node_modules/@will-cppa/pinecone-read-only-mcp/dist/index.js --api-key YOUR_API_KEY

Available Options

--api-key TEXT           Pinecone API key (or set PINECONE_API_KEY env var)
--index-name TEXT        Pinecone index name [default: rag-hybrid]
--rerank-model TEXT      Reranking model [default: bge-reranker-v2-m3]
--log-level TEXT         Logging level [default: INFO]
--help, -h               Show help message

Deployment

Production Readiness Defaults

  • Build now fails fast on TypeScript errors (npm run build no longer suppresses failures).
  • CI validates typecheck, lint, format, build, smoke run, tests, and package dry-run.
  • list_namespaces data is cached in-memory for 30 minutes to reduce repeated Pinecone calls.
  • Query/count flow has guardrails (suggest_query_params before execution) to prevent wasteful calls.

Deploy with npm Package

# install
npm i @will-cppa/pinecone-read-only-mcp

# run
npx @will-cppa/pinecone-read-only-mcp --api-key YOUR_API_KEY

Deploy with Docker

# build image
docker build -t pinecone-read-only-mcp:latest .

# run (stdio MCP server)
docker run --rm -i \
  -e PINECONE_API_KEY=YOUR_API_KEY \
  -e PINECONE_INDEX_NAME=rag-hybrid \
  pinecone-read-only-mcp:latest

Release Gate (recommended)

Before tagging/releasing:

npm run release:check

This runs full CI-equivalent checks and validates publish contents with npm pack --dry-run.

API Documentation

The server exposes the following tools via MCP:

list_namespaces

Discovers and lists all available namespaces in the configured Pinecone index, including metadata fields and record counts for each namespace.

Parameters: None

Returns: JSON object with namespace details including available metadata fields

metadata_fields values represent inferred field types from sampled records. Common values include: string, number, boolean, string[], and array.

Example response:

{
  "status": "success",
  "count": 3,
  "namespaces": [
    {
      "name": "namespace1",
      "record_count": 1500,
      "metadata_fields": {
        "author": "string",
        "year": "number",
        "category": "string"
      }
    },
    {
      "name": "namespace2",
      "record_count": 850,
      "metadata_fields": {
        "title": "string",
        "date": "string"
      }
    }
  ]
}

suggest_query_params

Suggests which fields to request and which tool to use (count, query_fast, or query_detailed), based on the namespace’s schema (from list_namespaces) and the user’s natural language query. This is a mandatory flow step before count/query tools.

Parameters:

| Parameter | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------------------------------------------------------------------------- | | namespace | string | Yes | Namespace to query (must match a name from list_namespaces) | | user_query | string | Yes | User’s question or intent (e.g. "list papers by John Doe with titles", "how many papers by Wong?") |

Returns: suggested_fields (only fields that exist in that namespace), use_count_tool, recommended_tool, explanation, and namespace_found.

Example response:

{
  "status": "success",
  "suggested_fields": ["document_number", "title", "url", "author"],
  "use_count_tool": false,
  "recommended_tool": "query_fast",
  "explanation": "User asked for a list or browse; use minimal fields (no chunk_text) for smaller payload and cost.",
  "namespace_found": true
}

Use suggested_fields as the fields parameter when calling query tools.

guided_query

Single orchestrator tool that runs the full flow in one call:

  1. namespace routing (if namespace is omitted),
  2. query param suggestion,
  3. execution via count, query_fast, or query_detailed.

It returns both the final result and a decision_trace for transparency.

Parameters:

| Parameter | Type | Required | Default | Description | | ----------------- | ------- | -------- | ------- | ----------------------------------------------------------------------------------- | | user_query | string | Yes | - | User question/intent | | namespace | string | No | - | Optional explicit namespace | | metadata_filter | object | No | - | Optional metadata filter | | top_k | integer | No | 10 | Query result size for query paths (1-100) | | preferred_tool | enum | No | auto | One of auto, count, query_fast, query_detailed | | enrich_urls | boolean | No | true | Auto-generate URLs for mailing and slack-Cpplang when metadata.url is missing |

Returns: JSON containing decision_trace and result.

generate_urls

Generates URLs for retrieved records when metadata does not contain url and URL is required.

Supported namespaces:

  • mailing
  • slack-Cpplang

Rules:

  • mailing: uses doc_id or thread_id
    Format: https://lists.boost.org/archives/list/{doc_id_or_thread_id}/
  • slack-Cpplang: prefer source directly if present; otherwise use team_id, channel_id, and doc_id
    message_id = doc_id.replace('.', '')
    Format: https://app.slack.com/{team_id}/{channel_id}/p{message_id}

Parameters:

| Parameter | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------------------------------------------------------------------- | | namespace | string | Yes | Namespace for URL-generation logic | | records | array | Yes | Retrieved records; each item can be either metadata itself or an object with metadata field |

Returns: Per-record generated URL, generation method, and reason if unavailable.

count

Returns the unique document count matching a metadata filter and semantic query. Use for questions like "how many papers by John Doe?" instead of the query tool. For performance, the count tool uses semantic (dense) search only (no hybrid or lexical) and requests only document identifiers (document_number, url, doc_id)—no chunk content—then deduplicates by document.

Parameters:

| Parameter | Type | Required | Description | | ----------------- | ------ | -------- | -------------------------------------------------------------------------------------------- | | namespace | string | Yes | Namespace to count in (use list_namespaces to discover) | | query_text | string | Yes | Search query; use a broad term (e.g. "paper", "document") when counting by metadata only | | metadata_filter | object | No | Same operators as query (e.g. {"author": {"$in": ["John Doe"]}} for wg21-papers) |

Returns: JSON with count (unique documents, up to 10,000), and truncated: true if there are at least 10,000 matches.

Example response:

{
  "status": "success",
  "count": 42,
  "truncated": false,
  "namespace": "wg21-papers",
  "metadata_filter": { "author": { "$in": ["John Doe"] } }
}

keyword_search

Performs keyword (lexical/sparse-only) search over the dedicated sparse index (default: rag-hybrid-sparse, i.e. {PINECONE_INDEX_NAME}-sparse). Use for exact or keyword-style queries. Does not use the dense index or semantic reranking. Call list_namespaces first to discover namespaces; suggest_query_params is optional.

Parameters:

| Parameter | Type | Required | Default | Description | | ----------------- | -------- | -------- | ------- | --------------------------------------------------------------------------- | | query_text | string | Yes | - | Search query text (keyword/lexical match) | | namespace | string | Yes | - | Namespace to search (use list_namespaces to discover) | | top_k | integer | No | 10 | Number of results to return (1-100) | | metadata_filter | object | No | - | Optional metadata filter (same operators as query) | | fields | string[] | No | - | Optional field names to return; omit for all fields |

Returns: JSON with status, query, namespace, index (sparse index name), result_count, and results (ids, metadata, scores). Result rows match the query tool shape (e.g. paper_number, title, author, url, content, score, reranked: false).

Example response:

{
  "status": "success",
  "query": "contracts C++",
  "namespace": "wg21-papers",
  "index": "rag-hybrid-sparse",
  "result_count": 5,
  "results": [
    {
      "paper_number": "P0548",
      "title": "Contracts for C++",
      "author": "John Doe",
      "url": "https://...",
      "content": "...",
      "score": 0.85,
      "reranked": false
    }
  ]
}

query

Performs hybrid semantic search over the specified namespace in the Pinecone index with optional metadata filtering. For count questions, use the count tool instead.

Parameters:

| Parameter | Type | Required | Default | Description | | ----------------- | -------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | query_text | string | Yes | - | Search query text | | namespace | string | Yes | - | Namespace to search (use list_namespaces to discover) | | top_k | integer | No | 10 | Number of results (1-100) | | use_reranking | boolean | No | true | Enable semantic reranking | | metadata_filter | object | No | - | Metadata filter to narrow results (e.g., {"author": "John", "year": 2023}) | | fields | string[] | No | - | Field names to return (e.g. ["document_number", "title", "url"]). Omit for all fields; include chunk_text for content. Reduces payload and cost. |

Returns: JSON object with search results (only requested fields when fields is set), relevance scores, and metadata

Example response:

{
  "status": "success",
  "query": "your search query",
  "namespace": "namespace1",
  "metadata_filter": { "author": "John Doe" },
  "result_count": 10,
  "results": [
    {
      "paper_number": "DOC-001",
      "title": "Document Title",
      "author": "John Doe",
      "url": "https://example.com/doc",
      "content": "Document content preview...",
      "score": 0.9234,
      "reranked": true
    }
  ]
}

Using Metadata Filters:

Metadata filters allow you to narrow down search results based on document properties. First, use list_namespaces to see available metadata fields, then apply filters.

Supported Operators (10 total):

| Operator | Syntax | Description | Example | | --------------------- | ----------------------- | ------------------------ | ------------------------------------------------------------------------ | | Equal | $eq or value directly | Exact match | {"status": "published"} or {"status": {"$eq": "published"}} | | Not Equal | $ne | Not equal to | {"status": {"$ne": "draft"}} | | Greater Than | $gt | Greater than | {"year": {"$gt": 2022}} | | Greater Than or Equal | $gte | Greater than or equal | {"timestamp": {"$gte": 1704067200}} | | Less Than | $lt | Less than | {"score": {"$lt": 0.5}} | | Less Than or Equal | $lte | Less than or equal | {"priority": {"$lte": 3}} | | In Array | $in | Value is in array field | {"tags": {"$in": ["cpp", "contracts"]}} (only for array-type fields) | | Not In Array | $nin | Value not in array field | {"tags": {"$nin": ["draft", "archived"]}} (only for array-type fields) |

Filter Examples:

// Exact match (implicit $eq) - works for single-value string fields
{"status": "published"}

// Exact string match - NOTE: requires full exact match
{"author": "John Doe"}  // Only matches if author field is exactly "John Doe"

// Array field contains value (use $in only for array-type fields)
{"tags": {"$in": ["cpp", "contracts"]}}  // Only if tags is stored as an array

// Numeric comparison
{"year": {"$gte": 2023}}

// Timestamp range (papers from last 2 years)
{"timestamp": {"$gte": 1704067200}}

// Multiple conditions on same field
{"score": {"$gt": 0.8, "$lt": 1.0}}
{"timestamp": {"$gte": 1704067200, "$lte": 1735689600}}

// Multiple fields (AND logic)
{
  "year": {"$gte": 2023},
  "status": "published",
  "timestamp": {"$gte": 1704067200}
}

// Array field not in list (only for array-type fields)
{"tags": {"$nin": ["draft", "template"]}}

Important Limitations:

  • String fields require EXACT match - No wildcards, partial matches, or substring searches
  • Comma-separated strings: If a field contains "John Doe, Herb Sutter", you cannot filter for just "John Doe"
    • You must match the entire string: {"author": "John Doe, Herb Sutter"}
    • To filter by individual authors, the data must be stored as an array field
  • $in and $nin operators: Only work on array-type fields, not comma-separated strings
  • Unsupported operators are rejected: Unknown operators (for example $regex) return a validation error
  • $in and $nin must use arrays: {"tags": {"$in": "cpp"}} is invalid; use {"tags": {"$in": ["cpp"]}}
  • Multiple conditions at the top level are combined with AND logic
  • Use comparison operators ($gt, $gte, $lt, $lte) for numeric and timestamp fields
  • Direct value assignment implies $eq (exact match)

How It Works

  1. Namespace Discovery: The list_namespaces tool queries your Pinecone index stats to discover available namespaces
  2. Hybrid Search: When querying, the tool searches both dense and sparse indexes in parallel
  3. Result Merging: Results from both indexes are merged and deduplicated
  4. Reranking (optional): The merged results are reranked using a semantic reranker for improved relevance

Development

Setup Development Environment

git clone https://github.com/CppDigest/pinecone-read-only-mcp-typescript.git
cd pinecone-read-only-mcp-typescript
npm install

Build

npm run build

Run Tests

npm test

Testing the keyword_search tool

  1. Connectivity and keyword search (script):
    Run the search test script (includes a keyword search step against the sparse index):

    PINECONE_API_KEY=your-key npm run test:search

    If the sparse index (rag-hybrid-sparse by default) does not exist or has no data, the keyword search step is skipped with a warning.

  2. Via MCP client:
    Start the server and call the keyword_search tool with query_text, namespace (from list_namespaces), and optional top_k or metadata_filter. Response shape is the same as the query tool (e.g. results with ids, metadata, scores; reranked is always false).

Code Quality

# Run linting
npm run lint

# Fix linting issues
npm run lint:fix

# Check formatting
npm run format:check

# Format code
npm run format

# Type check
npm run typecheck

Development Server

Run the server in development mode with auto-reload:

npm run dev -- --api-key YOUR_API_KEY

Contribution Guidelines

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Make your changes and add tests
  4. Ensure all tests pass: npm test
  5. Ensure code quality checks pass: npm run lint && npm run format:check && npm run typecheck
  6. Commit your changes: git commit -am 'Add some feature'
  7. Push to the branch: git push origin feature-name
  8. Submit a pull request

Dependencies

Production Dependencies

Development Dependencies

Comparison with Python Version

This TypeScript implementation provides the same functionality as the Python version with the following benefits:

  • Native Node.js integration
  • Better npm ecosystem integration
  • TypeScript type safety
  • Similar performance characteristics
  • Same API interface

Troubleshooting

API Key Issues

If you see "Pinecone API key is required" error:

  1. Ensure PINECONE_API_KEY environment variable is set, OR
  2. Pass --api-key option when running the server

Index Not Found

If you see index-related errors:

  1. Verify your index name is correct
  2. Ensure your API key has access to the index
  3. Check that both your-index-name and your-index-name-sparse indexes exist

Connection Issues

If you experience connection issues:

  1. Check your internet connection
  2. Verify Pinecone service status
  3. Ensure firewall/proxy settings allow connections to Pinecone

License

This project is licensed under the Boost Software License 1.0 - see the LICENSE file for details.

Authors

Acknowledgements

This project uses:

  • Pinecone for vector storage and retrieval
  • Model Context Protocol for standardized AI integration
  • Hybrid search approach combining dense embeddings with sparse BM25-style retrieval

Related Projects

Support

For issues and questions:

Changelog

See CHANGELOG.md for a list of changes in each version.