Skip to content

feat: ServerContext lifecycle — AsyncDisposable + stale-handler guards - #148

Merged
wpak-ai merged 3 commits into
cppalliance:mainfrom
jonathanMLDev:feat/server-context-lifecycle
Jun 10, 2026
Merged

feat: ServerContext lifecycle — AsyncDisposable + stale-handler guards#148
wpak-ai merged 3 commits into
cppalliance:mainfrom
jonathanMLDev:feat/server-context-lifecycle

Conversation

@jonathanMLDev

@jonathanMLDev jonathanMLDev commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

week_plan_v1 Item 2: ServerContext now implements AsyncDisposable so embedders can use await using for automatic teardown, and all nine tool handlers reject invocations on a disposed context with a structured LIFECYCLE error instead of silently hitting nullified state.

Issues addressed

Changes

  • ServerContext implements AsyncDisposable; teardown() sets disposed = true before clearing owned state
  • ServerHandle (McpServer & AsyncDisposable) returned from setupCoreServer / setupAllianceServer; exported from package root
  • await using on a server handle tears down context and resets mcpServerInitialized so re-setup succeeds
  • teardownServer() unchanged (sync backward-compat path; same teardown() body)
  • New LIFECYCLE tool error code + lifecycleToolError() factory
  • Disposed guard at entry of all 9 tool handlers (ctx?.disposedLIFECYCLE)
  • tsconfig.json: "lib": ["ES2022", "ESNext.Disposable"]

Acceptance criteria

#134 (async-disposable)

  • ServerContext has [Symbol.asyncDispose]()
  • Dispose resets client, config, caches, URL registry, suggest-flow
  • setupCoreServer() return type enables await using
  • teardownServer() remains for manual teardown
  • Test: await using tears down on scope exit
  • esnext.disposable in tsconfig

#135 (stale-handler guards)

  • disposed flag set by teardown / dispose
  • Stale handler invocations return LIFECYCLE error
  • All 9 tools check ctx.disposed before executing
  • Re-setup after teardown produces fresh, working handlers
  • Integration tests: stale handler → LIFECYCLE; teardown → setup → success

Test plan

  • npm test — 215 tests pass
  • npm run typecheck / npm run build — pass
  • server-context.lifecycle.test.tsawait using on ServerContext and setupCoreServer
  • lifecycle.context.test.ts — stale closure, fresh cycle, setup → teardown → re-setup
  • tool-error.test.tsLIFECYCLE schema parse
  • CI green on PR

Notes for reviewers

  • ServerHandle[Symbol.asyncDispose] resets mcpServerInitialized in addition to context teardown — required so await using allows a second setupCoreServer() in the same process.
  • Guards use ctx?.disposed (optional ctx legacy path unchanged). Setup always passes ctx; stale-handler bug is closure-based.
  • Per-context mcpServerInitialized scoping (multi-instance without teardown) is deferred to week_plan_v1 Item 3 / phase 4 setup API.

Summary by CodeRabbit

  • Bug Fixes

    • Tools now return proper error responses when the server context is disposed, preventing unexpected failures
  • New Features

    • Server now supports async disposal protocol for cleaner resource cleanup
    • Added lifecycle error detection and reporting across query utilities

@jonathanMLDev jonathanMLDev self-assigned this Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements type-enforced lifecycle management for ServerContext via the AsyncDisposable protocol. ServerContext now tracks disposal state and implements Symbol.asyncDispose. A new ServerHandle type wraps McpServer with disposal semantics. All tool handlers check ctx?.disposed and return a LIFECYCLE error when invoked on disposed contexts, preventing stale reference bugs across setup cycles.

Changes

ServerContext Async Lifecycle and Tool Disposal Guards

Layer / File(s) Summary
AsyncDisposable protocol and ServerHandle
src/core/server/server-context.ts, src/core/setup.ts, tsconfig.json
ServerContext implements AsyncDisposable with a disposed flag set during teardown. ServerHandle type extends McpServer with disposal, and setupCoreServer returns a handle with Symbol.asyncDispose that resets global state on scope exit. TypeScript lib includes ESNext.Disposable.
LIFECYCLE error type and schema
src/core/server/tool-error.ts, src/core/server/tool-error.test.ts
New LIFECYCLE error code added to tool error schema with recoverable: false. Helper function lifecycleToolError() constructs error payloads. Test verifies schema parsing and non-recoverable status.
Core server tool disposal guards
src/core/server/tools/count-tool.ts, src/core/server/tools/generate-urls-tool.ts, src/core/server/tools/keyword-search-tool.ts, src/core/server/tools/list-namespaces-tool.ts, src/core/server/tools/namespace-router-tool.ts, src/core/server/tools/query-documents-tool.ts, src/core/server/tools/query-tool.ts
Eight core tools import lifecycleToolError and add early guards: if ctx?.disposed is true, return error immediately instead of executing business logic.
Alliance tool disposal guards
src/alliance/tools/guided-query-tool.ts, src/alliance/tools/suggest-query-params-tool.ts
Alliance tools apply the same ctx?.disposed guard pattern to prevent execution on disposed contexts.
Integration, exports, and lifecycle tests
src/alliance/setup.ts, src/core/index.ts, src/core/server/server-context.lifecycle.test.ts, src/core/server/tools/lifecycle.context.test.ts
setupAllianceServer return type updated to ServerHandle. ServerHandle re-exported from public API. Tests verify await using scope-exit teardown, stale handler invalidation after context teardown, and fresh handler recovery after re-initialization.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes span tool handlers and core infrastructure with consistent patterns (disposal checks, error construction, and lifecycle tests) applied across multiple files. Logic is straightforward but requires verification that all tool entry points implement the guard consistently, that teardown properly sets disposed state, and that the async disposal protocol is correctly wired through setupCoreServer and ServerHandle.

