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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Tagged releases are published to npm from GitHub Actions when a **GitHub Release

### Added

- `guided_query` tool registered by `setupCoreServer` / package-root import (core-layer handler; no Alliance URL generators or index defaults required).
- `ServerContextComposition` interface plus `NamespaceCacheSeed` and `SuggestionFlowSeedEntry` types for dependency injection into `ServerContext`.
- `createIsolatedContext(config, composition?)` factory for multi-tenant embedders (no process-global side effects).
- 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.
Expand All @@ -22,7 +23,7 @@ Tagged releases are published to npm from GitHub Actions when a **GitHub Release
- `createServer(config, composition?)` now accepts an optional composition object.
- **Breaking (MCP):** Experimental tool response fields are nested under `experimental` on success payloads. Affected tools: `query`, `query_documents`, `guided_query`. Fields moved: `degraded`, `degradation_reason`, `hybrid_leg_failed`, `rerank_skipped_reason` (query-shaped tools); `decision_trace` (`guided_query`). Stable fields (`status`, `results`, `namespace`, etc.) are unchanged. See [MIGRATION.md](docs/MIGRATION.md#unreleased-stable-vs-experimental-response-fields).
- **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.
- **Breaking (core):** `setupCoreServer` MCP `instructions` use `CORE_SERVER_INSTRUCTIONS` (no `guided_query` / `suggest_query_params`). `resolveConfig` defaults `disableSuggestFlow` to `true` so `query` / `count` / `query_documents` work without Alliance tools. Alliance CLI / `resolveAllianceConfig` unchanged: gate on by default, `ALLIANCE_SERVER_INSTRUCTIONS`.
- **Breaking (core):** `setupCoreServer` MCP `instructions` use `CORE_SERVER_INSTRUCTIONS` (includes `guided_query`; no `suggest_query_params`). `resolveConfig` defaults `disableSuggestFlow` to `true` so `query` / `count` / `query_documents` work without Alliance tools. Alliance CLI / `resolveAllianceConfig` unchanged: gate on by default, `ALLIANCE_SERVER_INSTRUCTIONS`.
- **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).

