Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
# Required: Your Pinecone API key
PINECONE_API_KEY=your-pinecone-api-key-here

# Optional: Dense (hybrid) Pinecone index name (default: rag-hybrid when unset)
# PINECONE_INDEX_NAME=rag-hybrid
# Required: Dense (hybrid) Pinecone index name
PINECONE_INDEX_NAME=your-index-name

# Optional: Reranking model (CLI defaults to bge-reranker-v2-m3 when unset; see docs/CONFIGURATION.md)
# PINECONE_RERANK_MODEL=bge-reranker-v2-m3
# Optional: Reranking model (omit to disable rerank in core; Alliance CLI defaults when unset see docs/CONFIGURATION.md)
# PINECONE_RERANK_MODEL=your-rerank-model

# Optional: Default number of results to return (default: 10)
PINECONE_TOP_K=10
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Tagged releases are published to npm from GitHub Actions when a **GitHub Release

## [Unreleased]

### Changed

- **Breaking (core):** `resolveConfig` requires a Pinecone index name and no longer applies Alliance index/rerank defaults. Removed exported `DEFAULT_INDEX_NAME` and `DEFAULT_RERANK_MODEL` from the package root. Rerank is opt-in when `PINECONE_RERANK_MODEL` / `rerankModel` is unset.
- **Alliance CLI / `resolveAllianceConfig`:** When index or rerank env/CLI values are omitted, defaults remain `rag-hybrid` and `bge-reranker-v2-m3` (API-key-only MCP configs unchanged). See [examples/alliance/.env.example](examples/alliance/.env.example).
### Added

- Formal deprecation policy ([docs/deprecation-policy.md](docs/deprecation-policy.md)) and breaking-change release notes template ([docs/templates/breaking-change-release-notes.md](docs/templates/breaking-change-release-notes.md)).
Expand Down
48 changes: 31 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ The codebase is split into two layers:

## Configuration

You need a **Pinecone API key**. **Index** uses `PINECONE_INDEX_NAME` when set, else defaults to `rag-hybrid`; sparse index defaults to `{index}-sparse`. **Reranking** uses `PINECONE_RERANK_MODEL` when set, else `bge-reranker-v2-m3`. MCP configs with only `PINECONE_API_KEY` keep prior Alliance defaults. See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for every variable and CLI flag.
You need a **Pinecone API key**. **Index** (`PINECONE_INDEX_NAME` or `--index-name`) is required for core/library use; the **published CLI** defaults to `rag-hybrid` when unset (Alliance deployment). Sparse index defaults to `{index}-sparse`. **Rerank:** set `PINECONE_RERANK_MODEL` to enable; the CLI defaults to `bge-reranker-v2-m3` when unset. See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) (core vs Alliance table).

Quick reference:
Quick reference (published CLI / Alliance — core embedders require index, no index/rerank defaults):

| Variable | Required | Default |
| Variable | Required | Default (Alliance CLI) |
| ----------------------------------- | ----------------------- | --------------------------------- |
| `PINECONE_API_KEY` | Yes (for live Pinecone) | — |
| `PINECONE_INDEX_NAME` | No | `rag-hybrid` when unset |
| `PINECONE_RERANK_MODEL` | No | `bge-reranker-v2-m3` when unset |
| `PINECONE_INDEX_NAME` | No (CLI) / Yes (core) | `rag-hybrid` (CLI only) |
| `PINECONE_RERANK_MODEL` | No | `bge-reranker-v2-m3` (CLI only) |
| `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) |
Expand All @@ -132,9 +132,9 @@ The server uses **process-global** memory for the suggest-flow gate (`suggest_qu
Treat **`setupCoreServer()` / `setupAllianceServer()` as one logical server per Node process**: they mutate shared module singletons (suggest-flow map, namespaces cache, URL registry, config context, shared `PineconeClient` slot). A **second** setup call in the same process **throws** unless you call **`teardownServer()`** first.

- **Generic bridge only:** `import { setupCoreServer, teardownServer, ... } from '@will-cppa/pinecone-read-only-mcp'`
- **Full Alliance surface (CLI parity):** `import { setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance'`
- **Full Alliance surface (CLI parity):** `import { setupAllianceServer, resolveAllianceConfig } from '@will-cppa/pinecone-read-only-mcp/alliance'`

