LearnNewsExamplesServices
Frontmatter
id10982
titleMigrate per-server MCP services to flatter SDK structure
stateClosed
labels
epicaiarchitecture
assignees[]
createdAtMay 8, 2026, 8:12 PM
updatedAtMay 17, 2026, 9:05 PM
githubUrlhttps://github.com/neomjs/neo/issues/10982
authorneo-opus-4-7
commentsCount2
parentIssue10960
subIssues
10983 Migrate knowledge-base services to flatter SDK structure (M6 KB)
11161 Migrate knowledge-base services to SDK (M6 Tier-1)
11224 Migrate memory-core services to flatter SDK structure (M6 MC)
subIssuesCompleted3
subIssuesTotal3
blockedBy[]
blocking[]
closedAtMay 17, 2026, 9:05 PM

Migrate per-server MCP services to flatter SDK structure

Closedepicaiarchitecture
neo-opus-4-7
neo-opus-4-7 commented on May 8, 2026, 8:12 PM

Context

Filed 2026-05-08 as the canonical anchor for M6 of the v13 release path per learn/agentos/v13-path.md §4. M2 (BaseServer common class — #10965) shipped today plus M3/M4/M5 closed; M6 is the next architecturally substantive wave, currently NOT STARTED with no prep tickets filed per the #10960 status snapshot.

The Problem

ai/services.mjs is mature SDK substrate — already consumed by operator scripts (ai:summarize-sessions, ai:run-sandman, ai:backup), tests, and the Memory Core's own processPendingSummarizations path. But its imports today reach into per-server directories:

import KB_QueryService from './mcp/server/knowledge-base/services/QueryService.mjs';
import Memory_Service  from './mcp/server/memory-core/services/MemoryService.mjs';

This couples the SDK to per-server filesystem layout. With M2's BaseServer landed (PR #10966 + #10973-#10977) proving uniform Factory-pattern application across all 5 servers, the natural next move is decoupling service implementations from MCP server hosting: services flatten into the SDK boundary, MCP server Server.mjs files shrink to <50 LOC thin endpoint wrappers consuming services via SDK rather than via local imports.

The Architectural Reality

Empirical scope (verified 2026-05-08, dev ad952a10f):

Server Server.mjs LOC Service files Migration size
file-system 61 2 trivially small (already near target)
github-workflow 110 ~12 + queries/ + sync/ subdirs LARGE
knowledge-base 139 ~10 LARGE
memory-core 417 ~14 + lifecycle/ subdir XL (biggest lift)
neural-link 149 ~9 MEDIUM

Per v13-path.md §4 M6 exit gate: per-server Server.mjs files target <50 LOC.

The migration shape per v13-path.md D4:

  1. Services move OUT of ai/mcp/server/<server>/services/* into a flatter SDK structure (final layout TBD per first sub-ticket review)
  2. ai/services.mjs imports from new locations preserving namespaced prefixes (KB_*, Memory_*, GH_*, NL_*) — non-negotiable for SDK consumer compatibility
  3. Per-server Server.mjs imports services via SDK rather than directly from per-server services/
  4. BaseServer extension (M2 substrate) keeps server-specific tool registration; service singletons become SDK-owned

Critical invariant (M2 substrate carryover): the BaseServer's Factory pattern uniform application via RequestContextService.run({...}, ...) MUST remain intact. SDK-side service consumers must operate inside RequestContext when called via MCP dispatch; daemon-side calls without context still work via SHARED_USER_ID fallback per #10556.

The Fix

This epic decomposes into 4 Tier-1 sub-tickets (one per server with substantive service code):

  • KB SDK migration — knowledge-base services flattened to SDK; ~10 services + ChromaManager + toolService relocated
  • MC SDK migration — memory-core services flattened; ~14 services + lifecycle subdirs (largest lift; staged in 2-3 PRs likely)
  • GH-WF SDK migration — github-workflow services flattened; ~12 services + queries/sync subdirs
  • NL SDK migration — neural-link services flattened; ~9 services

file-system (61 LOC, 2 services) does NOT warrant its own sub-ticket per feedback_substrate_scope_restraint — overhead exceeds work; cleanup absorbed via incremental polish.

Each Tier-1 sub-ticket follows the same pattern:

  1. Move service files: ai/mcp/server/<server>/services/* → SDK-owned location
  2. Update ai/services.mjs imports preserving namespaced prefixes
  3. Update per-server Server.mjs to import from SDK; shrink to <50 LOC
  4. Verify Factory pattern uniformity (RequestContextService wraps dispatch unchanged)
  5. Run unit + integration matrix; capture LOC delta in PR body per AC7

Acceptance Criteria

  • AC1: All 4 Tier-1 sub-tickets filed under this epic via update_issue_relationship
  • AC2: All 4 Tier-1 sub-tickets shipped with cross-family review approval
  • AC3: Per-server Server.mjs files <50 LOC for all 5 servers (file-system trivially compliant; remaining 4 via sub-tickets)
  • AC4: ai/services.mjs imports point at flattened SDK layout, not per-server services/ dirs
  • AC5: Factory pattern (RequestContextService) uniform application preserved across all 5 servers (regression check via unit matrix)
  • AC6: No service-call-site signature changes — SDK consumers (operator scripts, tests, daemons) continue to import named singletons unchanged
  • AC7: Outcome metric: LOC moved from MCP server dirs → SDK measured per v13-path.md §8 target (>30% of pre-migration service LOC); reported in this epic's closing comment

Out of Scope

  • Service-internal refactors (separate tickets if needed)
  • Adding new tools or expanding service surface
  • file-system server migration as a dedicated PR (absorbed via incremental polish)
  • M7 release-cut work (separate epic)
  • Daemon scheduling changes (M3/M4 already complete)

Avoided Traps / Gold Standards Rejected

  • Rejected: bundle all 4 server migrations into one mega-PR. Per feedback_substrate_scope_restraint — per-server PRs are review-tractable; mega-PR reviews fragment.
  • Rejected: rename services during migration. Renaming + relocation in one PR doubles diff size. Migration preserves names + namespace prefixes; rename concerns deferred to follow-up tickets if needed.
  • Rejected: change SDK import path from ai/services.mjs to per-domain barrels. SDK consumers across the codebase already import from ai/services.mjs; switching would force a cascading breaking change. Internal layout flattens; external API stays.
  • Rejected: include file-system server as its own sub-ticket. Empirically 61 LOC + 2 services; the per-ticket overhead exceeds the work.

Related

  • Parent: #10960 (v13 Release Tracking)
  • Parent epic: #9999 (Cloud-Native Knowledge & Multi-Tenant Memory Core, v13 main epic)
  • Strategic anchor: learn/agentos/v13-path.md §4 M6 + D4 + §8 outcome metrics
  • M2 substrate predecessor: #10965 (BaseServer common class) — closed; provides the substrate this epic builds on
  • M3 daemon predecessor: #10956 (Memory Core summary sweeps to daemon) — closed
  • Sub-tickets: KB (forthcoming this session), MC + GH-WF + NL (forthcoming subsequent sessions; any agent can file following KB as template)

Origin Session ID: 7da190eb-af19-4e98-a3e2-f21f94f676c1

Retrieval Hint: query_raw_memories(query="M6 SDK migration per-server flatter SDK structure thin endpoint wrappers v13")