Context
Filed 2026-05-08 as the AC10 follow-up from M2 #10965. M2 substrate landed in dev across PR1 (#10966 BaseServer scaffold) + PR2-PR6 (5 per-server migrations: knowledge-base #10973, github-workflow #10974, neural-link #10975, memory-core #10977, file-system #10976) on 2026-05-08. AC10 of #10965 — "Documentation: either new learn/agentos/tooling/MCPServerBaseClass.md OR §-section added to learn/agentos/tooling/Introduction.md describing the extension contract + when to override which hook" — was deferred during the per-server migration sequence.
Per feedback_close_as_completed_authority discipline, #10965 stays open until AC10 lands or operator resolves the gap explicitly.
The Problem
ai/mcp/server/BaseServer.mjs has a substantial extension surface (2 required hooks + 8+ optional hooks + composable lifecycle hooks + the boot() overridable seam). Future per-server-authors (or external developers building on the substrate via M6 SDK migration) need a single canonical doc to:
- Understand which hooks to override for which per-server behavior
- Choose between the canonical
boot() vs custom boot() override paths
- Use the right escape-hatch for non-canonical bootstrap orders
- Avoid re-inventing patterns already covered by hooks (e.g.
onHealthGateFailure for telemetry, beforeToolDispatch for pre-validation, wrapDispatch for context wrapping)
Currently this knowledge is scattered across:
- BaseServer.mjs class-level JSDoc (good but verbose)
- 5 per-server
Server.mjs files (concrete examples, but no comparative narrative)
- BaseServer.spec.mjs unit tests (validates contracts but reads as test code, not pedagogy)
The Architectural Reality
Target surface: learn/agentos/tooling/MCPServerBaseClass.md (new) OR §-section in learn/agentos/tooling/Introduction.md (existing — preferred since Introduction.md already covers the broader MCP server architecture).
Audience:
- Per-server-authors maintaining the 5 in-tree servers
- M6 SDK migration consumers (Tier-1 only) — external users building on the same primitive
- Future cross-family agents picking up M-milestone work cold
Recommended pattern: §-section in Introduction.md keeps the doc ecosystem flat (no proliferation of doc files); a dedicated MCPServerBaseClass.md is appropriate only if the section grows past ~300 lines.
Decision: prefer §-section in Introduction.md; promote to dedicated file if section bloat warrants.
The Fix
Add §"MCP Server Base Class — extension contract" section to learn/agentos/tooling/Introduction.md covering:
- What BaseServer is — class-hierarchy ancestor for all 5 MCP servers; standardizes bootstrap/setupRequestHandlers/result-formatting/transport-connect into shared template-method scaffolding
- The two required override hooks —
getServerMetadata, getToolService. With concrete examples from the 5 in-tree servers
- Optional override hooks with when-to-use guidance:
getDependentServices — for services with ready() to await
getHealthExemptTools — for tools that bypass the health gate
getHealthService — for health-gated dispatch (default null = no gate)
wrapDispatch — for tool-dispatch context wrapping (memory-core: RequestContextService.run() for tenant binding)
beforeToolDispatch — for pre-dispatch validation that must fire before health gate (memory-core: AuthMiddleware.validateNoIdentitySpoof)
onHealthGateFailure — for telemetry on health-gate rejection (knowledge-base: KBRecorderService.log)
logStartupStatus — for per-server startup-output formatting
buildRequestContext — SSE-only per-request context construction
onSessionClosed — SSE-only session-disconnect cleanup
- Composable lifecycle hooks (
beforeMcpServerInit, beforeHealthcheck, afterHealthcheck, afterTransportConnected) — when to use no-op hooks vs override boot()
- The
boot() overridable seam — when canonical sequence vs custom override:
- Canonical sequence is sufficient when the per-server bootstrap order is: load-config → init-mcp → wait-services → healthcheck → transport. (PR2/PR3/PR6 use this.)
- Custom
boot() override when bootstrap order is non-canonical (e.g. neural-link's transport-before-services for MCP-handshake-tolerance per PR4; memory-core's stdio-identity-resolution between dependent-services and healthcheck per #10249 in PR5)
- Per-server reference table — quick lookup of which hooks each in-tree server overrides + why
- Common patterns the abstraction handles for free (vs what previously had to be hand-rolled per server) — quantified by the LOC reductions in PR2-PR6 (-50% / -51% / -30% / -28% / -60%)
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
learn/agentos/tooling/Introduction.md §-section |
This ticket; #10965 AC10 |
New §"MCP Server Base Class — extension contract" with the structure above |
Promote to standalone MCPServerBaseClass.md if section grows past ~300 lines |
This ticket §The Fix |
KB build picks up the section; ask_knowledge_base returns the doc when queried for "MCP server BaseServer extension hooks" |
Acceptance Criteria
Out of Scope
- Refactoring BaseServer.mjs's class-level JSDoc — the JSDoc IS the source of truth for behavior; this ticket adds pedagogical narrative around it, doesn't replace it.
- M6 SDK external-facing API docs — separate ticket per server, sequenced after M6 lands per-server SDKs.
- Breaking changes to the BaseServer contract — this is documentation only.
Avoided Traps / Gold Standards Rejected
- Rejected: dedicated
MCPServerBaseClass.md file upfront. Introduction.md already covers MCP server architecture; flat doc structure scales better than one-file-per-primitive. Promote only if section grows past readability threshold.
- Rejected: duplicate the BaseServer JSDoc in markdown. JSDoc is the single source of truth; markdown narrative complements it without duplicating content.
- Rejected: defer until M6 SDK migration. AC10 is part of M2's substrate definition; deferring it means M2 #10965 can't close-as-completed cleanly. Land it as a focused doc PR while the substrate is fresh in everyone's mind.
Related
- Parent ticket: #10965 — M2 BaseServer (this is the AC10 follow-up)
- Source primitives (in dev):
- Sibling milestone tickets:
- Adjacent doc surfaces:
learn/agentos/tooling/Introduction.md
learn/agentos/tooling/MemoryCoreMcpApi.md (per-server reference; pattern for the new section)
Origin Session ID: 005b6edf-85d8-4980-9e17-486b6b8bed3f
Retrieval Hint: query_raw_memories(query="MCP server BaseServer extension contract documentation hooks override boot seam M2 AC10")
Context
Filed 2026-05-08 as the AC10 follow-up from M2 #10965. M2 substrate landed in dev across PR1 (#10966 BaseServer scaffold) + PR2-PR6 (5 per-server migrations: knowledge-base #10973, github-workflow #10974, neural-link #10975, memory-core #10977, file-system #10976) on 2026-05-08. AC10 of #10965 — "Documentation: either new
learn/agentos/tooling/MCPServerBaseClass.mdOR §-section added tolearn/agentos/tooling/Introduction.mddescribing the extension contract + when to override which hook" — was deferred during the per-server migration sequence.Per
feedback_close_as_completed_authoritydiscipline, #10965 stays open until AC10 lands or operator resolves the gap explicitly.The Problem
ai/mcp/server/BaseServer.mjshas a substantial extension surface (2 required hooks + 8+ optional hooks + composable lifecycle hooks + theboot()overridable seam). Future per-server-authors (or external developers building on the substrate via M6 SDK migration) need a single canonical doc to:boot()vs customboot()override pathsonHealthGateFailurefor telemetry,beforeToolDispatchfor pre-validation,wrapDispatchfor context wrapping)Currently this knowledge is scattered across:
Server.mjsfiles (concrete examples, but no comparative narrative)The Architectural Reality
Target surface:
learn/agentos/tooling/MCPServerBaseClass.md(new) OR §-section inlearn/agentos/tooling/Introduction.md(existing — preferred since Introduction.md already covers the broader MCP server architecture).Audience:
Recommended pattern: §-section in Introduction.md keeps the doc ecosystem flat (no proliferation of doc files); a dedicated
MCPServerBaseClass.mdis appropriate only if the section grows past ~300 lines.Decision: prefer §-section in Introduction.md; promote to dedicated file if section bloat warrants.
The Fix
Add §"MCP Server Base Class — extension contract" section to
learn/agentos/tooling/Introduction.mdcovering:getServerMetadata,getToolService. With concrete examples from the 5 in-tree serversgetDependentServices— for services withready()to awaitgetHealthExemptTools— for tools that bypass the health gategetHealthService— for health-gated dispatch (default null = no gate)wrapDispatch— for tool-dispatch context wrapping (memory-core:RequestContextService.run()for tenant binding)beforeToolDispatch— for pre-dispatch validation that must fire before health gate (memory-core:AuthMiddleware.validateNoIdentitySpoof)onHealthGateFailure— for telemetry on health-gate rejection (knowledge-base:KBRecorderService.log)logStartupStatus— for per-server startup-output formattingbuildRequestContext— SSE-only per-request context constructiononSessionClosed— SSE-only session-disconnect cleanupbeforeMcpServerInit,beforeHealthcheck,afterHealthcheck,afterTransportConnected) — when to use no-op hooks vs overrideboot()boot()overridable seam — when canonical sequence vs custom override:boot()override when bootstrap order is non-canonical (e.g. neural-link's transport-before-services for MCP-handshake-tolerance per PR4; memory-core's stdio-identity-resolution between dependent-services and healthcheck per #10249 in PR5)Contract Ledger Matrix
learn/agentos/tooling/Introduction.md§-sectionMCPServerBaseClass.mdif section grows past ~300 linesask_knowledge_basereturns the doc when queried for "MCP server BaseServer extension hooks"Acceptance Criteria
learn/agentos/tooling/Introduction.md(or newMCPServerBaseClass.mdif section warrants standalone treatment).boot()seam, per-server reference table, LOC-reduction quantification.boot()override section covers BOTH canonical-sufficient cases (PR2/PR3/PR6) AND custom-required cases (PR4 neural-link, PR5 memory-core) with rationale.ask_knowledge_base(query="MCP server BaseServer extension hooks")returns the section.Out of Scope
Avoided Traps / Gold Standards Rejected
MCPServerBaseClass.mdfile upfront. Introduction.md already covers MCP server architecture; flat doc structure scales better than one-file-per-primitive. Promote only if section grows past readability threshold.Related
ai/mcp/server/BaseServer.mjs(class-level JSDoc)Server.mjsfiles post-migrationlearn/agentos/tooling/Introduction.mdlearn/agentos/tooling/MemoryCoreMcpApi.md(per-server reference; pattern for the new section)Origin Session ID:
005b6edf-85d8-4980-9e17-486b6b8bed3fRetrieval Hint:
query_raw_memories(query="MCP server BaseServer extension contract documentation hooks override boot seam M2 AC10")