@@ -60,6 +60,17 @@ import type { Transport, TransportSendOptions } from './transport.js';
6060 */
6161export type ProgressCallback = ( progress : Progress ) => void ;
6262
63+ /**
64+ * A JSON-RPC message that can be transformed by middleware.
65+ */
66+ export type JSONRPCMessageLike = JSONRPCRequest | JSONRPCNotification | JSONRPCResponse | JSONRPCResultResponse | JSONRPCErrorResponse ;
67+
68+ /**
69+ * Middleware function for transforming JSON-RPC messages.
70+ * Can be sync (returns message) or async (returns Promise<message>).
71+ */
72+ export type MessageMiddleware = ( message : JSONRPCMessageLike ) => JSONRPCMessageLike | Promise < JSONRPCMessageLike > ;
73+
6374/**
6475 * Additional initialization options.
6576 */
@@ -102,6 +113,16 @@ export type ProtocolOptions = {
102113 * appropriately (e.g., by failing the task, dropping messages, etc.).
103114 */
104115 maxTaskQueueSize ?: number ;
116+ /**
117+ * Middleware functions to apply to outgoing messages before sending.
118+ * Middleware is applied in order, with each function receiving the output of the previous.
119+ */
120+ sendMiddleware ?: MessageMiddleware [ ] ;
121+ /**
122+ * Middleware functions to apply to incoming messages after receiving.
123+ * Middleware is applied in order, with each function receiving the output of the previous.
124+ */
125+ receiveMiddleware ?: MessageMiddleware [ ] ;
105126} ;
106127
107128/**
@@ -603,6 +624,25 @@ export abstract class Protocol<SendRequestT extends Request, SendNotificationT e
603624 }
604625 }
605626
627+ /**
628+ * Applies a list of middleware functions to a message.
629+ * Middleware is applied in order, with each function receiving the output of the previous.
630+ */
631+ private async _applyMiddleware < T extends JSONRPCMessageLike > (
632+ message : T ,
633+ middlewareList : MessageMiddleware [ ] | undefined
634+ ) : Promise < T > {
635+ if ( ! middlewareList || middlewareList . length === 0 ) {
636+ return message ;
637+ }
638+
639+ let result : JSONRPCMessageLike = message ;
640+ for ( const middleware of middlewareList ) {
641+ result = await middleware ( result ) ;
642+ }
643+ return result as T ;
644+ }
645+
606646 /**
607647 * Attaches to the given transport, starts it, and starts listening for messages.
608648 *
@@ -625,15 +665,21 @@ export abstract class Protocol<SendRequestT extends Request, SendNotificationT e
625665 const _onmessage = this . _transport ?. onmessage ;
626666 this . _transport . onmessage = ( message , extra ) => {
627667 _onmessage ?.( message , extra ) ;
628- if ( isJSONRPCResultResponse ( message ) || isJSONRPCErrorResponse ( message ) ) {
629- this . _onresponse ( message ) ;
630- } else if ( isJSONRPCRequest ( message ) ) {
631- this . _onrequest ( message , extra ) ;
632- } else if ( isJSONRPCNotification ( message ) ) {
633- this . _onnotification ( message ) ;
634- } else {
635- this . _onerror ( new Error ( `Unknown message type: ${ JSON . stringify ( message ) } ` ) ) ;
636- }
668+
669+ // Apply receive middleware and then route the message
670+ this . _applyMiddleware ( message , this . _options ?. receiveMiddleware )
671+ . then ( transformedMessage => {
672+ if ( isJSONRPCResultResponse ( transformedMessage ) || isJSONRPCErrorResponse ( transformedMessage ) ) {
673+ this . _onresponse ( transformedMessage ) ;
674+ } else if ( isJSONRPCRequest ( transformedMessage ) ) {
675+ this . _onrequest ( transformedMessage , extra ) ;
676+ } else if ( isJSONRPCNotification ( transformedMessage ) ) {
677+ this . _onnotification ( transformedMessage ) ;
678+ } else {
679+ this . _onerror ( new Error ( `Unknown message type: ${ JSON . stringify ( transformedMessage ) } ` ) ) ;
680+ }
681+ } )
682+ . catch ( error => this . _onerror ( new Error ( `Receive middleware error: ${ error } ` ) ) ) ;
637683 } ;
638684
639685 await this . _transport . start ( ) ;
@@ -1211,23 +1257,38 @@ export abstract class Protocol<SendRequestT extends Request, SendNotificationT e
12111257 } ;
12121258 this . _requestResolvers . set ( messageId , responseResolver ) ;
12131259
1214- this . _enqueueTaskMessage ( relatedTaskId , {
1215- type : 'request' ,
1216- message : jsonrpcRequest ,
1217- timestamp : Date . now ( )
1218- } ) . catch ( error => {
1219- this . _cleanupTimeout ( messageId ) ;
1220- reject ( error ) ;
1221- } ) ;
1260+ // Apply send middleware before queuing
1261+ this . _applyMiddleware ( jsonrpcRequest , this . _options ?. sendMiddleware )
1262+ . then ( transformedRequest => {
1263+ this . _enqueueTaskMessage ( relatedTaskId , {
1264+ type : 'request' ,
1265+ message : transformedRequest as JSONRPCRequest ,
1266+ timestamp : Date . now ( )
1267+ } ) . catch ( error => {
1268+ this . _cleanupTimeout ( messageId ) ;
1269+ reject ( error ) ;
1270+ } ) ;
1271+ } )
1272+ . catch ( error => {
1273+ this . _cleanupTimeout ( messageId ) ;
1274+ reject ( error ) ;
1275+ } ) ;
12221276
12231277 // Don't send through transport - queued messages are delivered via tasks/result only
12241278 // This prevents duplicate delivery for bidirectional transports
12251279 } else {
1226- // No related task - send through transport normally
1227- this . _transport . send ( jsonrpcRequest , { relatedRequestId, resumptionToken, onresumptiontoken } ) . catch ( error => {
1228- this . _cleanupTimeout ( messageId ) ;
1229- reject ( error ) ;
1230- } ) ;
1280+ // No related task - apply send middleware and send through transport normally
1281+ this . _applyMiddleware ( jsonrpcRequest , this . _options ?. sendMiddleware )
1282+ . then ( transformedRequest => {
1283+ this . _transport ! . send ( transformedRequest as JSONRPCRequest , { relatedRequestId, resumptionToken, onresumptiontoken } ) . catch ( error => {
1284+ this . _cleanupTimeout ( messageId ) ;
1285+ reject ( error ) ;
1286+ } ) ;
1287+ } )
1288+ . catch ( error => {
1289+ this . _cleanupTimeout ( messageId ) ;
1290+ reject ( error ) ;
1291+ } ) ;
12311292 }
12321293 } ) ;
12331294 }
@@ -1302,9 +1363,12 @@ export abstract class Protocol<SendRequestT extends Request, SendNotificationT e
13021363 }
13031364 } ;
13041365
1366+ // Apply send middleware before queuing
1367+ const transformedNotification = await this . _applyMiddleware ( jsonrpcNotification , this . _options ?. sendMiddleware ) ;
1368+
13051369 await this . _enqueueTaskMessage ( relatedTaskId , {
13061370 type : 'notification' ,
1307- message : jsonrpcNotification ,
1371+ message : transformedNotification as JSONRPCNotification ,
13081372 timestamp : Date . now ( )
13091373 } ) ;
13101374
@@ -1358,9 +1422,13 @@ export abstract class Protocol<SendRequestT extends Request, SendNotificationT e
13581422 } ;
13591423 }
13601424
1361- // Send the notification, but don't await it here to avoid blocking .
1425+ // Apply send middleware and send the notification .
13621426 // Handle potential errors with a .catch().
1363- this . _transport ?. send ( jsonrpcNotification , options ) . catch ( error => this . _onerror ( error ) ) ;
1427+ this . _applyMiddleware ( jsonrpcNotification , this . _options ?. sendMiddleware )
1428+ . then ( transformedNotification => {
1429+ this . _transport ?. send ( transformedNotification as JSONRPCNotification , options ) . catch ( error => this . _onerror ( error ) ) ;
1430+ } )
1431+ . catch ( error => this . _onerror ( error ) ) ;
13641432 } ) ;
13651433
13661434 // Return immediately.
@@ -1386,7 +1454,9 @@ export abstract class Protocol<SendRequestT extends Request, SendNotificationT e
13861454 } ;
13871455 }
13881456
1389- await this . _transport . send ( jsonrpcNotification , options ) ;
1457+ // Apply send middleware before sending
1458+ const transformedNotification = await this . _applyMiddleware ( jsonrpcNotification , this . _options ?. sendMiddleware ) ;
1459+ await this . _transport . send ( transformedNotification as JSONRPCNotification , options ) ;
13901460 }
13911461
13921462 /**
0 commit comments