v2 - RFC Extract Tasks out of protocol.ts into TaskManager#1673
Conversation
…re and task MQ on constructor
🦋 Changeset detectedLatest commit: 3b7c0fd The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/server
@modelcontextprotocol/express
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
…lity' of github.com:KKonstantinov/typescript-sdk into feature/extract-tasks-in-task-manager-trigger-on-capability
|
Just leaving this thought process here. I wonder if looping through _modules just to support multiple modules (where we have only one right now) is premature abstraction/generalization here. This could fall back to direct calling of the task module now (while keeping it running only if the task capability is declared), and if additional modules are added in the future, this could probably be done in a 15 minute change/iteration. Wondering if it is worth the indirection today - probably not. Any new "module" I imagine would be a significant feature coming from the protocol spec and not a random SDK-level feature. Thus, it would have to be carefully implemented and reviewed anyway; and the looping of the _modules etc. could be added at that point. The real two benefits would be - tasks code runs runtime only if tasks is declared as a capability; ProtocolModule interface and Protocol Module could still exist if we removed the multi-module speculative abstraction; Still holds value in defining the contract, but Protocol would call the module directly rather than looping. Right now reading through the loop of _modules and seems like added cognitive complexity - but wanted to see how it'd look like. Leaving it as-is right now, but happy to remove that |
Based on #1449
Extract all task orchestration logic (creation, polling, queuing, routing) from the monolithic
Protocolclass into a dedicatedTaskManagerclass that implements a newProtocolModuleinterface.TaskManageris only instantiated whencapabilities.tasksis declared, keeping Protocol lean for non-task use cases.Motivation and Context
The
Protocolclass had grown to ~1800 lines, with roughly half dedicated to task management. This made it difficult to reason about, test, and extend independently. Extracting tasks intoTaskManagerachieves:ProtocolModuleinterface allows future modules to hook into request/response/notification lifecycle without modifying Protocolextra/ctxtask fields are grouped under a singletaskobject instead of scattered top-level propertiesHow Has This Been Tested?
pnpm test:all)pnpm typecheck:allpasses (except a pre-existing unrelated type error inexamples/client)experimental.tasks.*APIsInMemoryTaskStoreon both client and serverBreaking Changes
ProtocolOptions.taskStorecapabilities.tasks.taskStore(onClientOptions/ServerOptions)ProtocolOptions.taskMessageQueuecapabilities.tasks.taskMessageQueue(onClientOptions/ServerOptions)Protocol.assertTaskCapability()(abstract)TaskManagerOptionsProtocol.assertTaskHandlerCapability()(abstract)TaskManagerOptionsTypes of changes
Checklist
Additional context
New files:
packages/core/src/shared/taskManager.ts—TaskManagerclass implementingProtocolModulepackages/core/src/shared/protocolModule.ts—ProtocolModuleinterface and lifecycle typesArchitecture: Protocol now maintains a
_modulesarray. During request/response/notification processing, it delegates to each registered module in order. TaskManager is the first (and currently only) module. The interface is designed so additional modules can be added without further changes to Protocol.Test fixes: Integration tests for
createMessageStreamandelicitInputStreamwere updated to declaretaskscapability on the server, sinceexperimental.tasks.*methods correctly require it. ThecreateMessageStreamtask-related tests were also restructured with sharedbeforeEach/afterEachto eliminate repeated inline server creation.