Possibly related PRs

Suggested reviewers

  • AuraMindNest
  • wpak-ai

Poem

🐰 Hop on, let the protocol guide the way,
await using makes cleanup automatic today,
Disposed flags prevent the stale-state fray,
With LIFECYCLE errors, we handle decay. 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.33% 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
Title check ✅ Passed The title 'feat: ServerContext lifecycle — AsyncDisposable + stale-handler guards' accurately summarizes the main changes: implementing AsyncDisposable protocol and adding disposed state checks across handlers.
Linked Issues check ✅ Passed All coding requirements from issues #134 and #135 are implemented: ServerContext implements AsyncDisposable, disposal resets state, setupCoreServer returns ServerHandle for await using, disposed flag is tracked and checked in all 9 tool handlers, new LIFECYCLE error code added, and comprehensive tests verify lifecycle behavior.
Out of Scope Changes check ✅ Passed All changes are directly related to ServerContext lifecycle management. The tsconfig.json update adds ESNext.Disposable support required for AsyncDisposable, and all tool modifications add disposal checks as specified in issue #135.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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: 3

🤖 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 `@src/core/server/server-context.lifecycle.test.ts`:
- Around line 1-59: This test file (the ServerContext lifecycle tests using
ServerContext, createServer, setupCoreServer and teardownServer) fails Prettier;
run the project's Prettier formatter against the file (or run the repo-wide
formatting command), apply the automatic fixes so whitespace/semicolons/spacing
match the project's config, then re-commit the updated file so CI formatting
checks pass.

In `@src/core/server/server-context.ts`:
- Around line 269-271: The async disposal currently calls this.teardown() but
leaves the singleton defaultContext pointing at the disposed instance; update
the async [Symbol.asyncDispose]() implementation to, after teardown, check if
defaultContext === this and if so clear/reset defaultContext (e.g., set to
undefined/null) so a future setupCoreServer path cannot reuse a disposed
context; reference the async disposal method ([Symbol.asyncDispose]),
teardown(), and defaultContext when making the change.

In `@src/core/setup.ts`:
- Around line 90-93: The disposal currently sets mcpServerInitialized = false
only after awaiting ctx[Symbol.asyncDispose](), so if that call throws the flag
stays true; update handle[Symbol.asyncDispose] to invoke
ctx[Symbol.asyncDispose]() inside a try block and move the mcpServerInitialized
= false into a finally block so the flag is always reset even on errors (refer
to handle[Symbol.asyncDispose], ctx[Symbol.asyncDispose] and the
mcpServerInitialized flag).
🪄 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: 3acaf03c-f583-4bd3-97f7-160f8ec2b110

📥 Commits

Reviewing files that changed from the base of the PR and between 09efc3c and 6a79711.

📒 Files selected for processing (18)
  • src/alliance/setup.ts
  • src/alliance/tools/guided-query-tool.ts
  • src/alliance/tools/suggest-query-params-tool.ts
  • src/core/index.ts
  • src/core/server/server-context.lifecycle.test.ts
  • src/core/server/server-context.ts
  • src/core/server/tool-error.test.ts
  • src/core/server/tool-error.ts
  • src/core/server/tools/count-tool.ts
  • src/core/server/tools/generate-urls-tool.ts
  • src/core/server/tools/keyword-search-tool.ts
  • src/core/server/tools/lifecycle.context.test.ts
  • src/core/server/tools/list-namespaces-tool.ts
  • src/core/server/tools/namespace-router-tool.ts
  • src/core/server/tools/query-documents-tool.ts
  • src/core/server/tools/query-tool.ts
  • src/core/setup.ts
  • tsconfig.json

Comment thread src/core/server/server-context.lifecycle.test.ts
Comment thread src/core/server/server-context.ts
Comment thread src/core/setup.ts
@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.37838% with 8 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@09efc3c). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/alliance/tools/guided-query-tool.ts 50.00% 1 Missing ⚠️
src/alliance/tools/suggest-query-params-tool.ts 50.00% 1 Missing ⚠️
src/core/server/tools/count-tool.ts 50.00% 1 Missing ⚠️
src/core/server/tools/generate-urls-tool.ts 50.00% 1 Missing ⚠️
src/core/server/tools/keyword-search-tool.ts 50.00% 1 Missing ⚠️
src/core/server/tools/list-namespaces-tool.ts 50.00% 1 Missing ⚠️
src/core/server/tools/namespace-router-tool.ts 50.00% 1 Missing ⚠️
src/core/server/tools/query-documents-tool.ts 50.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #148   +/-   ##
=======================================
  Coverage        ?   85.79%           
=======================================
  Files           ?       39           
  Lines           ?     1478           
  Branches        ?      495           
=======================================
  Hits            ?     1268           
  Misses          ?      208           
  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.

@jonathanMLDev
jonathanMLDev requested a review from wpak-ai June 10, 2026 14:56
@wpak-ai
wpak-ai merged commit d8105f4 into cppalliance:main Jun 10, 2026
12 checks passed
@jonathanMLDev
jonathanMLDev deleted the feat/server-context-lifecycle 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.

Fix leaked ServerContext stale state across setup cycles ServerContext teardown: type-enforced lifecycle with async-disposable

3 participants