Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,22 @@ PINECONE_RERANK_MODEL=bge-reranker-v2-m3
PINECONE_TOP_K=10

# Optional: Logging level (default: INFO)
# Options: DEBUG, INFO, WARNING, ERROR, CRITICAL
# Options: DEBUG, INFO, WARN, ERROR
PINECONE_READ_ONLY_MCP_LOG_LEVEL=INFO

# Optional: Logging format (default: text)
# Options: text, json
PINECONE_READ_ONLY_MCP_LOG_FORMAT=text

# Optional: Sparse index name (default: ${PINECONE_INDEX_NAME}-sparse)
# PINECONE_SPARSE_INDEX_NAME=rag-hybrid-sparse

# Optional: Namespace + suggestion-flow cache TTL in seconds (default: 1800 = 30min)
# PINECONE_CACHE_TTL_SECONDS=1800

# Optional: Disable the suggest_query_params flow gate (default: false).
# WARNING: turning this on bypasses the safety guard. A WARN log fires at startup.
# PINECONE_DISABLE_SUGGEST_FLOW=false

# Optional: Request timeout for Pinecone calls, in milliseconds (default: 15000)
# PINECONE_REQUEST_TIMEOUT_MS=15000
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Match EditorConfig / Prettier so Linux CI and Windows devs agree on line endings.
* text=auto eol=lf
15 changes: 15 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ updates:
labels:
- "dependencies"
- "automated"
groups:
vitest:
patterns:
- "vitest"
- "@vitest/*"
typescript-eslint:
patterns:
- "typescript-eslint"
- "@typescript-eslint/*"
eslint-prettier:
patterns:
- "eslint"
- "@eslint/*"
- "prettier"
- "eslint-config-prettier"

- package-ecosystem: "github-actions"
directory: "/"
Expand Down
27 changes: 25 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ on:
branches: [main]
push:
branches: [main]
workflow_call: # Allow this workflow to be called by other workflows
workflow_call:

jobs:
build-and-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [18.x, 20.x, 22.x]

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Expand Down Expand Up @@ -41,9 +42,31 @@ jobs:
- name: Smoke test CLI
run: node dist/index.js --help

- name: Run tests
# @vitest/coverage-v8 imports node:inspector/promises (Node 19+). Keep 18.x in the matrix for runtime smoke but skip coverage there.
- name: Run tests with coverage
if: matrix.node-version != '18.x'
run: npm run test:coverage

- name: Run tests (Node 18, no coverage)
if: matrix.node-version == '18.x'
run: npm test

- name: Generate CycloneDX SBOM (lockfile-based)
run: npx --yes @cyclonedx/cyclonedx-npm --package-lock-only --output-file sbom.cdx.json

- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
name: sbom-cyclonedx-node-${{ matrix.node-version }}
path: sbom.cdx.json

- name: Upload coverage to Codecov
if: matrix.node-version == '20.x'
uses: codecov/codecov-action@v5
with:
files: ./coverage/lcov.info
fail_ci_if_error: false

quality:
runs-on: ubuntu-latest
steps:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ dist/
build/
*.tsbuildinfo

# data
data/


# Environment
.env
.env.local
Expand Down
2 changes: 1 addition & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ PUBLISHING.md
node_modules/
.vscode/
.idea/
dist/
docs/

