Problem
The shared tool-call path threads flat plain values through every layer, so each signature is the union of everything below it: executeToolAndUpdateTask takes ~20 fields, dispatchToolCall ~19, prepareToolCall ~13, executeSyncToolCall ~11. Adding or removing one value touches every layer — e.g. removing loadedToolNames in #1155 changed four signatures.
Proposal
Group params by lifetime into plain-data context objects, built once at the adapter boundary:
SessionContext — fixed after initialize: tools, actorStore, paymentProvider, allowUnauthMode, telemetryEnabled, telemetryEnv, transportType, clientContext, taskStore
RequestContext — one per tools/call: apifyToken, apifyClient, mcpSessionId, progressToken, signal, sendNotification, emitLog, requestHeaders
- Call-specific args stay inline:
tool, toolArgs, logSafeArgs, taskMode, logContext
Engine functions declare the narrowest view they read (Pick<SessionContext, ...> or a small interface), callers pass the whole context — call sites shrink to ~3 arguments while signatures still document real dependencies.
Non-goals
- No single merged
Context holding all lifetimes (that's the server object again).
- No behavior in contexts beyond the existing
sendNotification/emitLog capabilities.
- No behavior change; mechanical refactor only.
Sequencing
After #1140 — a request-scoped tool map moves tools from session to request scope, so decide that boundary first. Relevant to #1128: a stateless adapter would build the same contexts from its own request state, making the context types the protocol-neutral contract.
Problem
The shared tool-call path threads flat plain values through every layer, so each signature is the union of everything below it:
executeToolAndUpdateTasktakes ~20 fields,dispatchToolCall~19,prepareToolCall~13,executeSyncToolCall~11. Adding or removing one value touches every layer — e.g. removingloadedToolNamesin #1155 changed four signatures.Proposal
Group params by lifetime into plain-data context objects, built once at the adapter boundary:
SessionContext— fixed after initialize:tools,actorStore,paymentProvider,allowUnauthMode,telemetryEnabled,telemetryEnv,transportType,clientContext,taskStoreRequestContext— one pertools/call:apifyToken,apifyClient,mcpSessionId,progressToken,signal,sendNotification,emitLog,requestHeaderstool,toolArgs,logSafeArgs,taskMode,logContextEngine functions declare the narrowest view they read (
Pick<SessionContext, ...>or a small interface), callers pass the whole context — call sites shrink to ~3 arguments while signatures still document real dependencies.Non-goals
Contextholding all lifetimes (that's the server object again).sendNotification/emitLogcapabilities.Sequencing
After #1140 — a request-scoped tool map moves
toolsfrom session to request scope, so decide that boundary first. Relevant to #1128: a stateless adapter would build the same contexts from its own request state, making the context types the protocol-neutral contract.