## [0.2.0] - 2026-05-29
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ To try the server on **your own** Pinecone project (free tier, no Alliance index

The codebase is split into two layers:

- **`src/core/`** — generic MCP–Pinecone bridge (`PineconeClient`, `resolveConfig`, core MCP tools). Import from `@will-cppa/pinecone-read-only-mcp` (package root).
- **`src/alliance/`** — C++ Alliance app tools (`suggest_query_params`, `guided_query`, Boost/Slack URL builtins). Import from `@will-cppa/pinecone-read-only-mcp/alliance` and use `createServer(config)` → `ctx.setClient(...)` → `setupAllianceServer({ context: ctx })` for the full tool surface (what the CLI uses); see [Library embedding](#library-embedding) below.
- **`src/core/`** — generic MCP–Pinecone bridge (`PineconeClient`, `resolveConfig`, eight MCP tools including `guided_query`). Import from `@will-cppa/pinecone-read-only-mcp` (package root).
- **`src/alliance/`** — C++ Alliance app layer (`suggest_query_params`, Boost/Slack URL builtins). Import from `@will-cppa/pinecone-read-only-mcp/alliance` and use `createServer(config)` → `ctx.setClient(...)` → `setupAllianceServer({ context: ctx })` for the full tool surface (what the CLI uses); suggest-flow gate on by default. See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for core vs Alliance defaults and [Library embedding](#library-embedding) below.

## Configuration

Expand Down
2 changes: 2 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ For the full Alliance tool surface (including `suggest_query_params`, `guided_qu
| `resolveConfig` | Package root, `setupCoreServer`, quickstart | **Throws** | Omitted (no rerank) | Off (`disableSuggestFlow: true`) |
| `resolveAllianceConfig` | Published CLI, `setupAllianceServer` | `rag-hybrid` | `bge-reranker-v2-m3` | On (`disableSuggestFlow: false`) |

**Warning:** Switching between `resolveConfig` / `setupCoreServer` (package root) and `resolveAllianceConfig` / `setupAllianceServer` changes suggest-flow gate behavior. Core defaults bypass the gate; Alliance defaults enforce it. Use `guided_query` (registered in both setups) for single-call retrieval without manual `suggest_query_params`, or align `disableSuggestFlow` explicitly when migrating between entry points.

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
11 changes: 11 additions & 0 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,17 @@ Core `resolveConfig` throws `Missing Pinecone index name: …` when the index is
- 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.

### Suggest-flow gate (`disableSuggestFlow`) — intentional divergence

| Entry point | Default | Rationale |
| ----------- | ------- | --------- |
| `resolveConfig` / `setupCoreServer` | Gate **off** (`disableSuggestFlow: true`) | Generic embedders can call `query` / `count` / `query_documents` directly; `guided_query` is the recommended ceremony-free path |
| `resolveAllianceConfig` / CLI | Gate **on** (`disableSuggestFlow: false`) | Production MCP safety: manual `query` requires `suggest_query_params` first |

**Decision (unchanged):** Exposing `guided_query` in core does **not** change the core gate default. Core keeps the gate off so direct tool access remains available; Alliance keeps the gate on for CLI/MCP deployments.

**When migrating entry points:** If you move from Alliance to core (or vice versa), query gate behavior changes unless you set `disableSuggestFlow` explicitly. Use `guided_query` to avoid the multi-step suggest flow in either setup.

---

## Migrating to v0.2.0
Expand Down
4 changes: 2 additions & 2 deletions docs/TOOLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ Promotion process: [deprecation-policy.md § Stable vs experimental](./deprecati

| Setup | Tools | MCP instructions |
| ----- | ----- | ------------------ |
| `setupCoreServer` (package root) | **7:** `list_namespaces`, `namespace_router`, `count`, `query`, `keyword_search`, `query_documents`, `generate_urls` | `CORE_SERVER_INSTRUCTIONS` — no `guided_query` or `suggest_query_params` |
| `setupAllianceServer` / published CLI | **9:** core tools plus `suggest_query_params`, `guided_query` | `ALLIANCE_SERVER_INSTRUCTIONS` — includes guided/suggest quickstart |
| `setupCoreServer` (package root) | **8:** `list_namespaces`, `namespace_router`, `count`, `query`, `keyword_search`, `query_documents`, `generate_urls`, `guided_query` | `CORE_SERVER_INSTRUCTIONS` — includes `guided_query`; no `suggest_query_params` |
| `setupAllianceServer` / published CLI | **9:** core tools plus `suggest_query_params` | `ALLIANCE_SERVER_INSTRUCTIONS` — includes suggest-flow quickstart |

## Suggest-flow gate

Expand Down
122 changes: 122 additions & 0 deletions src/__tests__/cross-entry-point.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { setupAllianceServer } from '../alliance/setup.js';
import { resolveAllianceConfig } from '../alliance/config.js';
import { setPineconeClient } from '../core/index.js';
import { resolveConfig } from '../core/config.js';
import { getDefaultServerContext } from '../core/server/server-context.js';
import * as guidedQueryTool from '../core/server/tools/guided-query-tool.js';
import { registerQueryTool } from '../core/server/tools/query-tool.js';
import {
assertToolErrorCode,
createMockServer,
createTestServerContext,
makeHybridQueryResult,
parseToolJson,
} from '../core/server/tools/test-helpers.js';
import { setupCoreServer, teardownServer } from '../core/setup.js';
import { PineconeClient } from '../core/pinecone-client.js';

describe('cross-entry-point: core vs Alliance defaults', () => {
afterEach(() => {
teardownServer();
});

it('core entry point disables suggest-flow gate by default', () => {
const cfg = resolveConfig(
{ apiKey: 'sk-test', indexName: 'my-index' },
{ PINECONE_API_KEY: 'sk-test', PINECONE_INDEX_NAME: 'my-index' }
);
expect(cfg.disableSuggestFlow).toBe(true);
});

it('Alliance entry point enables suggest-flow gate by default', () => {
const cfg = resolveAllianceConfig({ apiKey: 'sk-test' }, { PINECONE_API_KEY: 'sk-test' });
expect(cfg.disableSuggestFlow).toBe(false);
});

it('core-initialized server: query succeeds without prior suggest_query_params', async () => {
const query = vi.fn().mockResolvedValue(makeHybridQueryResult());
const ctx = createTestServerContext({
config: {
disableSuggestFlow: true,
},
client: { query } as never,
});
const server = createMockServer();
registerQueryTool(server as never, ctx);
const body = parseToolJson(
await server.getHandler('query')!({
query_text: 'hello',
namespace: 'wg21',
preset: 'fast',
})
);
expect(body.status).toBe('success');
expect(query).toHaveBeenCalledOnce();
});

it('Alliance-initialized server: query returns FLOW_GATE without prior suggestion', async () => {
const cfg = resolveAllianceConfig(
{ apiKey: 'sk-test', indexName: 'my-index' },
{ PINECONE_API_KEY: 'sk-test', PINECONE_INDEX_NAME: 'my-index' }
);
const ctx = createTestServerContext({
config: cfg,
client: { query: vi.fn() } as never,
});
const server = createMockServer();
registerQueryTool(server as never, ctx);
const raw = await server.getHandler('query')!({
query_text: 'hello',
namespace: 'wg21',
preset: 'fast',
});
const err = assertToolErrorCode(raw, 'FLOW_GATE');
expect(err.suggestion).toBe("Call suggest_query_params for namespace 'wg21' first");
});

it('setupAllianceServer wires Alliance gate defaults: query returns FLOW_GATE', async () => {
const cfg = resolveAllianceConfig(
{ apiKey: 'sk-test', indexName: 'my-index' },
{ PINECONE_API_KEY: 'sk-test', PINECONE_INDEX_NAME: 'my-index' }
);
setPineconeClient(
new PineconeClient({
apiKey: cfg.apiKey,
indexName: cfg.indexName,
defaultTopK: cfg.defaultTopK,
})
);
await setupAllianceServer({ config: cfg });
const ctx = getDefaultServerContext();
expect(ctx.getConfig().disableSuggestFlow).toBe(false);

const server = createMockServer();
registerQueryTool(server as never, ctx);
const raw = await server.getHandler('query')!({
query_text: 'hello',
namespace: 'wg21',
preset: 'fast',
});
assertToolErrorCode(raw, 'FLOW_GATE');
});

it('core setup registers guided_query handler', async () => {
const cfg = resolveConfig({ apiKey: 'sk-cross', indexName: 'test-index' });
const ctx = createTestServerContext({
config: cfg,
client: new PineconeClient({
apiKey: cfg.apiKey,
indexName: cfg.indexName,
defaultTopK: cfg.defaultTopK,
}),
});
const registerSpy = vi.spyOn(guidedQueryTool, 'registerGuidedQueryTool');

await setupCoreServer({ context: ctx });

expect(registerSpy).toHaveBeenCalledOnce();
expect(ctx.hasToolsRegistered()).toBe(true);
registerSpy.mockRestore();
});
});
7 changes: 7 additions & 0 deletions src/alliance/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ export const DEFAULT_ALLIANCE_RERANK_MODEL = ALLIANCE_DEFAULT_RERANK_MODEL;
* Build {@link ServerConfig} for Alliance CLI and `setupAllianceServer`.
* Fills index and rerank from Alliance defaults when unset, then calls core `resolveConfig`.
*
* **Suggest-flow gate default:** After core resolution, `disableSuggestFlow` is overridden to
* `false` (gate on) unless `PINECONE_DISABLE_SUGGEST_FLOW` or `disableSuggestFlow` in overrides
* says otherwise. This differs from package-root {@link resolveConfig} (`true` / gate off).
* Switching between core and Alliance entry points changes query gate behavior — use
* `guided_query` (available in both) for ceremony-free retrieval, or call
* `suggest_query_params` before gated tools when the gate is on.
*
* Output is the `config` half of the embedder pattern `{ config, composition }`.
* Pair with {@link createIsolatedContext} or {@link createServer} and an optional
* {@link ServerContextComposition} for per-instance injectables.
Expand Down
4 changes: 1 addition & 3 deletions src/alliance/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { getDefaultServerContext, type ServerContext } from '../core/server/serv
import { resolveAllianceConfig } from './config.js';
import { setupCoreServer, type ServerHandle, type SetupCoreServerOptions } from '../core/setup.js';
import { registerBuiltinUrlGenerators } from './url-builtins.js';
import { registerGuidedQueryTool } from './tools/guided-query-tool.js';
import { registerSuggestQueryParamsTool } from './tools/suggest-query-params-tool.js';

/**
Expand Down Expand Up @@ -56,7 +55,7 @@ function normalizeSetupAllianceArgs(

/**
* Create and configure the MCP server with the full Alliance tool surface:
* all core tools plus `suggest_query_params`, `guided_query`, and built-in URL generators.
* all core tools (including `guided_query`) plus `suggest_query_params` and built-in URL generators.
*
* When `config` is omitted, resolves env via {@link resolveAllianceConfig} (Alliance index/rerank defaults when unset).
*/
Expand Down Expand Up @@ -88,6 +87,5 @@ export async function setupAllianceServer(

registerBuiltinUrlGenerators(resolvedCtx);
registerSuggestQueryParamsTool(server, resolvedCtx);
registerGuidedQueryTool(server, resolvedCtx);
return server;
}
Loading
Loading