1import type { EnvironmentId, ProviderInstanceId, ThreadId } from "@t3tools/contracts";
2import type * as Effect from "effect/Effect";
3
4/**
5 * Sent by MCP clients that cannot defer tools themselves. The T3 MCP server then
6 * lists only a core set plus `tool_search`, which lists the rest on demand.
7 */
8export const MCP_TOOL_EXPOSURE_HEADER = "t3-tool-exposure";
9
10export interface McpProviderSessionConfig {
11 readonly environmentId: EnvironmentId;
12 readonly threadId: ThreadId;
13 readonly providerSessionId: string;
14 readonly providerInstanceId: ProviderInstanceId;
15 readonly endpoint: string;
16 readonly authorizationHeader: string;
17 /** Omit preview_* instructions when the user withholds agent browser access. */
18 readonly browserToolsAvailable: boolean;
19 readonly capabilities?: ReadonlySet<string>;
20 readonly agentDeviceEnvironment?: Readonly<Record<string, string>>;
21 /** True while a delegated task this thread started will wake it with its result. */
22 readonly hasPendingWake?: Effect.Effect<boolean>;
23}
24
25export function withAgentDeviceEnvironment(
26 base: NodeJS.ProcessEnv,
27 config: Pick<McpProviderSessionConfig, "agentDeviceEnvironment"> | undefined,
28): NodeJS.ProcessEnv {
29 const extra = config?.agentDeviceEnvironment;
30 if (!extra) return base;
31 const separator = extra.PATH_SEPARATOR ?? ":";
32 const basePath = base.PATH ?? base.Path;
33 const { PATH: shimDir, PATH_SEPARATOR: _separator, ...rest } = extra;
34 return {
35 ...base,
36 ...rest,
37 ...(shimDir ? { PATH: basePath ? `${shimDir}${separator}${basePath}` : shimDir } : {}),
38 };
39}