@adtl/gateway 0.3.0 → 0.3.2
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 +59 -1
- package/dist/audit.d.ts +4 -2
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/cli.js +80 -15
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +49 -44
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -3
- package/dist/config.js.map +1 -1
- package/dist/gateway.d.ts +1 -1
- package/dist/gateway.js +1 -1
- package/dist/hooks/claudeCode.d.ts +43 -0
- package/dist/hooks/claudeCode.d.ts.map +1 -0
- package/dist/hooks/claudeCode.js +148 -0
- package/dist/hooks/claudeCode.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/preset.d.ts +16 -0
- package/dist/hooks/preset.d.ts.map +1 -0
- package/dist/hooks/preset.js +32 -0
- package/dist/hooks/preset.js.map +1 -0
- package/dist/hooks/run.d.ts +9 -0
- package/dist/hooks/run.d.ts.map +1 -0
- package/dist/hooks/run.js +44 -0
- package/dist/hooks/run.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init/fromMcpJson.d.ts +41 -0
- package/dist/init/fromMcpJson.d.ts.map +1 -0
- package/dist/init/fromMcpJson.js +141 -0
- package/dist/init/fromMcpJson.js.map +1 -0
- package/dist/init/index.d.ts +2 -0
- package/dist/init/index.d.ts.map +1 -1
- package/dist/init/index.js +2 -0
- package/dist/init/index.js.map +1 -1
- package/dist/init/run.d.ts +13 -0
- package/dist/init/run.d.ts.map +1 -1
- package/dist/init/run.js +83 -11
- package/dist/init/run.js.map +1 -1
- package/dist/startup.d.ts +12 -1
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +27 -3
- package/dist/startup.js.map +1 -1
- package/package.json +4 -4
- package/src/audit.ts +4 -2
- package/src/cli.ts +70 -15
- package/src/config.ts +9 -3
- package/src/gateway.ts +1 -1
- package/src/hooks/claudeCode.ts +194 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/preset.ts +47 -0
- package/src/hooks/run.ts +49 -0
- package/src/index.ts +1 -0
- package/src/init/fromMcpJson.ts +165 -0
- package/src/init/index.ts +2 -0
- package/src/init/run.ts +91 -12
- package/src/startup.ts +28 -4
package/src/startup.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
9
9
|
import { StdioClientTransport, getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10
10
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
11
11
|
import { INTERCEPTORS_EXTENSION, LABEL_INTERCEPTOR, POLICY_INTERCEPTOR, parseConfigText } from "@adtl/interceptors";
|
|
12
|
-
import type
|
|
12
|
+
import { defaultSessionsDir, type AdtlConfig } from "@adtl/labels";
|
|
13
13
|
import { parse as parseYaml } from "yaml";
|
|
14
14
|
import { ZodError } from "zod";
|
|
15
15
|
import { ApprovalBroker, type Notifier } from "./approvals.js";
|
|
@@ -49,6 +49,12 @@ export async function loadGatewayConfig(path: string): Promise<LoadedConfig> {
|
|
|
49
49
|
} catch (err) {
|
|
50
50
|
throw new GatewayConfigError(`Cannot read config file ${abs}: ${(err as Error).message}`);
|
|
51
51
|
}
|
|
52
|
+
return parseGatewayConfigText(text, abs);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Validate adtl.yaml text; `path` is where it lives (relative paths in it resolve against its directory). */
|
|
56
|
+
export function parseGatewayConfigText(text: string, path: string): LoadedConfig {
|
|
57
|
+
const abs = resolve(path);
|
|
52
58
|
let labels: AdtlConfig;
|
|
53
59
|
try {
|
|
54
60
|
labels = parseConfigText(text, abs);
|
|
@@ -117,6 +123,16 @@ export function createApprovals(cfg: GatewayConfig, env: NodeJS.ProcessEnv, log:
|
|
|
117
123
|
return new ApprovalBroker({ notifiers, timeoutMs: a.timeoutSeconds * 1000, log });
|
|
118
124
|
}
|
|
119
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Under Claude Code, which passes `CLAUDE_CODE_SESSION_ID` to stdio MCP
|
|
128
|
+
* servers, the gateway uses that id and keeps session labels in files, so the
|
|
129
|
+
* Claude Code hooks (`adtl-gateway hook`) add to the same session label.
|
|
130
|
+
*/
|
|
131
|
+
export function sharedSession(env: NodeJS.ProcessEnv): { sessionId: string; dir: string } | undefined {
|
|
132
|
+
const sessionId = env.CLAUDE_CODE_SESSION_ID?.trim();
|
|
133
|
+
return sessionId ? { sessionId, dir: defaultSessionsDir(env) } : undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
120
136
|
export interface StartedGateway {
|
|
121
137
|
gateway: AdtlGateway;
|
|
122
138
|
close(): Promise<void>;
|
|
@@ -134,9 +150,15 @@ export async function startGateway(
|
|
|
134
150
|
|
|
135
151
|
try {
|
|
136
152
|
// 1. Interceptor server (out of process, per the Interceptors WG).
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
153
|
+
const shared = sharedSession(env);
|
|
154
|
+
const custom = loaded.gateway.interceptors && expandUpstream("interceptors", loaded.gateway.interceptors, env);
|
|
155
|
+
const icfg: StdioUpstream = custom
|
|
156
|
+
? { ...custom, env: { ...custom.env, ...(shared ? { ADTL_SESSIONS_DIR: shared.dir } : {}) } }
|
|
157
|
+
: {
|
|
158
|
+
command: process.execPath,
|
|
159
|
+
args: [bundledInterceptorsCli(), "--config", loaded.path, ...(shared ? ["--sessions-dir", shared.dir] : [])],
|
|
160
|
+
env: {},
|
|
161
|
+
};
|
|
140
162
|
const interceptors = await connectUpstream("interceptors", icfg, baseDir);
|
|
141
163
|
clients.push(interceptors);
|
|
142
164
|
if (!interceptors.getServerCapabilities()?.extensions?.[INTERCEPTORS_EXTENSION]) {
|
|
@@ -152,6 +174,7 @@ export async function startGateway(
|
|
|
152
174
|
const audit = loaded.gateway.mode === "audit";
|
|
153
175
|
const invoker = new InterceptorInvoker(bound, loaded.gateway.interceptorTimeoutMs, audit ? "audit" : undefined);
|
|
154
176
|
log.info(`interceptors: ${names.join(", ")}`);
|
|
177
|
+
if (shared) log.info(`sharing session labels with Claude Code hooks (${shared.dir})`);
|
|
155
178
|
if (audit) log.warn("audit mode: calls are logged but never stopped or changed");
|
|
156
179
|
|
|
157
180
|
// 2. Upstream servers. One failing upstream does not stop the others.
|
|
@@ -178,6 +201,7 @@ export async function startGateway(
|
|
|
178
201
|
const auditLog = loaded.gateway.audit ? new JsonlAuditLog(resolve(baseDir, loaded.gateway.audit)) : undefined;
|
|
179
202
|
const approvals = createApprovals(loaded.gateway, env, log);
|
|
180
203
|
const gateway = new AdtlGateway({
|
|
204
|
+
...(shared ? { sessionId: shared.sessionId } : {}),
|
|
181
205
|
upstreams,
|
|
182
206
|
invoker,
|
|
183
207
|
...(auditLog ? { audit: auditLog } : {}),
|