@frontmcp/sdk 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/package.json +8 -19
- package/src/adapter/adapter.instance.js +5 -0
- package/src/adapter/adapter.instance.js.map +1 -1
- package/src/auth/authorization/authorization.class.d.ts +1 -4
- package/src/auth/authorization/authorization.class.js +6 -13
- package/src/auth/authorization/authorization.class.js.map +1 -1
- package/src/auth/flows/session.verify.flow.d.ts +1 -0
- package/src/auth/flows/session.verify.flow.js +11 -1
- package/src/auth/flows/session.verify.flow.js.map +1 -1
- package/src/auth/flows/well-known.jwks.flow.js +2 -2
- package/src/auth/flows/well-known.jwks.flow.js.map +1 -1
- package/src/auth/jwks/dev-key-persistence.d.ts +63 -0
- package/src/auth/jwks/dev-key-persistence.js +219 -0
- package/src/auth/jwks/dev-key-persistence.js.map +1 -0
- package/src/auth/jwks/index.d.ts +1 -0
- package/src/auth/jwks/index.js +1 -0
- package/src/auth/jwks/index.js.map +1 -1
- package/src/auth/jwks/jwks.service.d.ts +7 -4
- package/src/auth/jwks/jwks.service.js +81 -12
- package/src/auth/jwks/jwks.service.js.map +1 -1
- package/src/auth/jwks/jwks.types.d.ts +7 -0
- package/src/auth/jwks/jwks.types.js.map +1 -1
- package/src/auth/machine-id.d.ts +5 -0
- package/src/auth/machine-id.js +32 -0
- package/src/auth/machine-id.js.map +1 -0
- package/src/auth/session/index.d.ts +1 -0
- package/src/auth/session/index.js +3 -1
- package/src/auth/session/index.js.map +1 -1
- package/src/auth/session/record/session.base.js +5 -3
- package/src/auth/session/record/session.base.js.map +1 -1
- package/src/auth/session/record/session.stateless.d.ts +2 -2
- package/src/auth/session/record/session.stateless.js +5 -3
- package/src/auth/session/record/session.stateless.js.map +1 -1
- package/src/auth/session/redis-session.store.d.ts +64 -0
- package/src/auth/session/redis-session.store.js +204 -0
- package/src/auth/session/redis-session.store.js.map +1 -0
- package/src/auth/session/session.service.d.ts +0 -2
- package/src/auth/session/session.service.js +1 -7
- package/src/auth/session/session.service.js.map +1 -1
- package/src/auth/session/transport-session.manager.js +3 -5
- package/src/auth/session/transport-session.manager.js.map +1 -1
- package/src/auth/session/transport-session.types.d.ts +4 -0
- package/src/auth/session/transport-session.types.js +4 -3
- package/src/auth/session/transport-session.types.js.map +1 -1
- package/src/auth/session/utils/session-id.utils.d.ts +12 -1
- package/src/auth/session/utils/session-id.utils.js +48 -9
- package/src/auth/session/utils/session-id.utils.js.map +1 -1
- package/src/auth/ui/base-layout.d.ts +0 -8
- package/src/auth/ui/base-layout.js +1 -14
- package/src/auth/ui/base-layout.js.map +1 -1
- package/src/auth/ui/index.d.ts +3 -4
- package/src/auth/ui/index.js +10 -11
- package/src/auth/ui/index.js.map +1 -1
- package/src/auth/ui/{htmx-templates.d.ts → templates.d.ts} +5 -6
- package/src/auth/ui/{htmx-templates.js → templates.js} +8 -15
- package/src/auth/ui/templates.js.map +1 -0
- package/src/common/decorators/decorator-utils.js.map +1 -1
- package/src/common/decorators/front-mcp.decorator.js +28 -2
- package/src/common/decorators/front-mcp.decorator.js.map +1 -1
- package/src/common/index.d.ts +0 -1
- package/src/common/index.js +0 -1
- package/src/common/index.js.map +1 -1
- package/src/common/interfaces/adapter.interface.d.ts +6 -0
- package/src/common/interfaces/adapter.interface.js.map +1 -1
- package/src/common/interfaces/execution-context.interface.d.ts +52 -3
- package/src/common/interfaces/execution-context.interface.js +88 -3
- package/src/common/interfaces/execution-context.interface.js.map +1 -1
- package/src/common/interfaces/flow.interface.d.ts +13 -0
- package/src/common/interfaces/flow.interface.js +24 -0
- package/src/common/interfaces/flow.interface.js.map +1 -1
- package/src/common/interfaces/server.interface.d.ts +9 -0
- package/src/common/interfaces/server.interface.js.map +1 -1
- package/src/common/metadata/app.metadata.d.ts +108 -0
- package/src/common/metadata/front-mcp.metadata.d.ts +659 -2
- package/src/common/metadata/front-mcp.metadata.js +3 -1
- package/src/common/metadata/front-mcp.metadata.js.map +1 -1
- package/src/common/metadata/provider.metadata.d.ts +14 -0
- package/src/common/metadata/provider.metadata.js +18 -2
- package/src/common/metadata/provider.metadata.js.map +1 -1
- package/src/common/metadata/tool.metadata.d.ts +33 -1
- package/src/common/metadata/tool.metadata.js.map +1 -1
- package/src/common/migrate/auth-transport.migrate.d.ts +62 -0
- package/src/common/migrate/auth-transport.migrate.js +140 -0
- package/src/common/migrate/auth-transport.migrate.js.map +1 -0
- package/src/common/migrate/index.d.ts +1 -0
- package/src/common/migrate/index.js +6 -0
- package/src/common/migrate/index.js.map +1 -0
- package/src/common/schemas/http-output.schema.d.ts +10 -2
- package/src/common/schemas/index.d.ts +1 -0
- package/src/common/schemas/index.js +1 -0
- package/src/common/schemas/index.js.map +1 -1
- package/src/common/schemas/session-header.schema.d.ts +16 -0
- package/src/common/schemas/session-header.schema.js +42 -0
- package/src/common/schemas/session-header.schema.js.map +1 -0
- package/src/common/tokens/front-mcp.tokens.js +3 -1
- package/src/common/tokens/front-mcp.tokens.js.map +1 -1
- package/src/common/types/options/auth.options.d.ts +233 -3
- package/src/common/types/options/auth.options.js +29 -40
- package/src/common/types/options/auth.options.js.map +1 -1
- package/src/common/types/options/index.d.ts +2 -0
- package/src/common/types/options/index.js +2 -0
- package/src/common/types/options/index.js.map +1 -1
- package/src/common/types/options/redis.options.d.ts +22 -0
- package/src/common/types/options/redis.options.js +45 -0
- package/src/common/types/options/redis.options.js.map +1 -0
- package/src/common/types/options/transport.options.d.ts +84 -0
- package/src/common/types/options/transport.options.js +121 -0
- package/src/common/types/options/transport.options.js.map +1 -0
- package/src/completion/flows/complete.flow.d.ts +17 -2
- package/src/context/frontmcp-context-storage.d.ts +94 -0
- package/src/context/frontmcp-context-storage.js +183 -0
- package/src/context/frontmcp-context-storage.js.map +1 -0
- package/src/context/frontmcp-context.d.ts +269 -0
- package/src/context/frontmcp-context.js +360 -0
- package/src/context/frontmcp-context.js.map +1 -0
- package/src/context/frontmcp-context.provider.d.ts +43 -0
- package/src/context/frontmcp-context.provider.js +61 -0
- package/src/context/frontmcp-context.provider.js.map +1 -0
- package/src/context/index.d.ts +34 -0
- package/src/context/index.js +64 -0
- package/src/context/index.js.map +1 -0
- package/src/context/request-context-storage.d.ts +89 -0
- package/src/context/request-context-storage.js +183 -0
- package/src/context/request-context-storage.js.map +1 -0
- package/src/context/request-context.d.ts +184 -0
- package/src/context/request-context.js +209 -0
- package/src/context/request-context.js.map +1 -0
- package/src/context/request-context.provider.d.ts +37 -0
- package/src/context/request-context.provider.js +51 -0
- package/src/context/request-context.provider.js.map +1 -0
- package/src/context/session-key.provider.d.ts +45 -0
- package/src/context/session-key.provider.js +65 -0
- package/src/context/session-key.provider.js.map +1 -0
- package/src/context/trace-context.d.ts +43 -0
- package/src/context/trace-context.js +142 -0
- package/src/context/trace-context.js.map +1 -0
- package/src/errors/index.d.ts +1 -1
- package/src/errors/index.js +3 -1
- package/src/errors/index.js.map +1 -1
- package/src/errors/mcp.error.d.ts +7 -0
- package/src/errors/mcp.error.js +11 -1
- package/src/errors/mcp.error.js.map +1 -1
- package/src/flows/flow.instance.d.ts +16 -0
- package/src/flows/flow.instance.js +166 -80
- package/src/flows/flow.instance.js.map +1 -1
- package/src/flows/flow.registry.d.ts +5 -0
- package/src/flows/flow.registry.js +45 -3
- package/src/flows/flow.registry.js.map +1 -1
- package/src/front-mcp/front-mcp.d.ts +12 -0
- package/src/front-mcp/front-mcp.js +22 -3
- package/src/front-mcp/front-mcp.js.map +1 -1
- package/src/front-mcp/front-mcp.providers.d.ts +266 -1
- package/src/front-mcp/front-mcp.providers.js +2 -1
- package/src/front-mcp/front-mcp.providers.js.map +1 -1
- package/src/front-mcp/serverless-handler.d.ts +28 -0
- package/src/front-mcp/serverless-handler.js +61 -0
- package/src/front-mcp/serverless-handler.js.map +1 -0
- package/src/hooks/hooks.utils.d.ts +1 -1
- package/src/hooks/hooks.utils.js +10 -3
- package/src/hooks/hooks.utils.js.map +1 -1
- package/src/index.d.ts +8 -4
- package/src/index.js +20 -1
- package/src/index.js.map +1 -1
- package/src/logger/instances/instance.logger.js +0 -1
- package/src/logger/instances/instance.logger.js.map +1 -1
- package/src/logging/flows/set-level.flow.d.ts +17 -2
- package/src/notification/notification.service.js +5 -1
- package/src/notification/notification.service.js.map +1 -1
- package/src/prompt/flows/get-prompt.flow.d.ts +97 -2
- package/src/prompt/flows/prompts-list.flow.d.ts +12 -1
- package/src/provider/provider.registry.d.ts +97 -5
- package/src/provider/provider.registry.js +306 -9
- package/src/provider/provider.registry.js.map +1 -1
- package/src/provider/provider.types.d.ts +21 -3
- package/src/provider/provider.types.js.map +1 -1
- package/src/resource/flows/read-resource.flow.d.ts +22 -3
- package/src/resource/flows/resource-templates-list.flow.d.ts +20 -1
- package/src/resource/flows/resources-list.flow.d.ts +20 -1
- package/src/resource/flows/subscribe-resource.flow.d.ts +17 -2
- package/src/resource/flows/unsubscribe-resource.flow.d.ts +17 -2
- package/src/scope/flows/http.request.flow.js +43 -7
- package/src/scope/flows/http.request.flow.js.map +1 -1
- package/src/scope/scope.instance.js +12 -5
- package/src/scope/scope.instance.js.map +1 -1
- package/src/server/adapters/base.host.adapter.d.ts +9 -0
- package/src/server/adapters/base.host.adapter.js.map +1 -1
- package/src/server/adapters/express.host.adapter.d.ts +12 -0
- package/src/server/adapters/express.host.adapter.js +21 -1
- package/src/server/adapters/express.host.adapter.js.map +1 -1
- package/src/server/server.instance.d.ts +3 -0
- package/src/server/server.instance.js +14 -7
- package/src/server/server.instance.js.map +1 -1
- package/src/tool/flows/call-tool.flow.d.ts +118 -13
- package/src/tool/flows/call-tool.flow.js +240 -194
- package/src/tool/flows/call-tool.flow.js.map +1 -1
- package/src/tool/flows/tools-list.flow.d.ts +25 -11
- package/src/tool/flows/tools-list.flow.js +82 -31
- package/src/tool/flows/tools-list.flow.js.map +1 -1
- package/src/tool/tool.instance.d.ts +1 -4
- package/src/transport/adapters/transport.streamable-http.adapter.js +1 -0
- package/src/transport/adapters/transport.streamable-http.adapter.js.map +1 -1
- package/src/transport/flows/handle.sse.flow.js +9 -2
- package/src/transport/flows/handle.sse.flow.js.map +1 -1
- package/src/transport/flows/handle.streamable-http.flow.js +63 -6
- package/src/transport/flows/handle.streamable-http.flow.js.map +1 -1
- package/src/transport/mcp-handlers/complete-request.handler.d.ts +27 -1
- package/src/transport/mcp-handlers/get-prompt-request.handler.d.ts +52 -1
- package/src/transport/mcp-handlers/index.d.ts +413 -7
- package/src/transport/mcp-handlers/initialize-request.handler.js +12 -2
- package/src/transport/mcp-handlers/initialize-request.handler.js.map +1 -1
- package/src/transport/mcp-handlers/list-prompts-request.handler.d.ts +27 -1
- package/src/transport/mcp-handlers/list-resource-templates-request.handler.d.ts +32 -1
- package/src/transport/mcp-handlers/list-resources-request.handler.d.ts +32 -1
- package/src/transport/mcp-handlers/list-tools-request.handler.d.ts +30 -1
- package/src/transport/mcp-handlers/logging-set-level-request.handler.d.ts +20 -0
- package/src/transport/mcp-handlers/read-resource-request.handler.d.ts +27 -1
- package/src/transport/mcp-handlers/subscribe-request.handler.d.ts +20 -0
- package/src/transport/mcp-handlers/unsubscribe-request.handler.d.ts +20 -0
- package/src/transport/transport.registry.d.ts +68 -4
- package/src/transport/transport.registry.js +313 -11
- package/src/transport/transport.registry.js.map +1 -1
- package/src/auth/ui/htmx-templates.js.map +0 -1
- package/src/common/providers/session.provider.d.ts +0 -13
- package/src/common/providers/session.provider.js +0 -27
- package/src/common/providers/session.provider.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.streamable-http.adapter.js","sourceRoot":"","sources":["../../../../src/transport/adapters/transport.streamable-http.adapter.ts"],"names":[],"mappings":";;;AAAA,0FAAmG;AAGnG,uEAAkE;AAGlE,+BAAsC;AACtC,wDAAgD;AAGhD;;;;;GAKG;AACI,MAAM,yBAAyB,GAAG,CACvC,aAA4B,EAC5B,SAAiB,EACW,EAAE;IAC9B,OAAO,aAAa,KAAK,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;AAC1E,CAAC,CAAC;AALW,QAAA,yBAAyB,6BAKpC;AAEF,MAAa,8BAA+B,SAAQ,+CAAoD;IAC7F,eAAe,CAAC,SAAiB,EAAE,QAAwB;QAClE,MAAM,kBAAkB,GAAG,IAAA,iCAAyB,EAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAE/E,OAAO,IAAI,iDAA6B,CAAC;YACvC,kBAAkB;YAClB,eAAe,EAAE,GAAG,EAAE;gBACpB,kBAAkB;YACpB,CAAC;YACD,oBAAoB,EAAE,CAAC,SAAS,EAAE,EAAE;gBAClC,IAAI,SAAS,EAAE,CAAC;oBACd,OAAO,CAAC,GAAG,CAAC,wBAAwB,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;gBAChE,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YACD,wFAAwF;YACxF,kFAAkF;YAClF,4DAA4D;YAC5D,UAAU,EAAE,SAAS;SACtB,CAAC,CAAC;IACL,CAAC;IAED,UAAU,CAAC,GAA+B,EAAE,GAAmB;QAC7D,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAE/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE;YAC9D,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YAC1C,UAAU,EAAG,GAAG,CAAC,IAA4B,EAAE,MAAM;SACtD,CAAC,CAAC;QAEH,0DAA0D;QAC1D,MAAM,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAqB,CAAC;QAC9D,MAAM,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAmB,CAAC;QACxD,IAAI,YAAY,GAAG,EAAE,CAAC;QAEtB,8DAA8D;QAC9D,GAAG,CAAC,KAAK,GAAG,UAAgC,KAAU,EAAE,YAAkB,EAAE,EAAQ;YAClF,IAAI,KAAK,EAAE,CAAC;gBACV,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChH,CAAC;YACD,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QAC3D,CAAqB,CAAC;QAEtB,MAAM,OAAO,GAAG,IAAI,CAAC;QACrB,8DAA8D;QAC9D,GAAG,CAAC,GAAG,GAAG,UAAgC,KAAW,EAAE,YAAkB,EAAE,EAAQ;YACjF,IAAI,KAAK,EAAE,CAAC;gBACV,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChH,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE;gBACjE,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,OAAO,EAAE,GAAG,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE;gBACjC,WAAW,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;aACzC,CAAC,CAAC;YACH,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QACzD,CAAmB,CAAC;QAEpB,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,GAA+B,EAAE,GAAmB;QACtE,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,EAAE;QACF,qEAAqE;QACrE,kCAAkC;QAClC,uFAAuF;QACvF,sBAAsB;QACtB,IAAI;QAEJ,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,OAAO;YACT,CAAC;YACD,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,gBAA2B,EAC3B,OAAe,EACf,eAAkB;QAElB,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACvB,IAAA,4BAAU,EAAC,IAAI,CAAC,YAAY,EAAE,oBAAoB,EAAE;YAClD,OAAO;YACP,eAAe,EAAE,IAAA,iBAAY,EAAC,eAAsB,CAAC;SACtD,CAAC,EACF,EAAE,gBAAgB,EAAE,CACrB,CAAC;QAEF,OAAO,IAAI,OAAO,CAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3D,IAAI,CAAC,aAAa,GAAG;gBACnB,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE;oBAClB,OAAO,CAAC,MAA8B,CAAC,CAAC;oBACxC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;gBACjC,CAAC;gBACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE;oBACd,MAAM,CAAC,GAAG,CAAC,CAAC;oBACZ,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;gBACjC,CAAC;aACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"transport.streamable-http.adapter.js","sourceRoot":"","sources":["../../../../src/transport/adapters/transport.streamable-http.adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { TransportType, TypedElicitResult } from '../transport.types';\nimport { AuthenticatedServerRequest } from '../../server/server.types';\nimport { LocalTransportAdapter } from './transport.local.adapter';\nimport { RequestId } from '@modelcontextprotocol/sdk/types.js';\nimport { ZodType } from 'zod';\nimport { toJSONSchema } from 'zod/v4';\nimport { rpcRequest } from '../transport.error';\nimport { ServerResponse } from '../../common';\n\n/**\n * Stateless HTTP requests must be able to send multiple initialize calls without\n * tripping the MCP transport's \"already initialized\" guard. The upstream SDK\n * treats any transport with a session ID generator as stateful, so we disable\n * session generation entirely for stateless transports.\n */\nexport const resolveSessionIdGenerator = (\n transportType: TransportType,\n sessionId: string,\n): (() => string) | undefined => {\n return transportType === 'stateless-http' ? undefined : () => sessionId;\n};\n\nexport class TransportStreamableHttpAdapter extends LocalTransportAdapter<StreamableHTTPServerTransport> {\n override createTransport(sessionId: string, response: ServerResponse): StreamableHTTPServerTransport {\n const sessionIdGenerator = resolveSessionIdGenerator(this.key.type, sessionId);\n\n return new StreamableHTTPServerTransport({\n sessionIdGenerator,\n onsessionclosed: () => {\n // this.destroy();\n },\n onsessioninitialized: (sessionId) => {\n if (sessionId) {\n console.log(`session initialized: ${sessionId.slice(0, 40)}`);\n } else {\n console.log(`stateless session initialized`);\n }\n },\n // Disable eventStore to prevent priming events - Claude.ai's client doesn't handle them\n // The priming event has empty data with no `event:` type, which violates MCP spec\n // (\"Event types MUST be message\") and confuses some clients\n eventStore: undefined,\n });\n }\n\n initialize(req: AuthenticatedServerRequest, res: ServerResponse): Promise<void> {\n this.ensureAuthInfo(req, this);\n\n this.logger.info('[StreamableHttpAdapter] initialize() called', {\n method: req.method,\n sessionId: this.key.sessionId.slice(0, 30),\n bodyMethod: (req.body as { method?: string })?.method,\n });\n\n // Intercept response to log what gets sent back to client\n const originalWrite = res.write.bind(res) as typeof res.write;\n const originalEnd = res.end.bind(res) as typeof res.end;\n let responseBody = '';\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n res.write = function (this: ServerResponse, chunk: any, encodingOrCb?: any, cb?: any): boolean {\n if (chunk) {\n responseBody += typeof chunk === 'string' ? chunk : Buffer.isBuffer(chunk) ? chunk.toString() : String(chunk);\n }\n return originalWrite.call(this, chunk, encodingOrCb, cb);\n } as typeof res.write;\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const adapter = this;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n res.end = function (this: ServerResponse, chunk?: any, encodingOrCb?: any, cb?: any): ServerResponse {\n if (chunk) {\n responseBody += typeof chunk === 'string' ? chunk : Buffer.isBuffer(chunk) ? chunk.toString() : String(chunk);\n }\n adapter.logger.info('[StreamableHttpAdapter] initialize response', {\n statusCode: res.statusCode,\n headers: res.getHeaders?.() ?? {},\n bodyPreview: responseBody.slice(0, 1000),\n });\n return originalEnd.call(this, chunk, encodingOrCb, cb);\n } as typeof res.end;\n\n return this.transport.handleRequest(req, res, req.body);\n }\n\n async handleRequest(req: AuthenticatedServerRequest, res: ServerResponse): Promise<void> {\n this.ensureAuthInfo(req, this);\n //\n // if ((await this.isInitialized) && isInitializeRequest(req.body)) {\n // await this.transport.close();\n // this.isInitialized = this.connectStreamableTransport(req.authSession.session!.id);\n // await this.ready;\n // }\n\n if (req.method === 'GET') {\n return this.transport.handleRequest(req, res);\n } else {\n if (this.handleIfElicitResult(req)) {\n return;\n }\n return this.transport.handleRequest(req, res, req.body);\n }\n }\n\n async sendElicitRequest<T extends ZodType>(\n relatedRequestId: RequestId,\n message: string,\n requestedSchema: T,\n ): Promise<TypedElicitResult<T>> {\n await this.transport.send(\n rpcRequest(this.newRequestId, 'elicitation/create', {\n message,\n requestedSchema: toJSONSchema(requestedSchema as any),\n }),\n { relatedRequestId },\n );\n\n return new Promise<TypedElicitResult<T>>((resolve, reject) => {\n this.elicitHandler = {\n resolve: (result) => {\n resolve(result as TypedElicitResult<T>);\n this.elicitHandler = undefined;\n },\n reject: (err) => {\n reject(err);\n this.elicitHandler = undefined;\n },\n };\n });\n }\n}\n"]}
|
|
@@ -47,7 +47,14 @@ let HandleSseFlow = class HandleSseFlow extends common_1.FlowBase {
|
|
|
47
47
|
// This is the ID the client received from initialize and is referencing.
|
|
48
48
|
// Priority 2: Use session from authorization if header matches or is absent
|
|
49
49
|
// Priority 3: Create new session (first request - no header, no authorization.session)
|
|
50
|
-
const
|
|
50
|
+
const raw = request.headers?.['mcp-session-id'];
|
|
51
|
+
const rawMcpSessionHeader = typeof raw === 'string' ? raw : undefined;
|
|
52
|
+
const mcpSessionHeader = (0, common_1.validateMcpSessionHeader)(rawMcpSessionHeader);
|
|
53
|
+
// If client sent a header but validation failed, return 404
|
|
54
|
+
if (raw !== undefined && !mcpSessionHeader) {
|
|
55
|
+
this.respond(common_1.httpRespond.sessionNotFound('invalid session id'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
51
58
|
let session;
|
|
52
59
|
if (mcpSessionHeader) {
|
|
53
60
|
// Client sent session ID - ALWAYS use it for transport lookup
|
|
@@ -68,7 +75,7 @@ let HandleSseFlow = class HandleSseFlow extends common_1.FlowBase {
|
|
|
68
75
|
// No session - create new one (initialize request)
|
|
69
76
|
session = (0, session_id_utils_1.createSessionId)('legacy-sse', token, {
|
|
70
77
|
userAgent: request.headers?.['user-agent'],
|
|
71
|
-
platformDetectionConfig: this.scope.metadata?.
|
|
78
|
+
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
72
79
|
});
|
|
73
80
|
}
|
|
74
81
|
this.state.set(exports.stateSchema.parse({ token, session }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle.sse.flow.js","sourceRoot":"","sources":["../../../../src/transport/flows/handle.sse.flow.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Flow,\n httpInputSchema,\n FlowRunOptions,\n httpOutputSchema,\n FlowPlan,\n FlowBase,\n FlowHooksOf,\n sessionIdSchema,\n httpRespond,\n ServerRequestTokens,\n Authorization,\n normalizeEntryPrefix,\n normalizeScopeBase,\n} from '../../common';\nimport { z } from 'zod';\nimport { Scope } from '../../scope';\nimport { createSessionId } from '../../auth/session/utils/session-id.utils';\n\nexport const plan = {\n pre: ['parseInput', 'router'],\n execute: ['onInitialize', 'onMessage', 'onElicitResult'],\n post: [],\n finalize: ['cleanup'],\n} as const satisfies FlowPlan<string>;\n\n// Relaxed session schema for state - payload is optional when using mcp-session-id header directly\nconst stateSessionSchema = z.object({\n id: z.string(),\n payload: z\n .object({\n nodeId: z.string(),\n authSig: z.string(),\n uuid: z.string().uuid(),\n iat: z.number(),\n protocol: z.enum(['legacy-sse', 'sse', 'streamable-http', 'stateful-http', 'stateless-http']).optional(),\n isPublic: z.boolean().optional(),\n platformType: z\n .enum(['openai', 'claude', 'gemini', 'cursor', 'continue', 'cody', 'generic-mcp', 'ext-apps', 'unknown'])\n .optional(),\n })\n .optional(),\n});\n\nexport const stateSchema = z.object({\n token: z.string(),\n session: stateSessionSchema,\n requestType: z.enum(['initialize', 'message', 'elicitResult']).optional(),\n});\n\nconst name = 'handle:legacy-sse' as const;\nconst { Stage } = FlowHooksOf(name);\n\ndeclare global {\n interface ExtendFlows {\n 'handle:legacy-sse': FlowRunOptions<\n HandleSseFlow,\n typeof plan,\n typeof httpInputSchema,\n typeof httpOutputSchema,\n typeof stateSchema\n >;\n }\n}\n\n@Flow({\n name,\n access: 'authorized',\n inputSchema: httpInputSchema,\n outputSchema: httpOutputSchema,\n plan,\n})\nexport default class HandleSseFlow extends FlowBase<typeof name> {\n @Stage('parseInput')\n async parseInput() {\n const { request } = this.rawInput;\n\n const authorization = request[ServerRequestTokens.auth] as Authorization;\n const { token } = authorization;\n\n // CRITICAL: The mcp-session-id header is the client's reference to their session.\n // We MUST use this exact ID for transport registry lookup.\n //\n // Priority 1: Use mcp-session-id header if present (client's session ID for lookup)\n // This is the ID the client received from initialize and is referencing.\n // Priority 2: Use session from authorization if header matches or is absent\n // Priority 3: Create new session (first request - no header, no authorization.session)\n const mcpSessionHeader = request.headers?.['mcp-session-id'] as string | undefined;\n\n let session: { id: string; payload?: z.infer<typeof stateSchema>['session']['payload'] };\n\n if (mcpSessionHeader) {\n // Client sent session ID - ALWAYS use it for transport lookup\n // If authorization.session exists and matches, use its payload for protocol detection\n // If authorization.session differs or is missing, still use header ID (payload may be undefined)\n if (authorization.session?.id === mcpSessionHeader) {\n session = authorization.session;\n } else {\n session = { id: mcpSessionHeader };\n }\n } else if (authorization.session) {\n // No header but authorization has session - use it (shouldn't happen in normal flow)\n session = authorization.session;\n } else {\n // No session - create new one (initialize request)\n session = createSessionId('legacy-sse', token, {\n userAgent: request.headers?.['user-agent'] as string | undefined,\n platformDetectionConfig: (this.scope as Scope).metadata?.session?.platformDetection,\n });\n }\n\n this.state.set(stateSchema.parse({ token, session }));\n }\n\n @Stage('router')\n async router() {\n const { request } = this.rawInput;\n const scope = this.scope as Scope;\n const requestPath = normalizeEntryPrefix(request.path);\n const prefix = normalizeEntryPrefix(scope.entryPath);\n const scopePath = normalizeScopeBase(scope.routeBase);\n const basePath = `${prefix}${scopePath}`;\n\n if (requestPath === `${basePath}/sse`) {\n this.state.set('requestType', 'initialize');\n } else if (requestPath === `${basePath}/message`) {\n this.state.set('requestType', 'message');\n }\n }\n\n @Stage('onInitialize', {\n filter: ({ state: { requestType } }) => requestType === 'initialize',\n })\n async onInitialize() {\n const transportService = (this.scope as Scope).transportService;\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n const transport = await transportService.createTransporter('sse', token, session.id, response);\n await transport.initialize(request, response);\n this.handled();\n }\n\n @Stage('onElicitResult', {\n filter: ({ state: { requestType } }) => requestType === 'elicitResult',\n })\n async onElicitResult() {\n // const transport = await transportService.getTransporter('sse', token, session.id);\n // if (!transport) {\n // this.respond(httpRespond.rpcError('session not initialized'));\n // return;\n // }\n // await transport.handleRequest(request, response);\n this.fail(new Error('Not implemented'));\n }\n\n @Stage('onMessage', {\n filter: ({ state: { requestType } }) => requestType === 'message',\n })\n async onMessage() {\n const transportService = (this.scope as Scope).transportService;\n const logger = this.scopeLogger.child('handle:legacy-sse:onMessage');\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n const transport = await transportService.getTransporter('sse', token, session.id);\n if (!transport) {\n // Check if session was ever created to differentiate error types per MCP Spec 2025-11-25\n const wasCreated = transportService.wasSessionCreated('sse', token, session.id);\n const body = request.body as Record<string, unknown> | undefined;\n\n if (wasCreated) {\n // Session existed but was terminated/evicted → HTTP 404 (client should re-initialize)\n logger.info('Session expired - client should re-initialize', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n });\n this.respond(httpRespond.sessionExpired('session expired'));\n } else {\n // Session was never created → HTTP 404 (per user requirement: invalid/missing session = 404)\n logger.warn('Session not initialized - client attempted request without initializing', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n userAgent: (request.headers?.['user-agent'] as string | undefined)?.slice(0, 50),\n });\n this.respond(httpRespond.sessionNotFound('session not initialized'));\n }\n return;\n }\n await transport.handleRequest(request, response);\n this.handled();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"handle.sse.flow.js","sourceRoot":"","sources":["../../../../src/transport/flows/handle.sse.flow.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Flow,\n httpInputSchema,\n FlowRunOptions,\n httpOutputSchema,\n FlowPlan,\n FlowBase,\n FlowHooksOf,\n sessionIdSchema,\n httpRespond,\n ServerRequestTokens,\n Authorization,\n normalizeEntryPrefix,\n normalizeScopeBase,\n validateMcpSessionHeader,\n} from '../../common';\nimport { z } from 'zod';\nimport { Scope } from '../../scope';\nimport { createSessionId } from '../../auth/session/utils/session-id.utils';\n\nexport const plan = {\n pre: ['parseInput', 'router'],\n execute: ['onInitialize', 'onMessage', 'onElicitResult'],\n post: [],\n finalize: ['cleanup'],\n} as const satisfies FlowPlan<string>;\n\n// Relaxed session schema for state - payload is optional when using mcp-session-id header directly\nconst stateSessionSchema = z.object({\n id: z.string(),\n payload: z\n .object({\n nodeId: z.string(),\n authSig: z.string(),\n uuid: z.string().uuid(),\n iat: z.number(),\n protocol: z.enum(['legacy-sse', 'sse', 'streamable-http', 'stateful-http', 'stateless-http']).optional(),\n isPublic: z.boolean().optional(),\n platformType: z\n .enum(['openai', 'claude', 'gemini', 'cursor', 'continue', 'cody', 'generic-mcp', 'ext-apps', 'unknown'])\n .optional(),\n })\n .optional(),\n});\n\nexport const stateSchema = z.object({\n token: z.string(),\n session: stateSessionSchema,\n requestType: z.enum(['initialize', 'message', 'elicitResult']).optional(),\n});\n\nconst name = 'handle:legacy-sse' as const;\nconst { Stage } = FlowHooksOf(name);\n\ndeclare global {\n interface ExtendFlows {\n 'handle:legacy-sse': FlowRunOptions<\n HandleSseFlow,\n typeof plan,\n typeof httpInputSchema,\n typeof httpOutputSchema,\n typeof stateSchema\n >;\n }\n}\n\n@Flow({\n name,\n access: 'authorized',\n inputSchema: httpInputSchema,\n outputSchema: httpOutputSchema,\n plan,\n})\nexport default class HandleSseFlow extends FlowBase<typeof name> {\n @Stage('parseInput')\n async parseInput() {\n const { request } = this.rawInput;\n\n const authorization = request[ServerRequestTokens.auth] as Authorization;\n const { token } = authorization;\n\n // CRITICAL: The mcp-session-id header is the client's reference to their session.\n // We MUST use this exact ID for transport registry lookup.\n //\n // Priority 1: Use mcp-session-id header if present (client's session ID for lookup)\n // This is the ID the client received from initialize and is referencing.\n // Priority 2: Use session from authorization if header matches or is absent\n // Priority 3: Create new session (first request - no header, no authorization.session)\n const raw = request.headers?.['mcp-session-id'];\n const rawMcpSessionHeader = typeof raw === 'string' ? raw : undefined;\n const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);\n\n // If client sent a header but validation failed, return 404\n if (raw !== undefined && !mcpSessionHeader) {\n this.respond(httpRespond.sessionNotFound('invalid session id'));\n return;\n }\n\n let session: { id: string; payload?: z.infer<typeof stateSchema>['session']['payload'] };\n\n if (mcpSessionHeader) {\n // Client sent session ID - ALWAYS use it for transport lookup\n // If authorization.session exists and matches, use its payload for protocol detection\n // If authorization.session differs or is missing, still use header ID (payload may be undefined)\n if (authorization.session?.id === mcpSessionHeader) {\n session = authorization.session;\n } else {\n session = { id: mcpSessionHeader };\n }\n } else if (authorization.session) {\n // No header but authorization has session - use it (shouldn't happen in normal flow)\n session = authorization.session;\n } else {\n // No session - create new one (initialize request)\n session = createSessionId('legacy-sse', token, {\n userAgent: request.headers?.['user-agent'] as string | undefined,\n platformDetectionConfig: (this.scope as Scope).metadata.transport?.platformDetection,\n });\n }\n\n this.state.set(stateSchema.parse({ token, session }));\n }\n\n @Stage('router')\n async router() {\n const { request } = this.rawInput;\n const scope = this.scope as Scope;\n const requestPath = normalizeEntryPrefix(request.path);\n const prefix = normalizeEntryPrefix(scope.entryPath);\n const scopePath = normalizeScopeBase(scope.routeBase);\n const basePath = `${prefix}${scopePath}`;\n\n if (requestPath === `${basePath}/sse`) {\n this.state.set('requestType', 'initialize');\n } else if (requestPath === `${basePath}/message`) {\n this.state.set('requestType', 'message');\n }\n }\n\n @Stage('onInitialize', {\n filter: ({ state: { requestType } }) => requestType === 'initialize',\n })\n async onInitialize() {\n const transportService = (this.scope as Scope).transportService;\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n const transport = await transportService.createTransporter('sse', token, session.id, response);\n await transport.initialize(request, response);\n this.handled();\n }\n\n @Stage('onElicitResult', {\n filter: ({ state: { requestType } }) => requestType === 'elicitResult',\n })\n async onElicitResult() {\n // const transport = await transportService.getTransporter('sse', token, session.id);\n // if (!transport) {\n // this.respond(httpRespond.rpcError('session not initialized'));\n // return;\n // }\n // await transport.handleRequest(request, response);\n this.fail(new Error('Not implemented'));\n }\n\n @Stage('onMessage', {\n filter: ({ state: { requestType } }) => requestType === 'message',\n })\n async onMessage() {\n const transportService = (this.scope as Scope).transportService;\n const logger = this.scopeLogger.child('handle:legacy-sse:onMessage');\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n const transport = await transportService.getTransporter('sse', token, session.id);\n if (!transport) {\n // Check if session was ever created to differentiate error types per MCP Spec 2025-11-25\n const wasCreated = transportService.wasSessionCreated('sse', token, session.id);\n const body = request.body as Record<string, unknown> | undefined;\n\n if (wasCreated) {\n // Session existed but was terminated/evicted → HTTP 404 (client should re-initialize)\n logger.info('Session expired - client should re-initialize', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n });\n this.respond(httpRespond.sessionExpired('session expired'));\n } else {\n // Session was never created → HTTP 404 (per user requirement: invalid/missing session = 404)\n logger.warn('Session not initialized - client attempted request without initializing', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n userAgent: (request.headers?.['user-agent'] as string | undefined)?.slice(0, 50),\n });\n this.respond(httpRespond.sessionNotFound('session not initialized'));\n }\n return;\n }\n await transport.handleRequest(request, response);\n this.handled();\n }\n}\n"]}
|
|
@@ -40,7 +40,15 @@ let HandleStreamableHttpFlow = class HandleStreamableHttpFlow extends common_1.F
|
|
|
40
40
|
name = name;
|
|
41
41
|
async parseInput() {
|
|
42
42
|
const { request } = this.rawInput;
|
|
43
|
+
console.log('[DEBUG] parseInput: starting');
|
|
43
44
|
const authorization = request[common_1.ServerRequestTokens.auth];
|
|
45
|
+
console.log('[DEBUG] parseInput: authorization =', authorization
|
|
46
|
+
? {
|
|
47
|
+
hasToken: !!authorization.token,
|
|
48
|
+
hasSession: !!authorization.session,
|
|
49
|
+
sessionId: authorization.session?.id?.slice(0, 30),
|
|
50
|
+
}
|
|
51
|
+
: 'undefined');
|
|
44
52
|
const { token } = authorization;
|
|
45
53
|
// CRITICAL: The mcp-session-id header is the client's reference to their session.
|
|
46
54
|
// We MUST use this exact ID for transport registry lookup.
|
|
@@ -49,7 +57,14 @@ let HandleStreamableHttpFlow = class HandleStreamableHttpFlow extends common_1.F
|
|
|
49
57
|
// This is the ID the client received from initialize and is referencing.
|
|
50
58
|
// Priority 2: Use session from authorization if header matches or is absent
|
|
51
59
|
// Priority 3: Create new session (first request - no header, no authorization.session)
|
|
52
|
-
const
|
|
60
|
+
const raw = request.headers?.['mcp-session-id'];
|
|
61
|
+
const rawMcpSessionHeader = typeof raw === 'string' ? raw : undefined;
|
|
62
|
+
const mcpSessionHeader = (0, common_1.validateMcpSessionHeader)(rawMcpSessionHeader);
|
|
63
|
+
// If client sent a header but validation failed, return 404
|
|
64
|
+
if (raw !== undefined && !mcpSessionHeader) {
|
|
65
|
+
this.respond(common_1.httpRespond.sessionNotFound('invalid session id'));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
53
68
|
let session;
|
|
54
69
|
if (mcpSessionHeader) {
|
|
55
70
|
// Client sent session ID - ALWAYS use it for transport lookup
|
|
@@ -70,7 +85,7 @@ let HandleStreamableHttpFlow = class HandleStreamableHttpFlow extends common_1.F
|
|
|
70
85
|
// No session - create new one (initialize request)
|
|
71
86
|
session = (0, session_id_utils_1.createSessionId)('streamable-http', token, {
|
|
72
87
|
userAgent: request.headers?.['user-agent'],
|
|
73
|
-
platformDetectionConfig: this.scope.metadata?.
|
|
88
|
+
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
74
89
|
});
|
|
75
90
|
}
|
|
76
91
|
this.state.set(exports.stateSchema.parse({ token, session }));
|
|
@@ -138,10 +153,31 @@ let HandleStreamableHttpFlow = class HandleStreamableHttpFlow extends common_1.F
|
|
|
138
153
|
const logger = this.scopeLogger.child('handle:streamable-http:onMessage');
|
|
139
154
|
const { request, response } = this.rawInput;
|
|
140
155
|
const { token, session } = this.state.required;
|
|
141
|
-
|
|
156
|
+
// 1. Try to get existing transport from memory
|
|
157
|
+
let transport = await transportService.getTransporter('streamable-http', token, session.id);
|
|
158
|
+
// 2. If not in memory, check if session exists in Redis and recreate
|
|
159
|
+
if (!transport) {
|
|
160
|
+
try {
|
|
161
|
+
const storedSession = await transportService.getStoredSession('streamable-http', token, session.id);
|
|
162
|
+
if (storedSession) {
|
|
163
|
+
logger.info('Recreating transport from Redis session', {
|
|
164
|
+
sessionId: session.id?.slice(0, 20),
|
|
165
|
+
createdAt: storedSession.createdAt,
|
|
166
|
+
});
|
|
167
|
+
transport = await transportService.recreateTransporter('streamable-http', token, session.id, storedSession, response);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
// Log and fall through to 404 logic - transport remains undefined
|
|
172
|
+
logger.warn('Failed to recreate transport from stored session', {
|
|
173
|
+
sessionId: session.id?.slice(0, 20),
|
|
174
|
+
error: error instanceof Error ? error.message : String(error),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
142
178
|
if (!transport) {
|
|
143
179
|
// Check if session was ever created to differentiate error types per MCP Spec 2025-11-25
|
|
144
|
-
const wasCreated = transportService.
|
|
180
|
+
const wasCreated = await transportService.wasSessionCreatedAsync('streamable-http', token, session.id);
|
|
145
181
|
const body = request.body;
|
|
146
182
|
if (wasCreated) {
|
|
147
183
|
// Session existed but was terminated/evicted → HTTP 404 (client should re-initialize)
|
|
@@ -188,10 +224,31 @@ let HandleStreamableHttpFlow = class HandleStreamableHttpFlow extends common_1.F
|
|
|
188
224
|
}
|
|
189
225
|
async onSseListener() {
|
|
190
226
|
const transportService = this.scope.transportService;
|
|
227
|
+
const logger = this.scopeLogger.child('handle:streamable-http:onSseListener');
|
|
191
228
|
const { request, response } = this.rawInput;
|
|
192
229
|
const { token, session } = this.state.required;
|
|
193
|
-
//
|
|
194
|
-
|
|
230
|
+
// 1. Try to get existing transport from memory
|
|
231
|
+
let transport = await transportService.getTransporter('streamable-http', token, session.id);
|
|
232
|
+
// 2. If not in memory, check if session exists in Redis and recreate
|
|
233
|
+
if (!transport) {
|
|
234
|
+
try {
|
|
235
|
+
const storedSession = await transportService.getStoredSession('streamable-http', token, session.id);
|
|
236
|
+
if (storedSession) {
|
|
237
|
+
logger.info('Recreating transport from Redis session for SSE listener', {
|
|
238
|
+
sessionId: session.id?.slice(0, 20),
|
|
239
|
+
createdAt: storedSession.createdAt,
|
|
240
|
+
});
|
|
241
|
+
transport = await transportService.recreateTransporter('streamable-http', token, session.id, storedSession, response);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
// Log and fall through to 404 logic - transport remains undefined
|
|
246
|
+
logger.warn('Failed to recreate transport from stored session for SSE listener', {
|
|
247
|
+
sessionId: session.id?.slice(0, 20),
|
|
248
|
+
error: error instanceof Error ? error.message : String(error),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
195
252
|
if (!transport) {
|
|
196
253
|
this.respond(common_1.httpRespond.notFound('Session not found'));
|
|
197
254
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle.streamable-http.flow.js","sourceRoot":"","sources":["../../../../src/transport/flows/handle.streamable-http.flow.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Flow,\n httpInputSchema,\n FlowRunOptions,\n httpOutputSchema,\n FlowPlan,\n FlowBase,\n FlowHooksOf,\n sessionIdSchema,\n httpRespond,\n ServerRequestTokens,\n Authorization,\n FlowControl,\n} from '../../common';\nimport { z } from 'zod';\nimport { ElicitResultSchema, RequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { Scope } from '../../scope';\nimport { createSessionId } from '../../auth/session/utils/session-id.utils';\n\nexport const plan = {\n pre: ['parseInput', 'router'],\n execute: ['onInitialize', 'onMessage', 'onElicitResult', 'onSseListener'],\n post: [],\n finalize: ['cleanup'],\n} as const satisfies FlowPlan<string>;\n\n// Relaxed session schema for state - payload is optional when using mcp-session-id header directly\nconst stateSessionSchema = z.object({\n id: z.string(),\n payload: z\n .object({\n nodeId: z.string(),\n authSig: z.string(),\n uuid: z.string().uuid(),\n iat: z.number(),\n protocol: z.enum(['legacy-sse', 'sse', 'streamable-http', 'stateful-http', 'stateless-http']).optional(),\n isPublic: z.boolean().optional(),\n platformType: z\n .enum(['openai', 'claude', 'gemini', 'cursor', 'continue', 'cody', 'generic-mcp', 'ext-apps', 'unknown'])\n .optional(),\n })\n .optional(),\n});\n\nexport const stateSchema = z.object({\n token: z.string(),\n session: stateSessionSchema,\n requestType: z.enum(['initialize', 'message', 'elicitResult', 'sseListener']).optional(),\n});\n\nconst name = 'handle:streamable-http' as const;\nconst { Stage } = FlowHooksOf(name);\n\ndeclare global {\n interface ExtendFlows {\n 'handle:streamable-http': FlowRunOptions<\n HandleStreamableHttpFlow,\n typeof plan,\n typeof httpInputSchema,\n typeof httpOutputSchema,\n typeof stateSchema\n >;\n }\n}\n\n@Flow({\n name,\n plan,\n access: 'authorized',\n inputSchema: httpInputSchema,\n outputSchema: httpOutputSchema,\n})\nexport default class HandleStreamableHttpFlow extends FlowBase<typeof name> {\n name = name;\n\n @Stage('parseInput')\n async parseInput() {\n const { request } = this.rawInput;\n\n const authorization = request[ServerRequestTokens.auth] as Authorization;\n const { token } = authorization;\n\n // CRITICAL: The mcp-session-id header is the client's reference to their session.\n // We MUST use this exact ID for transport registry lookup.\n //\n // Priority 1: Use mcp-session-id header if present (client's session ID for lookup)\n // This is the ID the client received from initialize and is referencing.\n // Priority 2: Use session from authorization if header matches or is absent\n // Priority 3: Create new session (first request - no header, no authorization.session)\n const mcpSessionHeader = request.headers?.['mcp-session-id'] as string | undefined;\n\n let session: { id: string; payload?: z.infer<typeof stateSchema>['session']['payload'] };\n\n if (mcpSessionHeader) {\n // Client sent session ID - ALWAYS use it for transport lookup\n // If authorization.session exists and matches, use its payload for protocol detection\n // If authorization.session differs or is missing, still use header ID (payload may be undefined)\n if (authorization.session?.id === mcpSessionHeader) {\n session = authorization.session;\n } else {\n session = { id: mcpSessionHeader };\n }\n } else if (authorization.session) {\n // No header but authorization has session - use it (shouldn't happen in normal flow)\n session = authorization.session;\n } else {\n // No session - create new one (initialize request)\n session = createSessionId('streamable-http', token, {\n userAgent: request.headers?.['user-agent'] as string | undefined,\n platformDetectionConfig: (this.scope as Scope).metadata?.session?.platformDetection,\n });\n }\n\n this.state.set(stateSchema.parse({ token, session }));\n }\n\n @Stage('router')\n async router() {\n const { request } = this.rawInput;\n\n // GET requests are SSE listener streams - no body expected\n // Per MCP spec, clients can open SSE stream with GET + Accept: text/event-stream\n if (request.method.toUpperCase() === 'GET') {\n this.state.set('requestType', 'sseListener');\n return;\n }\n\n // POST requests have MCP JSON-RPC body\n const body = request.body as { method?: string } | undefined;\n const method = body?.method;\n\n // Use method-based detection for routing (more permissive than strict schema)\n // The actual schema validation happens in the MCP SDK's transport layer\n if (method === 'initialize') {\n this.state.set('requestType', 'initialize');\n } else if (ElicitResultSchema.safeParse(request.body).success) {\n this.state.set('requestType', 'elicitResult');\n } else if (method && RequestSchema.safeParse(request.body).success) {\n this.state.set('requestType', 'message');\n } else {\n this.respond(httpRespond.rpcError('Invalid Request'));\n }\n }\n\n @Stage('onInitialize', {\n filter: ({ state: { requestType } }) => requestType === 'initialize',\n })\n async onInitialize() {\n const transportService = (this.scope as Scope).transportService;\n const logger = (this.scope as Scope).logger.child('handle:streamable-http:onInitialize');\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n\n logger.info('onInitialize: creating transport', {\n sessionId: session.id.slice(0, 30),\n hasToken: !!token,\n tokenPrefix: token?.slice(0, 10),\n });\n\n try {\n const transport = await transportService.createTransporter('streamable-http', token, session.id, response);\n logger.info('onInitialize: transport created, calling initialize');\n await transport.initialize(request, response);\n logger.info('onInitialize: completed successfully');\n this.handled();\n } catch (error) {\n // FlowControl is expected control flow (from this.handled()), not an error\n if (error instanceof FlowControl) {\n throw error;\n }\n logger.error('onInitialize: failed', {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n throw error;\n }\n }\n\n @Stage('onElicitResult', {\n filter: ({ state: { requestType } }) => requestType === 'elicitResult',\n })\n async onElicitResult() {\n this.fail(new Error('Not implemented'));\n }\n\n @Stage('onMessage', {\n filter: ({ state: { requestType } }) => requestType === 'message',\n })\n async onMessage() {\n const transportService = (this.scope as Scope).transportService;\n const logger = this.scopeLogger.child('handle:streamable-http:onMessage');\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n const transport = await transportService.getTransporter('streamable-http', token, session.id);\n if (!transport) {\n // Check if session was ever created to differentiate error types per MCP Spec 2025-11-25\n const wasCreated = transportService.wasSessionCreated('streamable-http', token, session.id);\n const body = request.body as Record<string, unknown> | undefined;\n\n if (wasCreated) {\n // Session existed but was terminated/evicted → HTTP 404 (client should re-initialize)\n logger.info('Session expired - client should re-initialize', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n mcpSessionId: request.headers?.['mcp-session-id'],\n });\n this.respond(httpRespond.sessionExpired('session expired'));\n } else {\n // Session was never created → HTTP 404 (per user requirement: invalid/missing session = 404)\n logger.warn('Session not initialized - client attempted request without initializing', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n mcpSessionId: request.headers?.['mcp-session-id'],\n userAgent: (request.headers?.['user-agent'] as string | undefined)?.slice(0, 50),\n });\n this.respond(httpRespond.sessionNotFound('session not initialized'));\n }\n return;\n }\n\n try {\n await transport.handleRequest(request, response);\n this.handled();\n } catch (error) {\n // FlowControl is expected control flow, not an error\n if (!(error instanceof FlowControl)) {\n const body = request.body as Record<string, unknown> | undefined;\n logger.error('handleRequest failed', {\n error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error,\n method: body?.['method'],\n id: body?.['id'],\n sessionId: session.id?.slice(0, 20),\n });\n }\n throw error;\n }\n }\n\n @Stage('onSseListener', {\n filter: ({ state: { requestType } }) => requestType === 'sseListener',\n })\n async onSseListener() {\n const transportService = (this.scope as Scope).transportService;\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n\n // Get existing transport for this session - SSE listener requires existing session\n const transport = await transportService.getTransporter('streamable-http', token, session.id);\n if (!transport) {\n this.respond(httpRespond.notFound('Session not found'));\n return;\n }\n\n // Forward GET request to transport (opens SSE stream for server→client notifications)\n await transport.handleRequest(request, response);\n this.handled();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"handle.streamable-http.flow.js","sourceRoot":"","sources":["../../../../src/transport/flows/handle.streamable-http.flow.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Flow,\n httpInputSchema,\n FlowRunOptions,\n httpOutputSchema,\n FlowPlan,\n FlowBase,\n FlowHooksOf,\n sessionIdSchema,\n httpRespond,\n ServerRequestTokens,\n Authorization,\n FlowControl,\n validateMcpSessionHeader,\n} from '../../common';\nimport { z } from 'zod';\nimport { ElicitResultSchema, RequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { Scope } from '../../scope';\nimport { createSessionId } from '../../auth/session/utils/session-id.utils';\n\nexport const plan = {\n pre: ['parseInput', 'router'],\n execute: ['onInitialize', 'onMessage', 'onElicitResult', 'onSseListener'],\n post: [],\n finalize: ['cleanup'],\n} as const satisfies FlowPlan<string>;\n\n// Relaxed session schema for state - payload is optional when using mcp-session-id header directly\nconst stateSessionSchema = z.object({\n id: z.string(),\n payload: z\n .object({\n nodeId: z.string(),\n authSig: z.string(),\n uuid: z.string().uuid(),\n iat: z.number(),\n protocol: z.enum(['legacy-sse', 'sse', 'streamable-http', 'stateful-http', 'stateless-http']).optional(),\n isPublic: z.boolean().optional(),\n platformType: z\n .enum(['openai', 'claude', 'gemini', 'cursor', 'continue', 'cody', 'generic-mcp', 'ext-apps', 'unknown'])\n .optional(),\n })\n .optional(),\n});\n\nexport const stateSchema = z.object({\n token: z.string(),\n session: stateSessionSchema,\n requestType: z.enum(['initialize', 'message', 'elicitResult', 'sseListener']).optional(),\n});\n\nconst name = 'handle:streamable-http' as const;\nconst { Stage } = FlowHooksOf(name);\n\ndeclare global {\n interface ExtendFlows {\n 'handle:streamable-http': FlowRunOptions<\n HandleStreamableHttpFlow,\n typeof plan,\n typeof httpInputSchema,\n typeof httpOutputSchema,\n typeof stateSchema\n >;\n }\n}\n\n@Flow({\n name,\n plan,\n access: 'authorized',\n inputSchema: httpInputSchema,\n outputSchema: httpOutputSchema,\n})\nexport default class HandleStreamableHttpFlow extends FlowBase<typeof name> {\n name = name;\n\n @Stage('parseInput')\n async parseInput() {\n const { request } = this.rawInput;\n\n console.log('[DEBUG] parseInput: starting');\n const authorization = request[ServerRequestTokens.auth] as Authorization;\n console.log(\n '[DEBUG] parseInput: authorization =',\n authorization\n ? {\n hasToken: !!authorization.token,\n hasSession: !!authorization.session,\n sessionId: authorization.session?.id?.slice(0, 30),\n }\n : 'undefined',\n );\n const { token } = authorization;\n\n // CRITICAL: The mcp-session-id header is the client's reference to their session.\n // We MUST use this exact ID for transport registry lookup.\n //\n // Priority 1: Use mcp-session-id header if present (client's session ID for lookup)\n // This is the ID the client received from initialize and is referencing.\n // Priority 2: Use session from authorization if header matches or is absent\n // Priority 3: Create new session (first request - no header, no authorization.session)\n const raw = request.headers?.['mcp-session-id'];\n const rawMcpSessionHeader = typeof raw === 'string' ? raw : undefined;\n const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);\n\n // If client sent a header but validation failed, return 404\n if (raw !== undefined && !mcpSessionHeader) {\n this.respond(httpRespond.sessionNotFound('invalid session id'));\n return;\n }\n\n let session: { id: string; payload?: z.infer<typeof stateSchema>['session']['payload'] };\n\n if (mcpSessionHeader) {\n // Client sent session ID - ALWAYS use it for transport lookup\n // If authorization.session exists and matches, use its payload for protocol detection\n // If authorization.session differs or is missing, still use header ID (payload may be undefined)\n if (authorization.session?.id === mcpSessionHeader) {\n session = authorization.session;\n } else {\n session = { id: mcpSessionHeader };\n }\n } else if (authorization.session) {\n // No header but authorization has session - use it (shouldn't happen in normal flow)\n session = authorization.session;\n } else {\n // No session - create new one (initialize request)\n session = createSessionId('streamable-http', token, {\n userAgent: request.headers?.['user-agent'] as string | undefined,\n platformDetectionConfig: (this.scope as Scope).metadata.transport?.platformDetection,\n });\n }\n\n this.state.set(stateSchema.parse({ token, session }));\n }\n\n @Stage('router')\n async router() {\n const { request } = this.rawInput;\n\n // GET requests are SSE listener streams - no body expected\n // Per MCP spec, clients can open SSE stream with GET + Accept: text/event-stream\n if (request.method.toUpperCase() === 'GET') {\n this.state.set('requestType', 'sseListener');\n return;\n }\n\n // POST requests have MCP JSON-RPC body\n const body = request.body as { method?: string } | undefined;\n const method = body?.method;\n\n // Use method-based detection for routing (more permissive than strict schema)\n // The actual schema validation happens in the MCP SDK's transport layer\n if (method === 'initialize') {\n this.state.set('requestType', 'initialize');\n } else if (ElicitResultSchema.safeParse(request.body).success) {\n this.state.set('requestType', 'elicitResult');\n } else if (method && RequestSchema.safeParse(request.body).success) {\n this.state.set('requestType', 'message');\n } else {\n this.respond(httpRespond.rpcError('Invalid Request'));\n }\n }\n\n @Stage('onInitialize', {\n filter: ({ state: { requestType } }) => requestType === 'initialize',\n })\n async onInitialize() {\n const transportService = (this.scope as Scope).transportService;\n const logger = (this.scope as Scope).logger.child('handle:streamable-http:onInitialize');\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n\n logger.info('onInitialize: creating transport', {\n sessionId: session.id.slice(0, 30),\n hasToken: !!token,\n tokenPrefix: token?.slice(0, 10),\n });\n\n try {\n const transport = await transportService.createTransporter('streamable-http', token, session.id, response);\n logger.info('onInitialize: transport created, calling initialize');\n await transport.initialize(request, response);\n logger.info('onInitialize: completed successfully');\n this.handled();\n } catch (error) {\n // FlowControl is expected control flow (from this.handled()), not an error\n if (error instanceof FlowControl) {\n throw error;\n }\n logger.error('onInitialize: failed', {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n throw error;\n }\n }\n\n @Stage('onElicitResult', {\n filter: ({ state: { requestType } }) => requestType === 'elicitResult',\n })\n async onElicitResult() {\n this.fail(new Error('Not implemented'));\n }\n\n @Stage('onMessage', {\n filter: ({ state: { requestType } }) => requestType === 'message',\n })\n async onMessage() {\n const transportService = (this.scope as Scope).transportService;\n const logger = this.scopeLogger.child('handle:streamable-http:onMessage');\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n\n // 1. Try to get existing transport from memory\n let transport = await transportService.getTransporter('streamable-http', token, session.id);\n\n // 2. If not in memory, check if session exists in Redis and recreate\n if (!transport) {\n try {\n const storedSession = await transportService.getStoredSession('streamable-http', token, session.id);\n if (storedSession) {\n logger.info('Recreating transport from Redis session', {\n sessionId: session.id?.slice(0, 20),\n createdAt: storedSession.createdAt,\n });\n transport = await transportService.recreateTransporter(\n 'streamable-http',\n token,\n session.id,\n storedSession,\n response,\n );\n }\n } catch (error) {\n // Log and fall through to 404 logic - transport remains undefined\n logger.warn('Failed to recreate transport from stored session', {\n sessionId: session.id?.slice(0, 20),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (!transport) {\n // Check if session was ever created to differentiate error types per MCP Spec 2025-11-25\n const wasCreated = await transportService.wasSessionCreatedAsync('streamable-http', token, session.id);\n const body = request.body as Record<string, unknown> | undefined;\n\n if (wasCreated) {\n // Session existed but was terminated/evicted → HTTP 404 (client should re-initialize)\n logger.info('Session expired - client should re-initialize', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n mcpSessionId: request.headers?.['mcp-session-id'],\n });\n this.respond(httpRespond.sessionExpired('session expired'));\n } else {\n // Session was never created → HTTP 404 (per user requirement: invalid/missing session = 404)\n logger.warn('Session not initialized - client attempted request without initializing', {\n sessionId: session.id?.slice(0, 20),\n tokenHash: token.slice(0, 8),\n method: body?.['method'],\n requestId: body?.['id'],\n mcpSessionId: request.headers?.['mcp-session-id'],\n userAgent: (request.headers?.['user-agent'] as string | undefined)?.slice(0, 50),\n });\n this.respond(httpRespond.sessionNotFound('session not initialized'));\n }\n return;\n }\n\n try {\n await transport.handleRequest(request, response);\n this.handled();\n } catch (error) {\n // FlowControl is expected control flow, not an error\n if (!(error instanceof FlowControl)) {\n const body = request.body as Record<string, unknown> | undefined;\n logger.error('handleRequest failed', {\n error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error,\n method: body?.['method'],\n id: body?.['id'],\n sessionId: session.id?.slice(0, 20),\n });\n }\n throw error;\n }\n }\n\n @Stage('onSseListener', {\n filter: ({ state: { requestType } }) => requestType === 'sseListener',\n })\n async onSseListener() {\n const transportService = (this.scope as Scope).transportService;\n const logger = this.scopeLogger.child('handle:streamable-http:onSseListener');\n\n const { request, response } = this.rawInput;\n const { token, session } = this.state.required;\n\n // 1. Try to get existing transport from memory\n let transport = await transportService.getTransporter('streamable-http', token, session.id);\n\n // 2. If not in memory, check if session exists in Redis and recreate\n if (!transport) {\n try {\n const storedSession = await transportService.getStoredSession('streamable-http', token, session.id);\n if (storedSession) {\n logger.info('Recreating transport from Redis session for SSE listener', {\n sessionId: session.id?.slice(0, 20),\n createdAt: storedSession.createdAt,\n });\n transport = await transportService.recreateTransporter(\n 'streamable-http',\n token,\n session.id,\n storedSession,\n response,\n );\n }\n } catch (error) {\n // Log and fall through to 404 logic - transport remains undefined\n logger.warn('Failed to recreate transport from stored session for SSE listener', {\n sessionId: session.id?.slice(0, 20),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (!transport) {\n this.respond(httpRespond.notFound('Session not found'));\n return;\n }\n\n // Forward GET request to transport (opens SSE stream for server→client notifications)\n await transport.handleRequest(request, response);\n this.handled();\n }\n}\n"]}
|
|
@@ -4,8 +4,15 @@ export default function CompleteRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
4
4
|
requestSchema: import("zod").ZodObject<{
|
|
5
5
|
method: import("zod").ZodLiteral<"completion/complete">;
|
|
6
6
|
params: import("zod").ZodObject<{
|
|
7
|
+
task: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
8
|
+
ttl: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodNumber, import("zod").ZodNull]>>;
|
|
9
|
+
pollInterval: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
10
|
+
}, import("zod/v4/core").$loose>>;
|
|
7
11
|
_meta: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
8
12
|
progressToken: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodNumber]>>;
|
|
13
|
+
"io.modelcontextprotocol/related-task": import("zod").ZodOptional<import("zod").ZodObject<{
|
|
14
|
+
taskId: import("zod").ZodString;
|
|
15
|
+
}, import("zod/v4/core").$loose>>;
|
|
9
16
|
}, import("zod/v4/core").$loose>>;
|
|
10
17
|
ref: import("zod").ZodUnion<readonly [import("zod").ZodObject<{
|
|
11
18
|
type: import("zod").ZodLiteral<"ref/prompt">;
|
|
@@ -38,9 +45,18 @@ export default function CompleteRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
38
45
|
name: string;
|
|
39
46
|
value: string;
|
|
40
47
|
};
|
|
48
|
+
task?: {
|
|
49
|
+
[x: string]: unknown;
|
|
50
|
+
ttl?: number | null | undefined;
|
|
51
|
+
pollInterval?: number | undefined;
|
|
52
|
+
} | undefined;
|
|
41
53
|
_meta?: {
|
|
42
54
|
[x: string]: unknown;
|
|
43
55
|
progressToken?: string | number | undefined;
|
|
56
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
57
|
+
[x: string]: unknown;
|
|
58
|
+
taskId: string;
|
|
59
|
+
} | undefined;
|
|
44
60
|
} | undefined;
|
|
45
61
|
context?: {
|
|
46
62
|
arguments?: {
|
|
@@ -54,6 +70,10 @@ export default function CompleteRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
54
70
|
[x: string]: unknown;
|
|
55
71
|
_meta?: {
|
|
56
72
|
[x: string]: unknown;
|
|
73
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
74
|
+
[x: string]: unknown;
|
|
75
|
+
taskId: string;
|
|
76
|
+
} | undefined;
|
|
57
77
|
} | undefined;
|
|
58
78
|
} | undefined;
|
|
59
79
|
}>) => Promise<{
|
|
@@ -64,6 +84,12 @@ export default function CompleteRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
64
84
|
total?: number | undefined;
|
|
65
85
|
hasMore?: boolean | undefined;
|
|
66
86
|
};
|
|
67
|
-
_meta?:
|
|
87
|
+
_meta?: {
|
|
88
|
+
[x: string]: unknown;
|
|
89
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
90
|
+
[x: string]: unknown;
|
|
91
|
+
taskId: string;
|
|
92
|
+
} | undefined;
|
|
93
|
+
} | undefined;
|
|
68
94
|
}>;
|
|
69
95
|
};
|
|
@@ -4,8 +4,15 @@ export default function GetPromptRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
4
4
|
requestSchema: import("zod").ZodObject<{
|
|
5
5
|
method: import("zod").ZodLiteral<"prompts/get">;
|
|
6
6
|
params: import("zod").ZodObject<{
|
|
7
|
+
task: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
8
|
+
ttl: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodNumber, import("zod").ZodNull]>>;
|
|
9
|
+
pollInterval: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
10
|
+
}, import("zod/v4/core").$loose>>;
|
|
7
11
|
_meta: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
8
12
|
progressToken: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodNumber]>>;
|
|
13
|
+
"io.modelcontextprotocol/related-task": import("zod").ZodOptional<import("zod").ZodObject<{
|
|
14
|
+
taskId: import("zod").ZodString;
|
|
15
|
+
}, import("zod/v4/core").$loose>>;
|
|
9
16
|
}, import("zod/v4/core").$loose>>;
|
|
10
17
|
name: import("zod").ZodString;
|
|
11
18
|
arguments: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>>;
|
|
@@ -16,9 +23,18 @@ export default function GetPromptRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
16
23
|
params: {
|
|
17
24
|
[x: string]: unknown;
|
|
18
25
|
name: string;
|
|
26
|
+
task?: {
|
|
27
|
+
[x: string]: unknown;
|
|
28
|
+
ttl?: number | null | undefined;
|
|
29
|
+
pollInterval?: number | undefined;
|
|
30
|
+
} | undefined;
|
|
19
31
|
_meta?: {
|
|
20
32
|
[x: string]: unknown;
|
|
21
33
|
progressToken?: string | number | undefined;
|
|
34
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
35
|
+
[x: string]: unknown;
|
|
36
|
+
taskId: string;
|
|
37
|
+
} | undefined;
|
|
22
38
|
} | undefined;
|
|
23
39
|
arguments?: {
|
|
24
40
|
[x: string]: string;
|
|
@@ -30,6 +46,10 @@ export default function GetPromptRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
30
46
|
[x: string]: unknown;
|
|
31
47
|
_meta?: {
|
|
32
48
|
[x: string]: unknown;
|
|
49
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
50
|
+
[x: string]: unknown;
|
|
51
|
+
taskId: string;
|
|
52
|
+
} | undefined;
|
|
33
53
|
} | undefined;
|
|
34
54
|
} | undefined;
|
|
35
55
|
}>) => Promise<{
|
|
@@ -39,16 +59,31 @@ export default function GetPromptRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
39
59
|
content: {
|
|
40
60
|
type: "text";
|
|
41
61
|
text: string;
|
|
62
|
+
annotations?: {
|
|
63
|
+
audience?: ("user" | "assistant")[] | undefined;
|
|
64
|
+
priority?: number | undefined;
|
|
65
|
+
lastModified?: string | undefined;
|
|
66
|
+
} | undefined;
|
|
42
67
|
_meta?: Record<string, unknown> | undefined;
|
|
43
68
|
} | {
|
|
44
69
|
type: "image";
|
|
45
70
|
data: string;
|
|
46
71
|
mimeType: string;
|
|
72
|
+
annotations?: {
|
|
73
|
+
audience?: ("user" | "assistant")[] | undefined;
|
|
74
|
+
priority?: number | undefined;
|
|
75
|
+
lastModified?: string | undefined;
|
|
76
|
+
} | undefined;
|
|
47
77
|
_meta?: Record<string, unknown> | undefined;
|
|
48
78
|
} | {
|
|
49
79
|
type: "audio";
|
|
50
80
|
data: string;
|
|
51
81
|
mimeType: string;
|
|
82
|
+
annotations?: {
|
|
83
|
+
audience?: ("user" | "assistant")[] | undefined;
|
|
84
|
+
priority?: number | undefined;
|
|
85
|
+
lastModified?: string | undefined;
|
|
86
|
+
} | undefined;
|
|
52
87
|
_meta?: Record<string, unknown> | undefined;
|
|
53
88
|
} | {
|
|
54
89
|
uri: string;
|
|
@@ -56,6 +91,11 @@ export default function GetPromptRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
56
91
|
type: "resource_link";
|
|
57
92
|
description?: string | undefined;
|
|
58
93
|
mimeType?: string | undefined;
|
|
94
|
+
annotations?: {
|
|
95
|
+
audience?: ("user" | "assistant")[] | undefined;
|
|
96
|
+
priority?: number | undefined;
|
|
97
|
+
lastModified?: string | undefined;
|
|
98
|
+
} | undefined;
|
|
59
99
|
_meta?: {
|
|
60
100
|
[x: string]: unknown;
|
|
61
101
|
} | undefined;
|
|
@@ -78,10 +118,21 @@ export default function GetPromptRequestHandler({ scope }: McpHandlerOptions): {
|
|
|
78
118
|
mimeType?: string | undefined;
|
|
79
119
|
_meta?: Record<string, unknown> | undefined;
|
|
80
120
|
};
|
|
121
|
+
annotations?: {
|
|
122
|
+
audience?: ("user" | "assistant")[] | undefined;
|
|
123
|
+
priority?: number | undefined;
|
|
124
|
+
lastModified?: string | undefined;
|
|
125
|
+
} | undefined;
|
|
81
126
|
_meta?: Record<string, unknown> | undefined;
|
|
82
127
|
};
|
|
83
128
|
}[];
|
|
84
|
-
_meta?:
|
|
129
|
+
_meta?: {
|
|
130
|
+
[x: string]: unknown;
|
|
131
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
132
|
+
[x: string]: unknown;
|
|
133
|
+
taskId: string;
|
|
134
|
+
} | undefined;
|
|
135
|
+
} | undefined;
|
|
85
136
|
description?: string | undefined;
|
|
86
137
|
}>;
|
|
87
138
|
};
|