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 */
8import type { ThreadId } from "@t3tools/contracts";
9import * as Context from "effect/Context";
10import * as Effect from "effect/Effect";
11import * as Layer from "effect/Layer";
12import * as Ref from "effect/Ref";
13
14import type { McpProviderSessionConfig } from "./mcpSession.ts";
15
16export 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
25const 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
40export const layer = Layer.effect(McpProviderSessions, make);