Skip to content

feat(setup): explicit context API for multi-instance ServerContext embedding - #150

Merged
wpak-ai merged 5 commits into
cppalliance:mainfrom
jonathanMLDev:feat/server-context-setup-api
Jun 11, 2026
Merged

feat(setup): explicit context API for multi-instance ServerContext embedding#150
wpak-ai merged 5 commits into
cppalliance:mainfrom
jonathanMLDev:feat/server-context-setup-api

Conversation

@jonathanMLDev

@jonathanMLDev jonathanMLDev commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

setup now accepts { config?, context?, instructions? } so multiple isolated ServerContext instances can register tools in one process. The process-global mcpServerInitialized guard is replaced with per-context registration tracking; legacy positional setupCoreServer(config) and teardownServer() remain supported.

Changes

  • setupCoreServer / setupAllianceServer — options object + backward-compatible positional overloads
  • ServerContexttoolsRegistered guard (assertCanRegisterTools, markToolsRegistered); legacy double-setup still throws via peekDefaultServerContext()
  • Explicit context at setup preserves ctx.setClient(...) without pulling from the process default
  • Alliance tools and builtins bind to the same ctx passed to core setup
  • CLI: createServer(config)ctx.setClient(...)setupAllianceServer({ config, context: ctx })
  • Docs/examples: instance-first embedder recipe in README, MIGRATION.md, CONFIGURATION.md, library-embedding-demo.ts
  • New setup-multi-instance.test.ts — coexistence, URL/suggest-flow/cache isolation, injected client, await using

Acceptance criteria

  • setupCoreServer({ config?, context?, instructions? })
  • setupAllianceServer({ config?, context?, instructions? }) — same ctx for core + Alliance
  • Per-context init guard; different contexts can setup without teardownServer()
  • Injected client preserved when context is provided
  • teardownServer() valid for legacy single-server flows (documented)
  • CLI + library-embedding-demo + README/MIGRATION recipes updated
  • Multi-instance integration tests; legacy setup tests unchanged

Test plan

  • npm test — 245 tests pass
  • npm run build — pass
  • setup-multi-instance.test.ts — multi-setup, isolation, injected client, await using
  • server.test.ts / lifecycle.context.test.ts — legacy positional setup + teardownServer path
  • CI green on PR

Notes for reviewers

  • Legacy path without explicit context still uses createServer + client transfer from setPineconeClient; Alliance delegates that to setupCoreServer when context is omitted.
  • Passing both config and context calls setConfig, which clears an injected client — embedders should omit config when the context is already configured.

Related Issue

Summary by CodeRabbit

  • Documentation

    • Revised README, configuration, and migration docs to describe instance-first embedding and context-based setup, with updated examples and teardown guidance.
  • New Features

    • Per-context server instances with isolated clients, URL generators, namespaces cache, and suggest-flow state; explicit lifecycle/teardown support.
  • Tests

    • New multi-instance test suite validating isolation, client preservation, and lifecycle behavior.

…tracking and { config?, context?, instructions? } options so multiple isolated servers can coexist in one process while preserving legacy positional setup.
@jonathanMLDev jonathanMLDev self-assigned this Jun 10, 2026
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jonathanMLDev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 minutes and 10 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0ddd74db-fd1b-4c38-995f-385e748964a1

📥 Commits

Reviewing files that changed from the base of the PR and between 57bad8a and a0a53d8.

📒 Files selected for processing (1)
  • src/core/setup.ts
📝 Walkthrough

Walkthrough

This PR makes ServerContext instance-scoped: core/alliance setup accept optional context/options, per-context tool-registration and injected-client guards were added, docs/examples/CLI updated to an instance-first embedding flow, and tests validate multi-instance isolation and lifecycle.

Changes

Multi-instance ServerContext and Instance-first Setup API

