AgentBack — REST Middleware Chain

Group-sorted cascade mounted as the first Express handler — fronts every route, including install* surfaces.

Express app · one per RestServer · app.expressApp Client HTTP / MCP request request response Middleware chain toExpressMiddleware(ctx) · mounted 1st (constructor) group: cors CORS headers · preflight short-circuit RestServerConfig.cors group: parseBody json · text · urlencoded · raw RestServerConfig.bodyParser (json default) group: middleware app.middleware() · app.expressMiddleware() default user group next() next() topological sort · sortListOfGroups() cors → parseBody → middleware edges from group + upstream/downstreamGroups next() → router result ↩ Mounted in app.start() @api controllers → RestServer.dispatch: • authenticate → 401 • authorize → 403 • confirm / idempotency • Zod validate input → 400 / 422 • resolveInjectedArguments (slot 1+) • handler — input bundle = slot 0 • Zod validate response (log on mismatch) • sendResult (JSON) ↩ framework routes: • /openapi.json · /llms.txt · /llms-full.txt • error handler — sendError (mounted last) Mounted BEFORE app.start() via install* helpers: • /mcp — StreamableHTTP (mcp-http) • /console · /explorer • /mcp-inspector behind the chain ✓ — chain mounts 1st (in start() these would shadow the chain) DI container · MiddlewareView extensionFor(DEFAULT_MIDDLEWARE_CHAIN) topo-sorts groups · refreshes on binding change resolved lazily, per request discovers + sorts Legend group: cors group: parseBody group: middleware (user) install* surfaces DI / MiddlewareView chain boundary next() — cascade unwind / response

The chain (group model)

  • • Cascading: each middleware gets next(); runs code before and after downstream
  • • Order is by group, not registration: cors → parseBody → middleware
  • • CORS & body parsers are chain entries, not bare app.use
  • • Body parsing configurable: RestServerConfig.bodyParser

Chain-first mount

  • • Mounted as the 1st Express handler in the RestServer constructor
  • • Matches upstream LB4 ExpressServer ("1st Express middleware")
  • • Fronts install* routes (/mcp, /console…) mounted before start()
  • • Resolved lazily per request — late-bound middleware still join

Ordering API

  • app.middleware(fn, {group, upstreamGroups, downstreamGroups})
  • • Names: RestMiddlewareGroups.{CORS, PARSE_BODY, MIDDLEWARE}
  • • Topological sort via sortListOfGroups() / MiddlewareView
  • • ⚠ A middleware-group fn pointing downstream at parseBody = cycle