| 1 | /** |
| 2 | * The T3 MCP credential each thread's provider session should expose to its |
| 3 | * agent. The session manager writes it before a session starts; adapters read |
| 4 | * it when they build provider launch options. |
| 5 | * |
| 6 | * @module provider-core/server/McpProviderSessions |
| 7 | */ |
| 8 | import type { ThreadId } from "@t3tools/contracts"; |
| 9 | import * as Context from "effect/Context"; |
| 10 | import * as Effect from "effect/Effect"; |
| 11 | import * as Layer from "effect/Layer"; |
| 12 | import * as Ref from "effect/Ref"; |
| 13 | |
| 14 | import type { McpProviderSessionConfig } from "./mcpSession.ts"; |
| 15 | |
| 16 | export class McpProviderSessions extends Context.Service< |
| 17 | McpProviderSessions, |
| 18 | { |
| 19 | readonly set: (config: McpProviderSessionConfig) => Effect.Effect<void>; |
| 20 | readonly read: (threadId: ThreadId) => Effect.Effect<McpProviderSessionConfig | undefined>; |
| 21 | readonly clear: (threadId: ThreadId) => Effect.Effect<void>; |
| 22 | } |
| 23 | >()("@t3tools/provider-core/server/McpProviderSessions") {} |
| 24 | |
| 25 | const make = Effect.gen(function* () { |
| 26 | const sessions = yield* Ref.make(new Map<ThreadId, McpProviderSessionConfig>()); |
| 27 | return McpProviderSessions.of({ |
| 28 | set: (config) => |
| 29 | Ref.update(sessions, (current) => new Map(current).set(config.threadId, config)), |
| 30 | read: (threadId) => Ref.get(sessions).pipe(Effect.map((current) => current.get(threadId))), |
| 31 | clear: (threadId) => |
| 32 | Ref.update(sessions, (current) => { |
| 33 | const next = new Map(current); |
| 34 | next.delete(threadId); |
| 35 | return next; |
| 36 | }), |
| 37 | }); |
| 38 | }); |
| 39 | |
| 40 | export const layer = Layer.effect(McpProviderSessions, make); |