Layer / File(s) Summary
ServerContext lifecycle and guards
src/core/server/server-context.ts
Add private flags and public helpers for injected-client tracking and MCP tool registration (hasToolsRegistered(), assertCanRegisterTools(), markToolsRegistered()), reset on teardown, and export peekDefaultServerContext() to read the process-default without creating one.
Core setup: context-aware initialization
src/core/setup.ts
Refactor setupCoreServer to accept `ServerConfig
Alliance setup: options + context wiring
src/alliance/setup.ts, src/alliance/index.ts
Refactor setupAllianceServer to accept `ServerConfig
Public API exports
src/core/index.ts
Export SetupCoreServerOptions alongside existing core exports to expose the new options API.
Examples, docs and CLI composition
README.md, docs/CONFIGURATION.md, docs/MIGRATION.md, examples/alliance/library-embedding-demo.ts, src/index.ts
Update documentation, example, and CLI wiring to demonstrate the instance-first embedding pattern: createServer(config)ctx.setClient(...)setupAllianceServer({ context: ctx }), with explicit teardown semantics; remove legacy setPineconeClient recipe from recommended flow.
Multi-instance and setup guard tests
src/core/setup-multi-instance.test.ts, src/core/setup-guards.test.ts, src/core/server/server-context.test.ts
Add/extend tests verifying two independent contexts can register tools without teardown between them, registries/caches/suggest-flow remain isolated, injected clients are preserved when provided, await-using disposal affects only the bound handle, and invalid option shapes throw TypeError.

Sequence Diagram(s)

sequenceDiagram
  participant Embedder
  participant createServer
  participant ctx as ServerContext
  participant setupCoreServer
  participant setupAllianceServer
  participant MCP as MCP Router

  Embedder->>createServer: createServer(config)
  createServer-->>ctx: new ServerContext
  Embedder->>ctx: ctx.setClient(pineconeClient)
  Embedder->>setupCoreServer: setupCoreServer({ config, context: ctx })
  setupCoreServer->>ctx: ctx.assertCanRegisterTools()
  setupCoreServer->>MCP: register core tools & handlers
  setupCoreServer->>ctx: ctx.markToolsRegistered()
  setupCoreServer-->>Embedder: ServerHandle
  Embedder->>setupAllianceServer: setupAllianceServer({ config, context: ctx })
  setupAllianceServer->>setupCoreServer: delegate (reuse ctx)
  setupAllianceServer->>MCP: register URL generators & Alliance tools
  setupAllianceServer-->>Embedder: ServerHandle
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • AuraMindNest
  • wpak-ai

Poem

🐰 Context by context, no more global state,
Each instance runs tidy, isolated and great.
Tools register once, caches stay in line—
Set up, inject, teardown, one context at a time. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and concisely describes the main change: introducing explicit context API for multi-instance ServerContext embedding, which is the central objective of this PR.
Linked Issues check ✅ Passed The PR fully implements all acceptance criteria from issue #141: context-based setup API for both setupCoreServer and setupAllianceServer, per-instance tool registration tracking, preservation of injected clients, updated CLI/examples/docs, and integration tests demonstrating isolation of multiple ServerContext instances.
Out of Scope Changes check ✅ Passed All changes are within scope: documentation updates align with code changes, test additions cover new multi-instance capability, and modifications to setup APIs, ServerContext, and exports directly support the explicit context API objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/MIGRATION.md (1)

43-55: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Migration “recommended” snippets use a risky call shape (Lines 43-55, 63-66).

These examples pass both config and context after ctx.setClient(...), which can clear injected client state. Please migrate examples to context-only setup calls when the context is already configured.

Also applies to: 63-66

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/MIGRATION.md` around lines 43 - 55, The migration example currently
calls ctx.setClient(...) then calls setupAllianceServer with both config and
context, which can overwrite or clear the injected client state; change the call
to only pass the context after configuring the ctx (i.e., call
setupAllianceServer({ context: ctx }) instead of setupAllianceServer({ config,
context: ctx })), and update the other snippet referenced (lines 63-66)
similarly; locate usages of createServer, ctx.setClient, and setupAllianceServer
to make this change.
🧹 Nitpick comments (2)
src/alliance/setup.ts (1)

33-47: ⚖️ Poor tradeoff

Normalization silently accepts invalid input objects.

Same issue as src/core/setup.ts: if configOrOptions is an object matching neither ServerConfig nor SetupAllianceServerOptions, the fallback on line 46 returns legacyOptions ?? {}, silently discarding invalid input.

🛡️ Suggested defensive check
 function normalizeSetupAllianceArgs(
   configOrOptions?: ServerConfig | SetupAllianceServerOptions,
   legacyOptions?: Pick<SetupAllianceServerOptions, 'instructions'>
 ): SetupAllianceServerOptions {
   if (configOrOptions === undefined) {
     return legacyOptions ?? {};
   }
   if (isServerConfig(configOrOptions)) {
     return { config: configOrOptions, ...legacyOptions };
   }
   if (isSetupAllianceServerOptions(configOrOptions)) {
     return { ...configOrOptions, ...legacyOptions };
   }
+  throw new TypeError('configOrOptions must be a ServerConfig or SetupAllianceServerOptions');
-  return legacyOptions ?? {};
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/alliance/setup.ts` around lines 33 - 47, The normalizeSetupAllianceArgs
function currently swallows unknown object shapes and returns legacyOptions, so
add a defensive check: after the existing isServerConfig and
isSetupAllianceServerOptions branches, detect when configOrOptions is a non-null
object that matches neither predicate and throw a clear TypeError (or assert)
indicating invalid input to normalizeSetupAllianceArgs and include the offending
value; use the existing type guard functions isServerConfig and
isSetupAllianceServerOptions to decide and reference them in the error message
so callers get immediate feedback instead of silently losing data.
src/core/setup.ts (1)

