effect 4.0.7 → 4.1.1
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 +31 -1
- package/THIRD_PARTY_NOTICES.md +62 -0
- package/dist/BigDecimal.d.ts +139 -7
- package/dist/BigDecimal.d.ts.map +1 -1
- package/dist/BigDecimal.js +86 -14
- package/dist/BigDecimal.js.map +1 -1
- package/dist/Channel.d.ts +12 -6
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +9 -3
- package/dist/Channel.js.map +1 -1
- package/dist/Config.d.ts +7 -1
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js.map +1 -1
- package/dist/Context.d.ts +18 -1
- package/dist/Context.d.ts.map +1 -1
- package/dist/Context.js +27 -8
- package/dist/Context.js.map +1 -1
- package/dist/Cron.d.ts +81 -11
- package/dist/Cron.d.ts.map +1 -1
- package/dist/Cron.js +101 -26
- package/dist/Cron.js.map +1 -1
- package/dist/Duration.d.ts +78 -0
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +123 -0
- package/dist/Duration.js.map +1 -1
- package/dist/Effect.d.ts +164 -7
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +11 -1
- package/dist/Effect.js.map +1 -1
- package/dist/Equal.d.ts +2 -2
- package/dist/Equal.d.ts.map +1 -1
- package/dist/Equal.js +3 -3
- package/dist/Equal.js.map +1 -1
- package/dist/FileSystem.d.ts +59 -4
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js +9 -2
- package/dist/FileSystem.js.map +1 -1
- package/dist/Glob.d.ts +165 -0
- package/dist/Glob.d.ts.map +1 -0
- package/dist/Glob.js +127 -0
- package/dist/Glob.js.map +1 -0
- package/dist/Hash.d.ts +3 -2
- package/dist/Hash.d.ts.map +1 -1
- package/dist/Hash.js +5 -4
- package/dist/Hash.js.map +1 -1
- package/dist/Iterable.d.ts.map +1 -1
- package/dist/Iterable.js +11 -8
- package/dist/Iterable.js.map +1 -1
- package/dist/Match.d.ts +86 -0
- package/dist/Match.d.ts.map +1 -1
- package/dist/Match.js +72 -0
- package/dist/Match.js.map +1 -1
- package/dist/Path.d.ts.map +1 -1
- package/dist/Path.js +5 -1
- package/dist/Path.js.map +1 -1
- package/dist/Pool.d.ts +51 -0
- package/dist/Pool.d.ts.map +1 -1
- package/dist/Pool.js +61 -10
- package/dist/Pool.js.map +1 -1
- package/dist/Random.d.ts.map +1 -1
- package/dist/Random.js +3 -3
- package/dist/Random.js.map +1 -1
- package/dist/RcMap.d.ts.map +1 -1
- package/dist/RcMap.js +8 -2
- package/dist/RcMap.js.map +1 -1
- package/dist/Schedule.d.ts +18 -1
- package/dist/Schedule.d.ts.map +1 -1
- package/dist/Schedule.js +7 -2
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +668 -42
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +652 -1
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaGetter.d.ts +6 -1
- package/dist/SchemaGetter.d.ts.map +1 -1
- package/dist/SchemaGetter.js +22 -11
- package/dist/SchemaGetter.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +18 -2
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +20 -2
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/SchemaTransformation.d.ts +10 -5
- package/dist/SchemaTransformation.d.ts.map +1 -1
- package/dist/SchemaTransformation.js +8 -5
- package/dist/SchemaTransformation.js.map +1 -1
- package/dist/ScopedCache.d.ts.map +1 -1
- package/dist/ScopedCache.js +5 -7
- package/dist/ScopedCache.js.map +1 -1
- package/dist/Semaphore.d.ts +130 -0
- package/dist/Semaphore.d.ts.map +1 -1
- package/dist/Semaphore.js +40 -0
- package/dist/Semaphore.js.map +1 -1
- package/dist/Stream.d.ts +13 -4
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +9 -0
- package/dist/Stream.js.map +1 -1
- package/dist/Terminal.d.ts +18 -1
- package/dist/Terminal.d.ts.map +1 -1
- package/dist/Terminal.js +1 -1
- package/dist/Terminal.js.map +1 -1
- package/dist/ai/AiError.d.ts +43 -116
- package/dist/ai/AiError.d.ts.map +1 -1
- package/dist/ai/AiError.js +53 -72
- package/dist/ai/AiError.js.map +1 -1
- package/dist/ai/Decision.d.ts +196 -15
- package/dist/ai/Decision.d.ts.map +1 -1
- package/dist/ai/Decision.js +130 -0
- package/dist/ai/Decision.js.map +1 -1
- package/dist/ai/DecisionModel.d.ts +54 -13
- package/dist/ai/DecisionModel.d.ts.map +1 -1
- package/dist/ai/DecisionModel.js +123 -12
- package/dist/ai/DecisionModel.js.map +1 -1
- package/dist/ai/McpClient.d.ts +171 -19
- package/dist/ai/McpClient.d.ts.map +1 -1
- package/dist/ai/McpClient.js +277 -66
- package/dist/ai/McpClient.js.map +1 -1
- package/dist/ai/McpSchema.d.ts +108 -0
- package/dist/ai/McpSchema.d.ts.map +1 -1
- package/dist/ai/McpSchema.js +99 -0
- package/dist/ai/McpSchema.js.map +1 -1
- package/dist/ai/McpServer.d.ts +744 -29
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +763 -136
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/McpTest.d.ts +130 -0
- package/dist/ai/McpTest.d.ts.map +1 -0
- package/dist/ai/McpTest.js +237 -0
- package/dist/ai/McpTest.js.map +1 -0
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +20 -11
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Response.d.ts +1 -25
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js +1 -10
- package/dist/ai/Response.js.map +1 -1
- package/dist/ai/Tool.d.ts +19 -1
- package/dist/ai/Tool.d.ts.map +1 -1
- package/dist/ai/Tool.js +5 -7
- package/dist/ai/Tool.js.map +1 -1
- package/dist/ai/index.d.ts +5 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +5 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/internal/mcpCore.js +89 -15
- package/dist/ai/internal/mcpCore.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js +7 -6
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js +7 -6
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js +7 -6
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js +7 -6
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js +60 -17
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
- package/dist/ai/internal/mcpProtocol.js +25 -0
- package/dist/ai/internal/mcpProtocol.js.map +1 -1
- package/dist/ai/internal/mcpRuntime.js +8 -6
- package/dist/ai/internal/mcpRuntime.js.map +1 -1
- package/dist/ai/internal/mcpSkills.d.ts +2 -0
- package/dist/ai/internal/mcpSkills.d.ts.map +1 -0
- package/dist/ai/internal/mcpSkills.js +428 -0
- package/dist/ai/internal/mcpSkills.js.map +1 -0
- package/dist/ai/internal/mcpStatefulRuntime.js +6 -1
- package/dist/ai/internal/mcpStatefulRuntime.js.map +1 -1
- package/dist/cli/Argument.d.ts +6 -0
- package/dist/cli/Argument.d.ts.map +1 -1
- package/dist/cli/Argument.js +2 -0
- package/dist/cli/Argument.js.map +1 -1
- package/dist/cli/CliOutput.d.ts +65 -1
- package/dist/cli/CliOutput.d.ts.map +1 -1
- package/dist/cli/CliOutput.js +94 -37
- package/dist/cli/CliOutput.js.map +1 -1
- package/dist/cli/Command.d.ts +23 -0
- package/dist/cli/Command.d.ts.map +1 -1
- package/dist/cli/Command.js +8 -0
- package/dist/cli/Command.js.map +1 -1
- package/dist/cli/Flag.d.ts +107 -0
- package/dist/cli/Flag.d.ts.map +1 -1
- package/dist/cli/Flag.js +37 -0
- package/dist/cli/Flag.js.map +1 -1
- package/dist/cli/HelpDoc.d.ts +15 -1
- package/dist/cli/HelpDoc.d.ts.map +1 -1
- package/dist/cli/Param.d.ts +6 -0
- package/dist/cli/Param.d.ts.map +1 -1
- package/dist/cli/Param.js +2 -0
- package/dist/cli/Param.js.map +1 -1
- package/dist/cli/Primitive.d.ts +14 -0
- package/dist/cli/Primitive.d.ts.map +1 -1
- package/dist/cli/Primitive.js +15 -1
- package/dist/cli/Primitive.js.map +1 -1
- package/dist/cli/Prompt.d.ts +1 -0
- package/dist/cli/Prompt.d.ts.map +1 -1
- package/dist/cli/Prompt.js +1 -0
- package/dist/cli/Prompt.js.map +1 -1
- package/dist/cli/internal/help.d.ts.map +1 -1
- package/dist/cli/internal/help.js +17 -10
- package/dist/cli/internal/help.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +15 -5
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/Reply.d.ts +1 -1
- package/dist/cluster/Reply.d.ts.map +1 -1
- package/dist/cluster/Reply.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +93 -28
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/ShardingConfig.d.ts +72 -6
- package/dist/cluster/ShardingConfig.d.ts.map +1 -1
- package/dist/cluster/ShardingConfig.js +4 -0
- package/dist/cluster/ShardingConfig.js.map +1 -1
- package/dist/cluster/SingleRunner.d.ts +3 -3
- package/dist/cluster/SingleRunner.d.ts.map +1 -1
- package/dist/cluster/SingleRunner.js +1 -1
- package/dist/cluster/SqlMessageStorage.d.ts +37 -6
- package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
- package/dist/cluster/SqlMessageStorage.js +34 -7
- package/dist/cluster/SqlMessageStorage.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +23 -8
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +15 -7
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/crypto/Aead.d.ts +323 -0
- package/dist/crypto/Aead.d.ts.map +1 -0
- package/dist/crypto/Aead.js +331 -0
- package/dist/crypto/Aead.js.map +1 -0
- package/dist/crypto/Cipher.d.ts +236 -0
- package/dist/crypto/Cipher.d.ts.map +1 -0
- package/dist/crypto/Cipher.js +233 -0
- package/dist/crypto/Cipher.js.map +1 -0
- package/dist/crypto/CryptoError.d.ts +212 -0
- package/dist/crypto/CryptoError.d.ts.map +1 -0
- package/dist/crypto/CryptoError.js +202 -0
- package/dist/crypto/CryptoError.js.map +1 -0
- package/dist/crypto/Digest.d.ts +143 -0
- package/dist/crypto/Digest.d.ts.map +1 -0
- package/dist/crypto/Digest.js +146 -0
- package/dist/crypto/Digest.js.map +1 -0
- package/dist/crypto/Kdf.d.ts +220 -0
- package/dist/crypto/Kdf.d.ts.map +1 -0
- package/dist/crypto/Kdf.js +212 -0
- package/dist/crypto/Kdf.js.map +1 -0
- package/dist/crypto/KeyAgreement.d.ts +324 -0
- package/dist/crypto/KeyAgreement.d.ts.map +1 -0
- package/dist/crypto/KeyAgreement.js +303 -0
- package/dist/crypto/KeyAgreement.js.map +1 -0
- package/dist/crypto/KeyFormat.d.ts +341 -0
- package/dist/crypto/KeyFormat.d.ts.map +1 -0
- package/dist/crypto/KeyFormat.js +556 -0
- package/dist/crypto/KeyFormat.js.map +1 -0
- package/dist/crypto/KeyWrap.d.ts +390 -0
- package/dist/crypto/KeyWrap.d.ts.map +1 -0
- package/dist/crypto/KeyWrap.js +381 -0
- package/dist/crypto/KeyWrap.js.map +1 -0
- package/dist/crypto/Mac.d.ts +278 -0
- package/dist/crypto/Mac.d.ts.map +1 -0
- package/dist/crypto/Mac.js +288 -0
- package/dist/crypto/Mac.js.map +1 -0
- package/dist/crypto/SecureRandom.d.ts +340 -0
- package/dist/crypto/SecureRandom.d.ts.map +1 -0
- package/dist/crypto/SecureRandom.js +257 -0
- package/dist/crypto/SecureRandom.js.map +1 -0
- package/dist/crypto/Signature.d.ts +449 -0
- package/dist/crypto/Signature.d.ts.map +1 -0
- package/dist/crypto/Signature.js +484 -0
- package/dist/crypto/Signature.js.map +1 -0
- package/dist/crypto/WebCrypto.d.ts +80 -0
- package/dist/crypto/WebCrypto.d.ts.map +1 -0
- package/dist/crypto/WebCrypto.js +63 -0
- package/dist/crypto/WebCrypto.js.map +1 -0
- package/dist/crypto/index.d.ts +65 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +66 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/internal/asymmetric.d.ts +2 -0
- package/dist/crypto/internal/asymmetric.d.ts.map +1 -0
- package/dist/crypto/internal/asymmetric.js +210 -0
- package/dist/crypto/internal/asymmetric.js.map +1 -0
- package/dist/crypto/internal/chacha.d.ts +46 -0
- package/dist/crypto/internal/chacha.d.ts.map +1 -0
- package/dist/crypto/internal/chacha.js +885 -0
- package/dist/crypto/internal/chacha.js.map +1 -0
- package/dist/crypto/internal/der.d.ts +6 -0
- package/dist/crypto/internal/der.d.ts.map +1 -0
- package/dist/crypto/internal/der.js +86 -0
- package/dist/crypto/internal/der.js.map +1 -0
- package/dist/crypto/internal/digest.d.ts +2 -0
- package/dist/crypto/internal/digest.d.ts.map +1 -0
- package/dist/crypto/internal/digest.js +15 -0
- package/dist/crypto/internal/digest.js.map +1 -0
- package/dist/crypto/internal/key.d.ts +2 -0
- package/dist/crypto/internal/key.d.ts.map +1 -0
- package/dist/crypto/internal/key.js +171 -0
- package/dist/crypto/internal/key.js.map +1 -0
- package/dist/crypto/internal/md5.d.ts +39 -0
- package/dist/crypto/internal/md5.d.ts.map +1 -0
- package/dist/crypto/internal/md5.js +179 -0
- package/dist/crypto/internal/md5.js.map +1 -0
- package/dist/crypto/internal/webCrypto.d.ts +2 -0
- package/dist/crypto/internal/webCrypto.d.ts.map +1 -0
- package/dist/crypto/internal/webCrypto.js +111 -0
- package/dist/crypto/internal/webCrypto.js.map +1 -0
- package/dist/encoding/Base64Url.d.ts.map +1 -1
- package/dist/encoding/Base64Url.js +29 -5
- package/dist/encoding/Base64Url.js.map +1 -1
- package/dist/encoding/Csv.d.ts +608 -0
- package/dist/encoding/Csv.d.ts.map +1 -0
- package/dist/encoding/Csv.js +718 -0
- package/dist/encoding/Csv.js.map +1 -0
- package/dist/encoding/Hex.d.ts +3 -2
- package/dist/encoding/Hex.d.ts.map +1 -1
- package/dist/encoding/Hex.js +3 -2
- package/dist/encoding/Hex.js.map +1 -1
- package/dist/encoding/Ndjson.d.ts +5 -4
- package/dist/encoding/Ndjson.d.ts.map +1 -1
- package/dist/encoding/Ndjson.js +6 -5
- package/dist/encoding/Ndjson.js.map +1 -1
- package/dist/encoding/SchemaBinary.d.ts.map +1 -1
- package/dist/encoding/SchemaBinary.js +42 -4
- package/dist/encoding/SchemaBinary.js.map +1 -1
- package/dist/encoding/Sse.d.ts +3 -1
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +5 -3
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/encoding/Toml.d.ts +17 -3
- package/dist/encoding/Toml.d.ts.map +1 -1
- package/dist/encoding/Toml.js +104 -16
- package/dist/encoding/Toml.js.map +1 -1
- package/dist/encoding/Yaml.d.ts +8 -1
- package/dist/encoding/Yaml.d.ts.map +1 -1
- package/dist/encoding/Yaml.js +54 -18
- package/dist/encoding/Yaml.js.map +1 -1
- package/dist/encoding/index.d.ts +5 -0
- package/dist/encoding/index.d.ts.map +1 -1
- package/dist/encoding/index.js +5 -0
- package/dist/encoding/index.js.map +1 -1
- package/dist/eventlog/EventJournal.d.ts.map +1 -1
- package/dist/eventlog/EventJournal.js +6 -3
- package/dist/eventlog/EventJournal.js.map +1 -1
- package/dist/eventlog/EventLog.d.ts +126 -4
- package/dist/eventlog/EventLog.d.ts.map +1 -1
- package/dist/eventlog/EventLog.js +207 -12
- package/dist/eventlog/EventLog.js.map +1 -1
- package/dist/eventlog/EventLogEncryption.d.ts +41 -4
- package/dist/eventlog/EventLogEncryption.d.ts.map +1 -1
- package/dist/eventlog/EventLogEncryption.js +83 -64
- package/dist/eventlog/EventLogEncryption.js.map +1 -1
- package/dist/eventlog/EventLogMessage.d.ts +279 -0
- package/dist/eventlog/EventLogMessage.d.ts.map +1 -1
- package/dist/eventlog/EventLogMessage.js +217 -1
- package/dist/eventlog/EventLogMessage.js.map +1 -1
- package/dist/eventlog/EventLogRemote.d.ts +200 -28
- package/dist/eventlog/EventLogRemote.d.ts.map +1 -1
- package/dist/eventlog/EventLogRemote.js +186 -16
- package/dist/eventlog/EventLogRemote.js.map +1 -1
- package/dist/eventlog/EventLogServer.d.ts +10 -1
- package/dist/eventlog/EventLogServer.d.ts.map +1 -1
- package/dist/eventlog/EventLogServer.js +45 -22
- package/dist/eventlog/EventLogServer.js.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.d.ts +336 -5
- package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.js +769 -14
- package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.d.ts +17 -0
- package/dist/eventlog/EventLogServerUnencrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.js +14 -2
- package/dist/eventlog/EventLogServerUnencrypted.js.map +1 -1
- package/dist/eventlog/EventLogSessionAuth.d.ts +26 -3
- package/dist/eventlog/EventLogSessionAuth.d.ts.map +1 -1
- package/dist/eventlog/EventLogSessionAuth.js +63 -64
- package/dist/eventlog/EventLogSessionAuth.js.map +1 -1
- package/dist/eventlog/EventRow.d.ts +4 -0
- package/dist/eventlog/EventRow.d.ts.map +1 -1
- package/dist/eventlog/EventRow.js +12 -2
- package/dist/eventlog/EventRow.js.map +1 -1
- package/dist/eventlog/SqlEventJournal.js +2 -2
- package/dist/eventlog/SqlEventJournal.js.map +1 -1
- package/dist/eventlog/SqlEventLogServerEncrypted.d.ts +21 -5
- package/dist/eventlog/SqlEventLogServerEncrypted.d.ts.map +1 -1
- package/dist/eventlog/SqlEventLogServerEncrypted.js +1048 -113
- package/dist/eventlog/SqlEventLogServerEncrypted.js.map +1 -1
- package/dist/eventlog/SqlEventLogServerUnencrypted.js +2 -2
- package/dist/eventlog/SqlEventLogServerUnencrypted.js.map +1 -1
- package/dist/eventlog/internal/batches.d.ts +12 -0
- package/dist/eventlog/internal/batches.d.ts.map +1 -0
- package/dist/eventlog/internal/batches.js +26 -0
- package/dist/eventlog/internal/batches.js.map +1 -0
- package/dist/eventlog/internal/compaction.d.ts +38 -0
- package/dist/eventlog/internal/compaction.d.ts.map +1 -0
- package/dist/eventlog/internal/compaction.js +33 -0
- package/dist/eventlog/internal/compaction.js.map +1 -0
- package/dist/eventlog/internal/identityRootSecretDerivation.js +66 -67
- package/dist/eventlog/internal/identityRootSecretDerivation.js.map +1 -1
- package/dist/eventlog/internal/remoteCompaction.d.ts +31 -0
- package/dist/eventlog/internal/remoteCompaction.d.ts.map +1 -0
- package/dist/eventlog/internal/remoteCompaction.js +76 -0
- package/dist/eventlog/internal/remoteCompaction.js.map +1 -0
- package/dist/graphql/GraphQLClient.d.ts +3 -1
- package/dist/graphql/GraphQLClient.d.ts.map +1 -1
- package/dist/graphql/GraphQLClient.js.map +1 -1
- package/dist/graphql/GraphQLClientError.d.ts +14 -9
- package/dist/graphql/GraphQLClientError.d.ts.map +1 -1
- package/dist/graphql/GraphQLClientError.js +14 -21
- package/dist/graphql/GraphQLClientError.js.map +1 -1
- package/dist/graphql/GraphQLProtocol.d.ts +12 -3
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
- package/dist/graphql/GraphQLProtocol.js +4 -1
- package/dist/graphql/GraphQLProtocol.js.map +1 -1
- package/dist/http/Cookies.d.ts +172 -0
- package/dist/http/Cookies.d.ts.map +1 -1
- package/dist/http/Cookies.js +143 -1
- package/dist/http/Cookies.js.map +1 -1
- package/dist/http/FetchHttpClient.d.ts +26 -2
- package/dist/http/FetchHttpClient.d.ts.map +1 -1
- package/dist/http/FetchHttpClient.js +78 -15
- package/dist/http/FetchHttpClient.js.map +1 -1
- package/dist/http/HttpClient.d.ts +268 -15
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +140 -7
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpClientRequest.d.ts +9 -5
- package/dist/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/http/HttpClientRequest.js +2 -3
- package/dist/http/HttpClientRequest.js.map +1 -1
- package/dist/http/HttpClientResponse.d.ts.map +1 -1
- package/dist/http/HttpClientResponse.js +3 -2
- package/dist/http/HttpClientResponse.js.map +1 -1
- package/dist/http/HttpMethod.d.ts +7 -1
- package/dist/http/HttpMethod.d.ts.map +1 -1
- package/dist/http/HttpMethod.js +3 -8
- package/dist/http/HttpMethod.js.map +1 -1
- package/dist/http/HttpServerRequest.d.ts +5 -2
- package/dist/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/http/HttpServerRequest.js +44 -39
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/http/HttpServerResponse.js +3 -2
- package/dist/http/HttpServerResponse.js.map +1 -1
- package/dist/http/HttpTraceContext.d.ts +2 -1
- package/dist/http/HttpTraceContext.d.ts.map +1 -1
- package/dist/http/HttpTraceContext.js +7 -5
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/http/ProblemDetails.d.ts +96 -0
- package/dist/http/ProblemDetails.d.ts.map +1 -0
- package/dist/http/ProblemDetails.js +98 -0
- package/dist/http/ProblemDetails.js.map +1 -0
- package/dist/http/index.d.ts +5 -0
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +5 -0
- package/dist/http/index.js.map +1 -1
- package/dist/http/internal/decompression.js +3 -2
- package/dist/http/internal/decompression.js.map +1 -1
- package/dist/http/internal/mimeTypes.d.ts +4 -1
- package/dist/http/internal/mimeTypes.d.ts.map +1 -1
- package/dist/http/internal/mimeTypes.js +4 -1
- package/dist/http/internal/mimeTypes.js.map +1 -1
- package/dist/http/internal/urlParams.js +8 -0
- package/dist/http/internal/urlParams.js.map +1 -1
- package/dist/http-api/HttpApiBuilder.js +19 -5
- package/dist/http-api/HttpApiBuilder.js.map +1 -1
- package/dist/http-api/HttpApiClient.d.ts +63 -0
- package/dist/http-api/HttpApiClient.d.ts.map +1 -1
- package/dist/http-api/HttpApiClient.js +51 -0
- package/dist/http-api/HttpApiClient.js.map +1 -1
- package/dist/http-api/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/http-api/HttpApiEndpoint.js +14 -5
- package/dist/http-api/HttpApiEndpoint.js.map +1 -1
- package/dist/http-api/HttpApiError.d.ts +185 -13
- package/dist/http-api/HttpApiError.d.ts.map +1 -1
- package/dist/http-api/HttpApiError.js +128 -0
- package/dist/http-api/HttpApiError.js.map +1 -1
- package/dist/http-api/HttpApiMiddleware.d.ts +64 -17
- package/dist/http-api/HttpApiMiddleware.d.ts.map +1 -1
- package/dist/http-api/HttpApiMiddleware.js +85 -1
- package/dist/http-api/HttpApiMiddleware.js.map +1 -1
- package/dist/http-api/HttpApiSchema.d.ts +76 -14
- package/dist/http-api/HttpApiSchema.d.ts.map +1 -1
- package/dist/http-api/HttpApiSchema.js +54 -1
- package/dist/http-api/HttpApiSchema.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/internal/dateTime.js +49 -24
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +35 -14
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/glob.d.ts +2 -0
- package/dist/internal/glob.d.ts.map +1 -0
- package/dist/internal/glob.js +808 -0
- package/dist/internal/glob.js.map +1 -0
- package/dist/internal/graphql.js +21 -7
- package/dist/internal/graphql.js.map +1 -1
- package/dist/internal/graphqlHeaders.d.ts +7 -0
- package/dist/internal/graphqlHeaders.d.ts.map +1 -1
- package/dist/internal/graphqlHeaders.js +11 -0
- package/dist/internal/graphqlHeaders.js.map +1 -1
- package/dist/internal/matcher.js +10 -0
- package/dist/internal/matcher.js.map +1 -1
- package/dist/internal/persistence.js +9 -0
- package/dist/internal/persistence.js.map +1 -1
- package/dist/internal/rcRef.js +4 -1
- package/dist/internal/rcRef.js.map +1 -1
- package/dist/internal/request.js +29 -42
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/schema/fromJsonSchemaDocument.js +7 -8
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +6 -3
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/trie.js +42 -13
- package/dist/internal/trie.js.map +1 -1
- package/dist/internal/ulid.js +41 -0
- package/dist/internal/ulid.js.map +1 -1
- package/dist/internal/uuid.js +52 -8
- package/dist/internal/uuid.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/jose/JoseError.d.ts +285 -0
- package/dist/jose/JoseError.d.ts.map +1 -0
- package/dist/jose/JoseError.js +269 -0
- package/dist/jose/JoseError.js.map +1 -0
- package/dist/jose/Jwe.d.ts +128 -0
- package/dist/jose/Jwe.d.ts.map +1 -0
- package/dist/jose/Jwe.js +134 -0
- package/dist/jose/Jwe.js.map +1 -0
- package/dist/jose/Jwk.d.ts +597 -0
- package/dist/jose/Jwk.d.ts.map +1 -0
- package/dist/jose/Jwk.js +503 -0
- package/dist/jose/Jwk.js.map +1 -0
- package/dist/jose/Jwks.d.ts +236 -0
- package/dist/jose/Jwks.d.ts.map +1 -0
- package/dist/jose/Jwks.js +306 -0
- package/dist/jose/Jwks.js.map +1 -0
- package/dist/jose/Jws.d.ts +177 -0
- package/dist/jose/Jws.d.ts.map +1 -0
- package/dist/jose/Jws.js +183 -0
- package/dist/jose/Jws.js.map +1 -0
- package/dist/jose/Jwt.d.ts +270 -0
- package/dist/jose/Jwt.d.ts.map +1 -0
- package/dist/jose/Jwt.js +293 -0
- package/dist/jose/Jwt.js.map +1 -0
- package/dist/jose/index.d.ts +51 -0
- package/dist/jose/index.d.ts.map +1 -0
- package/dist/jose/index.js +52 -0
- package/dist/jose/index.js.map +1 -0
- package/dist/jose/internal/compact.d.ts +2 -0
- package/dist/jose/internal/compact.d.ts.map +1 -0
- package/dist/jose/internal/compact.js +179 -0
- package/dist/jose/internal/compact.js.map +1 -0
- package/dist/net/Host.d.ts.map +1 -1
- package/dist/net/Host.js +5 -10
- package/dist/net/Host.js.map +1 -1
- package/dist/observability/Otlp.d.ts +15 -4
- package/dist/observability/Otlp.d.ts.map +1 -1
- package/dist/observability/Otlp.js +10 -0
- package/dist/observability/Otlp.js.map +1 -1
- package/dist/observability/OtlpResource.d.ts +7 -0
- package/dist/observability/OtlpResource.d.ts.map +1 -1
- package/dist/observability/OtlpResource.js +11 -1
- package/dist/observability/OtlpResource.js.map +1 -1
- package/dist/observability/OtlpSerialization.d.ts +1 -1
- package/dist/observability/OtlpSerialization.d.ts.map +1 -1
- package/dist/observability/OtlpSerialization.js +10 -4
- package/dist/observability/OtlpSerialization.js.map +1 -1
- package/dist/observability/internal/otlpProtobuf.js +3 -3
- package/dist/observability/internal/otlpProtobuf.js.map +1 -1
- package/dist/observability/internal/protobuf.js +6 -0
- package/dist/observability/internal/protobuf.js.map +1 -1
- package/dist/persistence/CircuitBreaker.d.ts +98 -38
- package/dist/persistence/CircuitBreaker.d.ts.map +1 -1
- package/dist/persistence/CircuitBreaker.js +67 -29
- package/dist/persistence/CircuitBreaker.js.map +1 -1
- package/dist/persistence/KeyValueStore.d.ts +47 -2
- package/dist/persistence/KeyValueStore.d.ts.map +1 -1
- package/dist/persistence/KeyValueStore.js +129 -18
- package/dist/persistence/KeyValueStore.js.map +1 -1
- package/dist/persistence/PersistedQueue.d.ts +9 -0
- package/dist/persistence/PersistedQueue.d.ts.map +1 -1
- package/dist/persistence/PersistedQueue.js +94 -52
- package/dist/persistence/PersistedQueue.js.map +1 -1
- package/dist/persistence/Persistence.d.ts +10 -4
- package/dist/persistence/Persistence.d.ts.map +1 -1
- package/dist/persistence/Persistence.js +18 -11
- package/dist/persistence/Persistence.js.map +1 -1
- package/dist/persistence/RateLimiter.d.ts +8 -0
- package/dist/persistence/RateLimiter.d.ts.map +1 -1
- package/dist/persistence/RateLimiter.js +63 -12
- package/dist/persistence/RateLimiter.js.map +1 -1
- package/dist/persistence/index.d.ts +1 -1
- package/dist/persistence/index.js +1 -1
- package/dist/process/ChildProcess.d.ts +207 -67
- package/dist/process/ChildProcess.d.ts.map +1 -1
- package/dist/process/ChildProcess.js +56 -158
- package/dist/process/ChildProcess.js.map +1 -1
- package/dist/process/ChildProcessSpawner.d.ts +5 -0
- package/dist/process/ChildProcessSpawner.d.ts.map +1 -1
- package/dist/process/ChildProcessSpawner.js.map +1 -1
- package/dist/process/CommandLine.d.ts +294 -0
- package/dist/process/CommandLine.d.ts.map +1 -0
- package/dist/process/CommandLine.js +481 -0
- package/dist/process/CommandLine.js.map +1 -0
- package/dist/process/index.d.ts +5 -0
- package/dist/process/index.d.ts.map +1 -1
- package/dist/process/index.js +5 -0
- package/dist/process/index.js.map +1 -1
- package/dist/reactivity/Atom.d.ts +2 -1
- package/dist/reactivity/Atom.d.ts.map +1 -1
- package/dist/reactivity/Atom.js +3 -4
- package/dist/reactivity/Atom.js.map +1 -1
- package/dist/reactivity/AtomRegistry.js +17 -7
- package/dist/reactivity/AtomRegistry.js.map +1 -1
- package/dist/rpc/Rpc.d.ts +1 -1
- package/dist/rpc/Rpc.d.ts.map +1 -1
- package/dist/rpc/Rpc.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts +28 -1
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +78 -27
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcMessage.d.ts +13 -3
- package/dist/rpc/RpcMessage.d.ts.map +1 -1
- package/dist/rpc/RpcMessage.js +1 -0
- package/dist/rpc/RpcMessage.js.map +1 -1
- package/dist/rpc/RpcSerialization.d.ts.map +1 -1
- package/dist/rpc/RpcSerialization.js +6 -0
- package/dist/rpc/RpcSerialization.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts +31 -0
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +139 -66
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/schema/Model.d.ts +14 -0
- package/dist/schema/Model.d.ts.map +1 -1
- package/dist/schema/Model.js +18 -3
- package/dist/schema/Model.js.map +1 -1
- package/dist/sql/Migrator.d.ts +9 -20
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +20 -53
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/MigratorFileSystem.d.ts +21 -0
- package/dist/sql/MigratorFileSystem.d.ts.map +1 -0
- package/dist/sql/MigratorFileSystem.js +57 -0
- package/dist/sql/MigratorFileSystem.js.map +1 -0
- package/dist/sql/SqlClient.d.ts +38 -3
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +9 -12
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/sql/Statement.d.ts +61 -9
- package/dist/sql/Statement.d.ts.map +1 -1
- package/dist/sql/Statement.js +24 -33
- package/dist/sql/Statement.js.map +1 -1
- package/dist/sql/index.js +1 -1
- package/dist/testing/index.d.ts +0 -5
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +0 -5
- package/dist/testing/index.js.map +1 -1
- package/dist/workflow/Workflow.d.ts +4 -0
- package/dist/workflow/Workflow.d.ts.map +1 -1
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +5 -0
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/dist/workflow/internal/crypto.js +9 -8
- package/dist/workflow/internal/crypto.js.map +1 -1
- package/package.json +7 -1
- package/src/BigDecimal.ts +173 -16
- package/src/Channel.ts +17 -11
- package/src/Config.ts +7 -1
- package/src/Context.ts +34 -10
- package/src/Cron.ts +178 -29
- package/src/Duration.ts +140 -0
- package/src/Effect.ts +914 -85
- package/src/Equal.ts +3 -3
- package/src/FileSystem.ts +65 -4
- package/src/Glob.ts +205 -0
- package/src/Hash.ts +5 -4
- package/src/Iterable.ts +8 -5
- package/src/Match.ts +127 -0
- package/src/Path.ts +6 -1
- package/src/Pool.ts +75 -16
- package/src/Random.ts +3 -3
- package/src/RcMap.ts +5 -1
- package/src/Schedule.ts +26 -3
- package/src/Schema.ts +1191 -63
- package/src/SchemaGetter.ts +27 -11
- package/src/SchemaRepresentation.ts +23 -2
- package/src/SchemaTransformation.ts +10 -5
- package/src/ScopedCache.ts +5 -9
- package/src/Semaphore.ts +141 -0
- package/src/Stream.ts +15 -6
- package/src/Terminal.ts +19 -1
- package/src/ai/AiError.ts +56 -80
- package/src/ai/Decision.ts +257 -6
- package/src/ai/DecisionModel.ts +171 -28
- package/src/ai/McpClient.ts +488 -91
- package/src/ai/McpSchema.ts +119 -0
- package/src/ai/McpServer.ts +1525 -319
- package/src/ai/McpTest.ts +380 -0
- package/src/ai/Prompt.ts +16 -11
- package/src/ai/Response.ts +2 -22
- package/src/ai/Tool.ts +32 -18
- package/src/ai/index.ts +6 -0
- package/src/ai/internal/mcpCore.ts +243 -56
- package/src/ai/internal/mcpProtocol/v2024_11_05.ts +7 -8
- package/src/ai/internal/mcpProtocol/v2025_03_26.ts +7 -8
- package/src/ai/internal/mcpProtocol/v2025_06_18.ts +7 -8
- package/src/ai/internal/mcpProtocol/v2025_11_25.ts +7 -8
- package/src/ai/internal/mcpProtocol/v2026_07_28.ts +56 -17
- package/src/ai/internal/mcpProtocol.ts +44 -0
- package/src/ai/internal/mcpRuntime.ts +15 -8
- package/src/ai/internal/mcpSkills.ts +480 -0
- package/src/ai/internal/mcpStatefulRuntime.ts +14 -2
- package/src/cli/Argument.ts +6 -0
- package/src/cli/CliOutput.ts +117 -49
- package/src/cli/Command.ts +23 -0
- package/src/cli/Flag.ts +107 -0
- package/src/cli/HelpDoc.ts +18 -1
- package/src/cli/Param.ts +6 -0
- package/src/cli/Primitive.ts +16 -1
- package/src/cli/Prompt.ts +1 -0
- package/src/cli/internal/help.ts +21 -9
- package/src/cluster/ClusterWorkflowEngine.ts +22 -8
- package/src/cluster/Reply.ts +1 -1
- package/src/cluster/Sharding.ts +96 -26
- package/src/cluster/ShardingConfig.ts +41 -3
- package/src/cluster/SingleRunner.ts +3 -3
- package/src/cluster/SqlMessageStorage.ts +49 -17
- package/src/cluster/SqlRunnerStorage.ts +37 -27
- package/src/cluster/internal/entityManager.ts +24 -10
- package/src/crypto/Aead.ts +517 -0
- package/src/crypto/Cipher.ts +326 -0
- package/src/crypto/CryptoError.ts +242 -0
- package/src/crypto/Digest.ts +167 -0
- package/src/crypto/Kdf.ts +315 -0
- package/src/crypto/KeyAgreement.ts +489 -0
- package/src/crypto/KeyFormat.ts +741 -0
- package/src/crypto/KeyWrap.ts +639 -0
- package/src/crypto/Mac.ts +386 -0
- package/src/crypto/SecureRandom.ts +459 -0
- package/src/crypto/Signature.ts +673 -0
- package/src/crypto/WebCrypto.ts +84 -0
- package/src/crypto/index.ts +78 -0
- package/src/crypto/internal/asymmetric.ts +330 -0
- package/src/crypto/internal/chacha.ts +1088 -0
- package/src/crypto/internal/der.ts +110 -0
- package/src/crypto/internal/digest.ts +16 -0
- package/src/crypto/internal/key.ts +242 -0
- package/src/crypto/internal/md5.ts +170 -0
- package/src/crypto/internal/webCrypto.ts +150 -0
- package/src/encoding/Base64Url.ts +32 -5
- package/src/encoding/Csv.ts +1298 -0
- package/src/encoding/Hex.ts +3 -2
- package/src/encoding/Ndjson.ts +6 -5
- package/src/encoding/SchemaBinary.ts +40 -4
- package/src/encoding/Sse.ts +5 -3
- package/src/encoding/Toml.ts +85 -20
- package/src/encoding/Yaml.ts +61 -18
- package/src/encoding/index.ts +6 -0
- package/src/eventlog/EventJournal.ts +4 -3
- package/src/eventlog/EventLog.ts +347 -15
- package/src/eventlog/EventLogEncryption.ts +118 -110
- package/src/eventlog/EventLogMessage.ts +273 -1
- package/src/eventlog/EventLogRemote.ts +367 -23
- package/src/eventlog/EventLogServer.ts +54 -20
- package/src/eventlog/EventLogServerEncrypted.ts +1135 -67
- package/src/eventlog/EventLogServerUnencrypted.ts +19 -2
- package/src/eventlog/EventLogSessionAuth.ts +82 -70
- package/src/eventlog/EventRow.ts +12 -3
- package/src/eventlog/SqlEventJournal.ts +2 -2
- package/src/eventlog/SqlEventLogServerEncrypted.ts +1244 -136
- package/src/eventlog/SqlEventLogServerUnencrypted.ts +2 -2
- package/src/eventlog/internal/batches.ts +30 -0
- package/src/eventlog/internal/compaction.ts +64 -0
- package/src/eventlog/internal/identityRootSecretDerivation.ts +93 -123
- package/src/eventlog/internal/remoteCompaction.ts +92 -0
- package/src/graphql/GraphQLClient.ts +3 -1
- package/src/graphql/GraphQLClientError.ts +15 -22
- package/src/graphql/GraphQLProtocol.ts +12 -3
- package/src/http/Cookies.ts +281 -1
- package/src/http/FetchHttpClient.ts +88 -16
- package/src/http/HttpClient.ts +299 -33
- package/src/http/HttpClientRequest.ts +12 -9
- package/src/http/HttpClientResponse.ts +3 -2
- package/src/http/HttpMethod.ts +10 -2
- package/src/http/HttpServerRequest.ts +76 -53
- package/src/http/HttpServerResponse.ts +3 -2
- package/src/http/HttpTraceContext.ts +7 -4
- package/src/http/ProblemDetails.ts +149 -0
- package/src/http/index.ts +6 -0
- package/src/http/internal/decompression.ts +4 -4
- package/src/http/internal/mimeTypes.ts +4 -1
- package/src/http/internal/urlParams.ts +8 -0
- package/src/http-api/HttpApiBuilder.ts +24 -12
- package/src/http-api/HttpApiClient.ts +67 -1
- package/src/http-api/HttpApiEndpoint.ts +14 -5
- package/src/http-api/HttpApiError.ts +250 -0
- package/src/http-api/HttpApiMiddleware.ts +95 -1
- package/src/http-api/HttpApiSchema.ts +106 -15
- package/src/index.ts +6 -6
- package/src/internal/dateTime.ts +54 -24
- package/src/internal/effect.ts +40 -18
- package/src/internal/glob.ts +952 -0
- package/src/internal/graphql.ts +27 -9
- package/src/internal/graphqlHeaders.ts +13 -0
- package/src/internal/matcher.ts +17 -0
- package/src/internal/persistence.ts +11 -0
- package/src/internal/rcRef.ts +4 -1
- package/src/internal/request.ts +51 -58
- package/src/internal/schema/fromJsonSchemaDocument.ts +11 -10
- package/src/internal/schema/toCodeDocument.ts +7 -3
- package/src/internal/trie.ts +43 -14
- package/src/internal/ulid.ts +44 -0
- package/src/internal/uuid.ts +57 -16
- package/src/internal/version.ts +1 -1
- package/src/jose/JoseError.ts +329 -0
- package/src/jose/Jwe.ts +196 -0
- package/src/jose/Jwk.ts +777 -0
- package/src/jose/Jwks.ts +418 -0
- package/src/jose/Jws.ts +312 -0
- package/src/jose/Jwt.ts +493 -0
- package/src/jose/index.ts +58 -0
- package/src/jose/internal/compact.ts +195 -0
- package/src/net/Host.ts +5 -10
- package/src/observability/Otlp.ts +21 -4
- package/src/observability/OtlpResource.ts +9 -1
- package/src/observability/OtlpSerialization.ts +13 -5
- package/src/observability/internal/otlpProtobuf.ts +6 -6
- package/src/observability/internal/protobuf.ts +10 -0
- package/src/persistence/CircuitBreaker.ts +113 -48
- package/src/persistence/KeyValueStore.ts +219 -22
- package/src/persistence/PersistedQueue.ts +128 -59
- package/src/persistence/Persistence.ts +20 -13
- package/src/persistence/RateLimiter.ts +84 -15
- package/src/persistence/index.ts +1 -1
- package/src/process/ChildProcess.ts +255 -260
- package/src/process/ChildProcessSpawner.ts +5 -0
- package/src/process/CommandLine.ts +630 -0
- package/src/process/index.ts +6 -0
- package/src/reactivity/Atom.ts +5 -5
- package/src/reactivity/AtomRegistry.ts +20 -9
- package/src/rpc/Rpc.ts +3 -1
- package/src/rpc/RpcClient.ts +94 -38
- package/src/rpc/RpcMessage.ts +13 -3
- package/src/rpc/RpcSerialization.ts +3 -0
- package/src/rpc/RpcServer.ts +176 -78
- package/src/schema/Model.ts +26 -3
- package/src/sql/Migrator.ts +38 -80
- package/src/sql/MigratorFileSystem.ts +71 -0
- package/src/sql/SqlClient.ts +45 -24
- package/src/sql/Statement.ts +60 -29
- package/src/sql/index.ts +1 -1
- package/src/testing/index.ts +0 -6
- package/src/workflow/Workflow.ts +4 -0
- package/src/workflow/WorkflowEngine.ts +5 -0
- package/src/workflow/internal/crypto.ts +15 -11
- package/dist/Crypto.d.ts +0 -244
- package/dist/Crypto.d.ts.map +0 -1
- package/dist/Crypto.js +0 -139
- package/dist/Crypto.js.map +0 -1
- package/dist/testing/TestCrypto.d.ts +0 -73
- package/dist/testing/TestCrypto.d.ts.map +0 -1
- package/dist/testing/TestCrypto.js +0 -87
- package/dist/testing/TestCrypto.js.map +0 -1
- package/src/Crypto.ts +0 -347
- package/src/testing/TestCrypto.ts +0 -94
package/src/ai/McpServer.ts
CHANGED
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
import * as Arr from "../Array.ts"
|
|
15
15
|
import * as Cause from "../Cause.ts"
|
|
16
16
|
import * as Context from "../Context.ts"
|
|
17
|
+
import * as Digest from "../crypto/Digest.ts"
|
|
17
18
|
import * as Data from "../Data.ts"
|
|
18
19
|
import * as Deferred from "../Deferred.ts"
|
|
20
|
+
import * as Duration from "../Duration.ts"
|
|
19
21
|
import * as Effect from "../Effect.ts"
|
|
20
22
|
import * as ErrorReporter from "../ErrorReporter.ts"
|
|
21
23
|
import * as Exit from "../Exit.ts"
|
|
@@ -46,10 +48,13 @@ import * as SchemaAST from "../SchemaAST.ts"
|
|
|
46
48
|
import * as Scope from "../Scope.ts"
|
|
47
49
|
import type { Stdio } from "../Stdio.ts"
|
|
48
50
|
import * as Stream from "../Stream.ts"
|
|
51
|
+
import * as Tracer from "../Tracer.ts"
|
|
52
|
+
import type * as Types from "../Types.ts"
|
|
49
53
|
import * as AiError from "./AiError.ts"
|
|
50
54
|
import * as McpCore from "./internal/mcpCore.ts"
|
|
51
55
|
import * as McpProtocolInternal from "./internal/mcpProtocol.ts"
|
|
52
56
|
import * as McpRuntime from "./internal/mcpRuntime.ts"
|
|
57
|
+
import * as McpSkills from "./internal/mcpSkills.ts"
|
|
53
58
|
import * as InternalStructuredOutput from "./internal/structured-output.ts"
|
|
54
59
|
import type * as McpProtocol from "./McpProtocol.ts"
|
|
55
60
|
import * as McpSchema from "./McpSchema.ts"
|
|
@@ -103,8 +108,11 @@ interface QueuedServerNotification {
|
|
|
103
108
|
|
|
104
109
|
const internalState = new WeakMap<object, {
|
|
105
110
|
readonly core: McpCore.McpCore
|
|
111
|
+
// Registers a skill's own file, skipping the check that reserves it for the skill.
|
|
112
|
+
readonly addSkillFile: McpServer["Service"]["addResource"]
|
|
106
113
|
readonly notifications: Queue.Dequeue<QueuedServerNotification>
|
|
107
114
|
readonly notificationDelivery: { consumers: number; listChangeRevision: number; requestEndpoints: number }
|
|
115
|
+
readonly globalMiddleware: Array<middleware.Fn<any, any, any>>
|
|
108
116
|
}>()
|
|
109
117
|
|
|
110
118
|
// Request-scoped HTTP servers deliver a request's own notifications through
|
|
@@ -166,13 +174,29 @@ const toInternalServerNotification = (
|
|
|
166
174
|
}
|
|
167
175
|
}
|
|
168
176
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
const middlewareKeyPrefix = "effect/ai/McpServer/Middleware-"
|
|
178
|
+
|
|
179
|
+
// Do not capture request services or middleware stacks at registration.
|
|
180
|
+
const requestServiceKeys = new Set<string>([
|
|
181
|
+
McpRequestContext.key,
|
|
182
|
+
McpServerClient.key,
|
|
183
|
+
HttpServerRequest.HttpServerRequest.key,
|
|
184
|
+
HttpServerRequest.ParsedSearchParams.key,
|
|
185
|
+
HttpRouter.RouteContext.key,
|
|
186
|
+
CurrentLogLevel.key,
|
|
187
|
+
Scope.Scope.key,
|
|
188
|
+
Tracer.ParentSpan.key
|
|
189
|
+
])
|
|
190
|
+
|
|
191
|
+
const omitRequestServices = <Services>(context: Context.Context<Services>): Context.Context<Services> => {
|
|
192
|
+
const services = new Map<string, any>()
|
|
193
|
+
for (const [key, value] of context.mapUnsafe) {
|
|
194
|
+
if (!requestServiceKeys.has(key) && !key.startsWith(middlewareKeyPrefix)) {
|
|
195
|
+
services.set(key, value)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return Context.makeUnsafe(services)
|
|
199
|
+
}
|
|
176
200
|
|
|
177
201
|
const provideInvocationContext = <A, E, R>(
|
|
178
202
|
effect: Effect.Effect<A, E, R>,
|
|
@@ -199,6 +223,714 @@ const provideInvocationContext = <A, E, R>(
|
|
|
199
223
|
>
|
|
200
224
|
}
|
|
201
225
|
|
|
226
|
+
// -----------------------------------------------------------------------------
|
|
227
|
+
// Request-level dependencies
|
|
228
|
+
// -----------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Marks a request-level dependency of an MCP registration or middleware.
|
|
232
|
+
*
|
|
233
|
+
* **Details**
|
|
234
|
+
*
|
|
235
|
+
* Registrations carry handler dependencies as `McpRequest<"Requires", S>`.
|
|
236
|
+
* MCP middleware and transports discharge these markers; providing `S` with
|
|
237
|
+
* `Layer.provide` or `Effect.provide` does not.
|
|
238
|
+
*
|
|
239
|
+
* `layerHttp` and `layerHttpRequestScoped` convert the markers they don't
|
|
240
|
+
* discharge into `HttpRouter.Request` markers, so `HttpRouter.middleware` can
|
|
241
|
+
* satisfy them. On stdio and custom transports an undischarged marker is a
|
|
242
|
+
* compile error.
|
|
243
|
+
*
|
|
244
|
+
* @see {@link middleware} for discharging request-level dependencies
|
|
245
|
+
*
|
|
246
|
+
* @stability unstable
|
|
247
|
+
* @category utility types
|
|
248
|
+
* @since 4.0.0
|
|
249
|
+
*/
|
|
250
|
+
export interface McpRequest<Kind extends string, T> {
|
|
251
|
+
readonly _: unique symbol
|
|
252
|
+
readonly kind: Kind
|
|
253
|
+
readonly type: T
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Helper types for `McpRequest` markers.
|
|
258
|
+
*
|
|
259
|
+
* @stability unstable
|
|
260
|
+
* @category utility types
|
|
261
|
+
* @since 4.0.0
|
|
262
|
+
*/
|
|
263
|
+
export declare namespace McpRequest {
|
|
264
|
+
/**
|
|
265
|
+
* Wraps each member of a union in an `McpRequest` marker of the supplied kind.
|
|
266
|
+
*
|
|
267
|
+
* @stability unstable
|
|
268
|
+
* @category utility types
|
|
269
|
+
* @since 4.0.0
|
|
270
|
+
*/
|
|
271
|
+
export type From<Kind extends string, R> = R extends infer T ? McpRequest<Kind, T> : never
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Extracts the services from `McpRequest` markers of the supplied kind.
|
|
275
|
+
*
|
|
276
|
+
* @stability unstable
|
|
277
|
+
* @category utility types
|
|
278
|
+
* @since 4.0.0
|
|
279
|
+
*/
|
|
280
|
+
export type Only<Kind extends string, A> = A extends McpRequest<Kind, infer T> ? T : never
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Removes `McpRequest` markers from a union.
|
|
284
|
+
*
|
|
285
|
+
* @stability unstable
|
|
286
|
+
* @category utility types
|
|
287
|
+
* @since 4.0.0
|
|
288
|
+
*/
|
|
289
|
+
export type Without<A> = A extends McpRequest<infer _Kind, infer _> ? never : A
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Opaque handler result. Middleware can wrap execution and provide services,
|
|
294
|
+
* but cannot inspect or replace the result.
|
|
295
|
+
*
|
|
296
|
+
* @stability unstable
|
|
297
|
+
* @category middleware
|
|
298
|
+
* @since 4.0.0
|
|
299
|
+
*/
|
|
300
|
+
export interface MiddlewareSuccess {
|
|
301
|
+
readonly _: unique symbol
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* The request methods that run MCP middleware. More methods may be added, so
|
|
306
|
+
* don't `switch` on it exhaustively without a default case.
|
|
307
|
+
*
|
|
308
|
+
* @stability unstable
|
|
309
|
+
* @category middleware
|
|
310
|
+
* @since 4.0.0
|
|
311
|
+
*/
|
|
312
|
+
export type MiddlewareMethod =
|
|
313
|
+
| "tools/call"
|
|
314
|
+
| "resources/read"
|
|
315
|
+
| "prompts/get"
|
|
316
|
+
| "completion/complete"
|
|
317
|
+
| "tools/list"
|
|
318
|
+
| "resources/list"
|
|
319
|
+
| "resources/templates/list"
|
|
320
|
+
| "prompts/list"
|
|
321
|
+
| "skills/list"
|
|
322
|
+
| "skills/get"
|
|
323
|
+
| "resources/directory/read"
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Request metadata passed to MCP middleware.
|
|
327
|
+
*
|
|
328
|
+
* **Details**
|
|
329
|
+
*
|
|
330
|
+
* `target` is the tool name, the requested resource URI, or the prompt name.
|
|
331
|
+
* For `completion/complete` it is the prompt name, or the URI template of the
|
|
332
|
+
* resource template being completed. For `skills/get` it is the URI of the
|
|
333
|
+
* skill's `SKILL.md`. `payload` holds the request parameters.
|
|
334
|
+
*
|
|
335
|
+
* On list requests, middleware runs only when it wraps a {@link visibility},
|
|
336
|
+
* once for each registration it wraps. `target` is then the tool name, the
|
|
337
|
+
* resource URI, the URI template or the prompt name of that registration, and
|
|
338
|
+
* `payload` is `undefined`. `skills/list` and `resources/directory/read` are
|
|
339
|
+
* list requests whose `target` is the `SKILL.md` URI of each skill; a
|
|
340
|
+
* directory read checks only the skills that have the directory. A skill's
|
|
341
|
+
* files are resources, checked as `resources/list` and `resources/read` with
|
|
342
|
+
* their own URIs.
|
|
343
|
+
*
|
|
344
|
+
* `headers` are the HTTP request headers. They are empty on stdio, on custom
|
|
345
|
+
* transports and for in-process calls. `sessionId` is the `Mcp-Session-Id`
|
|
346
|
+
* header, so it is `undefined` outside sessionful HTTP.
|
|
347
|
+
*
|
|
348
|
+
* @stability unstable
|
|
349
|
+
* @category middleware
|
|
350
|
+
* @since 4.0.0
|
|
351
|
+
*/
|
|
352
|
+
export interface MiddlewareOptions {
|
|
353
|
+
readonly method: MiddlewareMethod
|
|
354
|
+
readonly target: string
|
|
355
|
+
readonly payload: unknown
|
|
356
|
+
readonly requestContext: McpRequestContext["Service"]
|
|
357
|
+
readonly headers: Headers.Headers
|
|
358
|
+
readonly sessionId: string | undefined
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const MiddlewareTypeId = "~effect/ai/McpServer/Middleware"
|
|
362
|
+
|
|
363
|
+
type MiddlewareConfig = {
|
|
364
|
+
provides: any
|
|
365
|
+
error: McpErrorBase
|
|
366
|
+
requires: any
|
|
367
|
+
layerError: any
|
|
368
|
+
layerRequires: any
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
type MiddlewareLayer<Config extends MiddlewareConfig, R> = Layer.Layer<
|
|
372
|
+
McpRequest.From<"Requires", Config["provides"]>,
|
|
373
|
+
Config["layerError"],
|
|
374
|
+
R | Config["layerRequires"] | McpRequest.From<"Requires", Config["requires"]>
|
|
375
|
+
>
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Composable MCP middleware.
|
|
379
|
+
*
|
|
380
|
+
* **Details**
|
|
381
|
+
*
|
|
382
|
+
* Provide `layer` to registration layers, or to the Effect form of a
|
|
383
|
+
* registration, to run the middleware for those registrations. Use
|
|
384
|
+
* `layerGlobal` to run it for every request on the server.
|
|
385
|
+
*
|
|
386
|
+
* Services the middleware reads per request are `McpRequest<"Requires", S>`
|
|
387
|
+
* requirements of `layer` and `layerGlobal`, like the request-level
|
|
388
|
+
* dependencies of a registration. A middleware that provides `S` meets them
|
|
389
|
+
* when it runs outside this one: `a.combine(b)` runs `b` outside `a`, and so
|
|
390
|
+
* does providing `b.layer` or `b.layerGlobal` outside `a.layer`, though
|
|
391
|
+
* `layerGlobal` installs `b` for the whole server. The transport discharges
|
|
392
|
+
* the services it supplies, and `layerHttp` turns the rest into
|
|
393
|
+
* `HttpRouter.Request` requirements that an `HttpRouter.middleware` can meet.
|
|
394
|
+
*
|
|
395
|
+
* @see {@link middleware} for creating MCP middleware
|
|
396
|
+
*
|
|
397
|
+
* @stability unstable
|
|
398
|
+
* @category middleware
|
|
399
|
+
* @since 4.0.0
|
|
400
|
+
*/
|
|
401
|
+
export interface Middleware<Config extends MiddlewareConfig> {
|
|
402
|
+
readonly [MiddlewareTypeId]: Config
|
|
403
|
+
readonly layer: MiddlewareLayer<Config, never>
|
|
404
|
+
readonly layerGlobal: MiddlewareLayer<Config, McpServer>
|
|
405
|
+
readonly combine: <Config2 extends MiddlewareConfig>(other: Middleware<Config2>) => Middleware<{
|
|
406
|
+
provides: Config2["provides"] | Config["provides"]
|
|
407
|
+
error: Config2["error"] | Config["error"]
|
|
408
|
+
requires: Exclude<Config["requires"], Config2["provides"]> | Config2["requires"]
|
|
409
|
+
layerError: Config["layerError"] | Config2["layerError"]
|
|
410
|
+
layerRequires: Config["layerRequires"] | Config2["layerRequires"]
|
|
411
|
+
}>
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Creates MCP middleware that runs around `tools/call`, `resources/read`,
|
|
416
|
+
* `prompts/get` and `completion/complete` requests.
|
|
417
|
+
*
|
|
418
|
+
* **Details**
|
|
419
|
+
*
|
|
420
|
+
* Middleware is how request-level dependencies are satisfied: declare the
|
|
421
|
+
* services it provides with `middleware<{ provides: S }>()` and provide them to
|
|
422
|
+
* the handler effect. It receives the request headers, session id and request
|
|
423
|
+
* context, so it can resolve the current user per request.
|
|
424
|
+
*
|
|
425
|
+
* Pass a function, or an Effect that builds the function. Services the Effect
|
|
426
|
+
* reads are requirements of the middleware layer. Services the function reads
|
|
427
|
+
* per request, other than `McpRequestContext`, are per-request requirements
|
|
428
|
+
* of the result; see {@link Middleware} for how they are met.
|
|
429
|
+
*
|
|
430
|
+
* Failures must be `McpErrorBase` values. A middleware failure is sent as a
|
|
431
|
+
* JSON-RPC error with its `code`, `message` and `data`, never as a tool
|
|
432
|
+
* result. Pick custom codes from the implementation-defined range
|
|
433
|
+
* (-32000 to -32019): any numeric `code` is sent as is. Defects are logged,
|
|
434
|
+
* reported to the `ErrorReporter` and sent as `InternalError("Internal error")`.
|
|
435
|
+
* Interruption propagates.
|
|
436
|
+
*
|
|
437
|
+
* Local middleware runs inside global middleware, and middleware provided both
|
|
438
|
+
* locally and globally runs once. Middleware never runs for `initialize`. It
|
|
439
|
+
* runs for list requests only when it wraps a {@link visibility}, so that the
|
|
440
|
+
* visibility check can read the services it provides.
|
|
441
|
+
*
|
|
442
|
+
* **Example** (Resolving the current user per request)
|
|
443
|
+
*
|
|
444
|
+
* ```ts
|
|
445
|
+
* import { Context, Effect, Layer, Schema } from "effect"
|
|
446
|
+
* import { McpSchema, McpServer, Tool, Toolkit } from "effect/ai"
|
|
447
|
+
*
|
|
448
|
+
* class CurrentUser extends Context.Service<CurrentUser, { readonly id: string }>()("CurrentUser") {}
|
|
449
|
+
*
|
|
450
|
+
* class Unauthorized extends Schema.Error<Unauthorized>("Unauthorized")({
|
|
451
|
+
* ...McpSchema.McpErrorBase.fields,
|
|
452
|
+
* _tag: Schema.tag("Unauthorized"),
|
|
453
|
+
* code: Schema.tag(-32001)
|
|
454
|
+
* }) {}
|
|
455
|
+
*
|
|
456
|
+
* const WhoAmI = Tool.make("WhoAmI", { success: Schema.String, dependencies: [CurrentUser] })
|
|
457
|
+
* const Tools = Toolkit.make(WhoAmI)
|
|
458
|
+
*
|
|
459
|
+
* const Auth = McpServer.middleware<{ provides: CurrentUser }>()((effect, { headers }) => {
|
|
460
|
+
* const token = headers["authorization"]
|
|
461
|
+
* return token === undefined
|
|
462
|
+
* ? Effect.fail(new Unauthorized({ message: "Missing credentials" }))
|
|
463
|
+
* : Effect.provideService(effect, CurrentUser, { id: token })
|
|
464
|
+
* })
|
|
465
|
+
*
|
|
466
|
+
* const Registrations = McpServer.toolkit(Tools).pipe(
|
|
467
|
+
* Layer.provide(Auth.layer),
|
|
468
|
+
* Layer.provide(Tools.toLayer({
|
|
469
|
+
* WhoAmI: () => Effect.map(CurrentUser, (user) => user.id)
|
|
470
|
+
* }))
|
|
471
|
+
* )
|
|
472
|
+
* ```
|
|
473
|
+
*
|
|
474
|
+
* @stability unstable
|
|
475
|
+
* @category middleware
|
|
476
|
+
* @since 4.0.0
|
|
477
|
+
*/
|
|
478
|
+
export const middleware:
|
|
479
|
+
& middleware.Make<never>
|
|
480
|
+
& (<Config extends { provides?: any } = {}>() => middleware.Make<
|
|
481
|
+
Config extends { provides: infer P } ? P : never
|
|
482
|
+
>) = function() {
|
|
483
|
+
if (arguments.length === 0) {
|
|
484
|
+
return makeMiddleware as any
|
|
485
|
+
}
|
|
486
|
+
return makeMiddleware(arguments[0], arguments[1]) as any
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Types used by `middleware`.
|
|
491
|
+
*
|
|
492
|
+
* @stability unstable
|
|
493
|
+
* @category middleware
|
|
494
|
+
* @since 4.0.0
|
|
495
|
+
*/
|
|
496
|
+
export declare namespace middleware {
|
|
497
|
+
/**
|
|
498
|
+
* The middleware function.
|
|
499
|
+
*
|
|
500
|
+
* @stability unstable
|
|
501
|
+
* @category middleware
|
|
502
|
+
* @since 4.0.0
|
|
503
|
+
*/
|
|
504
|
+
export type Fn<Provides, E, R> = (
|
|
505
|
+
effect: Effect.Effect<MiddlewareSuccess, McpErrorBase, Types.NoInfer<Provides>>,
|
|
506
|
+
options: MiddlewareOptions
|
|
507
|
+
) => Effect.Effect<MiddlewareSuccess, E, R>
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* The overloads of a middleware constructor.
|
|
511
|
+
*
|
|
512
|
+
* @stability unstable
|
|
513
|
+
* @category middleware
|
|
514
|
+
* @since 4.0.0
|
|
515
|
+
*/
|
|
516
|
+
export type Make<Provides> = {
|
|
517
|
+
<E extends McpErrorBase, R, EX, RX, const Global extends boolean = false>(
|
|
518
|
+
middleware: Effect.Effect<Fn<Provides, E, R>, EX, RX>,
|
|
519
|
+
options?: { readonly global?: Global | undefined }
|
|
520
|
+
): Made<Global, {
|
|
521
|
+
provides: Provides
|
|
522
|
+
error: E
|
|
523
|
+
requires: Exclude<R, McpRequestContext>
|
|
524
|
+
layerError: EX
|
|
525
|
+
layerRequires: Exclude<RX, Scope.Scope>
|
|
526
|
+
}>
|
|
527
|
+
<E extends McpErrorBase, R, const Global extends boolean = false>(
|
|
528
|
+
middleware: Fn<Provides, E, R>,
|
|
529
|
+
options?: { readonly global?: Global | undefined }
|
|
530
|
+
): Made<Global, {
|
|
531
|
+
provides: Provides
|
|
532
|
+
error: E
|
|
533
|
+
requires: Exclude<R, McpRequestContext>
|
|
534
|
+
layerError: never
|
|
535
|
+
layerRequires: never
|
|
536
|
+
}>
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Creates middleware that hides registrations per request.
|
|
542
|
+
*
|
|
543
|
+
* **Details**
|
|
544
|
+
*
|
|
545
|
+
* The check runs for every registration the middleware is provided to, on list
|
|
546
|
+
* requests and on calls, reads, gets and completions. When it returns `false`
|
|
547
|
+
* the registration is left out of list results, and requests for it fail as if
|
|
548
|
+
* it was not registered.
|
|
549
|
+
*
|
|
550
|
+
* The result is a `Middleware` and composes like one. The check receives the
|
|
551
|
+
* same {@link MiddlewareOptions} as middleware, and services it reads per
|
|
552
|
+
* request, other than `McpRequestContext`, are met the same way. Scope a
|
|
553
|
+
* visibility to some tools by providing its layer to their toolkit only, or
|
|
554
|
+
* branch on `target`.
|
|
555
|
+
*
|
|
556
|
+
* On a list request, the check and the middleware outside the innermost
|
|
557
|
+
* visibility run once for each registration. Middleware inside it does not
|
|
558
|
+
* run. A failure of that middleware or of a check fails the whole list
|
|
559
|
+
* request. It never hides a registration.
|
|
560
|
+
*
|
|
561
|
+
* Unlike `EnabledWhen`, a visibility runs the middleware around it on list
|
|
562
|
+
* requests, and middleware sees requests for hidden registrations.
|
|
563
|
+
*
|
|
564
|
+
* **Example** (Hiding admin tools from other users)
|
|
565
|
+
*
|
|
566
|
+
* ```ts
|
|
567
|
+
* import { Context, Effect, Layer, Schema } from "effect"
|
|
568
|
+
* import { McpServer, Tool, Toolkit } from "effect/ai"
|
|
569
|
+
*
|
|
570
|
+
* class CurrentUser extends Context.Service<CurrentUser, { readonly isAdmin: boolean }>()("CurrentUser") {}
|
|
571
|
+
*
|
|
572
|
+
* const AdminTools = Toolkit.make(Tool.make("DeleteUser", { success: Schema.String }))
|
|
573
|
+
*
|
|
574
|
+
* const Auth = McpServer.middleware<{ provides: CurrentUser }>()((effect, { headers }) =>
|
|
575
|
+
* Effect.provideService(effect, CurrentUser, { isAdmin: headers["x-role"] === "admin" })
|
|
576
|
+
* )
|
|
577
|
+
* const AdminOnly = McpServer.visibility(() => Effect.map(CurrentUser, (user) => user.isAdmin))
|
|
578
|
+
*
|
|
579
|
+
* const Registrations = McpServer.toolkit(AdminTools).pipe(
|
|
580
|
+
* Layer.provide(AdminOnly.combine(Auth).layer),
|
|
581
|
+
* Layer.provide(AdminTools.toLayer({ DeleteUser: () => Effect.succeed("deleted") }))
|
|
582
|
+
* )
|
|
583
|
+
* ```
|
|
584
|
+
*
|
|
585
|
+
* @see {@link middleware} for providing the services a check reads
|
|
586
|
+
*
|
|
587
|
+
* @stability unstable
|
|
588
|
+
* @category middleware
|
|
589
|
+
* @since 4.0.0
|
|
590
|
+
*/
|
|
591
|
+
export const visibility: visibility.Make = ((
|
|
592
|
+
check: AnyVisibilityCheck | Effect.Effect<AnyVisibilityCheck, any, any>,
|
|
593
|
+
options?: { readonly global?: boolean | undefined }
|
|
594
|
+
) => makeMiddleware(Effect.isEffect(check) ? Effect.map(check, makeGate) : makeGate(check), options)) as any
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Types used by `visibility`.
|
|
598
|
+
*
|
|
599
|
+
* @stability unstable
|
|
600
|
+
* @category middleware
|
|
601
|
+
* @since 4.0.0
|
|
602
|
+
*/
|
|
603
|
+
export declare namespace visibility {
|
|
604
|
+
/**
|
|
605
|
+
* The visibility check.
|
|
606
|
+
*
|
|
607
|
+
* @stability unstable
|
|
608
|
+
* @category middleware
|
|
609
|
+
* @since 4.0.0
|
|
610
|
+
*/
|
|
611
|
+
export type Check<E, R> = (options: MiddlewareOptions) => Effect.Effect<boolean, E, R>
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* The overloads of `visibility`.
|
|
615
|
+
*
|
|
616
|
+
* @stability unstable
|
|
617
|
+
* @category middleware
|
|
618
|
+
* @since 4.0.0
|
|
619
|
+
*/
|
|
620
|
+
export type Make = {
|
|
621
|
+
<E extends McpErrorBase, R, EX, RX, const Global extends boolean = false>(
|
|
622
|
+
check: Effect.Effect<Check<E, R>, EX, RX>,
|
|
623
|
+
options?: { readonly global?: Global | undefined }
|
|
624
|
+
): Made<Global, {
|
|
625
|
+
provides: never
|
|
626
|
+
error: E
|
|
627
|
+
requires: Exclude<R, McpRequestContext>
|
|
628
|
+
layerError: EX
|
|
629
|
+
layerRequires: Exclude<RX, Scope.Scope>
|
|
630
|
+
}>
|
|
631
|
+
<E extends McpErrorBase, R, const Global extends boolean = false>(
|
|
632
|
+
check: Check<E, R>,
|
|
633
|
+
options?: { readonly global?: Global | undefined }
|
|
634
|
+
): Made<Global, {
|
|
635
|
+
provides: never
|
|
636
|
+
error: E
|
|
637
|
+
requires: Exclude<R, McpRequestContext>
|
|
638
|
+
layerError: never
|
|
639
|
+
layerRequires: never
|
|
640
|
+
}>
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
type AnyVisibilityCheck = visibility.Check<any, any>
|
|
645
|
+
|
|
646
|
+
// Raised by a visibility gate. It is left out of the types because `makeInvoke`
|
|
647
|
+
// replaces it with the not-found error of the request. It still has the shape
|
|
648
|
+
// of an MCP error, since middleware outside the gate sees it as one.
|
|
649
|
+
class Hidden extends Data.TaggedError("effect/ai/McpServer/Hidden")<{
|
|
650
|
+
readonly code: number
|
|
651
|
+
readonly message: string
|
|
652
|
+
}> {}
|
|
653
|
+
|
|
654
|
+
const failHidden = Effect.fail(
|
|
655
|
+
new Hidden({ code: McpSchema.INVALID_PARAMS_ERROR_CODE, message: "Not found" })
|
|
656
|
+
) as Effect.Effect<never>
|
|
657
|
+
|
|
658
|
+
// Marks the middleware functions created by `visibility`.
|
|
659
|
+
const gates = new WeakSet<AnyMiddlewareFn>()
|
|
660
|
+
|
|
661
|
+
const makeGate = (check: AnyVisibilityCheck): AnyMiddlewareFn => {
|
|
662
|
+
const gate: AnyMiddlewareFn = (effect, options) =>
|
|
663
|
+
Effect.flatMap(check(options), (visible) => visible ? effect : failHidden)
|
|
664
|
+
gates.add(gate)
|
|
665
|
+
return gate
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
type Made<Global extends boolean, Config extends MiddlewareConfig> = Global extends true
|
|
669
|
+
? MiddlewareLayer<Config, McpServer>
|
|
670
|
+
: Middleware<Config>
|
|
671
|
+
|
|
672
|
+
type AnyMiddlewareFn = middleware.Fn<any, any, any>
|
|
673
|
+
|
|
674
|
+
class MiddlewareFn extends Context.Service<MiddlewareFn, AnyMiddlewareFn>()("effect/ai/McpServer/MiddlewareFn") {}
|
|
675
|
+
|
|
676
|
+
const makeMiddleware = (
|
|
677
|
+
fn: AnyMiddlewareFn | Effect.Effect<AnyMiddlewareFn, any, any>,
|
|
678
|
+
options?: { readonly global?: boolean | undefined }
|
|
679
|
+
) => {
|
|
680
|
+
const middleware = new MiddlewareImpl(
|
|
681
|
+
Effect.isEffect(fn) ? Layer.effect(MiddlewareFn)(fn) : Layer.succeed(MiddlewareFn, fn)
|
|
682
|
+
)
|
|
683
|
+
return options?.global ? middleware.layerGlobal : middleware
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
let middlewareId = 0
|
|
687
|
+
|
|
688
|
+
class MiddlewareImpl {
|
|
689
|
+
readonly [MiddlewareTypeId] = {} as any
|
|
690
|
+
readonly layer: Layer.Layer<never, any, any>
|
|
691
|
+
readonly layerGlobal: Layer.Layer<never, any, any>
|
|
692
|
+
readonly layerFn: Layer.Layer<MiddlewareFn, any, any>
|
|
693
|
+
readonly dependencies: Layer.Layer<any, any, any> | undefined
|
|
694
|
+
|
|
695
|
+
constructor(
|
|
696
|
+
layerFn: Layer.Layer<MiddlewareFn, any, any>,
|
|
697
|
+
dependencies?: Layer.Layer<any, any, any> | undefined
|
|
698
|
+
) {
|
|
699
|
+
this.layerFn = layerFn
|
|
700
|
+
this.dependencies = dependencies
|
|
701
|
+
const contextKey = `${middlewareKeyPrefix}${++middlewareId}`
|
|
702
|
+
this.layer = Layer.effectContext(Effect.gen(function*() {
|
|
703
|
+
const stack: Array<AnyMiddlewareFn> = [yield* MiddlewareFn]
|
|
704
|
+
if (dependencies) {
|
|
705
|
+
const memoMap = yield* Layer.CurrentMemoMap
|
|
706
|
+
const scope = yield* Effect.scope
|
|
707
|
+
stack.push(...getMiddleware(yield* Layer.buildWithMemoMap(dependencies, memoMap, scope)))
|
|
708
|
+
}
|
|
709
|
+
return Context.makeUnsafe<never>(new Map([[contextKey, stack]]))
|
|
710
|
+
})).pipe(Layer.provide(layerFn))
|
|
711
|
+
this.layerGlobal = Layer.effectDiscard(Effect.gen(function*() {
|
|
712
|
+
const stack: ReadonlyArray<AnyMiddlewareFn> = Context.getOrUndefinedUnsafe(
|
|
713
|
+
yield* Effect.context<never>(),
|
|
714
|
+
contextKey as any
|
|
715
|
+
)!
|
|
716
|
+
const { globalMiddleware } = internalState.get(yield* McpServer)!
|
|
717
|
+
yield* Effect.acquireRelease(
|
|
718
|
+
Effect.sync(() => {
|
|
719
|
+
globalMiddleware.push(...stack)
|
|
720
|
+
}),
|
|
721
|
+
() =>
|
|
722
|
+
Effect.sync(() => {
|
|
723
|
+
for (const fn of stack) {
|
|
724
|
+
const index = globalMiddleware.indexOf(fn)
|
|
725
|
+
if (index !== -1) globalMiddleware.splice(index, 1)
|
|
726
|
+
}
|
|
727
|
+
})
|
|
728
|
+
)
|
|
729
|
+
})).pipe(Layer.provide(this.layer))
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
combine(other: Middleware<any>): Middleware<any> {
|
|
733
|
+
return new MiddlewareImpl(
|
|
734
|
+
this.layerFn,
|
|
735
|
+
this.dependencies ? Layer.provideMerge(this.dependencies, other.layer as any) : other.layer as any
|
|
736
|
+
) as any
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// The innermost middleware comes first.
|
|
741
|
+
const getMiddleware = (context: Context.Context<never>): ReadonlyArray<AnyMiddlewareFn> => {
|
|
742
|
+
const stacks: Array<ReadonlyArray<AnyMiddlewareFn>> = []
|
|
743
|
+
let maxLength = 0
|
|
744
|
+
for (const [key, value] of context.mapUnsafe) {
|
|
745
|
+
if (key.startsWith(middlewareKeyPrefix)) {
|
|
746
|
+
stacks.push(value)
|
|
747
|
+
maxLength = Math.max(maxLength, value.length)
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
const unique = new Set<AnyMiddlewareFn>()
|
|
751
|
+
for (let i = maxLength - 1; i >= 0; i--) {
|
|
752
|
+
for (const stack of stacks) {
|
|
753
|
+
if (i < stack.length) unique.add(stack[i])
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return Arr.fromIterable(unique).reverse()
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const isMcpError = (error: unknown): error is McpErrorBase =>
|
|
760
|
+
Predicate.hasProperty(error, "code") && typeof error.code === "number" &&
|
|
761
|
+
Predicate.hasProperty(error, "message") && typeof error.message === "string"
|
|
762
|
+
|
|
763
|
+
// Distinguishes handler failures from failures raised or rewritten by middleware.
|
|
764
|
+
const HandlerFailure = Context.Reference<boolean>("effect/ai/McpServer/HandlerFailure", {
|
|
765
|
+
defaultValue: () => false
|
|
766
|
+
})
|
|
767
|
+
const handlerFailure = Context.make(HandlerFailure, true)
|
|
768
|
+
|
|
769
|
+
const internalError = new InternalError({ message: "Internal error" })
|
|
770
|
+
|
|
771
|
+
const rejectWith = (error: McpErrorBase) =>
|
|
772
|
+
Effect.fail(new McpCore.RequestRejected({ code: error.code, message: error.message, data: error.data, error }))
|
|
773
|
+
|
|
774
|
+
type CallMethod = "tools/call" | "resources/read" | "prompts/get" | "completion/complete" | "skills/get"
|
|
775
|
+
|
|
776
|
+
type ListMethod = Exclude<MiddlewareMethod, CallMethod>
|
|
777
|
+
|
|
778
|
+
interface NotFoundErrors {
|
|
779
|
+
readonly "tools/call": McpCore.ToolNotFound
|
|
780
|
+
readonly "resources/read": McpCore.ResourceNotFound
|
|
781
|
+
readonly "prompts/get": McpCore.PromptNotFound
|
|
782
|
+
readonly "completion/complete": InvalidParams
|
|
783
|
+
readonly "skills/get": McpCore.SkillNotFound
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const notFound = (method: CallMethod, target: string): NotFoundErrors[CallMethod] => {
|
|
787
|
+
switch (method) {
|
|
788
|
+
case "tools/call":
|
|
789
|
+
return new McpCore.ToolNotFound({ name: target })
|
|
790
|
+
case "resources/read":
|
|
791
|
+
return new McpCore.ResourceNotFound({ uri: target })
|
|
792
|
+
case "prompts/get":
|
|
793
|
+
return new McpCore.PromptNotFound({ name: target })
|
|
794
|
+
case "completion/complete":
|
|
795
|
+
return new InvalidParams({ message: "Unknown completion reference or argument" })
|
|
796
|
+
case "skills/get":
|
|
797
|
+
return new McpCore.SkillNotFound({ uri: target })
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
const isHidden = (error: unknown): error is Hidden => error instanceof Hidden
|
|
802
|
+
|
|
803
|
+
// Recovers a request rejected by a visibility gate. Any other cause, including
|
|
804
|
+
// one that also holds an interrupt, is propagated unchanged.
|
|
805
|
+
const catchHidden =
|
|
806
|
+
<B, E2>(onHidden: () => Effect.Effect<B, E2>) =>
|
|
807
|
+
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A | B, Exclude<E, Hidden> | E2, R> =>
|
|
808
|
+
Effect.catchCause(self, (cause): Effect.Effect<B, Exclude<E, Hidden> | E2> => {
|
|
809
|
+
const failure = Cause.findFail(cause)
|
|
810
|
+
return !Cause.hasInterrupts(cause) && Result.isSuccess(failure) && isHidden(failure.success.error)
|
|
811
|
+
? onHidden()
|
|
812
|
+
: Effect.failCause(cause as Cause.Cause<Exclude<E, Hidden>>)
|
|
813
|
+
})
|
|
814
|
+
|
|
815
|
+
// The innermost middleware comes first. Middleware provided both locally and
|
|
816
|
+
// globally runs once, at its outermost position.
|
|
817
|
+
const middlewareStack = (
|
|
818
|
+
localMiddleware: ReadonlyArray<AnyMiddlewareFn>,
|
|
819
|
+
globalMiddleware: ReadonlyArray<AnyMiddlewareFn>
|
|
820
|
+
): ReadonlyArray<AnyMiddlewareFn> => {
|
|
821
|
+
if (globalMiddleware.length === 0) {
|
|
822
|
+
return localMiddleware
|
|
823
|
+
}
|
|
824
|
+
if (localMiddleware.length === 0) {
|
|
825
|
+
return globalMiddleware
|
|
826
|
+
}
|
|
827
|
+
const stack = [...localMiddleware, ...globalMiddleware]
|
|
828
|
+
return stack.filter((fn, index) => stack.lastIndexOf(fn) === index)
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Runs a handler inside middleware. The handler's own failures pass through, a
|
|
832
|
+
// visibility gate fails with `Hidden`, and other failures become
|
|
833
|
+
// `RequestRejected`: middleware failures as JSON-RPC errors, anything else as
|
|
834
|
+
// a reported internal error.
|
|
835
|
+
const runMiddleware = <A, E>(
|
|
836
|
+
handler: Effect.Effect<A, E, any>,
|
|
837
|
+
middleware: ReadonlyArray<AnyMiddlewareFn>,
|
|
838
|
+
invocation: McpCore.McpInvocation,
|
|
839
|
+
request: Pick<MiddlewareOptions, "method" | "target" | "payload">
|
|
840
|
+
): Effect.Effect<A, E | Hidden | McpCore.RequestRejected> => {
|
|
841
|
+
const effect = middleware.length === 0 ? handler : Effect.withFiber((fiber) => {
|
|
842
|
+
const headers = Context.getOrUndefined(fiber.context, HttpServerRequest.HttpServerRequest)?.headers ??
|
|
843
|
+
Headers.empty
|
|
844
|
+
const options: MiddlewareOptions = {
|
|
845
|
+
...request,
|
|
846
|
+
requestContext: invocation.requestContext,
|
|
847
|
+
headers,
|
|
848
|
+
sessionId: headers[MCP_SESSION_ID_HEADER]
|
|
849
|
+
}
|
|
850
|
+
const handled = Effect.catchCause(handler, (cause) => Effect.failCause(Cause.annotate(cause, handlerFailure)))
|
|
851
|
+
return middleware.reduce((effect: Effect.Effect<any, any, any>, fn) => fn(effect, options), handled)
|
|
852
|
+
})
|
|
853
|
+
return provideInvocationContext(effect, invocation).pipe(
|
|
854
|
+
Effect.catchCause((cause): Effect.Effect<never, E | Hidden | McpCore.RequestRejected> => {
|
|
855
|
+
if (Cause.hasInterrupts(cause)) {
|
|
856
|
+
return Effect.failCause(cause)
|
|
857
|
+
}
|
|
858
|
+
const failure = Cause.findFail(cause)
|
|
859
|
+
if (Result.isSuccess(failure) && !Cause.hasDies(cause)) {
|
|
860
|
+
const error = failure.success.error
|
|
861
|
+
if (isHidden(error)) {
|
|
862
|
+
return Effect.fail(error)
|
|
863
|
+
}
|
|
864
|
+
if (middleware.length === 0 || Context.get(Cause.reasonAnnotations(failure.success), HandlerFailure)) {
|
|
865
|
+
return Effect.failCause(cause)
|
|
866
|
+
}
|
|
867
|
+
if (isMcpError(error)) {
|
|
868
|
+
return rejectWith(error)
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return Effect.logError(cause).pipe(
|
|
872
|
+
Effect.andThen(ErrorReporter.report(cause)),
|
|
873
|
+
Effect.andThen(rejectWith(internalError))
|
|
874
|
+
)
|
|
875
|
+
})
|
|
876
|
+
) as Effect.Effect<A, E | Hidden | McpCore.RequestRejected>
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// Request services override captured services; global middleware wraps local middleware.
|
|
880
|
+
const makeInvoke = (
|
|
881
|
+
context: Context.Context<never> | undefined,
|
|
882
|
+
globalMiddleware: ReadonlyArray<AnyMiddlewareFn>
|
|
883
|
+
) => {
|
|
884
|
+
const services = context === undefined ? Context.empty() : omitRequestServices(context)
|
|
885
|
+
const localMiddleware = context === undefined ? [] : getMiddleware(context)
|
|
886
|
+
const invoke = <A, E, M extends CallMethod>(
|
|
887
|
+
handler: Effect.Effect<A, E, any>,
|
|
888
|
+
invocation: McpCore.McpInvocation,
|
|
889
|
+
request: {
|
|
890
|
+
readonly method: M
|
|
891
|
+
readonly target: string
|
|
892
|
+
readonly payload: unknown
|
|
893
|
+
}
|
|
894
|
+
): Effect.Effect<A, E | NotFoundErrors[M] | McpCore.RequestRejected> =>
|
|
895
|
+
runMiddleware(
|
|
896
|
+
services.mapUnsafe.size === 0
|
|
897
|
+
? handler
|
|
898
|
+
: Effect.updateContext(handler, (context: Context.Context<any>) => Context.merge(services, context)),
|
|
899
|
+
middlewareStack(localMiddleware, globalMiddleware),
|
|
900
|
+
invocation,
|
|
901
|
+
request
|
|
902
|
+
).pipe(
|
|
903
|
+
catchHidden(() => Effect.fail(notFound(request.method, request.target) as NotFoundErrors[M]))
|
|
904
|
+
) as Effect.Effect<A, E | NotFoundErrors[M] | McpCore.RequestRejected>
|
|
905
|
+
// On list requests only the middleware outside the innermost visibility runs.
|
|
906
|
+
const visible = (method: ListMethod, target: string): McpCore.Visible => (invocation) => {
|
|
907
|
+
const middleware = middlewareStack(localMiddleware, globalMiddleware)
|
|
908
|
+
const innermost = middleware.findIndex((fn) => gates.has(fn))
|
|
909
|
+
if (innermost === -1) {
|
|
910
|
+
return Effect.succeed(true)
|
|
911
|
+
}
|
|
912
|
+
return runMiddleware(Effect.void, middleware.slice(innermost), invocation, { method, target, payload: undefined })
|
|
913
|
+
.pipe(
|
|
914
|
+
Effect.as(true),
|
|
915
|
+
catchHidden(() => Effect.succeed(false))
|
|
916
|
+
)
|
|
917
|
+
}
|
|
918
|
+
return { invoke, visible }
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// Applies the `EnabledWhen` annotation of a registration.
|
|
922
|
+
const isEnabled = (annotations: Context.Context<never>) => {
|
|
923
|
+
const enabledWhen = Context.getOrUndefined(annotations, EnabledWhen)
|
|
924
|
+
return (profile: McpCore.NegotiatedProtocolProfile<string>): boolean =>
|
|
925
|
+
enabledWhen === undefined || enabledWhen({
|
|
926
|
+
protocolVersion: profile.protocolVersion,
|
|
927
|
+
capabilities: profile.clientCapabilities,
|
|
928
|
+
clientInfo: profile.clientInfo
|
|
929
|
+
})
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const rejectedError = (rejected: McpCore.RequestRejected) => Effect.fail(rejected.error)
|
|
933
|
+
|
|
202
934
|
/**
|
|
203
935
|
* Service that stores and serves an MCP server's registered tools, resources,
|
|
204
936
|
* prompts, completions, and outgoing notifications.
|
|
@@ -225,6 +957,7 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
225
957
|
readonly addTool: (options: {
|
|
226
958
|
readonly tool: McpTool
|
|
227
959
|
readonly annotations: Context.Context<never>
|
|
960
|
+
readonly services?: Context.Context<never> | undefined
|
|
228
961
|
readonly handle: (
|
|
229
962
|
payload: any
|
|
230
963
|
) => Effect.Effect<
|
|
@@ -235,7 +968,7 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
235
968
|
}) => Effect.Effect<void>
|
|
236
969
|
readonly callTool: (
|
|
237
970
|
requests: typeof CallTool.payloadSchema.Type
|
|
238
|
-
) => Effect.Effect<CallToolResult, InternalError | InvalidParams, McpServerClient>
|
|
971
|
+
) => Effect.Effect<CallToolResult, McpErrorBase | InternalError | InvalidParams, McpServerClient>
|
|
239
972
|
|
|
240
973
|
readonly resources: ReadonlyArray<{
|
|
241
974
|
readonly resource: Resource
|
|
@@ -244,6 +977,7 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
244
977
|
readonly addResource: (options: {
|
|
245
978
|
readonly resource: Resource
|
|
246
979
|
readonly annotations: Context.Context<never>
|
|
980
|
+
readonly services?: Context.Context<never> | undefined
|
|
247
981
|
readonly handle: Effect.Effect<
|
|
248
982
|
ReadResourceResult,
|
|
249
983
|
InternalError,
|
|
@@ -259,6 +993,7 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
259
993
|
options: {
|
|
260
994
|
readonly template: ResourceTemplate
|
|
261
995
|
readonly annotations: Context.Context<never>
|
|
996
|
+
readonly services?: Context.Context<never> | undefined
|
|
262
997
|
readonly routerPath: string
|
|
263
998
|
readonly completions: Record<
|
|
264
999
|
string,
|
|
@@ -289,6 +1024,7 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
289
1024
|
readonly addPrompt: (options: {
|
|
290
1025
|
readonly prompt: Prompt
|
|
291
1026
|
readonly annotations: Context.Context<never>
|
|
1027
|
+
readonly services?: Context.Context<never> | undefined
|
|
292
1028
|
readonly completions: Record<
|
|
293
1029
|
string,
|
|
294
1030
|
(
|
|
@@ -302,11 +1038,11 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
302
1038
|
}) => Effect.Effect<void>
|
|
303
1039
|
readonly getPromptResult: (
|
|
304
1040
|
request: typeof GetPrompt.payloadSchema.Type
|
|
305
|
-
) => Effect.Effect<GetPromptResult, InternalError | InvalidParams, McpServerClient>
|
|
1041
|
+
) => Effect.Effect<GetPromptResult, McpErrorBase | InternalError | InvalidParams, McpServerClient>
|
|
306
1042
|
|
|
307
1043
|
readonly completion: (
|
|
308
1044
|
complete: typeof Complete.payloadSchema.Type
|
|
309
|
-
) => Effect.Effect<CompleteResult, InvalidParams | InternalError, McpServerClient>
|
|
1045
|
+
) => Effect.Effect<CompleteResult, McpErrorBase | InvalidParams | InternalError, McpServerClient>
|
|
310
1046
|
}>()("effect/ai/McpServer") {
|
|
311
1047
|
/**
|
|
312
1048
|
* Builds an MCP server service from registered tools, prompts, resources, and completions.
|
|
@@ -333,6 +1069,7 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
333
1069
|
readonly annotations: Context.Context<never>
|
|
334
1070
|
}> = []
|
|
335
1071
|
const notificationsQueue = yield* Queue.make<QueuedServerNotification>()
|
|
1072
|
+
const globalMiddleware: Array<AnyMiddlewareFn> = []
|
|
336
1073
|
const notificationDelivery = { consumers: 0, listChangeRevision: 0, requestEndpoints: 0 }
|
|
337
1074
|
// With only request-scoped endpoints, no long-lived server ever takes from the shared queue.
|
|
338
1075
|
const withoutSharedConsumer = () =>
|
|
@@ -405,6 +1142,38 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
405
1142
|
))
|
|
406
1143
|
})
|
|
407
1144
|
|
|
1145
|
+
// Checking skill ownership and both writes happen in one synchronous step,
|
|
1146
|
+
// so a skill cannot claim the URI in between. Skill files skip the check.
|
|
1147
|
+
const addResource = (
|
|
1148
|
+
options: Parameters<McpServer["Service"]["addResource"]>[0],
|
|
1149
|
+
checkOwnership: boolean
|
|
1150
|
+
): Effect.Effect<void> =>
|
|
1151
|
+
Effect.suspend(() => {
|
|
1152
|
+
if (checkOwnership && internalCore.skills.ownsFile(options.resource.uri)) {
|
|
1153
|
+
return Effect.die(
|
|
1154
|
+
new Cause.IllegalArgumentError(`Resource ${options.resource.uri} is a file of a registered skill`)
|
|
1155
|
+
)
|
|
1156
|
+
}
|
|
1157
|
+
const existingIndex = resources.findIndex(({ resource }) => resource.uri === options.resource.uri)
|
|
1158
|
+
if (existingIndex === -1) {
|
|
1159
|
+
resources.push(options)
|
|
1160
|
+
} else {
|
|
1161
|
+
resources[existingIndex] = options
|
|
1162
|
+
}
|
|
1163
|
+
const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
|
|
1164
|
+
internalCore.resources.register({
|
|
1165
|
+
descriptor: options.resource,
|
|
1166
|
+
visible: visible("resources/list", options.resource.uri),
|
|
1167
|
+
isVisible: isEnabled(options.annotations),
|
|
1168
|
+
read: (invocation) =>
|
|
1169
|
+
invoke(options.handle, invocation, {
|
|
1170
|
+
method: "resources/read",
|
|
1171
|
+
target: options.resource.uri,
|
|
1172
|
+
payload: { uri: options.resource.uri }
|
|
1173
|
+
})
|
|
1174
|
+
})
|
|
1175
|
+
return notifications.client["notifications/resources/list_changed"]({})
|
|
1176
|
+
})
|
|
408
1177
|
const service = McpServer.of({
|
|
409
1178
|
notifications: notifications.client,
|
|
410
1179
|
notifyElicitationComplete: ({ clientId, elicitationId }) =>
|
|
@@ -431,22 +1200,20 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
431
1200
|
} else {
|
|
432
1201
|
tools[existingIndex] = options
|
|
433
1202
|
}
|
|
434
|
-
const
|
|
1203
|
+
const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
|
|
435
1204
|
yield* internalCore.tools.register({
|
|
436
1205
|
descriptor: new McpTool({
|
|
437
1206
|
...options.tool,
|
|
438
1207
|
title: options.tool.title ?? options.tool.annotations?.title
|
|
439
1208
|
}),
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
{
|
|
443
|
-
protocolVersion: profile.protocolVersion,
|
|
444
|
-
capabilities: profile.clientCapabilities,
|
|
445
|
-
clientInfo: profile.clientInfo
|
|
446
|
-
}
|
|
447
|
-
),
|
|
1209
|
+
visible: visible("tools/list", options.tool.name),
|
|
1210
|
+
isVisible: isEnabled(options.annotations),
|
|
448
1211
|
handle: (call, invocation) =>
|
|
449
|
-
|
|
1212
|
+
invoke(options.handle(call.arguments), invocation, {
|
|
1213
|
+
method: "tools/call",
|
|
1214
|
+
target: call.name,
|
|
1215
|
+
payload: call
|
|
1216
|
+
}).pipe(
|
|
450
1217
|
Effect.catchTags({
|
|
451
1218
|
InternalError: (error) =>
|
|
452
1219
|
Effect.fail(
|
|
@@ -481,12 +1248,14 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
481
1248
|
request,
|
|
482
1249
|
McpProtocolInternal.invocationFromClient(client)
|
|
483
1250
|
).pipe(
|
|
484
|
-
Effect.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
1251
|
+
Effect.catch((error) =>
|
|
1252
|
+
error._tag === "RequestRejected" ? rejectedError(error) : Effect.fail(
|
|
1253
|
+
new InvalidParams({
|
|
1254
|
+
message: error._tag === "ToolNotFound"
|
|
1255
|
+
? `Tool '${error.name}' not found`
|
|
1256
|
+
: error.message
|
|
1257
|
+
})
|
|
1258
|
+
)
|
|
490
1259
|
)
|
|
491
1260
|
)
|
|
492
1261
|
if (result._tag === "InputRequired") {
|
|
@@ -500,87 +1269,74 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
500
1269
|
get resourceTemplates() {
|
|
501
1270
|
return resourceTemplates
|
|
502
1271
|
},
|
|
503
|
-
addResource:
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
resources[existingIndex] = options
|
|
509
|
-
}
|
|
510
|
-
yield* internalCore.resources.register({
|
|
511
|
-
descriptor: options.resource,
|
|
512
|
-
isVisible: (profile) => {
|
|
513
|
-
const enabledWhen = Context.getOrUndefined(options.annotations, EnabledWhen)
|
|
514
|
-
return enabledWhen === undefined || enabledWhen({
|
|
515
|
-
protocolVersion: profile.protocolVersion,
|
|
516
|
-
capabilities: profile.clientCapabilities,
|
|
517
|
-
clientInfo: profile.clientInfo
|
|
518
|
-
})
|
|
519
|
-
},
|
|
520
|
-
read: (invocation) => provideInvocationContext(options.handle, invocation)
|
|
521
|
-
})
|
|
522
|
-
yield* notifications.client["notifications/resources/list_changed"]({})
|
|
523
|
-
}),
|
|
524
|
-
addResourceTemplate: Effect.fnUntraced(function*({ annotations, completions, handle, routerPath, template }) {
|
|
525
|
-
const existingIndex = resourceTemplates.findIndex(({ template: current }) =>
|
|
526
|
-
current.uriTemplate === template.uriTemplate
|
|
527
|
-
)
|
|
528
|
-
if (existingIndex === -1) {
|
|
529
|
-
resourceTemplates.push({ template, annotations })
|
|
530
|
-
} else {
|
|
531
|
-
resourceTemplates[existingIndex] = { template, annotations }
|
|
532
|
-
}
|
|
533
|
-
const templateMatcher = makeUriMatcher<true>()
|
|
534
|
-
templateMatcher.add(routerPath, true)
|
|
535
|
-
yield* internalCore.resources.registerTemplate({
|
|
536
|
-
descriptor: template,
|
|
537
|
-
isVisible: (profile) => {
|
|
538
|
-
const enabledWhen = Context.getOrUndefined(annotations, EnabledWhen)
|
|
539
|
-
return enabledWhen === undefined || enabledWhen({
|
|
540
|
-
protocolVersion: profile.protocolVersion,
|
|
541
|
-
capabilities: profile.clientCapabilities,
|
|
542
|
-
clientInfo: profile.clientInfo
|
|
543
|
-
})
|
|
544
|
-
},
|
|
545
|
-
match: (uri) => {
|
|
546
|
-
const match = templateMatcher.find(uri)
|
|
547
|
-
if (match === undefined) {
|
|
548
|
-
return undefined
|
|
549
|
-
}
|
|
550
|
-
const params: Array<string> = []
|
|
551
|
-
for (const key of Object.keys(match.params)) {
|
|
552
|
-
params[Number(key)] = match.params[key]!
|
|
553
|
-
}
|
|
554
|
-
return params
|
|
555
|
-
},
|
|
556
|
-
read: (uri, params, invocation) => provideInvocationContext(handle(uri, Array.from(params)), invocation)
|
|
557
|
-
})
|
|
558
|
-
for (const [param, handle] of Object.entries(completions)) {
|
|
559
|
-
yield* internalCore.completions.register(
|
|
560
|
-
`resource/${template.uriTemplate}/${param}`,
|
|
561
|
-
(request, invocation) =>
|
|
562
|
-
provideInvocationContext(handle(request.argument.value, request.context), invocation).pipe(
|
|
563
|
-
Effect.map((result) => ({
|
|
564
|
-
values: result.completion.values,
|
|
565
|
-
total: result.completion.total,
|
|
566
|
-
hasMore: result.completion.hasMore,
|
|
567
|
-
metadata: result._meta
|
|
568
|
-
}))
|
|
569
|
-
)
|
|
1272
|
+
addResource: (options) => addResource(options, true),
|
|
1273
|
+
addResourceTemplate: Effect.fnUntraced(
|
|
1274
|
+
function*({ annotations, completions, handle, routerPath, services, template }) {
|
|
1275
|
+
const existingIndex = resourceTemplates.findIndex(({ template: current }) =>
|
|
1276
|
+
current.uriTemplate === template.uriTemplate
|
|
570
1277
|
)
|
|
1278
|
+
if (existingIndex === -1) {
|
|
1279
|
+
resourceTemplates.push({ template, annotations })
|
|
1280
|
+
} else {
|
|
1281
|
+
resourceTemplates[existingIndex] = { template, annotations }
|
|
1282
|
+
}
|
|
1283
|
+
const { invoke, visible } = makeInvoke(services, globalMiddleware)
|
|
1284
|
+
const templateMatcher = makeUriMatcher<true>()
|
|
1285
|
+
templateMatcher.add(routerPath, true)
|
|
1286
|
+
yield* internalCore.resources.registerTemplate({
|
|
1287
|
+
descriptor: template,
|
|
1288
|
+
visible: visible("resources/templates/list", template.uriTemplate),
|
|
1289
|
+
isVisible: isEnabled(annotations),
|
|
1290
|
+
match: (uri) => {
|
|
1291
|
+
const match = templateMatcher.find(uri)
|
|
1292
|
+
if (match === undefined) {
|
|
1293
|
+
return undefined
|
|
1294
|
+
}
|
|
1295
|
+
const params: Array<string> = []
|
|
1296
|
+
for (const key of Object.keys(match.params)) {
|
|
1297
|
+
params[Number(key)] = match.params[key]!
|
|
1298
|
+
}
|
|
1299
|
+
return params
|
|
1300
|
+
},
|
|
1301
|
+
read: (uri, params, invocation) =>
|
|
1302
|
+
invoke(handle(uri, Array.from(params)), invocation, {
|
|
1303
|
+
method: "resources/read",
|
|
1304
|
+
target: uri,
|
|
1305
|
+
payload: { uri }
|
|
1306
|
+
})
|
|
1307
|
+
})
|
|
1308
|
+
for (const [param, handle] of Object.entries(completions)) {
|
|
1309
|
+
yield* internalCore.completions.register(
|
|
1310
|
+
`resource/${template.uriTemplate}/${param}`,
|
|
1311
|
+
(request, invocation) =>
|
|
1312
|
+
invoke(handle(request.argument.value, request.context), invocation, {
|
|
1313
|
+
method: "completion/complete",
|
|
1314
|
+
target: template.uriTemplate,
|
|
1315
|
+
payload: request
|
|
1316
|
+
}).pipe(
|
|
1317
|
+
Effect.map((result) => ({
|
|
1318
|
+
values: result.completion.values,
|
|
1319
|
+
total: result.completion.total,
|
|
1320
|
+
hasMore: result.completion.hasMore,
|
|
1321
|
+
metadata: result._meta
|
|
1322
|
+
}))
|
|
1323
|
+
)
|
|
1324
|
+
)
|
|
1325
|
+
}
|
|
1326
|
+
yield* notifications.client["notifications/resources/list_changed"]({})
|
|
571
1327
|
}
|
|
572
|
-
|
|
573
|
-
}),
|
|
1328
|
+
),
|
|
574
1329
|
findResource: Effect.fnUntraced(function*(uri) {
|
|
575
1330
|
const client = yield* McpServerClient
|
|
576
1331
|
return yield* internalCore.resources.read(
|
|
577
1332
|
uri,
|
|
578
1333
|
McpProtocolInternal.invocationFromClient(client)
|
|
579
1334
|
).pipe(
|
|
580
|
-
Effect.
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
1335
|
+
Effect.catchTags({
|
|
1336
|
+
ResourceNotFound: (error) =>
|
|
1337
|
+
Effect.fail(new InvalidParams({ message: `Resource '${error.uri}' not found` })),
|
|
1338
|
+
RequestRejected: rejectedError
|
|
1339
|
+
})
|
|
584
1340
|
)
|
|
585
1341
|
}),
|
|
586
1342
|
get prompts() {
|
|
@@ -593,18 +1349,17 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
593
1349
|
} else {
|
|
594
1350
|
prompts[existingIndex] = options
|
|
595
1351
|
}
|
|
1352
|
+
const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
|
|
596
1353
|
yield* internalCore.prompts.register({
|
|
597
1354
|
descriptor: options.prompt,
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
return enabledWhen === undefined || enabledWhen({
|
|
601
|
-
protocolVersion: profile.protocolVersion,
|
|
602
|
-
capabilities: profile.clientCapabilities,
|
|
603
|
-
clientInfo: profile.clientInfo
|
|
604
|
-
})
|
|
605
|
-
},
|
|
1355
|
+
visible: visible("prompts/list", options.prompt.name),
|
|
1356
|
+
isVisible: isEnabled(options.annotations),
|
|
606
1357
|
get: (params, invocation) =>
|
|
607
|
-
|
|
1358
|
+
invoke(options.handle(params), invocation, {
|
|
1359
|
+
method: "prompts/get",
|
|
1360
|
+
target: options.prompt.name,
|
|
1361
|
+
payload: { name: options.prompt.name, arguments: params }
|
|
1362
|
+
}).pipe(
|
|
608
1363
|
Effect.map((result) =>
|
|
609
1364
|
Predicate.isTagged(result, "InputRequired")
|
|
610
1365
|
? McpCore.OperationOutcome.InputRequired(result)
|
|
@@ -616,7 +1371,11 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
616
1371
|
yield* internalCore.completions.register(
|
|
617
1372
|
`prompt/${options.prompt.name}/${param}`,
|
|
618
1373
|
(request, invocation) =>
|
|
619
|
-
|
|
1374
|
+
invoke(handle(request.argument.value, request.context), invocation, {
|
|
1375
|
+
method: "completion/complete",
|
|
1376
|
+
target: options.prompt.name,
|
|
1377
|
+
payload: request
|
|
1378
|
+
}).pipe(
|
|
620
1379
|
Effect.map((result) => ({
|
|
621
1380
|
values: result.completion.values,
|
|
622
1381
|
total: result.completion.total,
|
|
@@ -635,7 +1394,10 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
635
1394
|
params ?? {},
|
|
636
1395
|
McpProtocolInternal.invocationFromClient(client)
|
|
637
1396
|
).pipe(
|
|
638
|
-
Effect.
|
|
1397
|
+
Effect.catchTags({
|
|
1398
|
+
PromptNotFound: () => new InvalidParams({ message: `Prompt '${name}' not found` }),
|
|
1399
|
+
RequestRejected: rejectedError
|
|
1400
|
+
})
|
|
639
1401
|
)
|
|
640
1402
|
return outcome._tag === "Complete"
|
|
641
1403
|
? outcome.value
|
|
@@ -650,7 +1412,9 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
650
1412
|
: { type: "prompt", name: ref.name },
|
|
651
1413
|
argument: complete.argument,
|
|
652
1414
|
context: complete.context
|
|
653
|
-
}, McpProtocolInternal.invocationFromClient(client))
|
|
1415
|
+
}, McpProtocolInternal.invocationFromClient(client)).pipe(
|
|
1416
|
+
Effect.catchTag("RequestRejected", rejectedError)
|
|
1417
|
+
)
|
|
654
1418
|
return {
|
|
655
1419
|
_meta: result.metadata,
|
|
656
1420
|
completion: {
|
|
@@ -661,17 +1425,29 @@ export class McpServer extends Context.Service<McpServer, {
|
|
|
661
1425
|
}
|
|
662
1426
|
})
|
|
663
1427
|
})
|
|
664
|
-
internalState.set(service, {
|
|
1428
|
+
internalState.set(service, {
|
|
1429
|
+
core: internalCore,
|
|
1430
|
+
addSkillFile: (options) => addResource(options, false),
|
|
1431
|
+
notifications: notificationsQueue,
|
|
1432
|
+
notificationDelivery,
|
|
1433
|
+
globalMiddleware
|
|
1434
|
+
})
|
|
665
1435
|
return service
|
|
666
1436
|
})
|
|
667
1437
|
|
|
668
1438
|
/**
|
|
669
|
-
* Layer that provides the MCP server
|
|
1439
|
+
* Layer that provides the MCP server service.
|
|
1440
|
+
*
|
|
1441
|
+
* **Details**
|
|
1442
|
+
*
|
|
1443
|
+
* It doesn't run a transport or discharge request-level dependencies. Use it
|
|
1444
|
+
* to call registrations in process, providing their request-level
|
|
1445
|
+
* dependencies with MCP middleware.
|
|
670
1446
|
*
|
|
671
1447
|
* @stability unstable
|
|
672
1448
|
* @since 4.0.0
|
|
673
1449
|
*/
|
|
674
|
-
static readonly layer: Layer.Layer<McpServer
|
|
1450
|
+
static readonly layer: Layer.Layer<McpServer> = Layer.effect(McpServer)(McpServer.make)
|
|
675
1451
|
}
|
|
676
1452
|
|
|
677
1453
|
const MCP_SESSION_ID_HEADER = "mcp-session-id"
|
|
@@ -681,17 +1457,96 @@ const cancelledResponses = new WeakMap<object, string | number>()
|
|
|
681
1457
|
const httpPostResponses = new WeakMap<HttpServerRequest.HttpServerRequest, { expected: number }>()
|
|
682
1458
|
const requestKey = (requestId: string | number): string => `${typeof requestId}:${requestId}`
|
|
683
1459
|
|
|
684
|
-
interface ActiveRequest {
|
|
685
|
-
readonly requestId: RpcMessage.RequestId
|
|
686
|
-
readonly prepared: McpRuntime.PreparedRequest
|
|
687
|
-
readonly cancelled: boolean
|
|
688
|
-
readonly httpPost: { expected: number } | undefined
|
|
1460
|
+
interface ActiveRequest {
|
|
1461
|
+
readonly requestId: RpcMessage.RequestId
|
|
1462
|
+
readonly prepared: McpRuntime.PreparedRequest
|
|
1463
|
+
readonly cancelled: boolean
|
|
1464
|
+
readonly httpPost: { expected: number } | undefined
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
class McpClientKey extends Data.Class<{
|
|
1468
|
+
readonly clientId: number
|
|
1469
|
+
readonly profile: McpCore.NegotiatedProtocolProfile<string>
|
|
1470
|
+
}> {}
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* A client cache hint for one kind of `v2026_07_28` result.
|
|
1474
|
+
*
|
|
1475
|
+
* **Details**
|
|
1476
|
+
*
|
|
1477
|
+
* `ttl` is how long a client may treat the result as fresh. It is sent as a
|
|
1478
|
+
* whole number of milliseconds, rounded down, so it must be finite,
|
|
1479
|
+
* nonnegative and at most `Number.MAX_SAFE_INTEGER` milliseconds. Only
|
|
1480
|
+
* `"private"` scope is supported, so shared caches must not store the result.
|
|
1481
|
+
*
|
|
1482
|
+
* @stability unstable
|
|
1483
|
+
* @category models
|
|
1484
|
+
* @since 4.1.0
|
|
1485
|
+
*/
|
|
1486
|
+
export interface CacheHint {
|
|
1487
|
+
readonly ttl: Duration.Input
|
|
1488
|
+
readonly cacheScope: "private"
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* Client cache hints for `v2026_07_28` discovery and list results.
|
|
1493
|
+
*
|
|
1494
|
+
* **Details**
|
|
1495
|
+
*
|
|
1496
|
+
* Each entry sets the freshness and `cacheScope` of one result kind:
|
|
1497
|
+
* `server/discover`, `tools/list`, `resources/list`,
|
|
1498
|
+
* `resources/templates/list` and `prompts/list`. `skills` covers the Skills
|
|
1499
|
+
* extension's `skills/list`, `skills/get` and `resources/directory/read`.
|
|
1500
|
+
* Omitted entries, and `resources/read` results, keep
|
|
1501
|
+
* `{ ttlMs: 0, cacheScope: "private" }`. Earlier protocol revisions have no
|
|
1502
|
+
* cache hints and ignore this option.
|
|
1503
|
+
*
|
|
1504
|
+
* These are hints for clients. The server does not cache results, and
|
|
1505
|
+
* visibility and invocation checks still run on every request.
|
|
1506
|
+
*
|
|
1507
|
+
* **Gotchas**
|
|
1508
|
+
*
|
|
1509
|
+
* A positive `ttl` lets a client keep showing a list after registrations or
|
|
1510
|
+
* per-request visibility change, until the hint expires. Private scope does
|
|
1511
|
+
* not key a client's cache by user, so a client shared between users can
|
|
1512
|
+
* reuse one user's list for another.
|
|
1513
|
+
*
|
|
1514
|
+
* @stability unstable
|
|
1515
|
+
* @category models
|
|
1516
|
+
* @since 4.1.0
|
|
1517
|
+
*/
|
|
1518
|
+
export interface CacheHints {
|
|
1519
|
+
readonly discover?: CacheHint | undefined
|
|
1520
|
+
readonly tools?: CacheHint | undefined
|
|
1521
|
+
readonly resources?: CacheHint | undefined
|
|
1522
|
+
readonly resourceTemplates?: CacheHint | undefined
|
|
1523
|
+
readonly prompts?: CacheHint | undefined
|
|
1524
|
+
readonly skills?: CacheHint | undefined
|
|
689
1525
|
}
|
|
690
1526
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
1527
|
+
// Converts each hint to the wire's nonnegative integer `ttlMs` once, when the server is built.
|
|
1528
|
+
const normalizeCacheHints = (
|
|
1529
|
+
cacheHints: CacheHints | undefined
|
|
1530
|
+
): Effect.Effect<McpProtocolInternal.CacheHints | undefined, Cause.IllegalArgumentError> => {
|
|
1531
|
+
if (cacheHints === undefined) return Effect.succeed(undefined)
|
|
1532
|
+
const normalized: Record<string, { readonly ttlMs: number; readonly cacheScope: "private" }> = {}
|
|
1533
|
+
for (const [name, hint] of Object.entries(cacheHints)) {
|
|
1534
|
+
if (hint === undefined) continue
|
|
1535
|
+
const ttlMs = Option.match(Duration.fromInput(hint.ttl), {
|
|
1536
|
+
onNone: () => NaN,
|
|
1537
|
+
onSome: (ttl) => Math.floor(Duration.toMillis(ttl))
|
|
1538
|
+
})
|
|
1539
|
+
if (!Number.isSafeInteger(ttlMs) || ttlMs < 0 || hint.cacheScope !== "private") {
|
|
1540
|
+
return Effect.fail(
|
|
1541
|
+
new Cause.IllegalArgumentError(
|
|
1542
|
+
`McpServer cacheHints.${name} must have a finite, nonnegative ttl and a "private" cacheScope`
|
|
1543
|
+
)
|
|
1544
|
+
)
|
|
1545
|
+
}
|
|
1546
|
+
normalized[name] = { ttlMs, cacheScope: "private" }
|
|
1547
|
+
}
|
|
1548
|
+
return Effect.succeed(normalized)
|
|
1549
|
+
}
|
|
695
1550
|
|
|
696
1551
|
/**
|
|
697
1552
|
* Runs an MCP server over the current `RpcServer.Protocol`.
|
|
@@ -715,6 +1570,7 @@ export const run: (options: {
|
|
|
715
1570
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
716
1571
|
readonly protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
|
|
717
1572
|
readonly extensions?: ServerExtensions | undefined
|
|
1573
|
+
readonly cacheHints?: CacheHints | undefined
|
|
718
1574
|
}) => Effect.Effect<
|
|
719
1575
|
never,
|
|
720
1576
|
Cause.IllegalArgumentError,
|
|
@@ -728,12 +1584,14 @@ export const run: (options: {
|
|
|
728
1584
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
729
1585
|
readonly protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
|
|
730
1586
|
readonly extensions?: ServerExtensions | undefined
|
|
1587
|
+
readonly cacheHints?: CacheHints | undefined
|
|
731
1588
|
}) {
|
|
1589
|
+
const cacheHints = yield* normalizeCacheHints(options.cacheHints)
|
|
732
1590
|
const runtimeOption = yield* Effect.serviceOption(McpRuntime.ServerRuntime)
|
|
733
1591
|
const runtime = Option.isSome(runtimeOption)
|
|
734
1592
|
? runtimeOption.value
|
|
735
1593
|
: yield* McpRuntime.make(options.protocols)
|
|
736
|
-
return yield* runWithRuntime(options, runtime, "custom")
|
|
1594
|
+
return yield* runWithRuntime({ ...options, cacheHints }, runtime, "custom")
|
|
737
1595
|
})
|
|
738
1596
|
|
|
739
1597
|
const runWithRuntime = Effect.fnUntraced(function*(
|
|
@@ -745,6 +1603,7 @@ const runWithRuntime = Effect.fnUntraced(function*(
|
|
|
745
1603
|
readonly websiteUrl?: string | undefined
|
|
746
1604
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
747
1605
|
readonly extensions?: ServerExtensions | undefined
|
|
1606
|
+
readonly cacheHints?: McpProtocolInternal.CacheHints | undefined
|
|
748
1607
|
readonly allowSubscriptions?: boolean | undefined
|
|
749
1608
|
},
|
|
750
1609
|
runtime: McpRuntime.ServerRuntimeShape,
|
|
@@ -1365,7 +2224,8 @@ const runWithRuntime = Effect.fnUntraced(function*(
|
|
|
1365
2224
|
(requestContext?.clientId === clientId ? requestHeaders : undefined) ??
|
|
1366
2225
|
clientStates.get(clientId)?.sessionHeaders ?? Headers.empty,
|
|
1367
2226
|
notification,
|
|
1368
|
-
defaultLogLevel
|
|
2227
|
+
defaultLogLevel,
|
|
2228
|
+
listChangeRevision
|
|
1369
2229
|
)
|
|
1370
2230
|
) {
|
|
1371
2231
|
return
|
|
@@ -1412,6 +2272,37 @@ const runWithRuntime = Effect.fnUntraced(function*(
|
|
|
1412
2272
|
)
|
|
1413
2273
|
}, Effect.scoped)
|
|
1414
2274
|
|
|
2275
|
+
type StatefulProtocolAdapter = McpProtocol.ProtocolAdapter<
|
|
2276
|
+
McpProtocol.ProtocolVersion,
|
|
2277
|
+
McpProtocol.StatefulRuntimeDescriptor
|
|
2278
|
+
>
|
|
2279
|
+
|
|
2280
|
+
/**
|
|
2281
|
+
* Request-level services supplied by a transport.
|
|
2282
|
+
*
|
|
2283
|
+
* **Details**
|
|
2284
|
+
*
|
|
2285
|
+
* Every transport supplies `Scope`. `McpServerClient` is supplied only when
|
|
2286
|
+
* every configured protocol is known to be sessionful: a `v2026_07_28` request
|
|
2287
|
+
* has no client session, and a protocol array widened to `ProtocolAdapter`
|
|
2288
|
+
* might contain one. HTTP transports also supply `HttpServerRequest`.
|
|
2289
|
+
*
|
|
2290
|
+
* @stability unstable
|
|
2291
|
+
* @category utility types
|
|
2292
|
+
* @since 4.0.0
|
|
2293
|
+
*/
|
|
2294
|
+
export type ProvidedServices<
|
|
2295
|
+
Protocols extends ReadonlyArray<McpProtocol.ProtocolAdapter>,
|
|
2296
|
+
Http extends boolean = false
|
|
2297
|
+
> =
|
|
2298
|
+
| Scope.Scope
|
|
2299
|
+
| (Protocols[number] extends StatefulProtocolAdapter ? McpServerClient : never)
|
|
2300
|
+
| (Http extends true ? HttpServerRequest.HttpServerRequest : never)
|
|
2301
|
+
|
|
2302
|
+
type RemainingRequestServices<RR, Provided> = Exclude<McpRequest.Only<"Requires", RR>, Provided>
|
|
2303
|
+
|
|
2304
|
+
type RegistrationServices<RR> = Exclude<McpRequest.Without<RR>, McpServer>
|
|
2305
|
+
|
|
1415
2306
|
/**
|
|
1416
2307
|
* Creates a layer that starts an MCP server over an existing
|
|
1417
2308
|
* `RpcServer.Protocol` and provides `McpServer`. Request handlers receive
|
|
@@ -1430,6 +2321,11 @@ const runWithRuntime = Effect.fnUntraced(function*(
|
|
|
1430
2321
|
* `McpServer.layer`, so registration layers can use the `McpServer` service
|
|
1431
2322
|
* while the server is running.
|
|
1432
2323
|
*
|
|
2324
|
+
* Pass registration layers as `registrations` to build them before the server
|
|
2325
|
+
* reads its first request. The transport discharges the request-level
|
|
2326
|
+
* dependencies it supplies (see `ProvidedServices`); any other `McpRequest`
|
|
2327
|
+
* marker stays in the layer's requirements and must be met by MCP middleware.
|
|
2328
|
+
*
|
|
1433
2329
|
* **Gotchas**
|
|
1434
2330
|
*
|
|
1435
2331
|
* Unlike `layerStdio` and `layerHttp`, this layer does not install a concrete
|
|
@@ -1443,19 +2339,32 @@ const runWithRuntime = Effect.fnUntraced(function*(
|
|
|
1443
2339
|
* @category layers
|
|
1444
2340
|
* @since 4.0.0
|
|
1445
2341
|
*/
|
|
1446
|
-
export const layer =
|
|
2342
|
+
export const layer = <
|
|
2343
|
+
const Protocols extends Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>,
|
|
2344
|
+
RA = never,
|
|
2345
|
+
RE = never,
|
|
2346
|
+
RR = never
|
|
2347
|
+
>(options: {
|
|
1447
2348
|
readonly name: string
|
|
1448
2349
|
readonly version: string
|
|
1449
2350
|
readonly instructions?: string | undefined
|
|
1450
2351
|
readonly description?: string | undefined
|
|
1451
2352
|
readonly websiteUrl?: string | undefined
|
|
1452
2353
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
1453
|
-
readonly protocols:
|
|
2354
|
+
readonly protocols: Protocols
|
|
1454
2355
|
readonly extensions?: ServerExtensions | undefined
|
|
1455
|
-
|
|
2356
|
+
readonly cacheHints?: CacheHints | undefined
|
|
2357
|
+
readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
|
|
2358
|
+
}): Layer.Layer<
|
|
2359
|
+
McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols>>,
|
|
2360
|
+
Cause.IllegalArgumentError | RE,
|
|
2361
|
+
| RpcServer.Protocol
|
|
2362
|
+
| RegistrationServices<RR>
|
|
2363
|
+
| McpRequest.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols>>>
|
|
2364
|
+
> =>
|
|
1456
2365
|
layerWithRuntime(options, "custom").pipe(
|
|
1457
2366
|
Layer.provide(McpRuntime.layer(options.protocols))
|
|
1458
|
-
)
|
|
2367
|
+
) as any
|
|
1459
2368
|
|
|
1460
2369
|
const layerWithRuntime = (options: {
|
|
1461
2370
|
readonly name: string
|
|
@@ -1465,18 +2374,18 @@ const layerWithRuntime = (options: {
|
|
|
1465
2374
|
readonly websiteUrl?: string | undefined
|
|
1466
2375
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
1467
2376
|
readonly extensions?: ServerExtensions | undefined
|
|
2377
|
+
readonly cacheHints?: CacheHints | undefined
|
|
1468
2378
|
readonly allowSubscriptions?: boolean | undefined
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
never,
|
|
1472
|
-
RpcServer.Protocol | McpRuntime.ServerRuntime
|
|
1473
|
-
> =>
|
|
2379
|
+
readonly registrations?: Layer.Layer<any, any, any> | undefined
|
|
2380
|
+
}, transport: "custom" | "http" | "stdio") =>
|
|
1474
2381
|
Layer.effectDiscard(
|
|
1475
2382
|
Effect.gen(function*() {
|
|
2383
|
+
const cacheHints = yield* normalizeCacheHints(options.cacheHints)
|
|
1476
2384
|
const runtime = yield* McpRuntime.ServerRuntime
|
|
1477
|
-
yield* Effect.forkScoped(runWithRuntime(options, runtime, transport))
|
|
2385
|
+
yield* Effect.forkScoped(runWithRuntime({ ...options, cacheHints }, runtime, transport))
|
|
1478
2386
|
})
|
|
1479
2387
|
).pipe(
|
|
2388
|
+
Layer.provide(options.registrations ?? Layer.empty),
|
|
1480
2389
|
Layer.provideMerge(McpServer.layer)
|
|
1481
2390
|
)
|
|
1482
2391
|
|
|
@@ -1495,6 +2404,11 @@ const layerWithRuntime = (options: {
|
|
|
1495
2404
|
* `McpRequestContext` and legacy `McpServerClient` services to handlers, and
|
|
1496
2405
|
* requires `Stdio`.
|
|
1497
2406
|
*
|
|
2407
|
+
* Pass registration layers as `registrations` to build them before the server
|
|
2408
|
+
* reads its first request. The transport discharges the request-level
|
|
2409
|
+
* dependencies it supplies (see `ProvidedServices`); any other `McpRequest`
|
|
2410
|
+
* marker stays in the layer's requirements and must be met by MCP middleware.
|
|
2411
|
+
*
|
|
1498
2412
|
* @see {@link layer} for running over an existing `RpcServer.Protocol`
|
|
1499
2413
|
* @see {@link layerHttp} for the single-endpoint HTTP transport
|
|
1500
2414
|
*
|
|
@@ -1502,16 +2416,29 @@ const layerWithRuntime = (options: {
|
|
|
1502
2416
|
* @category layers
|
|
1503
2417
|
* @since 4.0.0
|
|
1504
2418
|
*/
|
|
1505
|
-
export const layerStdio =
|
|
2419
|
+
export const layerStdio = <
|
|
2420
|
+
const Protocols extends Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>,
|
|
2421
|
+
RA = never,
|
|
2422
|
+
RE = never,
|
|
2423
|
+
RR = never
|
|
2424
|
+
>(options: {
|
|
1506
2425
|
readonly name: string
|
|
1507
2426
|
readonly version: string
|
|
1508
2427
|
readonly instructions?: string | undefined
|
|
1509
2428
|
readonly description?: string | undefined
|
|
1510
2429
|
readonly websiteUrl?: string | undefined
|
|
1511
2430
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
1512
|
-
readonly protocols:
|
|
2431
|
+
readonly protocols: Protocols
|
|
1513
2432
|
readonly extensions?: ServerExtensions | undefined
|
|
1514
|
-
|
|
2433
|
+
readonly cacheHints?: CacheHints | undefined
|
|
2434
|
+
readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
|
|
2435
|
+
}): Layer.Layer<
|
|
2436
|
+
McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols>>,
|
|
2437
|
+
Cause.IllegalArgumentError | RE,
|
|
2438
|
+
| Stdio
|
|
2439
|
+
| RegistrationServices<RR>
|
|
2440
|
+
| McpRequest.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols>>>
|
|
2441
|
+
> =>
|
|
1515
2442
|
layerWithRuntime(options, "stdio").pipe(
|
|
1516
2443
|
Layer.provide(McpRuntime.layer(options.protocols)),
|
|
1517
2444
|
Layer.provide(RpcServer.layerProtocolStdio),
|
|
@@ -1519,7 +2446,7 @@ export const layerStdio = (options: {
|
|
|
1519
2446
|
RpcSerialization.RpcSerialization,
|
|
1520
2447
|
mcpStdioSerialization(options.protocols)
|
|
1521
2448
|
))
|
|
1522
|
-
)
|
|
2449
|
+
) as any
|
|
1523
2450
|
|
|
1524
2451
|
const mcpStdioSerialization = (
|
|
1525
2452
|
protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
|
|
@@ -1621,6 +2548,13 @@ const mcpStdioSerialization = (
|
|
|
1621
2548
|
* serverless hosts where execution must belong to each request, use
|
|
1622
2549
|
* `layerHttpRequestScoped` instead.
|
|
1623
2550
|
*
|
|
2551
|
+
* Pass registration layers as `registrations` to build them before the
|
|
2552
|
+
* endpoint serves its first request. The transport discharges the
|
|
2553
|
+
* request-level dependencies it supplies (see `ProvidedServices`) and converts
|
|
2554
|
+
* the remaining `McpRequest` markers into `HttpRouter.Request` markers, so
|
|
2555
|
+
* `HttpRouter.middleware` can provide them, for example to authenticate the
|
|
2556
|
+
* request and resolve the current user.
|
|
2557
|
+
*
|
|
1624
2558
|
* `layerHttp` always implements the single-endpoint Streamable HTTP topology.
|
|
1625
2559
|
* Using `v2024_11_05` here is a custom compatibility transport for that
|
|
1626
2560
|
* revision's schema. It does not implement the historical two-endpoint
|
|
@@ -1638,7 +2572,12 @@ const mcpStdioSerialization = (
|
|
|
1638
2572
|
* @category layers
|
|
1639
2573
|
* @since 4.0.0
|
|
1640
2574
|
*/
|
|
1641
|
-
export const layerHttp =
|
|
2575
|
+
export const layerHttp = <
|
|
2576
|
+
const Protocols extends Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>,
|
|
2577
|
+
RA = never,
|
|
2578
|
+
RE = never,
|
|
2579
|
+
RR = never
|
|
2580
|
+
>(options: {
|
|
1642
2581
|
readonly name: string
|
|
1643
2582
|
readonly version: string
|
|
1644
2583
|
readonly instructions?: string | undefined
|
|
@@ -1646,18 +2585,26 @@ export const layerHttp = (options: {
|
|
|
1646
2585
|
readonly websiteUrl?: string | undefined
|
|
1647
2586
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
1648
2587
|
readonly path: HttpRouter.PathInput
|
|
1649
|
-
readonly protocols:
|
|
2588
|
+
readonly protocols: Protocols
|
|
1650
2589
|
readonly extensions?: ServerExtensions | undefined
|
|
2590
|
+
readonly cacheHints?: CacheHints | undefined
|
|
1651
2591
|
readonly allowedOrigins?: ReadonlyArray<string> | undefined
|
|
1652
2592
|
readonly allowSessionTermination?: boolean | undefined
|
|
1653
2593
|
readonly allowSubscriptions?: boolean | undefined
|
|
1654
|
-
|
|
2594
|
+
readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
|
|
2595
|
+
}): Layer.Layer<
|
|
2596
|
+
McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols, true>>,
|
|
2597
|
+
Cause.IllegalArgumentError | RE,
|
|
2598
|
+
| HttpRouter.HttpRouter
|
|
2599
|
+
| RegistrationServices<RR>
|
|
2600
|
+
| HttpRouter.Request.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols, true>>>
|
|
2601
|
+
> => {
|
|
1655
2602
|
const runtime = McpRuntime.layer(options.protocols)
|
|
1656
2603
|
return layerWithRuntime(options, "http").pipe(
|
|
1657
2604
|
Layer.provide(layerMcpProtocolHttp(options)),
|
|
1658
2605
|
Layer.provide(runtime),
|
|
1659
2606
|
Layer.provide(RpcSerialization.layerJsonRpc())
|
|
1660
|
-
)
|
|
2607
|
+
) as any
|
|
1661
2608
|
}
|
|
1662
2609
|
|
|
1663
2610
|
/**
|
|
@@ -1688,13 +2635,24 @@ export const layerHttp = (options: {
|
|
|
1688
2635
|
* Configuring a sessionful protocol through an untyped caller fails layer
|
|
1689
2636
|
* construction with `IllegalArgumentError`.
|
|
1690
2637
|
*
|
|
2638
|
+
* Registrations passed as `registrations` are built once, before the routes
|
|
2639
|
+
* are added, and shared by every POST. Remaining `McpRequest` markers become
|
|
2640
|
+
* `HttpRouter.Request` markers, as with `layerHttp`.
|
|
2641
|
+
*
|
|
1691
2642
|
* @see {@link layerHttp} for the long-lived HTTP transport and HTTP admission policy
|
|
1692
2643
|
*
|
|
1693
2644
|
* @stability unstable
|
|
1694
2645
|
* @category layers
|
|
1695
2646
|
* @since 4.0.0
|
|
1696
2647
|
*/
|
|
1697
|
-
export const layerHttpRequestScoped =
|
|
2648
|
+
export const layerHttpRequestScoped = <
|
|
2649
|
+
const Protocols extends Arr.NonEmptyReadonlyArray<
|
|
2650
|
+
McpProtocol.ProtocolAdapter<McpProtocol.ProtocolVersion, McpProtocol.StatelessRuntimeDescriptor>
|
|
2651
|
+
>,
|
|
2652
|
+
RA = never,
|
|
2653
|
+
RE = never,
|
|
2654
|
+
RR = never
|
|
2655
|
+
>(options: {
|
|
1698
2656
|
readonly name: string
|
|
1699
2657
|
readonly version: string
|
|
1700
2658
|
readonly instructions?: string | undefined
|
|
@@ -1702,12 +2660,18 @@ export const layerHttpRequestScoped = (options: {
|
|
|
1702
2660
|
readonly websiteUrl?: string | undefined
|
|
1703
2661
|
readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
|
|
1704
2662
|
readonly path: HttpRouter.PathInput
|
|
1705
|
-
readonly protocols:
|
|
1706
|
-
McpProtocol.ProtocolAdapter<McpProtocol.ProtocolVersion, McpProtocol.StatelessRuntimeDescriptor>
|
|
1707
|
-
>
|
|
2663
|
+
readonly protocols: Protocols
|
|
1708
2664
|
readonly extensions?: ServerExtensions | undefined
|
|
2665
|
+
readonly cacheHints?: CacheHints | undefined
|
|
1709
2666
|
readonly allowedOrigins?: ReadonlyArray<string> | undefined
|
|
1710
|
-
|
|
2667
|
+
readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
|
|
2668
|
+
}): Layer.Layer<
|
|
2669
|
+
McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols, true>>,
|
|
2670
|
+
Cause.IllegalArgumentError | RE,
|
|
2671
|
+
| HttpRouter.HttpRouter
|
|
2672
|
+
| RegistrationServices<RR>
|
|
2673
|
+
| HttpRouter.Request.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols, true>>>
|
|
2674
|
+
> =>
|
|
1711
2675
|
Layer.effectDiscard(Effect.gen(function*() {
|
|
1712
2676
|
const runtime = yield* McpRuntime.ServerRuntime
|
|
1713
2677
|
const stateful = runtime.protocols.find((protocol) => protocol.runtime._tag === "Stateful")
|
|
@@ -1716,6 +2680,7 @@ export const layerHttpRequestScoped = (options: {
|
|
|
1716
2680
|
`McpServer.layerHttpRequestScoped does not support the sessionful MCP protocol ${stateful.protocolVersion}`
|
|
1717
2681
|
)
|
|
1718
2682
|
}
|
|
2683
|
+
const serverOptions = { ...options, cacheHints: yield* normalizeCacheHints(options.cacheHints) }
|
|
1719
2684
|
const server = yield* McpServer
|
|
1720
2685
|
const { core, notificationDelivery } = internalState.get(server)!
|
|
1721
2686
|
// Subscriptions are disabled, so handlers hold no per-request state and
|
|
@@ -1726,7 +2691,7 @@ export const layerHttpRequestScoped = (options: {
|
|
|
1726
2691
|
subscribeServerNotifications: Effect.die("Subscriptions are disabled for request-scoped MCP servers"),
|
|
1727
2692
|
getListChangeRevision: () => notificationDelivery.listChangeRevision,
|
|
1728
2693
|
defaultLogLevel: yield* CurrentLogLevel,
|
|
1729
|
-
serverInfo:
|
|
2694
|
+
serverInfo: serverOptions
|
|
1730
2695
|
}) as Effect.Effect<Context.Context<never>>)
|
|
1731
2696
|
yield* Effect.acquireRelease(
|
|
1732
2697
|
Effect.sync(() => {
|
|
@@ -1746,7 +2711,7 @@ export const layerHttpRequestScoped = (options: {
|
|
|
1746
2711
|
Effect.provideService(RpcSerialization.RpcSerialization, mcpHttpSerialization)
|
|
1747
2712
|
)
|
|
1748
2713
|
const notifications = yield* Queue.make<QueuedServerNotification>()
|
|
1749
|
-
yield* runWithRuntime(
|
|
2714
|
+
yield* runWithRuntime(serverOptions, runtime, "http", { notifications, handlers }).pipe(
|
|
1750
2715
|
Effect.provideService(RpcServer.Protocol, protocol),
|
|
1751
2716
|
Effect.provideService(McpServer, server),
|
|
1752
2717
|
Effect.forkScoped({ startImmediately: true })
|
|
@@ -1755,9 +2720,10 @@ export const layerHttpRequestScoped = (options: {
|
|
|
1755
2720
|
})
|
|
1756
2721
|
)
|
|
1757
2722
|
})).pipe(
|
|
2723
|
+
Layer.provide(options.registrations ?? Layer.empty),
|
|
1758
2724
|
Layer.provideMerge(McpServer.layer),
|
|
1759
2725
|
Layer.provide(McpRuntime.layer(options.protocols))
|
|
1760
|
-
)
|
|
2726
|
+
) as any
|
|
1761
2727
|
|
|
1762
2728
|
const layerMcpProtocolHttp = (options: {
|
|
1763
2729
|
readonly path: HttpRouter.PathInput
|
|
@@ -2026,20 +2992,50 @@ const toolErrorResult = (message: string): CallToolResult =>
|
|
|
2026
2992
|
const toolResultContent = (encoded: unknown): CallToolResult["content"] =>
|
|
2027
2993
|
encoded === undefined ? [] : [{ type: "text", text: JSON.stringify(encoded) }]
|
|
2028
2994
|
|
|
2995
|
+
/**
|
|
2996
|
+
* The requirements of a toolkit registration.
|
|
2997
|
+
*
|
|
2998
|
+
* **Details**
|
|
2999
|
+
*
|
|
3000
|
+
* Services a tool declares with `dependencies` or `Tool.addDependency` are
|
|
3001
|
+
* request-level: they are carried as `McpRequest<"Requires", S>` markers and
|
|
3002
|
+
* must be provided by MCP middleware or the transport. Parameter decoding and
|
|
3003
|
+
* result encoding services are required when the toolkit is registered,
|
|
3004
|
+
* unless a tool also declares them.
|
|
3005
|
+
*
|
|
3006
|
+
* @stability unstable
|
|
3007
|
+
* @category utility types
|
|
3008
|
+
* @since 4.0.0
|
|
3009
|
+
*/
|
|
3010
|
+
export type ToolkitRequirements<Tools extends Record<string, Tool.Any>> = 0 extends
|
|
3011
|
+
(1 & Tool.Requirements<Tools[keyof Tools]>) ? any :
|
|
3012
|
+
| Tool.HandlersFor<Tools>
|
|
3013
|
+
| RegistrationRequirements<Tool.SchemaServices<Tools[keyof Tools]>, Tool.Requirements<Tools[keyof Tools]>>
|
|
3014
|
+
|
|
3015
|
+
type RegistrationRequirements<SchemaServices, RequestServices> =
|
|
3016
|
+
| McpServer
|
|
3017
|
+
| Exclude<SchemaServices, RequestServices | McpRequestContext>
|
|
3018
|
+
| McpRequest.From<"Requires", Exclude<RequestServices, McpRequestContext>>
|
|
3019
|
+
|
|
2029
3020
|
/**
|
|
2030
3021
|
* Registers a `Toolkit` with the `McpServer`.
|
|
2031
3022
|
*
|
|
3023
|
+
* **Details**
|
|
3024
|
+
*
|
|
3025
|
+
* The MCP middleware in the current context, provided with
|
|
3026
|
+
* `Effect.provide(middleware.layer)`, runs around every call to the toolkit.
|
|
3027
|
+
*
|
|
3028
|
+
* @see {@link ToolkitRequirements} for which services are request-level
|
|
3029
|
+
*
|
|
2032
3030
|
* @stability unstable
|
|
2033
3031
|
* @category handlers
|
|
2034
3032
|
* @since 4.0.0
|
|
2035
3033
|
*/
|
|
2036
3034
|
export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
|
|
2037
3035
|
toolkit: Toolkit.Toolkit<Tools>
|
|
2038
|
-
) => Effect.Effect<
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
McpServer | Tool.HandlersFor<Tools> | Exclude<Tool.HandlerServices<Tools[keyof Tools]>, McpRequestContext>
|
|
2042
|
-
> = Effect.fnUntraced(function*<Tools extends Record<string, Tool.Any>>(
|
|
3036
|
+
) => Effect.Effect<void, never, ToolkitRequirements<Tools>> = Effect.fnUntraced(function*<
|
|
3037
|
+
Tools extends Record<string, Tool.Any>
|
|
3038
|
+
>(
|
|
2043
3039
|
toolkit: Toolkit.Toolkit<Tools>
|
|
2044
3040
|
) {
|
|
2045
3041
|
const registry = yield* McpServer
|
|
@@ -2058,19 +3054,14 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
|
|
|
2058
3054
|
}
|
|
2059
3055
|
return Context.makeUnsafe(services)
|
|
2060
3056
|
}))
|
|
2061
|
-
const services =
|
|
2062
|
-
yield* Effect.context<
|
|
2063
|
-
Exclude<Tool.HandlerServices<Tools[keyof Tools]>, McpRequestContext>
|
|
2064
|
-
>()
|
|
2065
|
-
)
|
|
2066
|
-
const reportCause = (cause: Cause.Cause<unknown>) => Effect.provideContext(ErrorReporter.report(cause), services)
|
|
3057
|
+
const services = yield* Effect.context<never>()
|
|
2067
3058
|
// Interruption propagates; anything else is logged, reported and scrubbed.
|
|
2068
3059
|
const internalToolError = (cause: Cause.Cause<unknown>) => {
|
|
2069
3060
|
const failure = Cause.findFail(cause)
|
|
2070
3061
|
return Result.isFailure(failure) && !Cause.hasDies(cause)
|
|
2071
3062
|
? Effect.failCause(failure.failure)
|
|
2072
3063
|
: Effect.logError(cause).pipe(
|
|
2073
|
-
Effect.andThen(
|
|
3064
|
+
Effect.andThen(ErrorReporter.report(cause)),
|
|
2074
3065
|
Effect.as(toolErrorResult(INTERNAL_TOOL_ERROR_MESSAGE))
|
|
2075
3066
|
)
|
|
2076
3067
|
}
|
|
@@ -2098,6 +3089,32 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
|
|
|
2098
3089
|
? Effect.succeed(toolErrorResult(error.message))
|
|
2099
3090
|
: Effect.map(encodeFailure(error), (encoded) =>
|
|
2100
3091
|
new CallToolResult({ isError: true, content: toolResultContent(encoded) }))
|
|
3092
|
+
// `structuredContent` must be JSON and match the advertised `outputSchema`, which is derived from the JSON codec.
|
|
3093
|
+
// The Toolkit has already encoded the result, so only the JSON conversion of its encoded form runs here.
|
|
3094
|
+
const encodeStructured = Schema.encodeUnknownEffect(Schema.toCodecJson(Schema.toEncoded(tool.successSchema))) as (
|
|
3095
|
+
result: unknown
|
|
3096
|
+
) => Effect.Effect<unknown, Schema.SchemaError, Tool.HandlerServices<Tools[keyof Tools]>>
|
|
3097
|
+
const successResult = (result: unknown) =>
|
|
3098
|
+
encodeStructured(result).pipe(
|
|
3099
|
+
Effect.mapError((cause) =>
|
|
3100
|
+
AiError.make({
|
|
3101
|
+
module: "McpServer",
|
|
3102
|
+
method: "registerToolkit",
|
|
3103
|
+
reason: new AiError.ToolResultEncodingError({
|
|
3104
|
+
toolName: tool.name,
|
|
3105
|
+
toolResult: result,
|
|
3106
|
+
description: cause.message
|
|
3107
|
+
})
|
|
3108
|
+
})
|
|
3109
|
+
),
|
|
3110
|
+
Effect.map((structuredContent) =>
|
|
3111
|
+
new CallToolResult({
|
|
3112
|
+
isError: false,
|
|
3113
|
+
structuredContent,
|
|
3114
|
+
content: toolResultContent(structuredContent)
|
|
3115
|
+
})
|
|
3116
|
+
)
|
|
3117
|
+
)
|
|
2101
3118
|
const handleCause = (cause: Cause.Cause<unknown>) => {
|
|
2102
3119
|
const failure = Cause.findFail(cause)
|
|
2103
3120
|
if (Result.isSuccess(failure)) {
|
|
@@ -2153,25 +3170,31 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
|
|
|
2153
3170
|
Stream.unwrap,
|
|
2154
3171
|
Stream.runLast,
|
|
2155
3172
|
Effect.flatMap(Effect.fromOption),
|
|
2156
|
-
Effect.flatMap((result)
|
|
3173
|
+
Effect.flatMap((result): Effect.Effect<
|
|
3174
|
+
CallToolResult,
|
|
3175
|
+
unknown,
|
|
3176
|
+
Tool.HandlerServices<Tools[keyof Tools]>
|
|
3177
|
+
> => {
|
|
3178
|
+
if (!result.isFailure) {
|
|
3179
|
+
// An absent result, such as `Schema.Void`, has no structured form.
|
|
3180
|
+
return result.encodedResult === undefined
|
|
3181
|
+
? Effect.succeed(new CallToolResult({ isError: false, content: [] }))
|
|
3182
|
+
: successResult(result.encodedResult)
|
|
3183
|
+
}
|
|
2157
3184
|
// Declared failures return their encoded payload; anything else is classified by origin.
|
|
2158
|
-
|
|
2159
|
-
? Effect.
|
|
3185
|
+
return result.failureOrigin === "handler"
|
|
3186
|
+
? Effect.succeed(
|
|
3187
|
+
new CallToolResult({ isError: true, content: toolResultContent(result.encodedResult) })
|
|
3188
|
+
)
|
|
3189
|
+
: Effect.failCause(Cause.annotate(
|
|
2160
3190
|
Cause.fail(result.result),
|
|
2161
3191
|
Context.make(Toolkit.FailureOrigin, result.failureOrigin ?? "result")
|
|
2162
3192
|
))
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
})
|
|
2169
|
-
)
|
|
2170
|
-
),
|
|
2171
|
-
Effect.catchCause(handleCause),
|
|
2172
|
-
Effect.provideContext(services as Context.Context<Tool.HandlerServices<Tools[keyof Tools]>>)
|
|
2173
|
-
)
|
|
2174
|
-
}
|
|
3193
|
+
}),
|
|
3194
|
+
Effect.catchCause(handleCause)
|
|
3195
|
+
) as Effect.Effect<CallToolResult, InvalidParams, never>
|
|
3196
|
+
},
|
|
3197
|
+
services
|
|
2175
3198
|
})
|
|
2176
3199
|
}
|
|
2177
3200
|
for (const registration of registrations) {
|
|
@@ -2201,7 +3224,14 @@ const toolJsonSchema = (schema: Schema.Constraint, strict: boolean): JsonSchema.
|
|
|
2201
3224
|
}
|
|
2202
3225
|
|
|
2203
3226
|
/**
|
|
2204
|
-
*
|
|
3227
|
+
* Creates a layer that registers a `Toolkit` with the `McpServer`.
|
|
3228
|
+
*
|
|
3229
|
+
* **Details**
|
|
3230
|
+
*
|
|
3231
|
+
* The layer requires `McpServer`. Pass it to a transport through the
|
|
3232
|
+
* `registrations` option, or provide the transport layer to it.
|
|
3233
|
+
*
|
|
3234
|
+
* @see {@link ToolkitRequirements} for which services are request-level
|
|
2205
3235
|
*
|
|
2206
3236
|
* @stability unstable
|
|
2207
3237
|
* @category layers
|
|
@@ -2209,14 +3239,7 @@ const toolJsonSchema = (schema: Schema.Constraint, strict: boolean): JsonSchema.
|
|
|
2209
3239
|
*/
|
|
2210
3240
|
export const toolkit = <Tools extends Record<string, Tool.Any>>(
|
|
2211
3241
|
toolkit: Toolkit.Toolkit<Tools>
|
|
2212
|
-
): Layer.Layer<
|
|
2213
|
-
never,
|
|
2214
|
-
never,
|
|
2215
|
-
Tool.HandlersFor<Tools> | Exclude<Tool.HandlerServices<Tools[keyof Tools]>, McpRequestContext>
|
|
2216
|
-
> =>
|
|
2217
|
-
Layer.effectDiscard(registerToolkit(toolkit)).pipe(
|
|
2218
|
-
Layer.provide(McpServer.layer)
|
|
2219
|
-
)
|
|
3242
|
+
): Layer.Layer<never, never, ToolkitRequirements<Tools>> => Layer.effectDiscard(registerToolkit(toolkit))
|
|
2220
3243
|
|
|
2221
3244
|
/**
|
|
2222
3245
|
* Utility type that validates a completion-handler record against the allowed
|
|
@@ -2272,6 +3295,90 @@ export type ResourceCompletions<Schemas extends ReadonlyArray<Schema.Constraint>
|
|
|
2272
3295
|
) => Effect.Effect<Array<Schemas[K]["Type"]>, any, any>
|
|
2273
3296
|
}
|
|
2274
3297
|
|
|
3298
|
+
// Leave defects and interruption to makeInvoke; convert only expected failures.
|
|
3299
|
+
const handlerFailureToInternalError = (cause: Cause.Cause<unknown>): Effect.Effect<never, InternalError> =>
|
|
3300
|
+
Cause.hasDies(cause) || Cause.hasInterrupts(cause)
|
|
3301
|
+
? Effect.failCause(cause as Cause.Cause<never>)
|
|
3302
|
+
: Effect.fail(new InternalError({ message: Cause.prettyErrors(cause)[0].message }))
|
|
3303
|
+
|
|
3304
|
+
const completionHandler = (
|
|
3305
|
+
handle: (input: string, context: CompletionContext) => Effect.Effect<any, any, any>,
|
|
3306
|
+
encodeValues: (values: unknown) => Effect.Effect<ReadonlyArray<unknown>, any, any>
|
|
3307
|
+
) =>
|
|
3308
|
+
(input: string, context: CompletionContext): Effect.Effect<CompleteResult, InternalError> =>
|
|
3309
|
+
handle(input, context).pipe(
|
|
3310
|
+
Effect.flatMap(encodeValues),
|
|
3311
|
+
Effect.map((values) => ({
|
|
3312
|
+
completion: {
|
|
3313
|
+
values: values as Array<string>,
|
|
3314
|
+
total: values.length,
|
|
3315
|
+
hasMore: false
|
|
3316
|
+
}
|
|
3317
|
+
})),
|
|
3318
|
+
Effect.catchCause(handlerFailureToInternalError)
|
|
3319
|
+
) as any
|
|
3320
|
+
|
|
3321
|
+
type TemplateParamKey<Schemas extends ReadonlyArray<Schema.Constraint>, K extends keyof Schemas> = Schemas[K] extends
|
|
3322
|
+
Param<infer Id, infer _S> ? Id : `param${K & string}`
|
|
3323
|
+
|
|
3324
|
+
type TemplateSchemaServices<Schemas extends ReadonlyArray<Schema.Constraint>, Completions> =
|
|
3325
|
+
| Schemas[number]["DecodingServices"]
|
|
3326
|
+
| {
|
|
3327
|
+
[K in Extract<keyof Schemas, `${number}`>]: TemplateParamKey<Schemas, K> extends keyof Completions
|
|
3328
|
+
? Schemas[K]["EncodingServices"]
|
|
3329
|
+
: never
|
|
3330
|
+
}[Extract<keyof Schemas, `${number}`>]
|
|
3331
|
+
|
|
3332
|
+
type PromptSchemaServices<Params extends Schema.Struct.Fields, Completions> =
|
|
3333
|
+
| Schema.Struct.DecodingServices<Params>
|
|
3334
|
+
| Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
|
|
3335
|
+
|
|
3336
|
+
/**
|
|
3337
|
+
* The requirements of a resource registration: the content handler's services
|
|
3338
|
+
* are request-level.
|
|
3339
|
+
*
|
|
3340
|
+
* @stability unstable
|
|
3341
|
+
* @category utility types
|
|
3342
|
+
* @since 4.0.0
|
|
3343
|
+
*/
|
|
3344
|
+
export type ResourceRequirements<R> = RegistrationRequirements<never, R>
|
|
3345
|
+
|
|
3346
|
+
/**
|
|
3347
|
+
* The requirements of a resource template registration.
|
|
3348
|
+
*
|
|
3349
|
+
* **Details**
|
|
3350
|
+
*
|
|
3351
|
+
* Services read by the content and completion handlers are request-level.
|
|
3352
|
+
* Parameter decoding services, and the encoding services of parameters with a
|
|
3353
|
+
* completion handler, are required when the template is registered, unless a
|
|
3354
|
+
* handler also reads them.
|
|
3355
|
+
*
|
|
3356
|
+
* @stability unstable
|
|
3357
|
+
* @category utility types
|
|
3358
|
+
* @since 4.0.0
|
|
3359
|
+
*/
|
|
3360
|
+
export type ResourceTemplateRequirements<Schemas extends ReadonlyArray<Schema.Constraint>, R, Completions> =
|
|
3361
|
+
RegistrationRequirements<TemplateSchemaServices<Schemas, Completions>, R | CompletionServices<Completions>>
|
|
3362
|
+
|
|
3363
|
+
/**
|
|
3364
|
+
* The requirements of a prompt registration.
|
|
3365
|
+
*
|
|
3366
|
+
* **Details**
|
|
3367
|
+
*
|
|
3368
|
+
* Services read by the content and completion handlers are request-level.
|
|
3369
|
+
* Parameter decoding services, and the encoding services of parameters with a
|
|
3370
|
+
* completion handler, are required when the prompt is registered, unless a
|
|
3371
|
+
* handler also reads them.
|
|
3372
|
+
*
|
|
3373
|
+
* @stability unstable
|
|
3374
|
+
* @category utility types
|
|
3375
|
+
* @since 4.0.0
|
|
3376
|
+
*/
|
|
3377
|
+
export type PromptRequirements<Params extends Schema.Struct.Fields, R, Completions> = RegistrationRequirements<
|
|
3378
|
+
PromptSchemaServices<Params, Completions>,
|
|
3379
|
+
R | CompletionServices<Completions>
|
|
3380
|
+
>
|
|
3381
|
+
|
|
2275
3382
|
/**
|
|
2276
3383
|
* Registers an MCP resource or resource template from an Effect program.
|
|
2277
3384
|
*
|
|
@@ -2306,7 +3413,7 @@ export const registerResource: {
|
|
|
2306
3413
|
>
|
|
2307
3414
|
readonly annotations?: Context.Context<never> | undefined
|
|
2308
3415
|
}
|
|
2309
|
-
): Effect.Effect<void, never,
|
|
3416
|
+
): Effect.Effect<void, never, ResourceRequirements<R>>
|
|
2310
3417
|
/**
|
|
2311
3418
|
* Registers an MCP resource or resource template from an Effect program.
|
|
2312
3419
|
*
|
|
@@ -2333,18 +3440,7 @@ export const registerResource: {
|
|
|
2333
3440
|
R
|
|
2334
3441
|
>
|
|
2335
3442
|
readonly annotations?: Context.Context<never> | undefined
|
|
2336
|
-
}) => Effect.Effect<
|
|
2337
|
-
void,
|
|
2338
|
-
never,
|
|
2339
|
-
| Exclude<
|
|
2340
|
-
| Schemas[number]["DecodingServices"]
|
|
2341
|
-
| Schemas[number]["EncodingServices"]
|
|
2342
|
-
| R
|
|
2343
|
-
| CompletionServices<Completions>,
|
|
2344
|
-
McpRequestContext
|
|
2345
|
-
>
|
|
2346
|
-
| McpServer
|
|
2347
|
-
>
|
|
3443
|
+
}) => Effect.Effect<void, never, ResourceTemplateRequirements<Schemas, R, Completions>>
|
|
2348
3444
|
} = function() {
|
|
2349
3445
|
if (arguments.length === 1) {
|
|
2350
3446
|
const options = arguments[0] as {
|
|
@@ -2358,20 +3454,17 @@ export const registerResource: {
|
|
|
2358
3454
|
readonly annotations?: Context.Context<never> | undefined
|
|
2359
3455
|
}
|
|
2360
3456
|
return Effect.gen(function*() {
|
|
2361
|
-
const services =
|
|
3457
|
+
const services = yield* Effect.context<never>()
|
|
2362
3458
|
const registry = yield* McpServer
|
|
2363
3459
|
yield* registry.addResource({
|
|
2364
3460
|
resource: new Resource({
|
|
2365
3461
|
...options,
|
|
2366
3462
|
annotations: options
|
|
2367
3463
|
}),
|
|
3464
|
+
services,
|
|
2368
3465
|
handle: options.content.pipe(
|
|
2369
|
-
Effect.provideContext(services),
|
|
2370
3466
|
Effect.map((content) => resolveResourceContent(options.uri, content)),
|
|
2371
|
-
Effect.catchCause(
|
|
2372
|
-
const prettyError = Cause.prettyErrors(cause)[0]
|
|
2373
|
-
return Effect.fail(new InternalError({ message: prettyError.message }))
|
|
2374
|
-
})
|
|
3467
|
+
Effect.catchCause(handlerFailureToInternalError)
|
|
2375
3468
|
),
|
|
2376
3469
|
annotations: options.annotations ?? Context.empty()
|
|
2377
3470
|
})
|
|
@@ -2405,7 +3498,7 @@ export const registerResource: {
|
|
|
2405
3498
|
>
|
|
2406
3499
|
readonly annotations?: Context.Context<never> | undefined
|
|
2407
3500
|
}) {
|
|
2408
|
-
const services =
|
|
3501
|
+
const services = yield* Effect.context<never>()
|
|
2409
3502
|
const registry = yield* McpServer
|
|
2410
3503
|
const decode = Schema.decodeUnknownEffect(schema)
|
|
2411
3504
|
const template = new ResourceTemplate({
|
|
@@ -2421,32 +3514,13 @@ export const registerResource: {
|
|
|
2421
3514
|
) => Effect.Effect<CompleteResult, InternalError>
|
|
2422
3515
|
> = Object.create(null)
|
|
2423
3516
|
for (const [param, handle] of Object.entries(options.completion ?? {})) {
|
|
2424
|
-
|
|
2425
|
-
const handler = (
|
|
2426
|
-
input: string,
|
|
2427
|
-
context: CompletionContext
|
|
2428
|
-
) =>
|
|
2429
|
-
handle(input, context).pipe(
|
|
2430
|
-
Effect.flatMap(encodeArray),
|
|
2431
|
-
Effect.map((values) => ({
|
|
2432
|
-
completion: {
|
|
2433
|
-
values: values as Array<string>,
|
|
2434
|
-
total: values.length,
|
|
2435
|
-
hasMore: false
|
|
2436
|
-
}
|
|
2437
|
-
})),
|
|
2438
|
-
Effect.catchCause((cause) => {
|
|
2439
|
-
const prettyError = Cause.prettyErrors(cause)[0]
|
|
2440
|
-
return Effect.fail(new InternalError({ message: prettyError.message }))
|
|
2441
|
-
}),
|
|
2442
|
-
Effect.provideContext(services)
|
|
2443
|
-
)
|
|
2444
|
-
completions[param] = handler
|
|
3517
|
+
completions[param] = completionHandler(handle, Schema.encodeUnknownEffect(Schema.Array(params[param])))
|
|
2445
3518
|
}
|
|
2446
3519
|
yield* registry.addResourceTemplate({
|
|
2447
3520
|
template,
|
|
2448
3521
|
routerPath,
|
|
2449
3522
|
completions,
|
|
3523
|
+
services,
|
|
2450
3524
|
annotations: options.annotations ?? Context.empty(),
|
|
2451
3525
|
handle: (uri, params) =>
|
|
2452
3526
|
decode(params).pipe(
|
|
@@ -2454,14 +3528,10 @@ export const registerResource: {
|
|
|
2454
3528
|
Effect.flatMap((params: any) =>
|
|
2455
3529
|
options.content(uri, ...params).pipe(
|
|
2456
3530
|
Effect.map((content) => resolveResourceContent(uri, content)),
|
|
2457
|
-
Effect.catchCause(
|
|
2458
|
-
const prettyError = Cause.prettyErrors(cause)[0]
|
|
2459
|
-
return Effect.fail(new InternalError({ message: prettyError.message }))
|
|
2460
|
-
})
|
|
3531
|
+
Effect.catchCause(handlerFailureToInternalError)
|
|
2461
3532
|
)
|
|
2462
|
-
)
|
|
2463
|
-
|
|
2464
|
-
)
|
|
3533
|
+
)
|
|
3534
|
+
) as Effect.Effect<ReadResourceResult, InvalidParams | InternalError>
|
|
2465
3535
|
})
|
|
2466
3536
|
})
|
|
2467
3537
|
} as any
|
|
@@ -2469,7 +3539,15 @@ export const registerResource: {
|
|
|
2469
3539
|
/**
|
|
2470
3540
|
* Creates a layer that registers an MCP resource or resource template.
|
|
2471
3541
|
*
|
|
3542
|
+
* **Details**
|
|
3543
|
+
*
|
|
3544
|
+
* Services read by the content and completion handlers are request-level, so
|
|
3545
|
+
* providing them with `Layer.provide` doesn't satisfy them. Read
|
|
3546
|
+
* construction-time services in an enclosing `Layer.unwrap` and close over
|
|
3547
|
+
* them, and provide per-request services with MCP middleware.
|
|
3548
|
+
*
|
|
2472
3549
|
* @see {@link registerResource} for the Effect-level resource registration API
|
|
3550
|
+
* @see {@link middleware} for providing request-level dependencies
|
|
2473
3551
|
*
|
|
2474
3552
|
* @stability unstable
|
|
2475
3553
|
* @category layers
|
|
@@ -2479,7 +3557,15 @@ export const resource: {
|
|
|
2479
3557
|
/**
|
|
2480
3558
|
* Creates a layer that registers an MCP resource or resource template.
|
|
2481
3559
|
*
|
|
3560
|
+
* **Details**
|
|
3561
|
+
*
|
|
3562
|
+
* Services read by the content and completion handlers are request-level, so
|
|
3563
|
+
* providing them with `Layer.provide` doesn't satisfy them. Read
|
|
3564
|
+
* construction-time services in an enclosing `Layer.unwrap` and close over
|
|
3565
|
+
* them, and provide per-request services with MCP middleware.
|
|
3566
|
+
*
|
|
2482
3567
|
* @see {@link registerResource} for the Effect-level resource registration API
|
|
3568
|
+
* @see {@link middleware} for providing request-level dependencies
|
|
2483
3569
|
*
|
|
2484
3570
|
* @stability unstable
|
|
2485
3571
|
* @category layers
|
|
@@ -2499,11 +3585,19 @@ export const resource: {
|
|
|
2499
3585
|
R
|
|
2500
3586
|
>
|
|
2501
3587
|
}
|
|
2502
|
-
): Layer.Layer<never, never,
|
|
3588
|
+
): Layer.Layer<never, never, ResourceRequirements<R>>
|
|
2503
3589
|
/**
|
|
2504
3590
|
* Creates a layer that registers an MCP resource or resource template.
|
|
2505
3591
|
*
|
|
3592
|
+
* **Details**
|
|
3593
|
+
*
|
|
3594
|
+
* Services read by the content and completion handlers are request-level, so
|
|
3595
|
+
* providing them with `Layer.provide` doesn't satisfy them. Read
|
|
3596
|
+
* construction-time services in an enclosing `Layer.unwrap` and close over
|
|
3597
|
+
* them, and provide per-request services with MCP middleware.
|
|
3598
|
+
*
|
|
2506
3599
|
* @see {@link registerResource} for the Effect-level resource registration API
|
|
3600
|
+
* @see {@link middleware} for providing request-level dependencies
|
|
2507
3601
|
*
|
|
2508
3602
|
* @stability unstable
|
|
2509
3603
|
* @category layers
|
|
@@ -2525,30 +3619,175 @@ export const resource: {
|
|
|
2525
3619
|
E,
|
|
2526
3620
|
R
|
|
2527
3621
|
>
|
|
2528
|
-
}) => Layer.Layer<
|
|
2529
|
-
never,
|
|
2530
|
-
never,
|
|
2531
|
-
Exclude<
|
|
2532
|
-
| Schemas[number]["DecodingServices"]
|
|
2533
|
-
| Schemas[number]["EncodingServices"]
|
|
2534
|
-
| R
|
|
2535
|
-
| CompletionServices<Completions>,
|
|
2536
|
-
McpRequestContext
|
|
2537
|
-
>
|
|
2538
|
-
>
|
|
3622
|
+
}) => Layer.Layer<never, never, ResourceTemplateRequirements<Schemas, R, Completions>>
|
|
2539
3623
|
} = function() {
|
|
2540
3624
|
if (arguments.length === 1) {
|
|
2541
|
-
return Layer.effectDiscard(registerResource(arguments[0]))
|
|
2542
|
-
Layer.provide(McpServer.layer)
|
|
2543
|
-
)
|
|
3625
|
+
return Layer.effectDiscard(registerResource(arguments[0]))
|
|
2544
3626
|
}
|
|
2545
3627
|
const register = registerResource(...(arguments as any as [any, any]))
|
|
2546
|
-
return (options: any) =>
|
|
2547
|
-
Layer.effectDiscard(register(options)).pipe(
|
|
2548
|
-
Layer.provide(McpServer.layer)
|
|
2549
|
-
)
|
|
3628
|
+
return (options: any) => Layer.effectDiscard(register(options))
|
|
2550
3629
|
} as any
|
|
2551
3630
|
|
|
3631
|
+
/**
|
|
3632
|
+
* A file of a skill: its text, its bytes, or either with an explicit MIME
|
|
3633
|
+
* type. Without one, the MIME type is inferred from the file extension.
|
|
3634
|
+
*
|
|
3635
|
+
* @stability unstable
|
|
3636
|
+
* @category models
|
|
3637
|
+
* @since 4.1.1
|
|
3638
|
+
*/
|
|
3639
|
+
export type SkillFile = string | Uint8Array | {
|
|
3640
|
+
readonly content: string | Uint8Array
|
|
3641
|
+
readonly mimeType?: string | undefined
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
/**
|
|
3645
|
+
* Options for {@link registerSkill} and {@link skill}.
|
|
3646
|
+
*
|
|
3647
|
+
* **Details**
|
|
3648
|
+
*
|
|
3649
|
+
* `uri` addresses the skill's `SKILL.md`, as
|
|
3650
|
+
* `skill://<skill-path>/SKILL.md`. Its last path segment is the skill's name,
|
|
3651
|
+
* which must equal the frontmatter's `name`. Other schemes work the same way.
|
|
3652
|
+
*
|
|
3653
|
+
* `files` maps paths relative to the skill root to the skill's files,
|
|
3654
|
+
* `SKILL.md` included. Files are served verbatim, and the skill's listed
|
|
3655
|
+
* frontmatter is parsed from `SKILL.md`. Quote frontmatter strings that a YAML
|
|
3656
|
+
* 1.1 parser reads as another type, such as `yes` or `1.0`.
|
|
3657
|
+
*
|
|
3658
|
+
* @stability unstable
|
|
3659
|
+
* @category models
|
|
3660
|
+
* @since 4.1.1
|
|
3661
|
+
*/
|
|
3662
|
+
export interface SkillOptions {
|
|
3663
|
+
readonly uri: string
|
|
3664
|
+
readonly files: { readonly "SKILL.md": SkillFile } & Readonly<Record<string, SkillFile>>
|
|
3665
|
+
readonly annotations?: Context.Context<never> | undefined
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
const skillFileEncoder = new TextEncoder()
|
|
3669
|
+
|
|
3670
|
+
// Bytes are copied so that later changes by the caller cannot alter what is
|
|
3671
|
+
// served under the listed digest. `Buffer#slice` shares memory, so copy with
|
|
3672
|
+
// the `Uint8Array` constructor.
|
|
3673
|
+
const toSkillSourceFile = (path: string, file: SkillFile): McpSkills.SourceFile => {
|
|
3674
|
+
const { content, mimeType } = typeof file === "string" || file instanceof Uint8Array ? { content: file } : file
|
|
3675
|
+
return {
|
|
3676
|
+
path,
|
|
3677
|
+
content: typeof content === "string" ? skillFileEncoder.encode(content) : new Uint8Array(content),
|
|
3678
|
+
mimeType
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3682
|
+
/**
|
|
3683
|
+
* Registers an Agent Skill under the MCP Skills extension (SEP-2640).
|
|
3684
|
+
*
|
|
3685
|
+
* **Details**
|
|
3686
|
+
*
|
|
3687
|
+
* Each file is registered as a resource, and the skill is listed by
|
|
3688
|
+
* `skills/list` and `skills/get` with a manifest of every file's SHA-256
|
|
3689
|
+
* digest and size, computed from the bytes served. Every directory of the
|
|
3690
|
+
* skill namespace is readable with `resources/directory/read`. The server
|
|
3691
|
+
* declares the extension once any skill is registered.
|
|
3692
|
+
*
|
|
3693
|
+
* Fails when the skill breaks the extension's rules: a name that does not
|
|
3694
|
+
* match the URI, a `SKILL.md` without YAML frontmatter, frontmatter that is
|
|
3695
|
+
* not valid {@link McpSchema.SkillFrontmatter}, a file path that leaves the
|
|
3696
|
+
* skill, or more than 512 files or 16 MiB in all. It also fails when the
|
|
3697
|
+
* skill's directory contains or lies inside another skill's, or one of its
|
|
3698
|
+
* files is already registered as a resource. Registering a resource at the
|
|
3699
|
+
* URI of a skill's file afterwards is a defect.
|
|
3700
|
+
*
|
|
3701
|
+
* SHA-256 runs on `crypto.subtle`.
|
|
3702
|
+
*
|
|
3703
|
+
* @see {@link skill} for the layer-based skill registration wrapper
|
|
3704
|
+
*
|
|
3705
|
+
* @stability unstable
|
|
3706
|
+
* @category handlers
|
|
3707
|
+
* @since 4.1.1
|
|
3708
|
+
*/
|
|
3709
|
+
export const registerSkill: (options: SkillOptions) => Effect.Effect<void, Cause.IllegalArgumentError, McpServer> =
|
|
3710
|
+
Effect.fnUntraced(function*(options: SkillOptions) {
|
|
3711
|
+
const files = Object.entries(options.files).map(([path, file]) => toSkillSourceFile(path, file))
|
|
3712
|
+
const skill = yield* McpSkills.makeStaticSkill({ uri: options.uri, files }).pipe(
|
|
3713
|
+
Effect.provide(Digest.layerWebCrypto)
|
|
3714
|
+
)
|
|
3715
|
+
|
|
3716
|
+
const registry = yield* McpServer
|
|
3717
|
+
const { addSkillFile, core, globalMiddleware } = internalState.get(registry)!
|
|
3718
|
+
const services = yield* Effect.context<never>()
|
|
3719
|
+
const annotations = options.annotations ?? Context.empty()
|
|
3720
|
+
const { invoke, visible } = makeInvoke(services, globalMiddleware)
|
|
3721
|
+
// Claims the skill's file URIs before they are registered as resources.
|
|
3722
|
+
yield* core.skills.register({
|
|
3723
|
+
entry: skill.entry,
|
|
3724
|
+
isVisible: isEnabled(annotations),
|
|
3725
|
+
visible: visible("skills/list", options.uri),
|
|
3726
|
+
visibleInDirectories: visible("resources/directory/read", options.uri),
|
|
3727
|
+
get: (invocation) =>
|
|
3728
|
+
invoke(Effect.succeed(skill.entry), invocation, {
|
|
3729
|
+
method: "skills/get",
|
|
3730
|
+
target: options.uri,
|
|
3731
|
+
payload: { uri: options.uri }
|
|
3732
|
+
}),
|
|
3733
|
+
directory: (uri) => skill.directories.get(uri)
|
|
3734
|
+
})
|
|
3735
|
+
for (const { content, resource, text } of skill.files) {
|
|
3736
|
+
const { uri, mimeType } = resource
|
|
3737
|
+
yield* addSkillFile({
|
|
3738
|
+
resource: new Resource(resource),
|
|
3739
|
+
annotations,
|
|
3740
|
+
services,
|
|
3741
|
+
handle: Effect.succeed({
|
|
3742
|
+
contents: [text === undefined ? { uri, mimeType, blob: content } : { uri, mimeType, text }]
|
|
3743
|
+
})
|
|
3744
|
+
})
|
|
3745
|
+
}
|
|
3746
|
+
})
|
|
3747
|
+
|
|
3748
|
+
/**
|
|
3749
|
+
* Creates a layer that registers an Agent Skill under the MCP Skills extension
|
|
3750
|
+
* (SEP-2640).
|
|
3751
|
+
*
|
|
3752
|
+
* **Example** (Publishing a skill with a supporting file)
|
|
3753
|
+
*
|
|
3754
|
+
* ```ts
|
|
3755
|
+
* import { Layer } from "effect"
|
|
3756
|
+
* import { McpProtocol, McpServer } from "effect/ai"
|
|
3757
|
+
*
|
|
3758
|
+
* const RefundsSkill = McpServer.skill({
|
|
3759
|
+
* uri: "skill://billing/refunds/SKILL.md",
|
|
3760
|
+
* files: {
|
|
3761
|
+
* "SKILL.md": `---
|
|
3762
|
+
* name: refunds
|
|
3763
|
+
* description: Process refunds using the billing tools
|
|
3764
|
+
* ---
|
|
3765
|
+
*
|
|
3766
|
+
* Read references/policy.md before issuing a refund.
|
|
3767
|
+
* `,
|
|
3768
|
+
* "references/policy.md": "Refunds above CHF 500 require manager approval.\n"
|
|
3769
|
+
* }
|
|
3770
|
+
* })
|
|
3771
|
+
*
|
|
3772
|
+
* const ServerLayer = RefundsSkill.pipe(
|
|
3773
|
+
* Layer.provide(McpServer.layerHttp({
|
|
3774
|
+
* name: "billing",
|
|
3775
|
+
* version: "1.0.0",
|
|
3776
|
+
* path: "/mcp",
|
|
3777
|
+
* protocols: [McpProtocol.v2026_07_28, McpProtocol.v2025_11_25]
|
|
3778
|
+
* }))
|
|
3779
|
+
* )
|
|
3780
|
+
* ```
|
|
3781
|
+
*
|
|
3782
|
+
* @see {@link registerSkill} for the Effect-level skill registration API
|
|
3783
|
+
*
|
|
3784
|
+
* @stability unstable
|
|
3785
|
+
* @category layers
|
|
3786
|
+
* @since 4.1.1
|
|
3787
|
+
*/
|
|
3788
|
+
export const skill = (options: SkillOptions): Layer.Layer<never, Cause.IllegalArgumentError, McpServer> =>
|
|
3789
|
+
Layer.effectDiscard(registerSkill(options))
|
|
3790
|
+
|
|
2552
3791
|
/**
|
|
2553
3792
|
* Registers an MCP prompt from an Effect program.
|
|
2554
3793
|
*
|
|
@@ -2585,18 +3824,7 @@ export const registerPrompt = <
|
|
|
2585
3824
|
) => Effect.Effect<Array<PromptMessage> | string, E, R>
|
|
2586
3825
|
readonly annotations?: Context.Context<never> | undefined
|
|
2587
3826
|
}
|
|
2588
|
-
): Effect.Effect<
|
|
2589
|
-
void,
|
|
2590
|
-
never,
|
|
2591
|
-
| Exclude<
|
|
2592
|
-
| Schema.Struct.DecodingServices<Params>
|
|
2593
|
-
| Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
|
|
2594
|
-
| R
|
|
2595
|
-
| CompletionServices<Completions>,
|
|
2596
|
-
McpRequestContext
|
|
2597
|
-
>
|
|
2598
|
-
| McpServer
|
|
2599
|
-
> => {
|
|
3827
|
+
): Effect.Effect<void, never, PromptRequirements<Params, R, Completions>> => {
|
|
2600
3828
|
const args = Arr.empty<PromptArgument>()
|
|
2601
3829
|
const props: Record<string, Schema.Constraint> = options.parameters ?? {}
|
|
2602
3830
|
for (const [name, prop] of Object.entries(props)) {
|
|
@@ -2624,17 +3852,7 @@ export const registerPrompt = <
|
|
|
2624
3852
|
> = options.completion ?? {}
|
|
2625
3853
|
return Effect.gen(function*() {
|
|
2626
3854
|
const registry = yield* McpServer
|
|
2627
|
-
const services =
|
|
2628
|
-
yield* Effect.context<
|
|
2629
|
-
Exclude<
|
|
2630
|
-
| R
|
|
2631
|
-
| Schema.Struct.DecodingServices<Params>
|
|
2632
|
-
| Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
|
|
2633
|
-
| CompletionServices<Completions>,
|
|
2634
|
-
McpRequestContext
|
|
2635
|
-
>
|
|
2636
|
-
>()
|
|
2637
|
-
)
|
|
3855
|
+
const services = yield* Effect.context<never>()
|
|
2638
3856
|
const completions: Record<
|
|
2639
3857
|
string,
|
|
2640
3858
|
(
|
|
@@ -2643,41 +3861,19 @@ export const registerPrompt = <
|
|
|
2643
3861
|
) => Effect.Effect<CompleteResult, InternalError, McpRequestContext>
|
|
2644
3862
|
> = Object.create(null)
|
|
2645
3863
|
for (const [param, handle] of Object.entries(completion)) {
|
|
2646
|
-
|
|
2647
|
-
const handler = (
|
|
2648
|
-
input: string,
|
|
2649
|
-
context: CompletionContext
|
|
2650
|
-
) =>
|
|
2651
|
-
handle(input, context).pipe(
|
|
2652
|
-
Effect.flatMap(encodeArray),
|
|
2653
|
-
Effect.map((values) => ({
|
|
2654
|
-
completion: {
|
|
2655
|
-
values: values as Array<string>,
|
|
2656
|
-
total: values.length,
|
|
2657
|
-
hasMore: false
|
|
2658
|
-
}
|
|
2659
|
-
})),
|
|
2660
|
-
Effect.catchCause((cause) => {
|
|
2661
|
-
const prettyError = Cause.prettyErrors(cause)[0]
|
|
2662
|
-
return Effect.fail(new InternalError({ message: prettyError.message }))
|
|
2663
|
-
}),
|
|
2664
|
-
Effect.provide(services)
|
|
2665
|
-
)
|
|
2666
|
-
completions[param] = handler as any
|
|
3864
|
+
completions[param] = completionHandler(handle, Schema.encodeUnknownEffect(Schema.Array(props[param])))
|
|
2667
3865
|
}
|
|
2668
3866
|
yield* registry.addPrompt({
|
|
2669
3867
|
prompt,
|
|
2670
3868
|
completions,
|
|
3869
|
+
services,
|
|
2671
3870
|
annotations: options.annotations ?? Context.empty(),
|
|
2672
3871
|
handle: (params) =>
|
|
2673
3872
|
decode(params).pipe(
|
|
2674
3873
|
Effect.mapError((error) => new InvalidParams({ message: error.message })),
|
|
2675
3874
|
Effect.flatMap((params) =>
|
|
2676
3875
|
options.content(params as any).pipe(
|
|
2677
|
-
Effect.catchCause(
|
|
2678
|
-
const prettyError = Cause.prettyErrors(cause)[0]
|
|
2679
|
-
return Effect.fail(new InternalError({ message: prettyError.message }))
|
|
2680
|
-
})
|
|
3876
|
+
Effect.catchCause(handlerFailureToInternalError)
|
|
2681
3877
|
)
|
|
2682
3878
|
),
|
|
2683
3879
|
Effect.map((messages) => {
|
|
@@ -2688,9 +3884,8 @@ export const registerPrompt = <
|
|
|
2688
3884
|
}] :
|
|
2689
3885
|
messages
|
|
2690
3886
|
return new GetPromptResult({ messages, description: prompt.description })
|
|
2691
|
-
})
|
|
2692
|
-
|
|
2693
|
-
)
|
|
3887
|
+
})
|
|
3888
|
+
) as Effect.Effect<GetPromptResult, InvalidParams | InternalError>
|
|
2694
3889
|
})
|
|
2695
3890
|
})
|
|
2696
3891
|
}
|
|
@@ -2698,7 +3893,15 @@ export const registerPrompt = <
|
|
|
2698
3893
|
/**
|
|
2699
3894
|
* Creates a layer that registers an MCP prompt.
|
|
2700
3895
|
*
|
|
3896
|
+
* **Details**
|
|
3897
|
+
*
|
|
3898
|
+
* Services read by the content and completion handlers are request-level, so
|
|
3899
|
+
* providing them with `Layer.provide` doesn't satisfy them. Read
|
|
3900
|
+
* construction-time services in an enclosing `Layer.unwrap` and close over
|
|
3901
|
+
* them, and provide per-request services with MCP middleware.
|
|
3902
|
+
*
|
|
2701
3903
|
* @see {@link registerPrompt} for the Effect-level prompt registration API
|
|
3904
|
+
* @see {@link middleware} for providing request-level dependencies
|
|
2702
3905
|
*
|
|
2703
3906
|
* @stability unstable
|
|
2704
3907
|
* @category layers
|
|
@@ -2726,20 +3929,7 @@ export const prompt = <
|
|
|
2726
3929
|
) => Effect.Effect<Array<PromptMessage> | string, E, R>
|
|
2727
3930
|
readonly annotations?: Context.Context<never> | undefined
|
|
2728
3931
|
}
|
|
2729
|
-
): Layer.Layer<
|
|
2730
|
-
never,
|
|
2731
|
-
never,
|
|
2732
|
-
Exclude<
|
|
2733
|
-
| Schema.Struct.DecodingServices<Params>
|
|
2734
|
-
| Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
|
|
2735
|
-
| R
|
|
2736
|
-
| CompletionServices<Completions>,
|
|
2737
|
-
McpRequestContext
|
|
2738
|
-
>
|
|
2739
|
-
> =>
|
|
2740
|
-
Layer.effectDiscard(registerPrompt(options)).pipe(
|
|
2741
|
-
Layer.provide(McpServer.layer)
|
|
2742
|
-
)
|
|
3932
|
+
): Layer.Layer<never, never, PromptRequirements<Params, R, Completions>> => Layer.effectDiscard(registerPrompt(options))
|
|
2743
3933
|
|
|
2744
3934
|
/**
|
|
2745
3935
|
* Collects structured input from the current MCP client and decodes the
|
|
@@ -2799,6 +3989,22 @@ export const clientCapabilities: Effect.Effect<
|
|
|
2799
3989
|
McpRequestContext
|
|
2800
3990
|
> = McpRequestContext.useSync((_) => _.clientCapabilities)
|
|
2801
3991
|
|
|
3992
|
+
/**
|
|
3993
|
+
* Decodes an `Mcp-Name` header, including base64-wrapped values.
|
|
3994
|
+
* Returns `undefined` for malformed values.
|
|
3995
|
+
*
|
|
3996
|
+
* **Details**
|
|
3997
|
+
*
|
|
3998
|
+
* Use in `HttpRouter.middleware` to identify the tool, prompt or resource
|
|
3999
|
+
* targeted by a `2026-07-28` request. Earlier protocols carry the name only
|
|
4000
|
+
* in the JSON-RPC body.
|
|
4001
|
+
*
|
|
4002
|
+
* @stability unstable
|
|
4003
|
+
* @category decoding
|
|
4004
|
+
* @since 4.0.0
|
|
4005
|
+
*/
|
|
4006
|
+
export const decodeNameHeader = (value: string): string | undefined => McpProtocolInternal.decodeRoutingHeader(value)
|
|
4007
|
+
|
|
2802
4008
|
// -----------------------------------------------------------------------------
|
|
2803
4009
|
// Internal
|
|
2804
4010
|
// -----------------------------------------------------------------------------
|