For the **generic bridge only**, see [examples/quickstart/mcp-demo.ts](examples/quickstart/mcp-demo.ts) (`setupCoreServer`). For the **full Alliance surface**, use `resolveConfig({ apiKey, indexName, ... })` → `setPineconeClient(new PineconeClient(...))` → `await setupAllianceServer(config)` → connect one MCP transport. See [examples/alliance/library-embedding-demo.ts](examples/alliance/library-embedding-demo.ts) and [docs/TOOLS.md](docs/TOOLS.md#suggest-flow-gate).
For the **generic bridge only**, see [examples/quickstart/mcp-demo.ts](examples/quickstart/mcp-demo.ts) (`setupCoreServer` + `resolveConfig` with required `indexName`). For the **full Alliance surface**, use `resolveAllianceConfig({ apiKey, ... })` (Alliance index/rerank defaults when omitted, same as the CLI) → `setPineconeClient(new PineconeClient(...))` → `await setupAllianceServer(config)` → connect one MCP transport. See [examples/alliance/library-embedding-demo.ts](examples/alliance/library-embedding-demo.ts) and [docs/TOOLS.md](docs/TOOLS.md#suggest-flow-gate).

### Custom URL generators

Expand All @@ -146,15 +146,21 @@ Import `registerUrlGenerator` and types `UrlGeneratorFn` / `UrlGenerationResult`
import {
PineconeClient,
registerUrlGenerator,
resolveConfig,
setPineconeClient,
type UrlGenerationResult,
type UrlGeneratorFn,
} from '@will-cppa/pinecone-read-only-mcp';
import { setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance';

const config = resolveConfig({ apiKey: '...', indexName: 'your-index' });
setPineconeClient(new PineconeClient({ apiKey: config.apiKey, indexName: config.indexName }));
import { resolveAllianceConfig, setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance';

const config = resolveAllianceConfig({ apiKey: '...' }); // optional: indexName, rerankModel
setPineconeClient(
new PineconeClient({
apiKey: config.apiKey,
indexName: config.indexName,
sparseIndexName: config.sparseIndexName,
rerankModel: config.rerankModel,
})
);
const server = await setupAllianceServer(config);

const myDocs: UrlGeneratorFn = (metadata): UrlGenerationResult => {
Expand Down Expand Up @@ -233,7 +239,7 @@ For a global installation:
"mcpServers": {
"pinecone-search": {
"command": "pinecone-read-only-mcp",
"args": ["--api-key", "your-api-key-here"]
"args": ["--api-key", "your-api-key-here", "--index-name", "your-index-name"]
}
}
}
Expand All @@ -246,19 +252,19 @@ For a global installation:
Run the server using npx (no installation required):

```bash
npx @will-cppa/pinecone-read-only-mcp@0.2.0 --api-key YOUR_API_KEY
npx @will-cppa/pinecone-read-only-mcp@0.2.0 --api-key YOUR_API_KEY --index-name YOUR_INDEX
```

Or if installed globally:

```bash
pinecone-read-only-mcp --api-key YOUR_API_KEY
pinecone-read-only-mcp --api-key YOUR_API_KEY --index-name YOUR_INDEX
```

Or if installed locally in your project:

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

### Available Options
Expand Down Expand Up @@ -741,11 +747,19 @@ Other benefits:

### API Key Issues

If you see "Pinecone API key is required" error:
If you see "Missing Pinecone API key" at startup:

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

### Missing Index Name

If you see "Missing Pinecone index name" at startup:

1. Set `PINECONE_INDEX_NAME` in your MCP config or `.env`, OR
2. Pass `--index-name` when running the server
3. Alliance deployers: see [examples/alliance/.env.example](examples/alliance/.env.example)

### Index Not Found

If you see index-related errors:
Expand Down
17 changes: 11 additions & 6 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Configuration

Configuration is built from **CLI flags** (when using the binary), **environment variables**, and **defaults**. Library callers use `resolveConfig(overrides)` with optional `ConfigOverrides`.
Configuration is built from **CLI flags** (when using the binary), **environment variables**, and **defaults**. Library callers use `resolveConfig(overrides)` (core) or `resolveAllianceConfig(overrides)` (Alliance CLI / `setupAllianceServer`) with optional `ConfigOverrides`.

## Precedence

Expand All @@ -15,9 +15,9 @@ Configuration is built from **CLI flags** (when using the binary), **environment
| Field | Source | Default / notes |
| ----- | ------ | --------------- |
| `apiKey` | `apiKey` / `PINECONE_API_KEY` | **Required** (non-empty after trim) |
| `indexName` | `indexName` / `PINECONE_INDEX_NAME` | `rag-hybrid` when env and overrides omit it |
| `indexName` | `indexName` / `PINECONE_INDEX_NAME` | **Required** (non-empty after trim) |
| `sparseIndexName` | `sparseIndexName` / `PINECONE_SPARSE_INDEX_NAME` | `{indexName}-sparse` |
| `rerankModel` | `rerankModel` / `PINECONE_RERANK_MODEL` | `bge-reranker-v2-m3` when env and overrides omit it |
| `rerankModel` | `rerankModel` / `PINECONE_RERANK_MODEL` | **Core:** omitted when unset (rerank disabled). **Alliance CLI:** `bge-reranker-v2-m3` when unset |
| `defaultTopK` | `defaultTopK` / `PINECONE_TOP_K` | `10` (positive int) |
| `logLevel` | `logLevel` / `PINECONE_READ_ONLY_MCP_LOG_LEVEL` | `INFO` (`DEBUG`–`ERROR`) |
| `logFormat` | `logFormat` / `PINECONE_READ_ONLY_MCP_LOG_FORMAT` | `text` or `json` |
Expand All @@ -26,13 +26,18 @@ Configuration is built from **CLI flags** (when using the binary), **environment
| `disableSuggestFlow` | `disableSuggestFlow` / `PINECONE_DISABLE_SUGGEST_FLOW` | `false` (bool parsing: true/1/yes/on) |
| `checkIndexes` | `checkIndexes` / `PINECONE_CHECK_INDEXES` | `false` |

**Throws** if `apiKey` is missing after trim.
**Throws** if `apiKey` or `indexName` is missing after trim.

For the full Alliance tool surface (including `suggest_query_params`, `guided_query`, and built-in URL generators), import from `@will-cppa/pinecone-read-only-mcp/alliance` and call `setupAllianceServer(config)`.

### Rerank model
### Core vs Alliance resolvers

`resolveConfig` uses `PINECONE_INDEX_NAME` / `PINECONE_RERANK_MODEL` when set; otherwise **`rag-hybrid`** and **`bge-reranker-v2-m3`**. MCP configs that only set `PINECONE_API_KEY` keep the same defaults as before.
| Resolver | When to use | Index when unset | Rerank when unset |
| -------- | ------------- | ---------------- | ----------------- |
| `resolveConfig` | Package root, `setupCoreServer`, quickstart | **Throws** | Omitted (no rerank) |
| `resolveAllianceConfig` | Published CLI, `setupAllianceServer` | `rag-hybrid` | `bge-reranker-v2-m3` |

C++ Alliance deployers can copy [examples/alliance/.env.example](../examples/alliance/.env.example). Constants: `ALLIANCE_DEFAULT_INDEX_NAME` / `ALLIANCE_DEFAULT_RERANK_MODEL` from `@will-cppa/pinecone-read-only-mcp/alliance`.

---

Expand Down
19 changes: 19 additions & 0 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ This guide is for **library and MCP client authors** upgrading from earlier **0.

Under [semver 0.y.z](https://semver.org/spec/v2.0.0.html#spec-item-4), **0.1.x → 0.2.0 is a breaking minor** — pin `@0.2.0` only after reading this guide.

## Unreleased: core vs Alliance config defaults

**Rationale:** Generic npm consumers must not silently connect to Alliance infrastructure or inherit Alliance rerank settings when using `resolveConfig` from the package root.

**Migration (core / `setupCoreServer`):**

1. Add `PINECONE_INDEX_NAME` to MCP `env` blocks, `.env`, or Docker `-e`, or pass `indexName` in `ConfigOverrides`.
2. Set `PINECONE_RERANK_MODEL` only when you want reranking; omit it to skip rerank (previously defaulted to `bge-reranker-v2-m3` in core).
3. Code that imported `DEFAULT_INDEX_NAME` or `DEFAULT_RERANK_MODEL` from the package root should use your own constants or [examples/alliance/preset.ts](../examples/alliance/preset.ts) for Alliance values.

Core `resolveConfig` throws `Missing Pinecone index name: …` when the index is unset (same pattern as the API key error).

**Alliance CLI / `setupAllianceServer` (unchanged for typical MCP configs):**

- The binary uses `resolveAllianceConfig`; API-key-only configs still default to `rag-hybrid` and `bge-reranker-v2-m3`.
- Explicit env overrides still win. Copy [examples/alliance/.env.example](../examples/alliance/.env.example) to document Alliance conventions.

---

## Migrating to v0.2.0

### Namespace trimming and suggest-flow
Expand Down
14 changes: 14 additions & 0 deletions examples/alliance/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# C++ Alliance Pinecone deployment (examples/alliance)
# Copy to .env and fill in your API key.
# The published CLI (resolveAllianceConfig) applies these defaults when variables are omitted.

PINECONE_API_KEY=your-pinecone-api-key-here

# Alliance dense index (CLI default when unset: rag-hybrid)
PINECONE_INDEX_NAME=rag-hybrid

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

# Alliance rerank model (CLI default when unset: bge-reranker-v2-m3)
# PINECONE_RERANK_MODEL=bge-reranker-v2-m3
6 changes: 4 additions & 2 deletions examples/alliance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ They assume a Pinecone index you control with compatible data (not necessarily t

## Required environment

Copy [`.env.example`](./.env.example) to `.env` and set your API key. For C++ Alliance infrastructure, use `PINECONE_INDEX_NAME=rag-hybrid` as documented there.

| Variable | Required | Notes |
| -------- | -------- | ----- |
| `PINECONE_API_KEY` | Yes | For live runs |
| `PINECONE_INDEX_NAME` | Yes | Your dense index name |
| `PINECONE_INDEX_NAME` | Yes | Dense index name (Alliance: `rag-hybrid`) |

Optional: `PINECONE_RERANK_MODEL`, `PINECONE_SPARSE_INDEX_NAME`, etc. See [docs/CONFIGURATION.md](../../docs/CONFIGURATION.md). CLI-only configs that set only `PINECONE_API_KEY` still use documented defaults (`rag-hybrid`, `bge-reranker-v2-m3`).
Optional: `PINECONE_RERANK_MODEL`, `PINECONE_SPARSE_INDEX_NAME`, etc. See [docs/CONFIGURATION.md](../../docs/CONFIGURATION.md). The **published CLI** uses `resolveAllianceConfig` and defaults to `rag-hybrid` / `bge-reranker-v2-m3` when those env vars are omitted. Demo constants: [`preset.ts`](./preset.ts).

## Files

Expand Down
17 changes: 4 additions & 13 deletions examples/alliance/library-embedding-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Library embedding: build the MCP server from a Node script (not the CLI).
*
* Pattern (mirrors `src/index.ts`):
* 1. `resolveConfig({ apiKey, indexName, ... })` — env rerank model or default bge-reranker-v2-m3.
* 1. `resolveAllianceConfig({ apiKey, indexName, ... })` — Alliance index/rerank defaults when unset.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
* 2. `new PineconeClient({ ... })` + `setPineconeClient(client)`.
* 3. `await setupAllianceServer(config)` then `server.connect(transport)`.
*
Expand All @@ -12,12 +12,8 @@
* (tests). For isolated tenants in production, prefer one server per Node process.
*/

import {
PineconeClient,
resolveConfig,
setPineconeClient,
} from '@will-cppa/pinecone-read-only-mcp';
import { setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance';
import { PineconeClient, setPineconeClient } from '@will-cppa/pinecone-read-only-mcp';
import { resolveAllianceConfig, setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance';

async function main(): Promise<void> {
const apiKey = process.env['PINECONE_API_KEY']?.trim();
Expand All @@ -27,12 +23,7 @@ async function main(): Promise<void> {
);
return;
}
const indexName = process.env['PINECONE_INDEX_NAME']?.trim();
if (!indexName) {
console.log('Set PINECONE_INDEX_NAME to run this example. Skipping live setup in doc-only mode.');
return;
}
const config = resolveConfig({ apiKey, indexName });
const config = resolveAllianceConfig({ apiKey });

setPineconeClient(
new PineconeClient({
Expand Down
5 changes: 5 additions & 0 deletions examples/alliance/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Alliance deployment constants for copy-paste in demos. Not imported by `src/`.
*/
export const ALLIANCE_INDEX_NAME = 'rag-hybrid';
export const ALLIANCE_RERANK_MODEL = 'bge-reranker-v2-m3';
Expand Down
27 changes: 23 additions & 4 deletions src/alliance/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { describe, expect, it } from 'vitest';
import { DEFAULT_RERANK_MODEL } from '../core/config.js';
import { resolveAllianceConfig } from './config.js';
import {
ALLIANCE_DEFAULT_INDEX_NAME,
ALLIANCE_DEFAULT_RERANK_MODEL,
resolveAllianceConfig,
} from './config.js';

describe('resolveAllianceConfig', () => {
it('applies Alliance rerank default when env and overrides omit rerankModel', () => {
it('applies Alliance index and rerank defaults when env omits both', () => {
const cfg = resolveAllianceConfig({ apiKey: 'sk-test' }, { PINECONE_API_KEY: 'sk-test' });
expect(cfg.indexName).toBe(ALLIANCE_DEFAULT_INDEX_NAME);
expect(cfg.sparseIndexName).toBe(`${ALLIANCE_DEFAULT_INDEX_NAME}-sparse`);
expect(cfg.rerankModel).toBe(ALLIANCE_DEFAULT_RERANK_MODEL);
});

it('applies Alliance rerank default when env and overrides omit rerankModel but index is set', () => {
const cfg = resolveAllianceConfig(
{ apiKey: 'sk-test', indexName: 'my-index' },
{ PINECONE_API_KEY: 'sk-test', PINECONE_INDEX_NAME: 'my-index' }
);
expect(cfg.rerankModel).toBe(DEFAULT_RERANK_MODEL);
expect(cfg.indexName).toBe('my-index');
expect(cfg.rerankModel).toBe(ALLIANCE_DEFAULT_RERANK_MODEL);
});

it('preserves explicit rerankModel from overrides', () => {
Expand All @@ -31,4 +42,12 @@ describe('resolveAllianceConfig', () => {
);
expect(cfg.rerankModel).toBe('env-reranker');
});

it('preserves explicit index from env over Alliance default', () => {
const cfg = resolveAllianceConfig(
{ apiKey: 'sk-test' },
{ PINECONE_API_KEY: 'sk-test', PINECONE_INDEX_NAME: 'custom-index' }
);
expect(cfg.indexName).toBe('custom-index');
});
});
33 changes: 22 additions & 11 deletions src/alliance/config.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
/**
* Alliance entry re-exports core config. Rerank default lives in {@link resolveConfig}
* (`PINECONE_RERANK_MODEL` when set, else `bge-reranker-v2-m3`).
* Alliance config resolver: applies C++ Alliance deployment defaults, then delegates to core {@link resolveConfig}.
*/

import {
DEFAULT_RERANK_MODEL,
resolveConfig,
trimOptional,
type ConfigOverrides,
type ServerConfig,
} from '../core/config.js';

/** @deprecated Use {@link DEFAULT_RERANK_MODEL} from core config. */
export const DEFAULT_ALLIANCE_RERANK_MODEL = DEFAULT_RERANK_MODEL;
/** C++ Alliance default dense index when env/CLI omit `PINECONE_INDEX_NAME`. */
export const ALLIANCE_DEFAULT_INDEX_NAME = 'rag-hybrid';

/** @deprecated No-op; {@link resolveConfig} already applies the rerank default. */
export function applyAllianceRerankDefault(config: ServerConfig): ServerConfig {
return config;
}
/** C++ Alliance default rerank model when env/CLI omit `PINECONE_RERANK_MODEL`. */
export const ALLIANCE_DEFAULT_RERANK_MODEL = 'bge-reranker-v2-m3';

/** @deprecated Use {@link ALLIANCE_DEFAULT_RERANK_MODEL}. */
export const DEFAULT_ALLIANCE_RERANK_MODEL = ALLIANCE_DEFAULT_RERANK_MODEL;

/** Alias for {@link resolveConfig} (Alliance CLI and `setupAllianceServer`). */
/**
* Build {@link ServerConfig} for Alliance CLI and `setupAllianceServer`.
* Fills index and rerank from Alliance defaults when unset, then calls core `resolveConfig`.
*/
export function resolveAllianceConfig(
overrides: ConfigOverrides = {},
env: NodeJS.ProcessEnv = process.env
): ServerConfig {
return resolveConfig(overrides, env);
const indexName =
trimOptional(overrides.indexName) ??
trimOptional(env['PINECONE_INDEX_NAME']) ??
ALLIANCE_DEFAULT_INDEX_NAME;
const rerankModel =
trimOptional(overrides.rerankModel) ??
trimOptional(env['PINECONE_RERANK_MODEL']) ??
ALLIANCE_DEFAULT_RERANK_MODEL;
Comment thread
jonathanMLDev marked this conversation as resolved.
return resolveConfig({ ...overrides, indexName, rerankModel }, env);
}
Loading
Loading