59-73: ⚖️ Poor tradeoff

Normalization silently accepts invalid input objects.

If configOrOptions is an object that matches neither ServerConfig nor SetupCoreServerOptions (e.g., { foo: 'bar' }), the fallback on line 72 returns legacyOptions ?? {}, silently discarding the invalid input without error. This loses type safety and could hide bugs when callers pass malformed objects.

🛡️ Suggested defensive check
 function normalizeSetupCoreServerArgs(
   configOrOptions?: ServerConfig | SetupCoreServerOptions,
   legacyOptions?: Pick<SetupCoreServerOptions, 'instructions'>
 ): SetupCoreServerOptions {
   if (configOrOptions === undefined) {
     return legacyOptions ?? {};
   }
   if (isServerConfig(configOrOptions)) {
     return { config: configOrOptions, ...legacyOptions };
   }
   if (isSetupCoreServerOptions(configOrOptions)) {
     return { ...configOrOptions, ...legacyOptions };
   }
+  throw new TypeError('configOrOptions must be a ServerConfig or SetupCoreServerOptions');
-  return legacyOptions ?? {};
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/setup.ts` around lines 59 - 73, The normalizeSetupCoreServerArgs
function currently swallows invalid objects (e.g., {foo:'bar'}) by falling back
to legacyOptions; change it to detect when configOrOptions is an object but
neither isServerConfig(configOrOptions) nor
isSetupCoreServerOptions(configOrOptions) and throw a clear TypeError (or
similar) instead of returning legacyOptions; update the function to perform this
defensive check after the two predicate checks and include the offending value
(or its type) in the error message so callers and tests can detect malformed
inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/CONFIGURATION.md`:
- Around line 66-69: The docs currently show calling setupAllianceServer({
config, context: ctx }) after creating a ctx and injecting the client; update
the instructions to avoid passing both config and context together once the
context has been fully configured. Change the examples to build ServerConfig via
resolveConfig(...) or resolveAllianceConfig(...), call const ctx =
createServer(config) and ctx.setClient(...), then call setupAllianceServer({
context: ctx }) (and likewise use setupCoreServer({ context: ctx }) for generic
tools) so only the already-configured context is passed; reference ServerConfig,
resolveConfig, resolveAllianceConfig, createServer, ctx.setClient,
setupAllianceServer, and setupCoreServer when making the edit.

In `@examples/alliance/library-embedding-demo.ts`:
- Line 44: The call to setupAllianceServer is passing both config and a
pre-configured ctx which can reset context state and drop injected clients;
update the invocation of setupAllianceServer (the example using
setupAllianceServer({ config, context: ctx })) to pass only the pre-configured
context (setupAllianceServer({ context: ctx })) after you create ctx and call
ctx.setClient(...) so the already-initialized context isn’t overwritten.
- Line 44: The call to setupAllianceServer passes both config and context which
can reset context state and drop injected clients; update the invocation of
setupAllianceServer so it only passes the context (ctx) and remove the config
argument (or ensure config does not include a pre-configured context) — locate
the setupAllianceServer(...) call and change it to pass just the context
parameter, keeping ctx as the injected client carrier.

In `@README.md`:
- Around line 139-144: The README shows passing a config that already contains a
pre-configured context which can clear injected clients and break embedding
flows; update the example so you do not embed the created server/context into
the config—call resolveAllianceConfig to build the config, createServer to build
the context and call ctx.setClient as needed, but when calling
setupAllianceServer pass only context via the context parameter (i.e.,
setupAllianceServer({ context: ctx })) and do not pass the config object that
contains the pre-configured ctx; update both occurrences around the example
lines and line 176 accordingly.

In `@src/alliance/setup.ts`:
- Around line 66-72: The bug is that setupAllianceServer passes a resolved
default config into setupCoreServer even when the caller did not provide
opts.config, which causes resolveSetupContext/context.setConfig to overwrite and
clear an injected client; change the call site in setupAllianceServer so that
setupCoreServer only receives a config property when opts.config is explicitly
provided (i.e., forward opts.config as-is, not opts.config ??
resolveAllianceConfig({})), preserving resolvedCtx and avoiding calling
context.setConfig implicitly; locate the call to setupCoreServer and the
surrounding resolvedCtx/opts handling to implement this conditional forwarding.

In `@src/core/setup.ts`:
- Around line 77-79: When both opts.config and opts.context are passed into
setupCoreServer, calling opts.context.setConfig(opts.config) can silently clear
an injected client via invalidateConfigDerivedState()/this.client; add a
defensive runtime guard in src/core/setup.ts before calling
opts.context.setConfig: check the context for an existing client (e.g., call
opts.context.getClient() or inspect opts.context.client accessor) and if a
client is present, throw a clear error (or at minimum log/warn and refuse to
overwrite) instructing callers to omit config when reusing a pre-configured
context; implement this check around the current
opts.context.setConfig(opts.config) call and include the symbols opts.config,
opts.context, setConfig, invalidateConfigDerivedState, and this.client in the
error message to aid debugging.

---

Outside diff comments:
In `@docs/MIGRATION.md`:
- Around line 43-55: The migration example currently calls ctx.setClient(...)
then calls setupAllianceServer with both config and context, which can overwrite
or clear the injected client state; change the call to only pass the context
after configuring the ctx (i.e., call setupAllianceServer({ context: ctx })
instead of setupAllianceServer({ config, context: ctx })), and update the other
snippet referenced (lines 63-66) similarly; locate usages of createServer,
ctx.setClient, and setupAllianceServer to make this change.

---

Nitpick comments:
In `@src/alliance/setup.ts`:
- Around line 33-47: The normalizeSetupAllianceArgs function currently swallows
unknown object shapes and returns legacyOptions, so add a defensive check: after
the existing isServerConfig and isSetupAllianceServerOptions branches, detect
when configOrOptions is a non-null object that matches neither predicate and
throw a clear TypeError (or assert) indicating invalid input to
normalizeSetupAllianceArgs and include the offending value; use the existing
type guard functions isServerConfig and isSetupAllianceServerOptions to decide
and reference them in the error message so callers get immediate feedback
instead of silently losing data.

In `@src/core/setup.ts`:
- Around line 59-73: The normalizeSetupCoreServerArgs function currently
swallows invalid objects (e.g., {foo:'bar'}) by falling back to legacyOptions;
change it to detect when configOrOptions is an object but neither
isServerConfig(configOrOptions) nor isSetupCoreServerOptions(configOrOptions)
and throw a clear TypeError (or similar) instead of returning legacyOptions;
update the function to perform this defensive check after the two predicate
checks and include the offending value (or its type) in the error message so
callers and tests can detect malformed inputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7af0ccaa-0fb5-4dd9-912e-71ce57e2d21f

📥 Commits

Reviewing files that changed from the base of the PR and between 5f65fc3 and 53a2700.

📒 Files selected for processing (11)
  • README.md
  • docs/CONFIGURATION.md
  • docs/MIGRATION.md
  • examples/alliance/library-embedding-demo.ts
  • src/alliance/index.ts
  • src/alliance/setup.ts
  • src/core/index.ts
  • src/core/server/server-context.ts
  • src/core/setup-multi-instance.test.ts
  • src/core/setup.ts
  • src/index.ts

Comment thread docs/CONFIGURATION.md
Comment thread examples/alliance/library-embedding-demo.ts Outdated
Comment thread README.md
Comment thread src/alliance/setup.ts Outdated
Comment thread src/core/setup.ts
@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.34615% with 9 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@5f65fc3). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/alliance/setup.ts 92.10% 3 Missing ⚠️
src/core/server/server-context.ts 86.36% 3 Missing ⚠️
src/core/setup.ts 93.18% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #150   +/-   ##
=======================================
  Coverage        ?   86.73%           
=======================================
  Files           ?       39           
  Lines           ?     1598           
  Branches        ?      552           
=======================================
  Hits            ?     1386           
  Misses          ?      210           
  Partials        ?        2           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@AuraMindNest
AuraMindNest requested a review from wpak-ai June 11, 2026 16:52
@wpak-ai
wpak-ai merged commit 61605dd into cppalliance:main Jun 11, 2026
12 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 15, 2026
3 tasks
@jonathanMLDev
jonathanMLDev deleted the feat/server-context-setup-api branch June 22, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setup / composition API

3 participants