AgentBack โ€” /mcp Request Lifecycle

A POST flows โ‘ โ†’โ‘ฆ through the group-sorted cascade into the route; an OPTIONS preflight short-circuits at โ‘ . Companion to middleware-chain.html.

next() next() next() โ†’ router OPTIONS preflight over rate limit guard rejects Client / Browser POST or OPTIONS /mcp Chain front door app.use(toExpressMiddleware) โ€” mounted 1st (constructor) resolves + group-sorts the chain per request โ‘  group: cors stamp Access-Control-* headers POST โ†’ next() ยท OPTIONS preflight โ†’ 204 (โœ— next) โ‘ก group: parseBody express.json() โ†’ req.body marks req._body = true โ‘ข group: middleware app.middleware(rateLimiter) under limit โ†’ next() POST /mcp route installMcpHttp โ€” mounted before start(), behind the chain โ‘ฃ ...guards โ€” authenticate โ†’ set req.auth { scopes } โ‘ค express.json() โ€” req._body set in โ‘ก โ†’ SKIP โ‘ฅ handler โ€” isInitializeRequest(req.body) โœ“ buildServer({ scopes }).connect(transport) โ‘ฆ transport.handleRequest(req, res, req.body) โ†’ JSON-RPC initialize result guards (โ‘ฃ) come from strategyAuth / OAuth โ€” per-route, not in the chain (MCP auth is session/scope-aware) 200 โ€” SSE / JSON-RPC stream server โ†’ client over Streamable HTTP OPTIONS preflight โ†’ 204 cascade STOPS at โ‘  โ€” no body, no auth, no transport over limit โ†’ 429 short-circuits before the router guard reject โ†’ 401 + WWW-Authenticate transport never built Legend chain front door cors / short-circuit parseBody middleware / success install* route (/mcp) next() (cascade continues) short-circuit exit (โœ— next)

Resolved order (POST)

  • โ€ข Chain is the 1st handler; cascade is group-sorted: cors โ†’ parseBody โ†’ middleware
  • โ€ข Each calls next(); on cascade end, toExpressMiddleware calls Express next() โ†’ router
  • โ€ข /mcp route (mounted by installMcpHttp) is the destination behind the chain
  • โ€ข โ‘ค the route's own express.json() no-ops (req._body set in โ‘ก)

Short-circuit exits

  • โ€ข OPTIONS preflight โ†’ cors ends 204 at โ‘ , no next() (cheapest exit)
  • โ€ข rate limit exceeded โ†’ 429 at โ‘ข, before the router
  • โ€ข auth guard rejects โ†’ 401 at โ‘ฃ, transport never built
  • โ€ข A non-preflight POST never short-circuits at โ‘  โ€” cors just stamps headers

Layering

  • โ€ข Edge concerns (cors, body, rate-limit) live in the chain โ€” uniform across all routes
  • โ€ข Identity (โ‘ฃ req.auth/scopes) lives on the /mcp route โ€” session/scope-aware
  • โ€ข Different layers, no collision: that's why the chain-first + per-session changes compose
  • โ€ข bodyParser:false โ†’ โ‘ก skipped, โ‘ค becomes the real parser; /mcp still works