@agent-vm/mcp-portal 0.0.69 → 0.0.70
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 +42 -11
- package/dist/agent-bearer-token-DCtpDPCZ.js +59 -0
- package/dist/agent-bearer-token-DCtpDPCZ.js.map +1 -0
- package/dist/bin/mcp-portal.d.ts +28 -0
- package/dist/bin/mcp-portal.d.ts.map +1 -0
- package/dist/bin/mcp-portal.js +318 -0
- package/dist/bin/mcp-portal.js.map +1 -0
- package/dist/{catalog-types--gUGFPpN.d.ts → catalog-types-BVuB4Ynx.d.ts} +1 -1
- package/dist/{catalog-types--gUGFPpN.d.ts.map → catalog-types-BVuB4Ynx.d.ts.map} +1 -1
- package/dist/cli/index.d.ts +101 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/core/index.d.ts +40 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +5 -0
- package/dist/hmac-env-B4shpRRB.js +20 -0
- package/dist/hmac-env-B4shpRRB.js.map +1 -0
- package/dist/hmac-token-DBqWY3-w.js +100 -0
- package/dist/hmac-token-DBqWY3-w.js.map +1 -0
- package/dist/index.d.ts +5 -485
- package/dist/index.js +4 -5
- package/dist/mcp-proxy/index.d.ts +24 -0
- package/dist/mcp-proxy/index.d.ts.map +1 -0
- package/dist/mcp-proxy/index.js +2 -0
- package/dist/portal-auth/agent-bearer-token.d.ts +22 -0
- package/dist/portal-auth/agent-bearer-token.d.ts.map +1 -0
- package/dist/portal-auth/agent-bearer-token.js +2 -0
- package/dist/portal-auth/hmac-env.d.ts +6 -0
- package/dist/portal-auth/hmac-env.d.ts.map +1 -0
- package/dist/portal-auth/hmac-env.js +2 -0
- package/dist/portal-auth/hmac-token.d.ts +40 -0
- package/dist/portal-auth/hmac-token.d.ts.map +1 -0
- package/dist/portal-auth/hmac-token.js +2 -0
- package/dist/portal-config/index.d.ts +11 -0
- package/dist/portal-config/index.d.ts.map +1 -0
- package/dist/{tool-vm → portal-config}/index.js +2 -3
- package/dist/portal-core-CZQI7Ob6.d.ts +264 -0
- package/dist/portal-core-CZQI7Ob6.d.ts.map +1 -0
- package/dist/portal-core-Cgu714CL.js +416 -0
- package/dist/portal-core-Cgu714CL.js.map +1 -0
- package/dist/portal-session-DG2CUjIo.d.ts +184 -0
- package/dist/portal-session-DG2CUjIo.d.ts.map +1 -0
- package/dist/portal-tools-DKci1szO.js +528 -0
- package/dist/portal-tools-DKci1szO.js.map +1 -0
- package/dist/resolve-agent-identity-DnC_Pmnh.js +550 -0
- package/dist/resolve-agent-identity-DnC_Pmnh.js.map +1 -0
- package/dist/resolve-agent-identity-FQL02YdW.d.ts +81 -0
- package/dist/resolve-agent-identity-FQL02YdW.d.ts.map +1 -0
- package/dist/serve-command-CnSMUybd.js +358 -0
- package/dist/serve-command-CnSMUybd.js.map +1 -0
- package/dist/testing/fake-upstream-mcp-server.d.ts +5 -2
- package/dist/testing/fake-upstream-mcp-server.d.ts.map +1 -1
- package/dist/testing/fake-upstream-mcp-server.js +14 -4
- package/dist/testing/fake-upstream-mcp-server.js.map +1 -1
- package/dist/typescript-artifact-BVLt3Ifd.js +60 -0
- package/dist/typescript-artifact-BVLt3Ifd.js.map +1 -0
- package/dist/upstream-mcp-client-runtime-JlsfTm7_.js +760 -0
- package/dist/upstream-mcp-client-runtime-JlsfTm7_.js.map +1 -0
- package/dist/upstream-response-middleware-1MZnAD9C.d.ts +115 -0
- package/dist/upstream-response-middleware-1MZnAD9C.d.ts.map +1 -0
- package/dist/upstream-response-middleware-BjUWZ2G8.js +172 -0
- package/dist/upstream-response-middleware-BjUWZ2G8.js.map +1 -0
- package/dist/{index-BcI9c8sg.d.ts → zod-schema-loader-DLGQpYFD.d.ts} +3 -9
- package/dist/zod-schema-loader-DLGQpYFD.d.ts.map +1 -0
- package/dist/{typescript-artifact-BqU8okQy.js → zod-schema-loader-yNekKNpm.js} +85 -55
- package/dist/zod-schema-loader-yNekKNpm.js.map +1 -0
- package/package.json +30 -13
- package/dist/bin/agent-vm-mcp-portal.d.ts +0 -10
- package/dist/bin/agent-vm-mcp-portal.d.ts.map +0 -1
- package/dist/bin/agent-vm-mcp-portal.js +0 -56
- package/dist/bin/agent-vm-mcp-portal.js.map +0 -1
- package/dist/bin/portal-server.d.ts +0 -55
- package/dist/bin/portal-server.d.ts.map +0 -1
- package/dist/bin/portal-server.js +0 -289
- package/dist/bin/portal-server.js.map +0 -1
- package/dist/index-BcI9c8sg.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/tool-vm/index.d.ts +0 -2
- package/dist/tool-vm-ihnzDyjJ.js +0 -3
- package/dist/typescript-artifact-BqU8okQy.js.map +0 -1
- package/dist/upstream-mcp-client-runtime-DiBCBsDj.js +0 -1729
- package/dist/upstream-mcp-client-runtime-DiBCBsDj.js.map +0 -1
- package/dist/zod-schema-loader-CDDtoRE1.js +0 -90
- package/dist/zod-schema-loader-CDDtoRE1.js.map +0 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { L as createPortalAgentIdentity, M as PortalAgentIdentity } from "./portal-session-DG2CUjIo.js";
|
|
2
|
+
import { a as PortalCore, y as PortalApprovalCall } from "./portal-core-CZQI7Ob6.js";
|
|
3
|
+
import { McpPortalAgentConfig, McpPortalConfig, ResolvedMcpPortalProfile, SecretValue } from "@agent-vm/config-contracts";
|
|
4
|
+
import { Hono } from "hono";
|
|
5
|
+
|
|
6
|
+
//#region src/mcp-proxy/portal-http-server.d.ts
|
|
7
|
+
interface PortalHttpAgentIdentity extends PortalAgentIdentity {}
|
|
8
|
+
interface PortalAgentBearerAuth {
|
|
9
|
+
readonly authorizationHeaderName: string;
|
|
10
|
+
readonly credentialVersionsByAgent?: Readonly<Record<string, number>>;
|
|
11
|
+
readonly masterKey: Buffer;
|
|
12
|
+
}
|
|
13
|
+
type PortalHttpAuditEvent = {
|
|
14
|
+
readonly agentId: string;
|
|
15
|
+
readonly clientAddress: string;
|
|
16
|
+
readonly decision: 'allow' | 'deny';
|
|
17
|
+
readonly kind: 'mcp_proxy_auth';
|
|
18
|
+
readonly reason?: 'malformed' | 'missing' | 'rate_limited' | 'signature-mismatch' | 'unknown_agent';
|
|
19
|
+
readonly timeMs: number;
|
|
20
|
+
};
|
|
21
|
+
interface PortalHttpAppOptions {
|
|
22
|
+
readonly agentBearerAuth: PortalAgentBearerAuth;
|
|
23
|
+
readonly auditErrorSink?: (error: Error, event: PortalHttpAuditEvent) => Promise<void> | void;
|
|
24
|
+
readonly auditSink?: (event: PortalHttpAuditEvent) => Promise<void> | void;
|
|
25
|
+
readonly authFailureLimit?: {
|
|
26
|
+
readonly maxFailures: number;
|
|
27
|
+
readonly windowMs: number;
|
|
28
|
+
};
|
|
29
|
+
readonly core: PortalCore;
|
|
30
|
+
readonly onSessionClosed?: (identity: PortalAgentIdentity) => Promise<void> | void;
|
|
31
|
+
readonly onSessionCloseError?: (error: Error, identity: PortalAgentIdentity) => Promise<void> | void;
|
|
32
|
+
readonly registeredAgentIds?: readonly string[];
|
|
33
|
+
readonly resolveAgentIdentity?: (agentId: string) => PortalHttpAgentIdentity | null;
|
|
34
|
+
}
|
|
35
|
+
type PortalHttpApp = Hono & {
|
|
36
|
+
readonly closePortalSessions: () => Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
declare function createPortalHttpApp(options: PortalHttpAppOptions): PortalHttpApp;
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/mcp-proxy/resolve-agent-identity.d.ts
|
|
41
|
+
interface ResolveAgentHmacKeysProps {
|
|
42
|
+
readonly agents: Readonly<Record<string, McpPortalAgentConfig>>;
|
|
43
|
+
readonly envKeys: ReadonlyMap<string, Buffer>;
|
|
44
|
+
readonly resolveSecret: (secret: SecretValue) => Promise<string>;
|
|
45
|
+
}
|
|
46
|
+
interface PortalAgentRuntimeRecord {
|
|
47
|
+
readonly agentId: string;
|
|
48
|
+
readonly hmacKey: Buffer;
|
|
49
|
+
readonly profile: ResolvedMcpPortalProfile;
|
|
50
|
+
readonly profileName: string;
|
|
51
|
+
}
|
|
52
|
+
interface PortalApprovalAuditEvent {
|
|
53
|
+
readonly agentId: string;
|
|
54
|
+
readonly decision: 'allow' | 'deny';
|
|
55
|
+
readonly kind: 'mcp_portal_approval';
|
|
56
|
+
readonly reason?: 'approval_token_invalid' | 'approval_token_missing' | 'no_approval_required';
|
|
57
|
+
readonly timeMs: number;
|
|
58
|
+
readonly verifierReason?: string;
|
|
59
|
+
}
|
|
60
|
+
declare function resolveAgentHmacKeys(props: ResolveAgentHmacKeysProps): Promise<ReadonlyMap<string, Buffer>>;
|
|
61
|
+
declare function createPortalAgentRuntimeRecords(props: {
|
|
62
|
+
readonly hmacKeys: ReadonlyMap<string, Buffer>;
|
|
63
|
+
readonly portalConfig: McpPortalConfig;
|
|
64
|
+
}): ReadonlyMap<string, PortalAgentRuntimeRecord>;
|
|
65
|
+
declare function createPortalHttpAgentResolver(records: ReadonlyMap<string, PortalAgentRuntimeRecord>): (agentId: string) => ReturnType<typeof createPortalAgentIdentity> | null;
|
|
66
|
+
declare function createPortalApprovalVerifier(props: {
|
|
67
|
+
readonly approvalTokenReplayCacheLimit?: number;
|
|
68
|
+
readonly auditErrorSink?: (error: Error, event: PortalApprovalAuditEvent) => void;
|
|
69
|
+
readonly auditSink?: (event: PortalApprovalAuditEvent) => void;
|
|
70
|
+
readonly records: ReadonlyMap<string, PortalAgentRuntimeRecord>;
|
|
71
|
+
}): (calls: readonly PortalApprovalCall[], agentId: string, token: string | undefined) => {
|
|
72
|
+
readonly kind: 'allow';
|
|
73
|
+
} | {
|
|
74
|
+
readonly kind: 'approval_token_invalid';
|
|
75
|
+
readonly reason: string;
|
|
76
|
+
} | {
|
|
77
|
+
readonly kind: 'approval_token_missing';
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { createPortalApprovalVerifier as a, PortalAgentBearerAuth as c, PortalHttpAppOptions as d, PortalHttpAuditEvent as f, createPortalAgentRuntimeRecords as i, PortalHttpAgentIdentity as l, PortalApprovalAuditEvent as n, createPortalHttpAgentResolver as o, createPortalHttpApp as p, ResolveAgentHmacKeysProps as r, resolveAgentHmacKeys as s, PortalAgentRuntimeRecord as t, PortalHttpApp as u };
|
|
81
|
+
//# sourceMappingURL=resolve-agent-identity-FQL02YdW.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-agent-identity-FQL02YdW.d.ts","names":[],"sources":["../src/mcp-proxy/portal-http-server.ts","../src/mcp-proxy/resolve-agent-identity.ts"],"mappings":";;;;;;UAWiB,uBAAA,SAAgC,mBAAA;AAAA,UAEhC,qBAAA;EAAA,SACP,uBAAA;EAAA,SACA,yBAAA,GAA4B,QAAA,CAAS,MAAA;EAAA,SACrC,SAAA,EAAW,MAAA;AAAA;AAAA,KAGT,oBAAA;EAAA,SACF,OAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,MAAA;EAAA,SAMA,MAAA;AAAA;AAAA,UAGO,oBAAA;EAAA,SACP,eAAA,EAAiB,qBAAA;EAAA,SACjB,cAAA,IAAkB,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,oBAAA,KAAyB,OAAA;EAAA,SAChE,SAAA,IAAa,KAAA,EAAO,oBAAA,KAAyB,OAAA;EAAA,SAC7C,gBAAA;IAAA,SACC,WAAA;IAAA,SACA,QAAA;EAAA;EAAA,SAED,IAAA,EAAM,UAAA;EAAA,SACN,eAAA,IAAmB,QAAA,EAAU,mBAAA,KAAwB,OAAA;EAAA,SACrD,mBAAA,IACR,KAAA,EAAO,KAAA,EACP,QAAA,EAAU,mBAAA,KACN,OAAA;EAAA,SACI,kBAAA;EAAA,SACA,oBAAA,IAAwB,OAAA,aAAoB,uBAAA;AAAA;AAAA,KAG1C,aAAA,GAAgB,IAAA;EAAA,SAClB,mBAAA,QAA2B,OAAA;AAAA;AAAA,iBAiDrB,mBAAA,CAAoB,OAAA,EAAS,oBAAA,GAAuB,aAAA;;;UCrFnD,yBAAA;EAAA,SACP,MAAA,EAAQ,QAAA,CAAS,MAAA,SAAe,oBAAA;EAAA,SAChC,OAAA,EAAS,WAAA,SAAoB,MAAA;EAAA,SAC7B,aAAA,GAAgB,MAAA,EAAQ,WAAA,KAAgB,OAAA;AAAA;AAAA,UAGjC,wBAAA;EAAA,SACP,OAAA;EAAA,SACA,OAAA,EAAS,MAAA;EAAA,SACT,OAAA,EAAS,wBAAA;EAAA,SACT,WAAA;AAAA;AAAA,UAGO,wBAAA;EAAA,SACP,OAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;EAAA,SACA,cAAA;AAAA;AAAA,iBAuBY,oBAAA,CACrB,KAAA,EAAO,yBAAA,GACL,OAAA,CAAQ,WAAA,SAAoB,MAAA;AAAA,iBAef,+BAAA,CAAgC,KAAA;EAAA,SACtC,QAAA,EAAU,WAAA,SAAoB,MAAA;EAAA,SAC9B,YAAA,EAAc,eAAA;AAAA,IACpB,WAAA,SAAoB,wBAAA;AAAA,iBAiBR,6BAAA,CACf,OAAA,EAAS,WAAA,SAAoB,wBAAA,KAC1B,OAAA,aAAoB,UAAA,QAAkB,yBAAA;AAAA,iBAsC1B,4BAAA,CAA6B,KAAA;EAAA,SACnC,6BAAA;EAAA,SACA,cAAA,IAAkB,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,wBAAA;EAAA,SACvC,SAAA,IAAa,KAAA,EAAO,wBAAA;EAAA,SACpB,OAAA,EAAS,WAAA,SAAoB,wBAAA;AAAA,KAEtC,KAAA,WAAgB,kBAAA,IAChB,OAAA,UACA,KAAA;EAAA,SAEa,IAAA;AAAA;EAAA,SACA,IAAA;EAAA,SAAyC,MAAA;AAAA;EAAA,SACzC,IAAA;AAAA"}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { t as createUpstreamMcpClientRuntime } from "./upstream-mcp-client-runtime-JlsfTm7_.js";
|
|
2
|
+
import { i as resolveUpstreamServers, n as createPortalCore } from "./portal-core-Cgu714CL.js";
|
|
3
|
+
import { t as decodePortalMasterKey } from "./agent-bearer-token-DCtpDPCZ.js";
|
|
4
|
+
import { a as createPortalHttpApp, n as createPortalApprovalVerifier, r as createPortalHttpAgentResolver, t as createPortalAgentRuntimeRecords } from "./resolve-agent-identity-DnC_Pmnh.js";
|
|
5
|
+
import { createHmac } from "node:crypto";
|
|
6
|
+
import { loadMcpConfig, loadMcpPortalConfig, resolveMcpPortalProfile } from "@agent-vm/config-contracts";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { parseArgs } from "node:util";
|
|
9
|
+
import { createCompositeSecretResolver, createSecretResolver, resolveServiceAccountToken } from "@agent-vm/secrets";
|
|
10
|
+
import { serve } from "@hono/node-server";
|
|
11
|
+
//#region src/bin/secret-value-resolver.ts
|
|
12
|
+
function secretRefFromSecretValue(secret) {
|
|
13
|
+
if (secret.source === "environment") return {
|
|
14
|
+
ref: secret.name,
|
|
15
|
+
source: "environment"
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
ref: secret.ref,
|
|
19
|
+
source: "1password"
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async function resolveSecretValue(secret, props) {
|
|
23
|
+
if (secret.source === "environment") {
|
|
24
|
+
const value = props.env[secret.name];
|
|
25
|
+
if (value === void 0 || value.length === 0) throw new Error(`Missing environment secret ${secret.name}.`);
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
if (props.secretResolver === void 0) throw new Error("Secret with source '1password' requires a configured secret resolver.");
|
|
29
|
+
return await props.secretResolver.resolve(secretRefFromSecretValue(secret));
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/cli/serve-command.ts
|
|
33
|
+
function requirePortalTokenSourceValue(env, name, sourceType) {
|
|
34
|
+
const value = env[name]?.trim();
|
|
35
|
+
if (value === void 0 || value.length === 0) throw new Error(`${name} is required when AGENT_VM_MCP_PORTAL_OP_TOKEN_SOURCE=${sourceType}.`);
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
function readPortalOnePasswordTokenSource(env) {
|
|
39
|
+
const sourceType = env.AGENT_VM_MCP_PORTAL_OP_TOKEN_SOURCE?.trim();
|
|
40
|
+
if (sourceType === void 0 || sourceType.length === 0) {
|
|
41
|
+
const configuredEnvVar = env.AGENT_VM_MCP_PORTAL_OP_TOKEN_ENV_VAR?.trim();
|
|
42
|
+
const envVar = configuredEnvVar === void 0 || configuredEnvVar.length === 0 ? "OP_SERVICE_ACCOUNT_TOKEN" : configuredEnvVar;
|
|
43
|
+
const token = env[envVar]?.trim();
|
|
44
|
+
return token === void 0 || token.length === 0 ? null : {
|
|
45
|
+
envVar,
|
|
46
|
+
type: "env"
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (sourceType === "env") return {
|
|
50
|
+
envVar: requirePortalTokenSourceValue(env, "AGENT_VM_MCP_PORTAL_OP_TOKEN_ENV_VAR", sourceType),
|
|
51
|
+
type: "env"
|
|
52
|
+
};
|
|
53
|
+
if (sourceType === "op-cli") return {
|
|
54
|
+
ref: requirePortalTokenSourceValue(env, "AGENT_VM_MCP_PORTAL_OP_TOKEN_REF", sourceType),
|
|
55
|
+
type: "op-cli"
|
|
56
|
+
};
|
|
57
|
+
if (sourceType === "keychain") return {
|
|
58
|
+
account: requirePortalTokenSourceValue(env, "AGENT_VM_MCP_PORTAL_OP_TOKEN_KEYCHAIN_ACCOUNT", sourceType),
|
|
59
|
+
service: requirePortalTokenSourceValue(env, "AGENT_VM_MCP_PORTAL_OP_TOKEN_KEYCHAIN_SERVICE", sourceType),
|
|
60
|
+
type: "keychain"
|
|
61
|
+
};
|
|
62
|
+
throw new Error(`Unsupported AGENT_VM_MCP_PORTAL_OP_TOKEN_SOURCE "${sourceType}".`);
|
|
63
|
+
}
|
|
64
|
+
async function resolvePortalServiceAccountToken(props) {
|
|
65
|
+
if (props.tokenSource.type !== "env") return await props.resolveToken(props.tokenSource);
|
|
66
|
+
const envVar = props.tokenSource.envVar ?? "OP_SERVICE_ACCOUNT_TOKEN";
|
|
67
|
+
const token = props.env[envVar]?.trim();
|
|
68
|
+
if (token === void 0 || token.length === 0) throw new Error(`Environment variable ${envVar} is not set`);
|
|
69
|
+
return token;
|
|
70
|
+
}
|
|
71
|
+
async function createServeSecretResolver(env, dependencies = {}) {
|
|
72
|
+
const tokenSource = readPortalOnePasswordTokenSource(env);
|
|
73
|
+
const resolveToken = dependencies.resolveServiceAccountToken ?? resolveServiceAccountToken;
|
|
74
|
+
const createResolver = dependencies.createOnePasswordSecretResolver ?? createSecretResolver;
|
|
75
|
+
return createCompositeSecretResolver(tokenSource === null ? null : await createResolver({ serviceAccountToken: await resolvePortalServiceAccountToken({
|
|
76
|
+
env,
|
|
77
|
+
resolveToken,
|
|
78
|
+
tokenSource
|
|
79
|
+
}) }), env);
|
|
80
|
+
}
|
|
81
|
+
function parsePort(value) {
|
|
82
|
+
if (value === void 0) return;
|
|
83
|
+
const port = Number(value);
|
|
84
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(`Invalid --port value "${value}".`);
|
|
85
|
+
return port;
|
|
86
|
+
}
|
|
87
|
+
function parsePortalServerCliArgs(argv) {
|
|
88
|
+
const parsed = parseArgs({
|
|
89
|
+
args: [...argv],
|
|
90
|
+
options: {
|
|
91
|
+
agent: {
|
|
92
|
+
multiple: true,
|
|
93
|
+
type: "string"
|
|
94
|
+
},
|
|
95
|
+
"config-dir": { type: "string" },
|
|
96
|
+
port: {
|
|
97
|
+
short: "p",
|
|
98
|
+
type: "string"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
strict: true
|
|
102
|
+
});
|
|
103
|
+
const configDir = parsed.values["config-dir"];
|
|
104
|
+
if (typeof configDir !== "string" || configDir.length === 0) throw new Error("--config-dir <path> is required.");
|
|
105
|
+
const rawAgentOverrides = parsed.values.agent;
|
|
106
|
+
const args = {
|
|
107
|
+
agentOverrides: Array.isArray(rawAgentOverrides) ? rawAgentOverrides : [],
|
|
108
|
+
configDir
|
|
109
|
+
};
|
|
110
|
+
const port = parsePort(parsed.values.port);
|
|
111
|
+
return port === void 0 ? args : {
|
|
112
|
+
...args,
|
|
113
|
+
port
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function applyAgentOverrides(agents, overrides) {
|
|
117
|
+
const nextAgents = { ...agents };
|
|
118
|
+
for (const override of overrides) {
|
|
119
|
+
const [agentId, profileName, extra] = override.split("=");
|
|
120
|
+
if (agentId === void 0 || profileName === void 0 || extra !== void 0 || agentId.length === 0 || profileName.length === 0) throw new Error(`Invalid --agent override "${override}". Expected <agentId>=<profile>.`);
|
|
121
|
+
const existingAgent = nextAgents[agentId];
|
|
122
|
+
if (existingAgent === void 0) throw new Error(`Cannot override unknown MCP Portal agent "${agentId}".`);
|
|
123
|
+
nextAgents[agentId] = {
|
|
124
|
+
...existingAgent,
|
|
125
|
+
profile: profileName
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return nextAgents;
|
|
129
|
+
}
|
|
130
|
+
function createDeferredPort() {
|
|
131
|
+
let rejectPort;
|
|
132
|
+
let resolvePort;
|
|
133
|
+
return {
|
|
134
|
+
promise: new Promise((resolve, reject) => {
|
|
135
|
+
rejectPort = reject;
|
|
136
|
+
resolvePort = resolve;
|
|
137
|
+
}),
|
|
138
|
+
reject: (error) => {
|
|
139
|
+
if (rejectPort === void 0) throw new Error("MCP Portal port rejector was not initialized.");
|
|
140
|
+
rejectPort(error);
|
|
141
|
+
},
|
|
142
|
+
resolve: (port) => {
|
|
143
|
+
if (resolvePort === void 0) throw new Error("MCP Portal port resolver was not initialized.");
|
|
144
|
+
resolvePort(port);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function defaultPortalServerLogger() {
|
|
149
|
+
return { log: (event) => {
|
|
150
|
+
process.stderr.write(`${JSON.stringify(event)}\n`);
|
|
151
|
+
} };
|
|
152
|
+
}
|
|
153
|
+
function handlePortalServerError(props) {
|
|
154
|
+
props.logger.log({
|
|
155
|
+
event: "server_error",
|
|
156
|
+
level: "error",
|
|
157
|
+
message: props.error.message,
|
|
158
|
+
...props.error.stack === void 0 ? {} : { stack: props.error.stack }
|
|
159
|
+
});
|
|
160
|
+
if (!props.hasListened) props.listeningPort.reject(props.error);
|
|
161
|
+
}
|
|
162
|
+
function closeNodeServer(server) {
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
server.close((error) => {
|
|
165
|
+
if (error) reject(error);
|
|
166
|
+
else resolve();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function selectorsFromNamespaceTools(namespaceTools) {
|
|
171
|
+
return Object.entries(namespaceTools).flatMap(([namespace, toolNames]) => toolNames.map((toolName) => ({
|
|
172
|
+
namespace,
|
|
173
|
+
toolName
|
|
174
|
+
})));
|
|
175
|
+
}
|
|
176
|
+
function buildProfilePolicyMaps(portalConfig) {
|
|
177
|
+
const enabledNamespacesByAgent = {};
|
|
178
|
+
const enabledToolsByAgent = {};
|
|
179
|
+
const hiddenToolsByAgent = {};
|
|
180
|
+
const profileTtls = [];
|
|
181
|
+
for (const [agentId, agent] of Object.entries(portalConfig.agents)) {
|
|
182
|
+
const profile = resolveMcpPortalProfile(portalConfig, agent.profile);
|
|
183
|
+
enabledNamespacesByAgent[agentId] = profile.enabledNamespaces;
|
|
184
|
+
enabledToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.enabledToolsByNamespace);
|
|
185
|
+
hiddenToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.hiddenToolsByNamespace);
|
|
186
|
+
profileTtls.push(profile.cache.catalogTtlMs);
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
cacheTtlMs: profileTtls.length === 0 ? 6e4 : Math.min(...profileTtls),
|
|
190
|
+
enabledNamespacesByAgent,
|
|
191
|
+
enabledToolsByAgent,
|
|
192
|
+
hiddenToolsByAgent
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function withAgentOverrides(portalConfig, agentOverrides) {
|
|
196
|
+
return {
|
|
197
|
+
...portalConfig,
|
|
198
|
+
agents: applyAgentOverrides(portalConfig.agents, agentOverrides)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function requireProxyConfig(portalConfig) {
|
|
202
|
+
if (portalConfig.externalAuth === void 0 || portalConfig.mcpProxy === void 0) throw new Error("mcp-proxy startup requires mcp-portal.config.jsonc externalAuth.masterKey and mcpProxy settings.");
|
|
203
|
+
return {
|
|
204
|
+
externalAuth: portalConfig.externalAuth,
|
|
205
|
+
mcpProxy: portalConfig.mcpProxy
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function deriveApprovalHmacKeysFromMasterKey(props) {
|
|
209
|
+
return new Map(props.agentIds.map((agentId) => [agentId, createHmac("sha256", props.masterKey).update(`mcp-portal:approval-agent:${agentId}`).digest()]));
|
|
210
|
+
}
|
|
211
|
+
function credentialVersionsByAgent(portalConfig) {
|
|
212
|
+
return Object.fromEntries(Object.entries(portalConfig.agents).map(([agentId, agent]) => [agentId, agent.credentialVersion]));
|
|
213
|
+
}
|
|
214
|
+
async function startPortalServer(props) {
|
|
215
|
+
const logger = props.logger ?? defaultPortalServerLogger();
|
|
216
|
+
const serveFn = props.serveFn ?? serve;
|
|
217
|
+
let defaultSecretResolverPromise;
|
|
218
|
+
const getDefaultSecretResolver = () => {
|
|
219
|
+
defaultSecretResolverPromise ??= createServeSecretResolver(props.env);
|
|
220
|
+
return defaultSecretResolverPromise;
|
|
221
|
+
};
|
|
222
|
+
const resolveSecret = props.resolveSecret ?? (async (secret) => resolveSecretValue(secret, {
|
|
223
|
+
env: props.env,
|
|
224
|
+
secretResolver: await getDefaultSecretResolver()
|
|
225
|
+
}));
|
|
226
|
+
const mcpConfig = await loadMcpConfig(join(props.args.configDir, "mcp.config.jsonc"));
|
|
227
|
+
const portalConfig = withAgentOverrides(await loadMcpPortalConfig(join(props.args.configDir, "mcp-portal.config.jsonc")), props.args.agentOverrides);
|
|
228
|
+
const proxyStartup = requireProxyConfig(portalConfig);
|
|
229
|
+
const masterKey = decodePortalMasterKey(await resolveSecret(proxyStartup.externalAuth.masterKey));
|
|
230
|
+
const agentRecords = createPortalAgentRuntimeRecords({
|
|
231
|
+
hmacKeys: deriveApprovalHmacKeysFromMasterKey({
|
|
232
|
+
agentIds: Object.keys(portalConfig.agents),
|
|
233
|
+
masterKey
|
|
234
|
+
}),
|
|
235
|
+
portalConfig
|
|
236
|
+
});
|
|
237
|
+
const upstreamServers = await resolveUpstreamServers({
|
|
238
|
+
config: mcpConfig,
|
|
239
|
+
resolveSecret
|
|
240
|
+
});
|
|
241
|
+
const upstreamRuntime = createUpstreamMcpClientRuntime({
|
|
242
|
+
additionalRedactionValues: [masterKey.toString("base64url")],
|
|
243
|
+
onCloseError: (error, context) => {
|
|
244
|
+
logger.log({
|
|
245
|
+
agentScopeId: context.agentScopeId,
|
|
246
|
+
event: "upstream_close_error",
|
|
247
|
+
level: "warn",
|
|
248
|
+
message: error.message,
|
|
249
|
+
...context.namespace === void 0 ? {} : { namespace: context.namespace }
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
servers: upstreamServers
|
|
253
|
+
});
|
|
254
|
+
const profilePolicyMaps = buildProfilePolicyMaps(portalConfig);
|
|
255
|
+
const verifyApproval = createPortalApprovalVerifier({
|
|
256
|
+
auditErrorSink: (error, event) => {
|
|
257
|
+
logger.log({
|
|
258
|
+
agentId: event.agentId,
|
|
259
|
+
event: "mcp_portal_approval_audit_error",
|
|
260
|
+
level: "warn",
|
|
261
|
+
message: error.message,
|
|
262
|
+
timeMs: event.timeMs
|
|
263
|
+
});
|
|
264
|
+
},
|
|
265
|
+
auditSink: (event) => {
|
|
266
|
+
logger.log({
|
|
267
|
+
agentId: event.agentId,
|
|
268
|
+
decision: event.decision,
|
|
269
|
+
event: "mcp_portal_approval",
|
|
270
|
+
level: event.decision === "allow" ? "info" : "warn",
|
|
271
|
+
..."reason" in event ? { reason: event.reason } : {},
|
|
272
|
+
timeMs: event.timeMs,
|
|
273
|
+
..."verifierReason" in event ? { verifierReason: event.verifierReason } : {}
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
records: agentRecords
|
|
277
|
+
});
|
|
278
|
+
const core = createPortalCore({
|
|
279
|
+
accessPolicy: {
|
|
280
|
+
defaultPolicy: "deny-all",
|
|
281
|
+
enabledNamespacesByAgent: profilePolicyMaps.enabledNamespacesByAgent,
|
|
282
|
+
enabledToolsByAgent: profilePolicyMaps.enabledToolsByAgent,
|
|
283
|
+
hiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent
|
|
284
|
+
},
|
|
285
|
+
approval: (calls, identity, approvalToken) => verifyApproval(calls, identity.agentId, approvalToken),
|
|
286
|
+
catalogTtlMs: profilePolicyMaps.cacheTtlMs,
|
|
287
|
+
runtime: {
|
|
288
|
+
...upstreamRuntime,
|
|
289
|
+
callUpstreamTool: upstreamRuntime.callTool
|
|
290
|
+
},
|
|
291
|
+
upstreamNamespaces: upstreamServers.map((server) => server.namespace)
|
|
292
|
+
});
|
|
293
|
+
const app = createPortalHttpApp({
|
|
294
|
+
agentBearerAuth: {
|
|
295
|
+
authorizationHeaderName: proxyStartup.mcpProxy.auth.headerName,
|
|
296
|
+
credentialVersionsByAgent: credentialVersionsByAgent(portalConfig),
|
|
297
|
+
masterKey
|
|
298
|
+
},
|
|
299
|
+
auditSink: (event) => {
|
|
300
|
+
logger.log({
|
|
301
|
+
agentId: event.agentId,
|
|
302
|
+
clientAddress: event.clientAddress,
|
|
303
|
+
decision: event.decision,
|
|
304
|
+
event: "mcp_proxy_auth",
|
|
305
|
+
level: event.decision === "allow" ? "info" : "warn",
|
|
306
|
+
...event.reason === void 0 ? {} : { reason: event.reason },
|
|
307
|
+
timeMs: event.timeMs
|
|
308
|
+
});
|
|
309
|
+
},
|
|
310
|
+
auditErrorSink: (error, event) => {
|
|
311
|
+
logger.log({
|
|
312
|
+
agentId: event.agentId,
|
|
313
|
+
clientAddress: event.clientAddress,
|
|
314
|
+
event: "mcp_proxy_auth_audit_error",
|
|
315
|
+
level: "warn",
|
|
316
|
+
message: error.message,
|
|
317
|
+
timeMs: event.timeMs
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
core,
|
|
321
|
+
onSessionClosed: async (identity) => {
|
|
322
|
+
await core.invalidateSession(identity);
|
|
323
|
+
},
|
|
324
|
+
registeredAgentIds: Object.keys(portalConfig.agents),
|
|
325
|
+
resolveAgentIdentity: createPortalHttpAgentResolver(agentRecords)
|
|
326
|
+
});
|
|
327
|
+
const listeningPort = createDeferredPort();
|
|
328
|
+
let hasListened = false;
|
|
329
|
+
const server = serveFn({
|
|
330
|
+
fetch: app.fetch,
|
|
331
|
+
hostname: proxyStartup.mcpProxy.server.host,
|
|
332
|
+
port: props.args.port ?? proxyStartup.mcpProxy.server.port
|
|
333
|
+
}, (info) => {
|
|
334
|
+
hasListened = true;
|
|
335
|
+
process.stdout.write(`listening port=${String(info.port)}\n`);
|
|
336
|
+
listeningPort.resolve(info.port);
|
|
337
|
+
});
|
|
338
|
+
server.on("error", (error) => {
|
|
339
|
+
handlePortalServerError({
|
|
340
|
+
error,
|
|
341
|
+
hasListened,
|
|
342
|
+
listeningPort,
|
|
343
|
+
logger
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
return {
|
|
347
|
+
close: async () => {
|
|
348
|
+
await app.closePortalSessions();
|
|
349
|
+
await core.close();
|
|
350
|
+
await closeNodeServer(server);
|
|
351
|
+
},
|
|
352
|
+
port: await listeningPort.promise
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
export { handlePortalServerError as a, resolveSecretValue as c, deriveApprovalHmacKeysFromMasterKey as i, buildProfilePolicyMaps as n, parsePortalServerCliArgs as o, createServeSecretResolver as r, startPortalServer as s, applyAgentOverrides as t };
|
|
357
|
+
|
|
358
|
+
//# sourceMappingURL=serve-command-CnSMUybd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-command-CnSMUybd.js","names":["createOnePasswordSecretResolver"],"sources":["../src/bin/secret-value-resolver.ts","../src/cli/serve-command.ts"],"sourcesContent":["import type { SecretValue } from '@agent-vm/config-contracts';\nimport type { SecretRef, SecretResolver } from '@agent-vm/secrets';\n\nexport interface ResolveSecretValueProps {\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly secretResolver?: SecretResolver;\n}\n\nfunction secretRefFromSecretValue(secret: SecretValue): SecretRef {\n\tif (secret.source === 'environment') {\n\t\treturn { ref: secret.name, source: 'environment' };\n\t}\n\treturn { ref: secret.ref, source: '1password' };\n}\n\nexport async function resolveSecretValue(\n\tsecret: SecretValue,\n\tprops: ResolveSecretValueProps,\n): Promise<string> {\n\tif (secret.source === 'environment') {\n\t\tconst value = props.env[secret.name];\n\t\tif (value === undefined || value.length === 0) {\n\t\t\tthrow new Error(`Missing environment secret ${secret.name}.`);\n\t\t}\n\t\treturn value;\n\t}\n\n\tif (props.secretResolver === undefined) {\n\t\tthrow new Error(\"Secret with source '1password' requires a configured secret resolver.\");\n\t}\n\treturn await props.secretResolver.resolve(secretRefFromSecretValue(secret));\n}\n","import { createHmac } from 'node:crypto';\nimport { join } from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport {\n\tloadMcpConfig,\n\tloadMcpPortalConfig,\n\tresolveMcpPortalProfile,\n\ttype McpPortalAgentConfig,\n\ttype McpPortalConfig,\n\ttype McpPortalExternalAuthConfig,\n\ttype McpPortalProxyConfig,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\nimport {\n\tcreateCompositeSecretResolver,\n\tcreateSecretResolver as createOnePasswordSecretResolver,\n\tresolveServiceAccountToken,\n\ttype SecretResolver,\n\ttype TokenSource,\n} from '@agent-vm/secrets';\nimport { serve } from '@hono/node-server';\n\nimport { resolveSecretValue } from '../bin/secret-value-resolver.js';\nimport { createPortalCore } from '../core/portal-core.js';\nimport { resolveUpstreamServers } from '../core/provider-runtime.js';\nimport { createPortalHttpApp, type PortalHttpAuditEvent } from '../mcp-proxy/portal-http-server.js';\nimport {\n\tcreatePortalAgentRuntimeRecords,\n\tcreatePortalApprovalVerifier,\n\tcreatePortalHttpAgentResolver,\n\ttype PortalApprovalAuditEvent,\n} from '../mcp-proxy/resolve-agent-identity.js';\nimport type { PortalToolSelector } from '../portal-access-policy.js';\nimport { decodePortalMasterKey } from '../portal-auth/agent-bearer-token.js';\nimport { createUpstreamMcpClientRuntime } from '../upstream-mcp-client-runtime.js';\n\ntype PortalNodeServer = ReturnType<typeof serve>;\ntype PortalServeFunction = typeof serve;\n\nexport type PortalServerLogEvent =\n\t| {\n\t\t\treadonly event: 'server_error';\n\t\t\treadonly level: 'error';\n\t\t\treadonly message: string;\n\t\t\treadonly stack?: string;\n\t }\n\t| {\n\t\t\treadonly agentId: string;\n\t\t\treadonly clientAddress: string;\n\t\t\treadonly decision: PortalHttpAuditEvent['decision'];\n\t\t\treadonly event: 'mcp_proxy_auth';\n\t\t\treadonly level: 'info' | 'warn';\n\t\t\treadonly reason?: PortalHttpAuditEvent['reason'];\n\t\t\treadonly timeMs: number;\n\t }\n\t| {\n\t\t\treadonly agentId: string;\n\t\t\treadonly clientAddress: string;\n\t\t\treadonly event: 'mcp_proxy_auth_audit_error';\n\t\t\treadonly level: 'warn';\n\t\t\treadonly message: string;\n\t\t\treadonly timeMs: number;\n\t }\n\t| {\n\t\t\treadonly agentId: string;\n\t\t\treadonly decision: PortalApprovalAuditEvent['decision'];\n\t\t\treadonly event: 'mcp_portal_approval';\n\t\t\treadonly level: 'info' | 'warn';\n\t\t\treadonly reason?: PortalApprovalAuditEvent['reason'];\n\t\t\treadonly timeMs: number;\n\t\t\treadonly verifierReason?: string;\n\t }\n\t| {\n\t\t\treadonly agentId: string;\n\t\t\treadonly event: 'mcp_portal_approval_audit_error';\n\t\t\treadonly level: 'warn';\n\t\t\treadonly message: string;\n\t\t\treadonly timeMs: number;\n\t }\n\t| {\n\t\t\treadonly agentScopeId: string;\n\t\t\treadonly event: 'upstream_close_error';\n\t\t\treadonly level: 'warn';\n\t\t\treadonly message: string;\n\t\t\treadonly namespace?: string;\n\t };\n\nexport interface PortalServerLogger {\n\treadonly log: (event: PortalServerLogEvent) => void;\n}\n\nexport interface PortalServerCliArgs {\n\treadonly agentOverrides: readonly string[];\n\treadonly configDir: string;\n\treadonly port?: number;\n}\n\nexport interface StartPortalServerProps {\n\treadonly args: PortalServerCliArgs;\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly logger?: PortalServerLogger;\n\treadonly resolveSecret?: (secret: SecretValue) => Promise<string>;\n\treadonly serveFn?: PortalServeFunction;\n}\n\nexport interface CreateServeSecretResolverDependencies {\n\treadonly createOnePasswordSecretResolver?: typeof createOnePasswordSecretResolver;\n\treadonly resolveServiceAccountToken?: typeof resolveServiceAccountToken;\n}\n\nfunction requirePortalTokenSourceValue(\n\tenv: Readonly<Record<string, string | undefined>>,\n\tname: string,\n\tsourceType: string,\n): string {\n\tconst value = env[name]?.trim();\n\tif (value === undefined || value.length === 0) {\n\t\tthrow new Error(`${name} is required when AGENT_VM_MCP_PORTAL_OP_TOKEN_SOURCE=${sourceType}.`);\n\t}\n\treturn value;\n}\n\nfunction readPortalOnePasswordTokenSource(\n\tenv: Readonly<Record<string, string | undefined>>,\n): TokenSource | null {\n\tconst sourceType = env.AGENT_VM_MCP_PORTAL_OP_TOKEN_SOURCE?.trim();\n\tif (sourceType === undefined || sourceType.length === 0) {\n\t\tconst configuredEnvVar = env.AGENT_VM_MCP_PORTAL_OP_TOKEN_ENV_VAR?.trim();\n\t\tconst envVar =\n\t\t\tconfiguredEnvVar === undefined || configuredEnvVar.length === 0\n\t\t\t\t? 'OP_SERVICE_ACCOUNT_TOKEN'\n\t\t\t\t: configuredEnvVar;\n\t\tconst token = env[envVar]?.trim();\n\t\treturn token === undefined || token.length === 0 ? null : { envVar, type: 'env' };\n\t}\n\n\tif (sourceType === 'env') {\n\t\treturn {\n\t\t\tenvVar: requirePortalTokenSourceValue(\n\t\t\t\tenv,\n\t\t\t\t'AGENT_VM_MCP_PORTAL_OP_TOKEN_ENV_VAR',\n\t\t\t\tsourceType,\n\t\t\t),\n\t\t\ttype: 'env',\n\t\t};\n\t}\n\tif (sourceType === 'op-cli') {\n\t\treturn {\n\t\t\tref: requirePortalTokenSourceValue(env, 'AGENT_VM_MCP_PORTAL_OP_TOKEN_REF', sourceType),\n\t\t\ttype: 'op-cli',\n\t\t};\n\t}\n\tif (sourceType === 'keychain') {\n\t\treturn {\n\t\t\taccount: requirePortalTokenSourceValue(\n\t\t\t\tenv,\n\t\t\t\t'AGENT_VM_MCP_PORTAL_OP_TOKEN_KEYCHAIN_ACCOUNT',\n\t\t\t\tsourceType,\n\t\t\t),\n\t\t\tservice: requirePortalTokenSourceValue(\n\t\t\t\tenv,\n\t\t\t\t'AGENT_VM_MCP_PORTAL_OP_TOKEN_KEYCHAIN_SERVICE',\n\t\t\t\tsourceType,\n\t\t\t),\n\t\t\ttype: 'keychain',\n\t\t};\n\t}\n\n\tthrow new Error(`Unsupported AGENT_VM_MCP_PORTAL_OP_TOKEN_SOURCE \"${sourceType}\".`);\n}\n\nasync function resolvePortalServiceAccountToken(props: {\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly resolveToken: typeof resolveServiceAccountToken;\n\treadonly tokenSource: TokenSource;\n}): Promise<string> {\n\tif (props.tokenSource.type !== 'env') {\n\t\treturn await props.resolveToken(props.tokenSource);\n\t}\n\tconst envVar = props.tokenSource.envVar ?? 'OP_SERVICE_ACCOUNT_TOKEN';\n\tconst token = props.env[envVar]?.trim();\n\tif (token === undefined || token.length === 0) {\n\t\tthrow new Error(`Environment variable ${envVar} is not set`);\n\t}\n\treturn token;\n}\n\nexport async function createServeSecretResolver(\n\tenv: Readonly<Record<string, string | undefined>>,\n\tdependencies: CreateServeSecretResolverDependencies = {},\n): Promise<SecretResolver> {\n\tconst tokenSource = readPortalOnePasswordTokenSource(env);\n\tconst resolveToken = dependencies.resolveServiceAccountToken ?? resolveServiceAccountToken;\n\tconst createResolver =\n\t\tdependencies.createOnePasswordSecretResolver ?? createOnePasswordSecretResolver;\n\tconst onePasswordResolver =\n\t\ttokenSource === null\n\t\t\t? null\n\t\t\t: await createResolver({\n\t\t\t\t\tserviceAccountToken: await resolvePortalServiceAccountToken({\n\t\t\t\t\t\tenv,\n\t\t\t\t\t\tresolveToken,\n\t\t\t\t\t\ttokenSource,\n\t\t\t\t\t}),\n\t\t\t\t});\n\treturn createCompositeSecretResolver(onePasswordResolver, env);\n}\n\nexport interface ProfilePolicyMaps {\n\treadonly enabledNamespacesByAgent: Readonly<Record<string, readonly string[]>>;\n\treadonly enabledToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n\treadonly hiddenToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n}\n\nfunction parsePort(value: string | undefined): number | undefined {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tconst port = Number(value);\n\tif (!Number.isInteger(port) || port < 0 || port > 65_535) {\n\t\tthrow new Error(`Invalid --port value \"${value}\".`);\n\t}\n\treturn port;\n}\n\nexport function parsePortalServerCliArgs(argv: readonly string[]): PortalServerCliArgs {\n\tconst parsed = parseArgs({\n\t\targs: [...argv],\n\t\toptions: {\n\t\t\tagent: { multiple: true, type: 'string' },\n\t\t\t'config-dir': { type: 'string' },\n\t\t\tport: { short: 'p', type: 'string' },\n\t\t},\n\t\tstrict: true,\n\t});\n\tconst configDir = parsed.values['config-dir'];\n\tif (typeof configDir !== 'string' || configDir.length === 0) {\n\t\tthrow new Error('--config-dir <path> is required.');\n\t}\n\tconst rawAgentOverrides = parsed.values.agent;\n\tconst args = {\n\t\tagentOverrides: Array.isArray(rawAgentOverrides) ? rawAgentOverrides : [],\n\t\tconfigDir,\n\t};\n\tconst port = parsePort(parsed.values.port);\n\treturn port === undefined ? args : { ...args, port };\n}\n\nexport function applyAgentOverrides(\n\tagents: Readonly<Record<string, McpPortalAgentConfig>>,\n\toverrides: readonly string[],\n): Readonly<Record<string, McpPortalAgentConfig>> {\n\tconst nextAgents: Record<string, McpPortalAgentConfig> = { ...agents };\n\tfor (const override of overrides) {\n\t\tconst [agentId, profileName, extra] = override.split('=');\n\t\tif (\n\t\t\tagentId === undefined ||\n\t\t\tprofileName === undefined ||\n\t\t\textra !== undefined ||\n\t\t\tagentId.length === 0 ||\n\t\t\tprofileName.length === 0\n\t\t) {\n\t\t\tthrow new Error(`Invalid --agent override \"${override}\". Expected <agentId>=<profile>.`);\n\t\t}\n\t\tconst existingAgent = nextAgents[agentId];\n\t\tif (existingAgent === undefined) {\n\t\t\tthrow new Error(`Cannot override unknown MCP Portal agent \"${agentId}\".`);\n\t\t}\n\t\tnextAgents[agentId] = { ...existingAgent, profile: profileName };\n\t}\n\treturn nextAgents;\n}\n\nexport interface DeferredPort {\n\treadonly promise: Promise<number>;\n\treadonly reject: (error: Error) => void;\n\treadonly resolve: (port: number) => void;\n}\n\nfunction createDeferredPort(): DeferredPort {\n\tlet rejectPort: ((error: Error) => void) | undefined;\n\tlet resolvePort: ((port: number) => void) | undefined;\n\tconst promise = new Promise<number>((resolve, reject) => {\n\t\trejectPort = reject;\n\t\tresolvePort = resolve;\n\t});\n\treturn {\n\t\tpromise,\n\t\treject: (error) => {\n\t\t\tif (rejectPort === undefined) {\n\t\t\t\tthrow new Error('MCP Portal port rejector was not initialized.');\n\t\t\t}\n\t\t\trejectPort(error);\n\t\t},\n\t\tresolve: (port) => {\n\t\t\tif (resolvePort === undefined) {\n\t\t\t\tthrow new Error('MCP Portal port resolver was not initialized.');\n\t\t\t}\n\t\t\tresolvePort(port);\n\t\t},\n\t};\n}\n\nfunction defaultPortalServerLogger(): PortalServerLogger {\n\treturn {\n\t\tlog: (event) => {\n\t\t\tprocess.stderr.write(`${JSON.stringify(event)}\\n`);\n\t\t},\n\t};\n}\n\nexport function handlePortalServerError(props: {\n\treadonly error: Error;\n\treadonly hasListened: boolean;\n\treadonly listeningPort: DeferredPort;\n\treadonly logger: PortalServerLogger;\n}): void {\n\tprops.logger.log({\n\t\tevent: 'server_error',\n\t\tlevel: 'error',\n\t\tmessage: props.error.message,\n\t\t...(props.error.stack === undefined ? {} : { stack: props.error.stack }),\n\t});\n\tif (!props.hasListened) {\n\t\tprops.listeningPort.reject(props.error);\n\t}\n}\n\nfunction closeNodeServer(server: PortalNodeServer): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tserver.close((error) => {\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t} else {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}\n\nfunction selectorsFromNamespaceTools(\n\tnamespaceTools: Readonly<Record<string, readonly string[]>>,\n): readonly PortalToolSelector[] {\n\treturn Object.entries(namespaceTools).flatMap(([namespace, toolNames]) =>\n\t\ttoolNames.map((toolName) => ({ namespace, toolName })),\n\t);\n}\n\nexport function buildProfilePolicyMaps(\n\tportalConfig: McpPortalConfig,\n): ProfilePolicyMaps & { readonly cacheTtlMs: number } {\n\tconst enabledNamespacesByAgent: Record<string, readonly string[]> = {};\n\tconst enabledToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst hiddenToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst profileTtls: number[] = [];\n\n\tfor (const [agentId, agent] of Object.entries(portalConfig.agents)) {\n\t\tconst profile: ResolvedMcpPortalProfile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tenabledNamespacesByAgent[agentId] = profile.enabledNamespaces;\n\t\tenabledToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.enabledToolsByNamespace);\n\t\thiddenToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.hiddenToolsByNamespace);\n\t\tprofileTtls.push(profile.cache.catalogTtlMs);\n\t}\n\n\treturn {\n\t\tcacheTtlMs: profileTtls.length === 0 ? 60_000 : Math.min(...profileTtls),\n\t\tenabledNamespacesByAgent,\n\t\tenabledToolsByAgent,\n\t\thiddenToolsByAgent,\n\t};\n}\n\nfunction withAgentOverrides(\n\tportalConfig: McpPortalConfig,\n\tagentOverrides: readonly string[],\n): McpPortalConfig {\n\treturn {\n\t\t...portalConfig,\n\t\tagents: applyAgentOverrides(portalConfig.agents, agentOverrides),\n\t};\n}\n\nfunction requireProxyConfig(portalConfig: McpPortalConfig): {\n\treadonly externalAuth: McpPortalExternalAuthConfig;\n\treadonly mcpProxy: McpPortalProxyConfig;\n} {\n\tif (portalConfig.externalAuth === undefined || portalConfig.mcpProxy === undefined) {\n\t\tthrow new Error(\n\t\t\t'mcp-proxy startup requires mcp-portal.config.jsonc externalAuth.masterKey and mcpProxy settings.',\n\t\t);\n\t}\n\treturn {\n\t\texternalAuth: portalConfig.externalAuth,\n\t\tmcpProxy: portalConfig.mcpProxy,\n\t};\n}\n\nexport function deriveApprovalHmacKeysFromMasterKey(props: {\n\treadonly agentIds: readonly string[];\n\treadonly masterKey: Buffer;\n}): ReadonlyMap<string, Buffer> {\n\treturn new Map(\n\t\tprops.agentIds.map((agentId) => [\n\t\t\tagentId,\n\t\t\tcreateHmac('sha256', props.masterKey).update(`mcp-portal:approval-agent:${agentId}`).digest(),\n\t\t]),\n\t);\n}\n\nfunction credentialVersionsByAgent(\n\tportalConfig: McpPortalConfig,\n): Readonly<Record<string, number>> {\n\treturn Object.fromEntries(\n\t\tObject.entries(portalConfig.agents).map(([agentId, agent]) => [\n\t\t\tagentId,\n\t\t\tagent.credentialVersion,\n\t\t]),\n\t);\n}\n\nexport async function startPortalServer(\n\tprops: StartPortalServerProps,\n): Promise<{ readonly close: () => Promise<void>; readonly port: number }> {\n\tconst logger = props.logger ?? defaultPortalServerLogger();\n\tconst serveFn = props.serveFn ?? serve;\n\tlet defaultSecretResolverPromise: Promise<SecretResolver> | undefined;\n\tconst getDefaultSecretResolver = (): Promise<SecretResolver> => {\n\t\tdefaultSecretResolverPromise ??= createServeSecretResolver(props.env);\n\t\treturn defaultSecretResolverPromise;\n\t};\n\tconst resolveSecret =\n\t\tprops.resolveSecret ??\n\t\t(async (secret: SecretValue) =>\n\t\t\tresolveSecretValue(secret, {\n\t\t\t\tenv: props.env,\n\t\t\t\tsecretResolver: await getDefaultSecretResolver(),\n\t\t\t}));\n\tconst mcpConfig = await loadMcpConfig(join(props.args.configDir, 'mcp.config.jsonc'));\n\tconst portalConfig = withAgentOverrides(\n\t\tawait loadMcpPortalConfig(join(props.args.configDir, 'mcp-portal.config.jsonc')),\n\t\tprops.args.agentOverrides,\n\t);\n\tconst proxyStartup = requireProxyConfig(portalConfig);\n\tconst masterKey = decodePortalMasterKey(await resolveSecret(proxyStartup.externalAuth.masterKey));\n\tconst hmacKeys = deriveApprovalHmacKeysFromMasterKey({\n\t\tagentIds: Object.keys(portalConfig.agents),\n\t\tmasterKey,\n\t});\n\tconst agentRecords = createPortalAgentRuntimeRecords({ hmacKeys, portalConfig });\n\tconst upstreamServers = await resolveUpstreamServers({ config: mcpConfig, resolveSecret });\n\tconst upstreamRuntime = createUpstreamMcpClientRuntime({\n\t\tadditionalRedactionValues: [masterKey.toString('base64url')],\n\t\tonCloseError: (error, context) => {\n\t\t\tlogger.log({\n\t\t\t\tagentScopeId: context.agentScopeId,\n\t\t\t\tevent: 'upstream_close_error',\n\t\t\t\tlevel: 'warn',\n\t\t\t\tmessage: error.message,\n\t\t\t\t...(context.namespace === undefined ? {} : { namespace: context.namespace }),\n\t\t\t});\n\t\t},\n\t\tservers: upstreamServers,\n\t});\n\tconst profilePolicyMaps = buildProfilePolicyMaps(portalConfig);\n\tconst verifyApproval = createPortalApprovalVerifier({\n\t\tauditErrorSink: (error, event) => {\n\t\t\tlogger.log({\n\t\t\t\tagentId: event.agentId,\n\t\t\t\tevent: 'mcp_portal_approval_audit_error',\n\t\t\t\tlevel: 'warn',\n\t\t\t\tmessage: error.message,\n\t\t\t\ttimeMs: event.timeMs,\n\t\t\t});\n\t\t},\n\t\tauditSink: (event) => {\n\t\t\tlogger.log({\n\t\t\t\tagentId: event.agentId,\n\t\t\t\tdecision: event.decision,\n\t\t\t\tevent: 'mcp_portal_approval',\n\t\t\t\tlevel: event.decision === 'allow' ? 'info' : 'warn',\n\t\t\t\t...('reason' in event ? { reason: event.reason } : {}),\n\t\t\t\ttimeMs: event.timeMs,\n\t\t\t\t...('verifierReason' in event ? { verifierReason: event.verifierReason } : {}),\n\t\t\t});\n\t\t},\n\t\trecords: agentRecords,\n\t});\n\tconst core = createPortalCore({\n\t\taccessPolicy: {\n\t\t\tdefaultPolicy: 'deny-all',\n\t\t\tenabledNamespacesByAgent: profilePolicyMaps.enabledNamespacesByAgent,\n\t\t\tenabledToolsByAgent: profilePolicyMaps.enabledToolsByAgent,\n\t\t\thiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent,\n\t\t},\n\t\tapproval: (calls, identity, approvalToken) =>\n\t\t\tverifyApproval(calls, identity.agentId, approvalToken),\n\t\tcatalogTtlMs: profilePolicyMaps.cacheTtlMs,\n\t\truntime: {\n\t\t\t...upstreamRuntime,\n\t\t\tcallUpstreamTool: upstreamRuntime.callTool,\n\t\t},\n\t\tupstreamNamespaces: upstreamServers.map((server) => server.namespace),\n\t});\n\tconst app = createPortalHttpApp({\n\t\tagentBearerAuth: {\n\t\t\tauthorizationHeaderName: proxyStartup.mcpProxy.auth.headerName,\n\t\t\tcredentialVersionsByAgent: credentialVersionsByAgent(portalConfig),\n\t\t\tmasterKey,\n\t\t},\n\t\tauditSink: (event) => {\n\t\t\tlogger.log({\n\t\t\t\tagentId: event.agentId,\n\t\t\t\tclientAddress: event.clientAddress,\n\t\t\t\tdecision: event.decision,\n\t\t\t\tevent: 'mcp_proxy_auth',\n\t\t\t\tlevel: event.decision === 'allow' ? 'info' : 'warn',\n\t\t\t\t...(event.reason === undefined ? {} : { reason: event.reason }),\n\t\t\t\ttimeMs: event.timeMs,\n\t\t\t});\n\t\t},\n\t\tauditErrorSink: (error, event) => {\n\t\t\tlogger.log({\n\t\t\t\tagentId: event.agentId,\n\t\t\t\tclientAddress: event.clientAddress,\n\t\t\t\tevent: 'mcp_proxy_auth_audit_error',\n\t\t\t\tlevel: 'warn',\n\t\t\t\tmessage: error.message,\n\t\t\t\ttimeMs: event.timeMs,\n\t\t\t});\n\t\t},\n\t\tcore,\n\t\tonSessionClosed: async (identity) => {\n\t\t\tawait core.invalidateSession(identity);\n\t\t},\n\t\tregisteredAgentIds: Object.keys(portalConfig.agents),\n\t\tresolveAgentIdentity: createPortalHttpAgentResolver(agentRecords),\n\t});\n\tconst listeningPort = createDeferredPort();\n\tlet hasListened = false;\n\tconst server = serveFn(\n\t\t{\n\t\t\tfetch: app.fetch,\n\t\t\thostname: proxyStartup.mcpProxy.server.host,\n\t\t\tport: props.args.port ?? proxyStartup.mcpProxy.server.port,\n\t\t},\n\t\t(info) => {\n\t\t\thasListened = true;\n\t\t\tprocess.stdout.write(`listening port=${String(info.port)}\\n`);\n\t\t\tlisteningPort.resolve(info.port);\n\t\t},\n\t);\n\tserver.on('error', (error: Error) => {\n\t\thandlePortalServerError({ error, hasListened, listeningPort, logger });\n\t});\n\tconst port = await listeningPort.promise;\n\n\treturn {\n\t\tclose: async () => {\n\t\t\tawait app.closePortalSessions();\n\t\t\tawait core.close();\n\t\t\tawait closeNodeServer(server);\n\t\t},\n\t\tport,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -12,8 +12,11 @@ interface StartedFakeUpstreamMcpServer {
|
|
|
12
12
|
readonly port: number;
|
|
13
13
|
readonly url: string;
|
|
14
14
|
}
|
|
15
|
+
interface FakeUpstreamMcpServerOptions {
|
|
16
|
+
readonly emitProgress?: boolean;
|
|
17
|
+
}
|
|
15
18
|
declare function createFakeUpstreamTools(): readonly Tool[];
|
|
16
|
-
declare function startFakeUpstreamMcpServer(): Promise<StartedFakeUpstreamMcpServer>;
|
|
19
|
+
declare function startFakeUpstreamMcpServer(options?: FakeUpstreamMcpServerOptions): Promise<StartedFakeUpstreamMcpServer>;
|
|
17
20
|
//#endregion
|
|
18
|
-
export { FakeUpstreamToolCallRecord, StartedFakeUpstreamMcpServer, createFakeUpstreamTools, fakeUpstreamNamespace, startFakeUpstreamMcpServer };
|
|
21
|
+
export { FakeUpstreamMcpServerOptions, FakeUpstreamToolCallRecord, StartedFakeUpstreamMcpServer, createFakeUpstreamTools, fakeUpstreamNamespace, startFakeUpstreamMcpServer };
|
|
19
22
|
//# sourceMappingURL=fake-upstream-mcp-server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-upstream-mcp-server.d.ts","names":[],"sources":["../../src/testing/fake-upstream-mcp-server.ts"],"mappings":";;;cAWa,qBAAA;AAAA,UAEI,0BAAA;EAAA,SACP,cAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGO,4BAAA;EAAA,SACP,KAAA,WAAgB,0BAAA;EAAA,SAChB,KAAA,QAAa,OAAA;EAAA,SACb,IAAA;EAAA,SACA,GAAA;AAAA;AAAA,iBA4CM,uBAAA,CAAA,YAAoC,IAAA;AAAA,iBA2B9B,0BAAA,
|
|
1
|
+
{"version":3,"file":"fake-upstream-mcp-server.d.ts","names":[],"sources":["../../src/testing/fake-upstream-mcp-server.ts"],"mappings":";;;cAWa,qBAAA;AAAA,UAEI,0BAAA;EAAA,SACP,cAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGO,4BAAA;EAAA,SACP,KAAA,WAAgB,0BAAA;EAAA,SAChB,KAAA,QAAa,OAAA;EAAA,SACb,IAAA;EAAA,SACA,GAAA;AAAA;AAAA,UAGO,4BAAA;EAAA,SACP,YAAA;AAAA;AAAA,iBA4CM,uBAAA,CAAA,YAAoC,IAAA;AAAA,iBA2B9B,0BAAA,CACrB,OAAA,GAAS,4BAAA,GACP,OAAA,CAAQ,4BAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
-
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
4
|
import { serve } from "@hono/node-server";
|
|
5
|
+
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
6
6
|
//#region src/testing/fake-upstream-mcp-server.ts
|
|
7
7
|
const fakeUpstreamNamespace = "upstream-mock";
|
|
8
8
|
function isObjectRecord(value) {
|
|
@@ -75,7 +75,7 @@ function createFakeUpstreamTools() {
|
|
|
75
75
|
name: "write_thing"
|
|
76
76
|
}];
|
|
77
77
|
}
|
|
78
|
-
async function startFakeUpstreamMcpServer() {
|
|
78
|
+
async function startFakeUpstreamMcpServer(options = {}) {
|
|
79
79
|
const calls = [];
|
|
80
80
|
const tools = createFakeUpstreamTools();
|
|
81
81
|
const toolsByName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
@@ -87,7 +87,7 @@ async function startFakeUpstreamMcpServer() {
|
|
|
87
87
|
version: "1.0.0"
|
|
88
88
|
}, { capabilities: { tools: { listChanged: false } } });
|
|
89
89
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
90
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
90
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
91
91
|
const tool = toolsByName.get(request.params.name);
|
|
92
92
|
if (tool === void 0) return {
|
|
93
93
|
content: [{
|
|
@@ -96,6 +96,16 @@ async function startFakeUpstreamMcpServer() {
|
|
|
96
96
|
}],
|
|
97
97
|
isError: true
|
|
98
98
|
};
|
|
99
|
+
const progressToken = extra["_meta"]?.progressToken;
|
|
100
|
+
if (options.emitProgress === true && progressToken !== void 0) await extra.sendNotification({
|
|
101
|
+
method: "notifications/progress",
|
|
102
|
+
params: {
|
|
103
|
+
message: "fake upstream half done",
|
|
104
|
+
progress: 1,
|
|
105
|
+
progressToken,
|
|
106
|
+
total: 2
|
|
107
|
+
}
|
|
108
|
+
});
|
|
99
109
|
const argumentsValue = isObjectRecord(request.params.arguments) ? request.params.arguments : {};
|
|
100
110
|
calls.push({
|
|
101
111
|
argumentsValue,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-upstream-mcp-server.js","names":[],"sources":["../../src/testing/fake-upstream-mcp-server.ts"],"sourcesContent":["import { serve, type ServerType } from '@hono/node-server';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';\nimport {\n\tCallToolRequestSchema,\n\tListToolsRequestSchema,\n\ttype CallToolResult,\n\ttype Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { Hono } from 'hono';\n\nexport const fakeUpstreamNamespace = 'upstream-mock';\n\nexport interface FakeUpstreamToolCallRecord {\n\treadonly argumentsValue: unknown;\n\treadonly name: string;\n}\n\nexport interface StartedFakeUpstreamMcpServer {\n\treadonly calls: readonly FakeUpstreamToolCallRecord[];\n\treadonly close: () => Promise<void>;\n\treadonly port: number;\n\treadonly url: string;\n}\n\ninterface StartedHonoServer {\n\treadonly port: number;\n\treadonly server: ServerType;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function closeServer(server: ServerType): Promise<void> {\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.close((error) => {\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresolve();\n\t\t});\n\t});\n}\n\nasync function serveHonoOnOpenPort(app: Hono): Promise<StartedHonoServer> {\n\treturn await new Promise<StartedHonoServer>((resolve) => {\n\t\tconst server = serve({ fetch: app.fetch, hostname: '127.0.0.1', port: 0 }, (info) => {\n\t\t\tresolve({ port: info.port, server });\n\t\t});\n\t});\n}\n\nfunction createToolResult(name: string, argumentsValue: unknown): CallToolResult {\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttext: JSON.stringify({ arguments: argumentsValue, name, ok: true }),\n\t\t\t\ttype: 'text',\n\t\t\t},\n\t\t],\n\t\tstructuredContent: { name, ok: true },\n\t};\n}\n\nexport function createFakeUpstreamTools(): readonly Tool[] {\n\treturn [\n\t\t{\n\t\t\tannotations: { destructiveHint: false, readOnlyHint: true },\n\t\t\tdescription: 'Reads a mock record.',\n\t\t\tinputSchema: {\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: { title: { type: 'string' } },\n\t\t\t\trequired: ['title'],\n\t\t\t\ttype: 'object',\n\t\t\t},\n\t\t\tname: 'read_thing',\n\t\t},\n\t\t{\n\t\t\tannotations: { destructiveHint: true },\n\t\t\tdescription: 'Writes a mock record.',\n\t\t\tinputSchema: {\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: { title: { type: 'string' } },\n\t\t\t\trequired: ['title'],\n\t\t\t\ttype: 'object',\n\t\t\t},\n\t\t\tname: 'write_thing',\n\t\t},\n\t] satisfies readonly Tool[];\n}\n\nexport async function startFakeUpstreamMcpServer(): Promise<StartedFakeUpstreamMcpServer> {\n\tconst calls: FakeUpstreamToolCallRecord[] = [];\n\tconst tools = createFakeUpstreamTools();\n\tconst toolsByName = new Map(tools.map((tool) => [tool.name, tool]));\n\tconst app = new Hono();\n\n\tapp.all('/mcp', async (context) => {\n\t\tconst transport = new WebStandardStreamableHTTPServerTransport();\n\t\tconst server = new Server(\n\t\t\t{ name: 'portal-upstream-fixture', version: '1.0.0' },\n\t\t\t{ capabilities: { tools: { listChanged: false } } },\n\t\t);\n\n\t\tserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));\n\t\tserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n\t\t\tconst tool = toolsByName.get(request.params.name);\n\t\t\tif (tool === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ text: `Unknown tool ${request.params.name}`, type: 'text' }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst argumentsValue = isObjectRecord(request.params.arguments)\n\t\t\t\t? request.params.arguments\n\t\t\t\t: {};\n\t\t\tcalls.push({ argumentsValue, name: tool.name });\n\t\t\treturn createToolResult(tool.name, argumentsValue);\n\t\t});\n\n\t\tawait server.connect(transport);\n\t\treturn await transport.handleRequest(context.req.raw);\n\t});\n\n\tconst startedServer = await serveHonoOnOpenPort(app);\n\treturn {\n\t\tcalls,\n\t\tclose: async () => {\n\t\t\tawait closeServer(startedServer.server);\n\t\t},\n\t\tport: startedServer.port,\n\t\turl: `http://127.0.0.1:${String(startedServer.port)}/mcp`,\n\t};\n}\n"],"mappings":";;;;;;AAWA,MAAa,wBAAwB;
|
|
1
|
+
{"version":3,"file":"fake-upstream-mcp-server.js","names":[],"sources":["../../src/testing/fake-upstream-mcp-server.ts"],"sourcesContent":["import { serve, type ServerType } from '@hono/node-server';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';\nimport {\n\tCallToolRequestSchema,\n\tListToolsRequestSchema,\n\ttype CallToolResult,\n\ttype Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { Hono } from 'hono';\n\nexport const fakeUpstreamNamespace = 'upstream-mock';\n\nexport interface FakeUpstreamToolCallRecord {\n\treadonly argumentsValue: unknown;\n\treadonly name: string;\n}\n\nexport interface StartedFakeUpstreamMcpServer {\n\treadonly calls: readonly FakeUpstreamToolCallRecord[];\n\treadonly close: () => Promise<void>;\n\treadonly port: number;\n\treadonly url: string;\n}\n\nexport interface FakeUpstreamMcpServerOptions {\n\treadonly emitProgress?: boolean;\n}\n\ninterface StartedHonoServer {\n\treadonly port: number;\n\treadonly server: ServerType;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function closeServer(server: ServerType): Promise<void> {\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.close((error) => {\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresolve();\n\t\t});\n\t});\n}\n\nasync function serveHonoOnOpenPort(app: Hono): Promise<StartedHonoServer> {\n\treturn await new Promise<StartedHonoServer>((resolve) => {\n\t\tconst server = serve({ fetch: app.fetch, hostname: '127.0.0.1', port: 0 }, (info) => {\n\t\t\tresolve({ port: info.port, server });\n\t\t});\n\t});\n}\n\nfunction createToolResult(name: string, argumentsValue: unknown): CallToolResult {\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttext: JSON.stringify({ arguments: argumentsValue, name, ok: true }),\n\t\t\t\ttype: 'text',\n\t\t\t},\n\t\t],\n\t\tstructuredContent: { name, ok: true },\n\t};\n}\n\nexport function createFakeUpstreamTools(): readonly Tool[] {\n\treturn [\n\t\t{\n\t\t\tannotations: { destructiveHint: false, readOnlyHint: true },\n\t\t\tdescription: 'Reads a mock record.',\n\t\t\tinputSchema: {\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: { title: { type: 'string' } },\n\t\t\t\trequired: ['title'],\n\t\t\t\ttype: 'object',\n\t\t\t},\n\t\t\tname: 'read_thing',\n\t\t},\n\t\t{\n\t\t\tannotations: { destructiveHint: true },\n\t\t\tdescription: 'Writes a mock record.',\n\t\t\tinputSchema: {\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: { title: { type: 'string' } },\n\t\t\t\trequired: ['title'],\n\t\t\t\ttype: 'object',\n\t\t\t},\n\t\t\tname: 'write_thing',\n\t\t},\n\t] satisfies readonly Tool[];\n}\n\nexport async function startFakeUpstreamMcpServer(\n\toptions: FakeUpstreamMcpServerOptions = {},\n): Promise<StartedFakeUpstreamMcpServer> {\n\tconst calls: FakeUpstreamToolCallRecord[] = [];\n\tconst tools = createFakeUpstreamTools();\n\tconst toolsByName = new Map(tools.map((tool) => [tool.name, tool]));\n\tconst app = new Hono();\n\n\tapp.all('/mcp', async (context) => {\n\t\tconst transport = new WebStandardStreamableHTTPServerTransport();\n\t\tconst server = new Server(\n\t\t\t{ name: 'portal-upstream-fixture', version: '1.0.0' },\n\t\t\t{ capabilities: { tools: { listChanged: false } } },\n\t\t);\n\n\t\tserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));\n\t\tserver.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n\t\t\tconst tool = toolsByName.get(request.params.name);\n\t\t\tif (tool === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ text: `Unknown tool ${request.params.name}`, type: 'text' }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst progressToken = extra['_meta']?.progressToken;\n\t\t\tif (options.emitProgress === true && progressToken !== undefined) {\n\t\t\t\tawait extra.sendNotification({\n\t\t\t\t\tmethod: 'notifications/progress',\n\t\t\t\t\tparams: {\n\t\t\t\t\t\tmessage: 'fake upstream half done',\n\t\t\t\t\t\tprogress: 1,\n\t\t\t\t\t\tprogressToken,\n\t\t\t\t\t\ttotal: 2,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst argumentsValue = isObjectRecord(request.params.arguments)\n\t\t\t\t? request.params.arguments\n\t\t\t\t: {};\n\t\t\tcalls.push({ argumentsValue, name: tool.name });\n\t\t\treturn createToolResult(tool.name, argumentsValue);\n\t\t});\n\n\t\tawait server.connect(transport);\n\t\treturn await transport.handleRequest(context.req.raw);\n\t});\n\n\tconst startedServer = await serveHonoOnOpenPort(app);\n\treturn {\n\t\tcalls,\n\t\tclose: async () => {\n\t\t\tawait closeServer(startedServer.server);\n\t\t},\n\t\tport: startedServer.port,\n\t\turl: `http://127.0.0.1:${String(startedServer.port)}/mcp`,\n\t};\n}\n"],"mappings":"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"}
|