# Testing
coverage/
Expand Down
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"bracketSpacing": true
"bracketSpacing": true,
"endOfLine": "lf"
}
59 changes: 38 additions & 21 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,54 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Future releases are managed automatically by [release-please](https://github.com/googleapis/release-please).

## [Unreleased]

### Added

- `list_namespaces` tool: discovers all namespaces with record counts and sampled metadata fields
- `namespace_router` tool: ranks namespaces by relevance to a natural-language query
- `suggest_query_params` tool: mandatory flow gate that recommends fields and tool variant before queries
- `count` tool: counts unique documents matching a query, with `truncated` flag when results exceed `COUNT_TOP_K`
- `query_fast` tool: lightweight chunk-level search with minimal field set
- `query_detailed` tool: chunk-level search with optional semantic reranking
- `query` tool: unified query entry-point supporting `query_fast` and `query_detailed` modes
- `guided_query` tool: single-call orchestrator that runs routing → suggestion → execution, returning a `decision_trace`
- `generate_urls` tool: synthesizes URLs for records whose metadata lacks a `url` field
- `query_documents` tool: reassembles full documents from chunks grouped by document identifier
- Centralized structured logger (`src/logger.ts`) with level-gated stderr output and stack-trace capture
- Dockerfile for containerised deployment
- `About.md` project documentation covering architecture, tools, and operating principles
- `registerBuiltinUrlGenerators()` for built-in URL generators; `setupServer()` invokes it so CLI/library parity stays default.
- Discriminated result type for `listNamespacesFromKeywordIndex()` (`KeywordIndexNamespacesResult`).
- Unit tests for `withRetry` / `withTimeout` in `src/server/retry.test.ts`.
- `SERVER_VERSION` is now read from `package.json` at runtime so MCP `serverInfo` always matches the published package version.
- `--version` CLI flag prints the package version and exits.
- `list_namespaces` response now includes `expires_at_iso` so clients see the cache expiry as an ISO-8601 timestamp without converting `cache_ttl_seconds`.
- `docs/` handbook: `TOOLS.md`, `CONFIGURATION.md`, `FAQ.md`, `MIGRATION.md`, `CI_CD.md`, and `docs/README.md` index; root `RELEASING.md` stub points to `docs/RELEASING.md`.
Comment thread
jonathanMLDev marked this conversation as resolved.
Outdated
- `SECURITY.md`, `CONTRIBUTING.md`, and `CODE_OF_CONDUCT.md` for OSS hygiene.
- `examples/README.md` describing the library embedding sample.
- GitHub Actions: **multi-OS** CI matrix (Ubuntu, Windows, macOS × Node 18/20/22), **Codecov** upload (Ubuntu + Node 20), **CycloneDX SBOM** artifact, **Release Please**, and **Docker** multi-arch publish to **GHCR**.
Comment thread
jonathanMLDev marked this conversation as resolved.
Outdated
- `src/config.test.ts` and `npm run test:coverage` with Vitest coverage thresholds (see `vitest.config.ts`).
- `@vitest/coverage-v8` devDependency for coverage reports (`lcov`, `json-summary`, HTML).

### Changed

- Modularised server into focused files under `src/server/` (tools, caches, formatters, suggestion flow)
- CI workflow updated: multi-node matrix (`18.x`, `20.x`, `22.x`), separate quality job with `continue-on-error`
- Replaced all `console.error` calls in `pinecone-client.ts` with typed `logInfo` / `logDebug` / `logError`
- **Breaking (MCP):** Single hybrid `query` tool with `preset` (`fast` | `detailed` | `full`); removed separate `query_fast` / `query_detailed` tool registrations.
- **Breaking (library):** Stopped re-exporting `withRetry` / `withTimeout` from the package entry (`server.ts`).
- `withTimeout` aborts an internal `AbortSignal` on deadline (cooperative cancellation).
- `PineconeClient`: shared hit-field extraction, safer merge dedup without empty `_id` collisions, metadata sampling skips zero-vector probe when dimension is unknown, `listNamespacesFromKeywordIndex` surfaces errors via `{ ok: false }`.
- Metadata filter manual validation accepts primitive arrays for `$in`/`$nin` including numbers (matches Zod).
- README: deployment model for process-global gate/cache/registry; adjusted feature wording vs pre-1.0 semver.
- `.npmignore` no longer excludes `dist/` (still shipped via `package.json` `files`).
- `.env.example` log-level options corrected to the four levels actually supported (`DEBUG`, `INFO`, `WARN`, `ERROR`); the stale `WARNING`/`CRITICAL` values are gone.
- README Slack URL example now matches the generator output (`https://app.slack.com/client/{team_id}/{channel_id}/p{messageId}`).
- README "Comparison with Python Version" no longer claims an identical API interface; the new TypeScript-only tools (`guided_query`, `query_documents`, `keyword_search`, `namespace_router`, `suggest_query_params`, `count`, `generate_urls`) are listed explicitly.
- `npm run ci` now runs `test:coverage` so merges are gated on coverage thresholds.
- CI: on Node **18.x**, run `npm test` only; **`test:coverage`** runs on **20.x** / **22.x** because Vitest V8 coverage uses `node:inspector/promises` (Node **≥19**).
- Dependabot groups related **vitest**, **typescript-eslint**, and **eslint/prettier** updates.

### Fixed

- Timestamp-based metadata filter now correctly handles numeric epoch values
### Removed

- Dead `test:mcp` npm script (referenced a `test-mcp-server.js` file that has never existed).

### Security
## [0.1.6] - 2026-04-24

- N/A
Historical 0.1.x releases (0.1.0 → 0.1.6) shipped the full tool surface
(`list_namespaces`, `namespace_router`, `suggest_query_params`, `count`,
`query`, `query_fast`, `query_detailed`, `keyword_search`, `query_documents`,
`guided_query`, `generate_urls`), the structured `src/logger.ts`, the
`Dockerfile`, and the modularised `src/server/` layout. See git history for
details — going forward, all changes are tracked here by release-please.

## [0.1.1] - 2026-01-27

Expand Down Expand Up @@ -69,6 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Environment variable support
- Full documentation and examples

[Unreleased]: https://github.com/CppDigest/pinecone-read-only-mcp-typescript/compare/v0.1.1...HEAD
[Unreleased]: https://github.com/CppDigest/pinecone-read-only-mcp-typescript/compare/v0.1.6...HEAD
[0.1.6]: https://github.com/CppDigest/pinecone-read-only-mcp-typescript/compare/v0.1.1...v0.1.6
[0.1.1]: https://github.com/CppDigest/pinecone-read-only-mcp-typescript/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/CppDigest/pinecone-read-only-mcp-typescript/releases/tag/v0.1.0
60 changes: 44 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,28 @@

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

## Documentation

| Doc | Description |
|-----|---------------|
| [docs/README.md](docs/README.md) | Index of all guides |
| [docs/TOOLS.md](docs/TOOLS.md) | Tool catalog & flows |
| [docs/CONFIGURATION.md](docs/CONFIGURATION.md) | Env vars, CLI flags, library config |
| [docs/FAQ.md](docs/FAQ.md) | Common questions |
| [docs/MIGRATION.md](docs/MIGRATION.md) | Deprecations & breaking changes |
| [docs/CI_CD.md](docs/CI_CD.md) | GitHub Actions, SBOM, Docker, releases |
| [RELEASING.md](RELEASING.md) | Pointer to the full release guide in `docs/` |
| [CONTRIBUTING.md](CONTRIBUTING.md) | How to contribute |
| [SECURITY.md](SECURITY.md) | Vulnerability reporting |

## 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
- **Fast presets**: Lazy initialization, connection pooling, and efficient result merging; use the `query` tool `preset=fast` / `detailed` to trade latency vs quality (no published benchmarks yet — treat descriptions as qualitative).
- **Production-oriented defaults**: Input validation, error handling, and configurable logging (semantic versioning is pre-1.0 — review CHANGELOG before upgrading).
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- **TypeScript Support**: Full TypeScript support with type definitions

## Installation
Expand Down Expand Up @@ -54,16 +68,23 @@ npm run build

## Configuration

The server requires a Pinecone API key and supports the following configuration options:
You need a **Pinecone API key** and (by default) a **dense** index plus matching **sparse** index; see [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for every environment variable and CLI flag.

Quick reference:

| Variable | Required | Default |
| -------- | -------- | ------- |
| `PINECONE_API_KEY` | Yes (for live Pinecone) | — |
| `PINECONE_INDEX_NAME` | No | `rag-hybrid` |
| `PINECONE_SPARSE_INDEX_NAME` | No | `{index}-sparse` |
| `PINECONE_READ_ONLY_MCP_LOG_LEVEL` | No | `INFO` (`DEBUG`–`ERROR`) |
| `PINECONE_READ_ONLY_MCP_LOG_FORMAT` | No | `text` (`json` for log pipelines) |

### Environment Variables
Run `pinecone-read-only-mcp --help` for CLI equivalents (`--cache-ttl-seconds`, `--request-timeout-ms`, `--disable-suggest-flow`, etc.).

| 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 |
### Deployment model

The server uses **process-global** memory for the suggest-flow gate (`suggest_query_params` context), namespaces cache, URL generator registry, and active configuration. **Stdio MCP (one client per Node process)** matches this model. If you embed `setupServer` behind a multi-tenant HTTP transport, isolate those structures per session yourself or treat the suggest-flow guard as best-effort only.

### Claude Desktop Configuration

Expand Down Expand Up @@ -237,7 +258,7 @@ Discovers and lists all available namespaces in the configured Pinecone index, i

### `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.
Suggests which **fields** to request and which path to use (`count`, or hybrid query as **fast** vs **detailed** — implemented via the `query` tool `preset` argument), 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:**

Expand Down Expand Up @@ -269,7 +290,7 @@ 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`.
3. execution via `count` or hybrid `query` (fast vs detailed behavior).

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

Expand All @@ -281,7 +302,7 @@ It returns both the final result and a `decision_trace` for transparency.
| `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` |
| `preferred_tool` | enum | No | `auto` | One of `auto`, `count`, `fast`, `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`.
Expand All @@ -301,7 +322,7 @@ Rules:
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}`
Format: `https://app.slack.com/client/{team_id}/{channel_id}/p{message_id}`

**Parameters:**

Expand Down Expand Up @@ -577,13 +598,20 @@ npm run dev -- --api-key YOUR_API_KEY

## Comparison with Python Version

This TypeScript implementation provides the same functionality as the [Python version](https://github.com/CppDigest/pinecone-read-only-mcp) with the following benefits:
This TypeScript implementation grew out of the [Python version](https://github.com/CppDigest/pinecone-read-only-mcp) and now exposes a strict superset of its tool surface, including:

- `guided_query` (single-call orchestrator with decision trace)
- `query_documents` (full-document reassembly from chunks)
- `keyword_search` (sparse-index-only retrieval)
- `namespace_router` and `suggest_query_params` (flow guidance)
- `count` and `generate_urls`

Other benefits:

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

## Troubleshooting

Expand Down
7 changes: 7 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Examples

| File | Description |
|------|-------------|
| [custom-url-generator.ts](./custom-url-generator.ts) | Embed the MCP server as a library, register a **custom URL generator** for a namespace, and wire `PineconeClient` + `setupServer()`. |

Run with `npx tsx examples/custom-url-generator.ts` after `npm install` (requires valid Pinecone credentials in env).
Loading
Loading