diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b56738..5ec171c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ Tagged releases are published to npm from GitHub Actions when a **GitHub Release - **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). - **Breaking (library):** Trimmed public re-exports — `buildQueryExperimental` and `buildGuidedQueryExperimental` removed from package root and `/alliance` entry. See [MIGRATION.md](docs/MIGRATION.md#unreleased-trimmed-library-exports). +### Deprecated + +- Module-level singleton facades — use `ServerContext` instance methods via `createServer(config)` and `{ context: ctx }` at setup instead. Deprecated in the **next minor release** (see `[Unreleased]` until version is tagged); earliest removal **two minor releases later** per [deprecation-policy.md](docs/deprecation-policy.md#deprecation-window). Affected symbols: `getPineconeClient`, `setPineconeClient`, `clearPineconeClient`, `getServerConfig`, `setServerConfig`, `resetServerConfig`, `registerUrlGenerator`, `unregisterUrlGenerator`, `generateUrlForNamespace`, `hasUrlGenerator`, `resetUrlGenerationRegistry`, `markSuggested`, `requireSuggested`, `resetSuggestionFlow`, `getNamespacesWithCache`, `invalidateNamespacesCache`, `getDefaultServerContext`. See [MIGRATION.md § Legacy module-facade deprecations](docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations) and [deprecation-policy.md](docs/deprecation-policy.md#active-deprecations-legacy-module-facades). + ### Added - Zod schemas for all nine MCP tool success responses (`queryResponseSchema`, `guidedQueryResponseSchema`, etc.) exported from the package root for client-side validation. Success payloads are runtime-validated before return. diff --git a/README.md b/README.md index 079ff92..e578282 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,14 @@ npm install npm run build ``` +## Stability + +This package ships as **`0.y.z`**. Under [semver §4](https://semver.org/spec/v2.0.0.html#spec-item-4), **minor versions may contain breaking changes** until `1.0.0`. Pin an exact version or use `~` (tilde) ranges — not `^` (caret) — until 1.0 to avoid absorbing breaking minors automatically. + +Breaking changes include: type signature changes, tool schema changes, default behavior changes, and removed exports. + +See [docs/deprecation-policy.md](docs/deprecation-policy.md) for the full deprecation window (minimum two minors before removal). + ## Quick start To try the server on **your own** Pinecone project (free tier, no Alliance index), follow [examples/quickstart/README.md](examples/quickstart/README.md): create two integrated-embedding indexes, copy [examples/quickstart/.env.example](examples/quickstart/.env.example), seed sample data, and run the MCP demo. Use an explicit `PINECONE_INDEX_NAME` in that flow rather than relying on Alliance default index names. @@ -129,7 +137,7 @@ Each **`ServerContext`** owns its own suggest-flow gate, namespaces cache, URL g Pass `config` at setup only when the context is not yet configured; after `createServer` + `setClient`, pass `{ context: ctx }` only. -Legacy module getters (`setPineconeClient`, `registerUrlGenerator`, etc.) still delegate to a process-default context when you omit `context` at setup. +Module-level singleton facades (`setPineconeClient`, `registerUrlGenerator`, `getDefaultServerContext`, etc.) are **deprecated** — they delegate to a process-default context when you omit `context` at setup. Prefer explicit `ServerContext` per [Library embedding](#library-embedding). See [docs/deprecation-policy.md](docs/deprecation-policy.md#active-deprecations-legacy-module-facades). ### Library embedding @@ -145,21 +153,35 @@ ctx.setClient(new PineconeClient({ /* ... */ })); const server = await setupAllianceServer({ context: ctx }); ``` -Use **`await using server = await setupAllianceServer({ context: ctx })`** for automatic teardown, or call **`ctx.teardown()`** when done. For legacy single-server flows that rely on the process-default context, **`teardownServer()`** resets that default before re-initializing. +Use **`await using server = await setupAllianceServer({ context: ctx })`** for automatic teardown, or call **`ctx.teardown()`** when done. For the **generic bridge only**, see [examples/quickstart/mcp-demo.ts](examples/quickstart/mcp-demo.ts). For the **full Alliance surface**, see [examples/alliance/library-embedding-demo.ts](examples/alliance/library-embedding-demo.ts) and [docs/TOOLS.md](docs/TOOLS.md#suggest-flow-gate). +#### Legacy (deprecated) + +Process-default / facade-based setup remains available during the deprecation window (removal per [deprecation-policy.md](docs/deprecation-policy.md) — two minors after the deprecation minor): + +```ts +import { PineconeClient, setPineconeClient } from '@will-cppa/pinecone-read-only-mcp'; +import { resolveAllianceConfig, setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance'; + +setPineconeClient(new PineconeClient({ /* ... */ })); +const server = await setupAllianceServer(resolveAllianceConfig({ apiKey: '...' })); +// Call teardownServer() before re-initializing the process-default context. +``` + +Do not use this pattern for new code or multi-tenant embedding. See [docs/MIGRATION.md](docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations). + ### Custom URL generators Namespaces other than `mailing` and `slack-Cpplang` (or different URL rules for any namespace) can use programmatic registration — no fork required. -Import `registerUrlGenerator` and types `UrlGeneratorFn` / `UrlGenerationResult` from `@will-cppa/pinecone-read-only-mcp`. Register **additional** namespaces before tools that emit URLs run. Built-in `mailing` / `slack-Cpplang` generators are installed by `setupAllianceServer` (not by `setupCoreServer`). +Register **additional** namespaces on your `ServerContext` before tools that emit URLs run. Built-in `mailing` / `slack-Cpplang` generators are installed by `setupAllianceServer` (not by `setupCoreServer`). ```ts import { createServer, PineconeClient, - registerUrlGenerator, type UrlGenerationResult, type UrlGeneratorFn, } from '@will-cppa/pinecone-read-only-mcp'; @@ -184,7 +206,7 @@ const myDocs: UrlGeneratorFn = (metadata): UrlGenerationResult => { : { url: null, method: 'unavailable', reason: 'doc_id missing' }; }; -registerUrlGenerator('product-docs', myDocs); +ctx.registerUrlGenerator('product-docs', myDocs); ``` A fuller embedding sample lives in [examples/alliance/custom-url-generator.ts](examples/alliance/custom-url-generator.ts). diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 633d9e0..4471b57 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -69,6 +69,102 @@ When no experimental fields apply, the `experimental` key is **omitted** (not an **Promotion:** Moving a field from `experimental` to stable requires CHANGELOG, TOOLS.md, and schema updates per [deprecation-policy.md § Stable vs experimental](./deprecation-policy.md#stable-vs-experimental-mcp-response-fields). +## Unreleased: Legacy module-facade deprecations + +**Rationale:** Module-level singleton facades (`setPineconeClient`, `registerUrlGenerator`, `getDefaultServerContext`, etc.) delegate to a process-global `ServerContext`. They complicate multi-tenant embedding and hide initialization order. They are marked `@deprecated` in JSDoc; earliest removal is **two minor releases after** the deprecation minor (see [deprecation-policy.md § Deprecation window](./deprecation-policy.md#deprecation-window)). + +**Who is affected:** Library embedders importing facade functions from `@will-cppa/pinecone-read-only-mcp` or `/alliance`. + +**Recommended pattern:** `createServer(config)` → `ctx.setClient(...)` → `setupCoreServer({ context: ctx })` or `setupAllianceServer({ context: ctx })`. + +### Client + +**Before (deprecated):** + +```ts +import { PineconeClient, setPineconeClient } from '@will-cppa/pinecone-read-only-mcp'; + +setPineconeClient(new PineconeClient({ /* ... */ })); +``` + +**After:** + +```ts +import { createServer, PineconeClient, resolveConfig } from '@will-cppa/pinecone-read-only-mcp'; + +const config = resolveConfig({ apiKey: '...', indexName: 'my-index' }); +const ctx = createServer(config); +ctx.setClient(new PineconeClient({ /* ... */ })); +``` + +### Config + +**Before (deprecated):** `getServerConfig()` / `setServerConfig(config)` / `resetServerConfig()`. + +**After:** `ctx.getConfig()` / `ctx.setConfig(config)` / `ctx.teardown()`. + +### URL registry + +**Before (deprecated):** + +```ts +import { registerUrlGenerator } from '@will-cppa/pinecone-read-only-mcp'; + +registerUrlGenerator('my-ns', myGenerator); +``` + +**After:** + +```ts +ctx.registerUrlGenerator('my-ns', myGenerator); +``` + +Same for `unregisterUrlGenerator`, `generateUrlForNamespace`, `hasUrlGenerator`, and `resetUrlGenerationRegistry` → `ctx.unregisterUrlGenerator`, `ctx.generateUrlForNamespace`, `ctx.hasUrlGenerator`, `ctx.resetUrlGenerators`. + +### Suggest-flow gate + +**Before (deprecated):** `markSuggested`, `requireSuggested`, `resetSuggestionFlow`. + +**After:** `ctx.markSuggested`, `ctx.requireSuggested`, `ctx.resetSuggestionFlow`. + +### Namespaces cache + +**Before (deprecated):** `getNamespacesWithCache()`, `invalidateNamespacesCache()`. + +**After:** `ctx.getNamespacesWithCache()`, `ctx.invalidateNamespacesCache()`. + +### Process-default context + +**Before (deprecated):** + +```ts +import { getDefaultServerContext, setupCoreServer } from '@will-cppa/pinecone-read-only-mcp'; + +await setupCoreServer(config); // uses process default +const ctx = getDefaultServerContext(); +``` + +**After:** + +```ts +const ctx = createServer(config); +ctx.setClient(client); +await setupCoreServer({ context: ctx }); +``` + +### Teardown + +**Before:** `teardownServer()` resets the process-default context. + +**After:** `await ctx.teardown()` or `await using server = await setupAllianceServer({ context: ctx })` for automatic cleanup. `teardownServer()` remains available during the deprecation window for legacy single-server flows; prefer per-context lifecycle for new code. + +### CLI and tests + +- **CLI:** unchanged — the binary uses internal setup paths. +- **Test fakes:** pass a dedicated `ServerContext` via `createIsolatedContext` or `createServer` + `{ context: ctx }` at setup instead of mutating process globals. + +See [deprecation-policy.md § Active deprecations](./deprecation-policy.md#active-deprecations-legacy-module-facades) for the full inventory. + ## Unreleased: trimmed library exports **Who is affected:** Library embedders that imported `buildQueryExperimental` or `buildGuidedQueryExperimental` from `@will-cppa/pinecone-read-only-mcp` or `/alliance`. @@ -86,11 +182,11 @@ import { buildQueryExperimental } from '@will-cppa/pinecone-read-only-mcp'; `PineconeClient.query()` return types (`HybridQueryResult`, etc.) and all Zod response schemas remain on the public surface. -## Unreleased: `ServerContext` instance APIs (phase 1) +## Unreleased: `ServerContext` instance APIs (initial) -**Rationale:** Process-global singletons (Pinecone client slot, config, URL registry, suggest-flow gate, namespaces cache) complicate testing and multi-tenant embedding. Phase 1 introduces an opt-in **`ServerContext`** without removing legacy getters. +**Rationale:** Process-global singletons (Pinecone client slot, config, URL registry, suggest-flow gate, namespaces cache) complicate testing and multi-tenant embedding. The initial milestone introduces an opt-in **`ServerContext`**; legacy module facades are deprecated (see [Legacy module-facade deprecations](#unreleased-legacy-module-facade-deprecations)). -**Now (0.2.x — unchanged for existing embedders):** +**Deprecated (migrate before removal):** ```ts import { PineconeClient, setPineconeClient } from '@will-cppa/pinecone-read-only-mcp'; @@ -108,9 +204,9 @@ setPineconeClient( const server = await setupAllianceServer(config); ``` -Module-level helpers (`getPineconeClient`, `registerUrlGenerator`, `requireSuggested`, etc.) continue to work; they delegate to a process-default context. +Module-level helpers (`getPineconeClient`, `registerUrlGenerator`, `requireSuggested`, etc.) still work during the deprecation window; they delegate to a process-default context. -**New (recommended — phase 4 explicit context at setup):** For one-shot client injection at construction, see [ServerContext composition API](#unreleased-servercontext-composition-api) (`createServer(config, { client })` or `createIsolatedContext`). +**Recommended (instance-first):** For one-shot client injection at construction, see [ServerContext composition API](#unreleased-servercontext-composition-api) (`createServer(config, { client })` or `createIsolatedContext`). ```ts import { createServer, PineconeClient } from '@will-cppa/pinecone-read-only-mcp'; @@ -178,7 +274,7 @@ import { registerQueryTool, registerCountTool, registerListNamespacesTool } from registerQueryTool(server, ctx); ``` -**Later (future minors/major):** Legacy module getters will be marked `### Deprecated` per [deprecation-policy.md](./deprecation-policy.md). +**Later:** Legacy module getters will be removed at the earliest removal minor per [deprecation-policy.md](./deprecation-policy.md). See also [deprecation-policy.md § Future instance APIs](./deprecation-policy.md#future-instance-apis-servercontext). @@ -222,7 +318,7 @@ await setupCoreServer({ context: ctx }); Suggest-flow gate settings (`disableSuggestFlow`, `cacheTtlMs`) remain on `ServerConfig`, not on composition. -See also [ServerContext instance APIs (phase 1)](#unreleased-servercontext-instance-apis-phase-1) for legacy vs explicit-context setup. +See also [ServerContext instance APIs (initial)](#unreleased-servercontext-instance-apis-initial) for legacy vs explicit-context setup. --- diff --git a/docs/PACKAGE_SPLIT_EVAL.md b/docs/PACKAGE_SPLIT_EVAL.md index af0b1c0..c1fbc1e 100644 --- a/docs/PACKAGE_SPLIT_EVAL.md +++ b/docs/PACKAGE_SPLIT_EVAL.md @@ -7,7 +7,7 @@ | Can core and alliance be separate npm packages? | **Yes, technically feasible.** Production dependency is one-way (`alliance` → `core`); no circular imports. | | Which consumers use which layer? | **Alliance layer:** CLI, MCP client configs, Alliance examples, internal C++ Alliance deployments. **Core layer:** generic embedders, core-only setup, shared types/errors. No known external community consumers yet (pre-1.0). | | Recommended package structure | **npm workspace monorepo** in this repository (not separate git repos) if/when the split proceeds. | -| **Decision** | **Split later** — after phase 5 legacy-getter deprecation completes and one deprecation window has elapsed. Keep the unified package until then. | +| **Decision** | **Split later** — after legacy facade deprecation completes and one deprecation window has elapsed. Keep the unified package until then. | The source boundary (`src/core/` vs `src/alliance/`) is already clean enough to become a package boundary. The remaining blockers are public API surface (legacy module facades still exported from core), build/workspace tooling (not yet present), and low external adoption incentive while the project is still pre-1.0. @@ -88,7 +88,7 @@ Core setup uses `CORE_SERVER_INSTRUCTIONS` (7 tools). Alliance setup uses `ALLIA ### 2.5 What is already decoupled -Phases 1–4 of the ServerContext roadmap established: +The ServerContext instance API on main established: - Per-instance `ServerContext` with URL registry, suggest-flow gate, namespaces cache, and client slot - All 9 tool handlers accept optional `ctx` @@ -153,7 +153,7 @@ A split requires: | `vitest` config spanning workspace packages | Low–medium | | npm publish: two packages, version coordination policy | Medium | -Estimated implementation effort for the split itself: **~3–5 days** (not including phase 5 API cleanup or consumer migration docs). +Estimated implementation effort for the split itself: **~3–5 days** (not including legacy facade removal or consumer migration docs). ### 3.5 Public API blockers (must resolve before split) @@ -162,9 +162,9 @@ The core public API (`src/core/index.ts`) still exports **legacy module facades* - `setPineconeClient` - `registerUrlGenerator`, `unregisterUrlGenerator`, `generateUrlForNamespace`, `hasUrlGenerator` -These are Alliance-era singleton patterns. Publishing them as the stable surface of a standalone "generic core" package would cement the wrong contract. **Phase 5** deprecates and eventually removes these exports, leaving `ServerContext` + setup APIs as the supported public contract. +These are Alliance-era singleton patterns. Publishing them as the stable surface of a standalone "generic core" package would cement the wrong contract. **Legacy facade deprecation** marks and eventually removes these exports, leaving `ServerContext` + setup APIs as the supported public contract. -Until phase 5 completes, "core" is generic in _source layout_ but not yet generic in _published API_. +Until facade removal at 1.0, "core" is generic in _source layout_ but not yet generic in _published API_. ### 3.6 Extension surface (T23) and package split @@ -262,7 +262,7 @@ pinecone-read-only-mcp-typescript/ **Suggested version policy:** -- Core: conservative minors; API stable toward 1.0 after phase 5 +- Core: conservative minors; API stable toward 1.0 after legacy facade removal - Alliance: faster minors; `dependencies: { "@will-cppa/pinecone-read-only-mcp": "^0.x.0" }` with CI matrix testing latest compatible core ### 5.2 Option B: Separate git repositories @@ -281,7 +281,7 @@ Continue with `exports["."]` and `exports["./alliance"]` in one package. **Pros:** Zero build migration; single version; simplest publish story. -**Cons:** Alliance-only changes always bump the shared version; eval T23 coupling perception remains; core public API still carries legacy facades until phase 5 regardless. +**Cons:** Alliance-only changes always bump the shared version; eval T23 coupling perception remains; core public API still carries legacy facades until facade removal regardless. --- @@ -289,13 +289,13 @@ Continue with `exports["."]` and `exports["./alliance"]` in one package. ### Recommended: **Split later** (not now) -Defer the npm package split until **after phase 5 legacy-getter deprecation** has shipped and **one deprecation policy window** has elapsed (see [deprecation-policy.md](./deprecation-policy.md)). +Defer the npm package split until **after legacy facade deprecation** has shipped and **one deprecation policy window** has elapsed (see [deprecation-policy.md](./deprecation-policy.md)). Do **not** implement workspace packages in the current sprint. This PR delivers the evaluation only. ### Rationale -1. **Source boundary is ready; published API is not.** Phases 1–4 cleaned instance-path architecture, but core still exports `setPineconeClient`, global URL registry helpers, and `getDefaultServerContext`. Splitting now would publish those as the long-term "generic core" contract. Phase 5 must finish first. +1. **Source boundary is ready; published API is not.** The ServerContext instance API is in place on main, but core still exports `setPineconeClient`, global URL registry helpers, and `getDefaultServerContext`. Splitting now would publish those as the long-term "generic core" contract. Legacy facade deprecation and removal must finish first. 2. **Low external adoption incentive.** All current consumers are internal or documentation-driven. Shared version bumps are inconvenient but not blocking release velocity today. @@ -308,9 +308,9 @@ Do **not** implement workspace packages in the current sprint. This PR delivers | Option | When it makes sense | Why not now | | ----------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------ | | **Split now** | External core-only adopters blocked by Alliance cadence | Legacy facades still in core exports; tooling not ready | -| **Split with phase 4 only** | Urgent multi-team release decoupling | Phase 5 still required for clean API; no urgent consumer pressure | +| **Split with instance API only** | Urgent multi-team release decoupling | Legacy facade removal still required for clean API; no urgent consumer pressure | | **Keep unified indefinitely** | Single consumer, stable 1.0 shipped | Loses future cadence decoupling; re-evaluate at 1.0 planning | -| **Split at 1.0** | Clean semver major for both packages | **Preferred target window** — combine with phase 5 removal release | +| **Split at 1.0** | Clean semver major for both packages | **Preferred target window** — combine with facade removal release | --- @@ -318,8 +318,8 @@ Do **not** implement workspace packages in the current sprint. This PR delivers Proceed with Option A (workspace monorepo) when **all** of the following are true: -- [ ] Phase 5 release 1: legacy facades marked `@deprecated` in `src/core/index.ts` -- [ ] Phase 5 release 3 (or agreed 1.0): module-level singleton accessors removed from public exports +- [ ] Release 1: legacy facades marked `@deprecated` in `src/core/index.ts` +- [ ] Release 3 (or agreed 1.0): module-level singleton accessors removed from public exports - [ ] `src/types.ts` contains only core-shared types; Alliance-specific types live under `src/alliance/` - [ ] `src/logger.ts` owned by core; Alliance uses core export - [ ] `constants.ts` split between packages (no Alliance instructions in core tarball) @@ -327,7 +327,7 @@ Proceed with Option A (workspace monorepo) when **all** of the following are tru - [ ] `MIGRATION.md` documents package names, shim period, and MCP config updates - [ ] At least one **external** or **multi-team** consumer needs independent Alliance release cadence -**Suggested trigger:** planning for **1.0.0** major release, combining phase 5 removal with package split if checklist is complete. +**Suggested trigger:** planning for **1.0.0** major release, combining facade removal with package split if checklist is complete. --- diff --git a/docs/deprecation-policy.md b/docs/deprecation-policy.md index 67963f3..bf1c750 100644 --- a/docs/deprecation-policy.md +++ b/docs/deprecation-policy.md @@ -32,6 +32,21 @@ Renames may ship the **replacement immediately** alongside the deprecated alias APIs deprecated **before** this policy was published follow the removal target recorded in CHANGELOG and source comments at deprecation time. The `paper_number` field on query result rows (use `document_id` instead) was deprecated in **0.2.0** with removal planned no earlier than the **next major** release after `1.0.0`; it will not be removed in a `0.y` minor without an explicit CHANGELOG entry and MIGRATION update. +### Active deprecations - legacy module facades + +Module-level singleton facades delegate to `getDefaultServerContext()`. Migrate to **`ServerContext`** instance methods via `createServer(config)` and pass `{ context: ctx }` to `setupCoreServer` / `setupAllianceServer`. Deprecated in the **next published minor** after merge; earliest removal **two minor releases later** (per [Deprecation window](#deprecation-window) above). See [MIGRATION.md § Legacy module-facade deprecations](./MIGRATION.md#unreleased-legacy-module-facade-deprecations). + +| Facade | Layer | Replacement | Deprecated in | Earliest removal | +| ------ | ----- | ----------- | ------------- | ---------------- | +| `getPineconeClient` / `setPineconeClient` / `clearPineconeClient` | core | `ctx.getClient()` / `ctx.setClient()` / `ctx.clearClient()` | next minor (TBD at release) | two minors after deprecation minor | +| `getServerConfig` / `setServerConfig` / `resetServerConfig` | core | `ctx.getConfig()` / `ctx.setConfig()` / `ctx.teardown()` | next minor (TBD at release) | two minors after deprecation minor | +| `registerUrlGenerator` / `unregisterUrlGenerator` / `generateUrlForNamespace` / `hasUrlGenerator` / `resetUrlGenerationRegistry` | core | `ctx.registerUrlGenerator()` etc. / `ctx.resetUrlGenerators()` | next minor (TBD at release) | two minors after deprecation minor | +| `markSuggested` / `requireSuggested` / `resetSuggestionFlow` | core | `ctx.markSuggested()` / `ctx.requireSuggested()` / `ctx.resetSuggestionFlow()` | next minor (TBD at release) | two minors after deprecation minor | +| `getNamespacesWithCache` / `invalidateNamespacesCache` | core | `ctx.getNamespacesWithCache()` / `ctx.invalidateNamespacesCache()` | next minor (TBD at release) | two minors after deprecation minor | +| `getDefaultServerContext` | core | Return value of `createServer` or explicit `context` at setup | next minor (TBD at release) | two minors after deprecation minor | + +`teardownServer()` remains supported during the deprecation window; prefer `ctx.teardown()` or `await using` on the setup handle. Documented in MIGRATION.md; not marked `@deprecated` until a later release. + ## How we deprecate (maintainer checklist) For each deprecated public surface: @@ -93,13 +108,9 @@ New response fields added before `1.0.0` default to `experimental` unless explic ## Future instance APIs (`ServerContext`) -Phase 1 of the **`ServerContext`** / **`createServer(config)`** refactor is available while legacy module-level getters remain supported. See [MIGRATION.md § ServerContext instance APIs](./MIGRATION.md#unreleased-servercontext-instance-apis-phase-1) for upgrade steps. - -That work will: +Legacy module-level facades are deprecated per the [active deprecations table](./deprecation-policy.md#active-deprecations-legacy-module-facades) above. `ServerContext` + `createServer` / setup APIs are the supported public contract going forward. -- Add new instance APIs without removing legacy getters in the same release. -- Document legacy getters under `### Deprecated` with a named removal target per this policy. -- Link migration steps from [MIGRATION.md](./MIGRATION.md) to this document. +See [MIGRATION.md § Legacy module-facade deprecations](./MIGRATION.md#unreleased-legacy-module-facade-deprecations) for before/after embedder snippets. ## CHANGELOG format for breaking changes diff --git a/examples/alliance/custom-url-generator.ts b/examples/alliance/custom-url-generator.ts index 859f450..66dd72a 100644 --- a/examples/alliance/custom-url-generator.ts +++ b/examples/alliance/custom-url-generator.ts @@ -7,39 +7,21 @@ * registered by `setupAllianceServer` (Alliance layer); everything else is up to you. * * Usage: - * 1. Import `registerUrlGenerator` from `@will-cppa/pinecone-read-only-mcp`. - * 2. Import `setupAllianceServer` from `@will-cppa/pinecone-read-only-mcp/alliance`. - * 3. Call `registerUrlGenerator(namespace, fn)` before `setupAllianceServer(config)`. - * 4. The generate_urls tool and query row enrichment use the registry automatically. + * 1. `createServer(config)` → `ctx.setClient(...)` → `ctx.registerUrlGenerator(namespace, fn)`. + * 2. `await setupAllianceServer({ context: ctx })`. + * 3. The generate_urls tool and query row enrichment use the registry automatically. * * Run from a project that depends on the package, or use this repo after `npm run build`. */ import { + createServer, PineconeClient, - registerUrlGenerator, resolveConfig, - setPineconeClient, type UrlGenerationResult, } from '@will-cppa/pinecone-read-only-mcp'; import { setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance'; -registerUrlGenerator('product-docs', (metadata): UrlGenerationResult => { - const product = typeof metadata['product'] === 'string' ? metadata['product'] : null; - const slug = typeof metadata['slug'] === 'string' ? metadata['slug'] : null; - if (!product || !slug) { - return { - url: null, - method: 'unavailable', - reason: 'product-docs requires both `product` and `slug` metadata fields', - }; - } - return { - url: `https://docs.example.com/${product}/${slug}`, - method: 'generated.custom', - }; -}); - async function main(): Promise { const apiKey = process.env['PINECONE_API_KEY']?.trim(); const indexName = process.env['PINECONE_INDEX_NAME']?.trim(); @@ -51,7 +33,8 @@ async function main(): Promise { } const config = resolveConfig({ apiKey, indexName }); - setPineconeClient( + const ctx = createServer(config); + ctx.setClient( new PineconeClient({ apiKey: config.apiKey, indexName: config.indexName, @@ -61,7 +44,23 @@ async function main(): Promise { }) ); - const server = await setupAllianceServer(config); + ctx.registerUrlGenerator('product-docs', (metadata): UrlGenerationResult => { + const product = typeof metadata['product'] === 'string' ? metadata['product'] : null; + const slug = typeof metadata['slug'] === 'string' ? metadata['slug'] : null; + if (!product || !slug) { + return { + url: null, + method: 'unavailable', + reason: 'product-docs requires both `product` and `slug` metadata fields', + }; + } + return { + url: `https://docs.example.com/${product}/${slug}`, + method: 'generated.custom', + }; + }); + + const server = await setupAllianceServer({ context: ctx }); void server; console.log('Custom URL generator registered for namespace "product-docs".'); } diff --git a/examples/alliance/guided-query-demo.ts b/examples/alliance/guided-query-demo.ts index 6c10a77..3a272e5 100644 --- a/examples/alliance/guided-query-demo.ts +++ b/examples/alliance/guided-query-demo.ts @@ -16,9 +16,9 @@ */ import { + createServer, PineconeClient, resolveConfig, - setPineconeClient, } from '@will-cppa/pinecone-read-only-mcp'; import { setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance'; @@ -34,7 +34,8 @@ async function main(): Promise { } const config = resolveConfig({ apiKey, indexName }); - setPineconeClient( + const ctx = createServer(config); + ctx.setClient( new PineconeClient({ apiKey: config.apiKey, indexName: config.indexName, @@ -45,7 +46,7 @@ async function main(): Promise { }) ); - const server = await setupAllianceServer(config); + const server = await setupAllianceServer({ context: ctx }); void server; console.log('Server ready — call guided_query({ user_query, preferred_tool?: "auto" }).'); } diff --git a/examples/alliance/library-embedding-demo.ts b/examples/alliance/library-embedding-demo.ts index 41c8e52..b04fbcd 100644 --- a/examples/alliance/library-embedding-demo.ts +++ b/examples/alliance/library-embedding-demo.ts @@ -14,9 +14,9 @@ * `await using server = await setupAllianceServer({ context: ctx })` for * automatic teardown, or call `ctx.teardown()` when done. * - * **Legacy (single process-default server):** `setPineconeClient(client)` then - * `await setupAllianceServer(config)` still works; call `teardownServer()` before - * re-initializing the default context. + * **Legacy (deprecated):** `setPineconeClient(client)` then + * `await setupAllianceServer(config)` still works during the deprecation window; + * see [docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations](docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations). */ import { createServer, PineconeClient } from '@will-cppa/pinecone-read-only-mcp'; diff --git a/examples/alliance/suggest-flow-demo.ts b/examples/alliance/suggest-flow-demo.ts index e7f76e4..01df57a 100644 --- a/examples/alliance/suggest-flow-demo.ts +++ b/examples/alliance/suggest-flow-demo.ts @@ -17,9 +17,9 @@ */ import { + createServer, PineconeClient, resolveConfig, - setPineconeClient, } from '@will-cppa/pinecone-read-only-mcp'; import { setupAllianceServer } from '@will-cppa/pinecone-read-only-mcp/alliance'; @@ -35,7 +35,8 @@ async function main(): Promise { } const config = resolveConfig({ apiKey, indexName }); - setPineconeClient( + const ctx = createServer(config); + ctx.setClient( new PineconeClient({ apiKey: config.apiKey, indexName: config.indexName, @@ -46,7 +47,7 @@ async function main(): Promise { }) ); - const server = await setupAllianceServer(config); + const server = await setupAllianceServer({ context: ctx }); // With an MCP client connected to `server`, invoke tools in order: // 1) suggest_query_params({ namespace: "mailing".trim(), user_query: "..." }) // 2) query({ query_text, namespace: "mailing", preset: "detailed", ... }) diff --git a/examples/quickstart/mcp-demo.ts b/examples/quickstart/mcp-demo.ts index b9b6732..80229c5 100644 --- a/examples/quickstart/mcp-demo.ts +++ b/examples/quickstart/mcp-demo.ts @@ -8,11 +8,10 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { config as loadEnv } from 'dotenv'; import { + createServer, PineconeClient, resolveConfig, - setPineconeClient, setupCoreServer, - teardownServer, } from '@will-cppa/pinecone-read-only-mcp'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -48,7 +47,8 @@ async function main(): Promise { indexName, }); - setPineconeClient( + const ctx = createServer(config); + ctx.setClient( new PineconeClient({ apiKey: config.apiKey, indexName: config.indexName, @@ -59,7 +59,7 @@ async function main(): Promise { ); const { clientTransport, serverTransport } = createLinkedTransports(); - const server = await setupCoreServer(config); + const server = await setupCoreServer({ context: ctx }); await server.connect(serverTransport); const client = new Client({ name: 'quickstart-demo', version: '1.0.0' }); @@ -122,7 +122,7 @@ async function main(): Promise { } finally { await client.close(); await server.close(); - teardownServer(); + await ctx.teardown(); } } diff --git a/src/core/server/client-context.ts b/src/core/server/client-context.ts index aac7fd1..c447672 100644 --- a/src/core/server/client-context.ts +++ b/src/core/server/client-context.ts @@ -1,17 +1,41 @@ import { PineconeClient } from '../pinecone-client.js'; import { getDefaultServerContext } from './server-context.js'; -/** Return the shared Pinecone client; throws if setPineconeClient has not been called. */ +/** + * Return the shared Pinecone client; throws if setPineconeClient has not been called. + * + * @deprecated Legacy module facade. Use {@link ServerContext.getClient} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.getClient + */ export function getPineconeClient(): PineconeClient { return getDefaultServerContext().getClientIfSet(); } -/** Set the shared Pinecone client used by all MCP tools. */ +/** + * Set the shared Pinecone client used by all MCP tools. + * + * @deprecated Legacy module facade. Use {@link ServerContext.setClient} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.setClient + */ export function setPineconeClient(client: PineconeClient): void { getDefaultServerContext().setClient(client); } -/** Clear the shared client (used by {@link teardownServer} and tests). */ +/** + * Clear the shared client (used by {@link teardownServer} and tests). + * + * @deprecated Legacy module facade. Use {@link ServerContext.clearClient} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.clearClient + */ export function clearPineconeClient(): void { getDefaultServerContext().clearClient(); } diff --git a/src/core/server/config-context.ts b/src/core/server/config-context.ts index e89ced1..52d3e1d 100644 --- a/src/core/server/config-context.ts +++ b/src/core/server/config-context.ts @@ -5,12 +5,28 @@ import { setPendingServerConfig, } from './server-context.js'; -/** Replace the process-global server config (called from setup with CLI/env-derived config). */ +/** + * Replace the process-global server config (called from setup with CLI/env-derived config). + * + * @deprecated Legacy module facade. Use {@link ServerContext.setConfig} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.setConfig + */ export function setServerConfig(config: ServerConfig): void { setPendingServerConfig(config); } -/** Clear active config so the next `getServerConfig()` resolves again (used by {@link teardownServer}). */ +/** + * Clear active config so the next `getServerConfig()` resolves again (used by {@link teardownServer}). + * + * @deprecated Legacy module facade. Use {@link ServerContext.teardown} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.teardown + */ export function resetServerConfig(): void { setDefaultServerContext(null); } @@ -22,6 +38,12 @@ export function resetServerConfig(): void { * When setup runs without an explicit config, falls back to `resolveConfig({})` * (requires `PINECONE_API_KEY` and `PINECONE_INDEX_NAME` or throws). Alliance apps should * pass config from `resolveAllianceConfig()` into `setupAllianceServer(config)`. + * + * @deprecated Legacy module facade. Use {@link ServerContext.getConfig} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.getConfig */ export function getServerConfig(): ServerConfig { return getDefaultServerContext().getConfig(); diff --git a/src/core/server/namespaces-cache.ts b/src/core/server/namespaces-cache.ts index 8814cbc..09d9eac 100644 --- a/src/core/server/namespaces-cache.ts +++ b/src/core/server/namespaces-cache.ts @@ -5,6 +5,12 @@ export type { NamespaceInfo }; /** * Return namespace list with metadata; uses an in-memory cache whose TTL is * sourced from the active `ServerConfig.cacheTtlMs`. + * + * @deprecated Legacy module facade. Use {@link ServerContext.getNamespacesWithCache} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.getNamespacesWithCache */ export async function getNamespacesWithCache(): Promise<{ data: NamespaceInfo[]; @@ -14,7 +20,15 @@ export async function getNamespacesWithCache(): Promise<{ return getDefaultServerContext().getNamespacesWithCache(); } -/** Clear the namespaces cache so the next call to getNamespacesWithCache refetches. */ +/** + * Clear the namespaces cache so the next call to getNamespacesWithCache refetches. + * + * @deprecated Legacy module facade. Use {@link ServerContext.invalidateNamespacesCache} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.invalidateNamespacesCache + */ export function invalidateNamespacesCache(): void { getDefaultServerContext().invalidateNamespacesCache(); } diff --git a/src/core/server/server-context.ts b/src/core/server/server-context.ts index 3345131..235df8a 100644 --- a/src/core/server/server-context.ts +++ b/src/core/server/server-context.ts @@ -159,7 +159,7 @@ export class ServerContext implements AsyncDisposable { /** Return the client only when explicitly injected (legacy {@link getPineconeClient} path). */ getClientIfSet(): PineconeClient { if (!this.clientExplicitlySet || !this.client) { - throw new Error('Pinecone client not initialized. Call setPineconeClient first.'); + throw new Error('Pinecone client not initialized. Call ServerContext.setClient() first.'); } return this.client; } @@ -373,7 +373,15 @@ export function peekDefaultServerContext(): ServerContext | null { return defaultContext; } -/** Process-default context used by legacy module facades. */ +/** + * Process-default context used by legacy module facades. + * + * @deprecated Legacy module facade. Pass a {@link ServerContext} from {@link createServer} + * explicitly to setup APIs instead. Removal follows docs/deprecation-policy.md (no earlier + * than two minor releases after the deprecation minor). See + * docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see createServer + */ export function getDefaultServerContext(): ServerContext { if (!defaultContext) { const cfg = pendingConfig ?? undefined; diff --git a/src/core/server/suggestion-flow.ts b/src/core/server/suggestion-flow.ts index 403d668..f2efda6 100644 --- a/src/core/server/suggestion-flow.ts +++ b/src/core/server/suggestion-flow.ts @@ -8,7 +8,15 @@ type FlowState = { user_query: string; }; -/** Record that suggest_query_params was called for this namespace (enables query/count for the flow). */ +/** + * Record that suggest_query_params was called for this namespace (enables query/count for the flow). + * + * @deprecated Legacy module facade. Use {@link ServerContext.markSuggested} on a + * {@link ServerContext} from {@link createServer} instead. Removal follows + * docs/deprecation-policy.md (no earlier than two minor releases after the + * deprecation minor). See docs/MIGRATION.md#unreleased-legacy-module-facade-deprecations. + * @see ServerContext.markSuggested + */ export function markSuggested(namespace: string, state: Omit): void { getDefaultServerContext().markSuggested(namespace, state); } @@ -20,6 +28,12 @@ export function markSuggested(namespace: string, state: Omit