@sellable/install
Version:
One-command installer for Sellable MCP in Claude Code, Codex, and Hermes
1,292 lines (1,252 loc) • 37.5 kB
JavaScript
import { spawn } from "node:child_process";
import { createHash, createPublicKey, randomUUID, verify } from "node:crypto";
import {
chmodSync,
closeSync,
constants,
existsSync,
fsyncSync,
lstatSync,
openSync,
readFileSync,
realpathSync,
renameSync,
rmSync,
writeFileSync,
} from "node:fs";
import { basename, dirname, isAbsolute, join, relative } from "node:path";
import { createInterface } from "node:readline";
import { fileURLToPath } from "node:url";
import {
FIXED_TURN_BINDING_KEYS,
validateMcpRuntimeBinding,
} from "./mcp-runtime-binding.mjs";
const SLACK_BODY_KEYS = Object.freeze([
"schemaVersion",
"audience",
"workspaceId",
"agentId",
"runtimeId",
"profileId",
"revisionId",
"installationId",
"teamId",
"channelId",
"threadId",
"requesterId",
"eventId",
"providerRequestId",
"slackGeneration",
"routeGeneration",
"membershipGeneration",
"serviceCredentialGeneration",
"modelCredentialGeneration",
"runtimeGeneration",
"fence",
"turnId",
"bodyDigest",
"nonce",
"issuedAt",
"expiresAt",
]);
const SLACK_EXPECTED_KEYS = Object.freeze(
SLACK_BODY_KEYS.filter(
(key) =>
!["schemaVersion", "audience", "nonce", "issuedAt", "expiresAt"].includes(
key
)
)
);
const ENDPOINT_TOOL_KEYS = Object.freeze([
"name",
"version",
"decision",
"generation",
]);
const ENDPOINT_BODY_KEYS = Object.freeze([
"schemaVersion",
"audience",
"principalKind",
"routes",
"workspaceId",
"agentId",
"endpointId",
"revisionId",
"conversationId",
"runId",
"attemptId",
"claimId",
"runtimeId",
"profileId",
"runtimeGeneration",
"profileGeneration",
"serviceCredentialGeneration",
"toolPolicyGeneration",
"allowedTools",
"allowedToolNames",
"allowedToolDigest",
"fence",
"turnId",
"bodyDigest",
"nonce",
"issuedAt",
"expiresAt",
]);
const ENDPOINT_EXPECTED_KEYS = Object.freeze(
ENDPOINT_BODY_KEYS.filter(
(key) =>
![
"schemaVersion",
"audience",
"principalKind",
"routes",
"nonce",
"issuedAt",
"expiresAt",
].includes(key)
)
);
const DESCRIPTOR_SIGNING_DOMAIN = "sellable-agent/mcp-turn-descriptor/v1";
const SAFE_ID = /^[A-Za-z0-9_.:-]{1,256}$/;
const SHA256 = /^[a-f0-9]{64}$/;
const MAX_JSONRPC_LINE_BYTES = 1024 * 1024;
function stableJson(value) {
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
if (value && typeof value === "object") {
return `{${Object.keys(value)
.sort()
.map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`)
.join(",")}}`;
}
return JSON.stringify(value);
}
function exactKeys(value, keys) {
return Boolean(
value &&
typeof value === "object" &&
!Array.isArray(value) &&
Object.keys(value).sort().join("\0") === [...keys].sort().join("\0")
);
}
function sha256(value) {
return createHash("sha256").update(value).digest("hex");
}
function privateDirectory(pathValue) {
try {
if (!isAbsolute(pathValue) || !existsSync(pathValue)) return null;
const link = lstatSync(pathValue);
if (
link.isSymbolicLink() ||
!link.isDirectory() ||
(link.mode & 0o077) !== 0
)
return null;
return realpathSync(pathValue);
} catch {
return null;
}
}
function directChild(root, candidate) {
try {
if (!isAbsolute(candidate) || realpathSync(dirname(candidate)) !== root)
return false;
const canonicalCandidate = join(root, basename(candidate));
const path = relative(root, canonicalCandidate);
return (
path.length > 0 && !path.startsWith("..") && basename(candidate) === path
);
} catch {
return false;
}
}
function descriptorShape(body) {
if (!body || typeof body !== "object" || Array.isArray(body)) return false;
if (body.schemaVersion === "sellable-agent-mcp-endpoint-run/v1") {
if (
!exactKeys(body, ENDPOINT_BODY_KEYS) ||
body.audience !== "sellable-agent-mcp-context-proxy/v1" ||
body.principalKind !== "endpoint_run" ||
stableJson(body.routes) !== stableJson(["sellable-mcp"]) ||
!SHA256.test(body.bodyDigest ?? "") ||
!SHA256.test(body.allowedToolDigest ?? "") ||
!/^[1-9][0-9]{0,19}$/.test(body.fence ?? "") ||
!SAFE_ID.test(body.nonce ?? "") ||
!SAFE_ID.test(body.turnId ?? "")
)
return false;
for (const key of [
"runtimeGeneration",
"profileGeneration",
"serviceCredentialGeneration",
"toolPolicyGeneration",
]) {
if (!Number.isSafeInteger(body[key]) || body[key] < 1) return false;
}
for (const key of [
"workspaceId",
"agentId",
"endpointId",
"revisionId",
"conversationId",
"runId",
"attemptId",
"claimId",
"runtimeId",
"profileId",
]) {
if (typeof body[key] !== "string" || !SAFE_ID.test(body[key]))
return false;
}
if (
!Array.isArray(body.allowedTools) ||
!Array.isArray(body.allowedToolNames) ||
body.allowedTools.length > 1024 ||
body.allowedTools.length !== body.allowedToolNames.length ||
body.allowedTools.some(
(tool) =>
!exactKeys(tool, ENDPOINT_TOOL_KEYS) ||
typeof tool.name !== "string" ||
!/^[a-z][a-z0-9_]{0,127}$/.test(tool.name) ||
typeof tool.version !== "string" ||
!SAFE_ID.test(tool.version) ||
!["AUTO", "REQUESTER_CONFIRM", "WORKSPACE_APPROVER", "DENY"].includes(
tool.decision
) ||
!Number.isSafeInteger(tool.generation) ||
tool.generation < 1
) ||
new Set(body.allowedToolNames).size !== body.allowedToolNames.length ||
stableJson(body.allowedTools.map((tool) => tool.name)) !==
stableJson(body.allowedToolNames) ||
sha256(stableJson(body.allowedTools)) !== body.allowedToolDigest
)
return false;
const issuedAt = Date.parse(body.issuedAt);
const expiresAt = Date.parse(body.expiresAt);
return (
Number.isFinite(issuedAt) &&
Number.isFinite(expiresAt) &&
expiresAt > issuedAt
);
}
if (!exactKeys(body, SLACK_BODY_KEYS)) return false;
if (
body.schemaVersion !== "sellable-agent-mcp-turn/v1" ||
body.audience !== "sellable-agent-mcp-context-proxy/v1" ||
!SHA256.test(body.bodyDigest ?? "") ||
!/^[1-9][0-9]{0,19}$/.test(body.fence ?? "") ||
!SAFE_ID.test(body.nonce ?? "") ||
!SAFE_ID.test(body.turnId ?? "")
)
return false;
for (const key of [
"slackGeneration",
"routeGeneration",
"membershipGeneration",
"serviceCredentialGeneration",
"modelCredentialGeneration",
"runtimeGeneration",
]) {
if (!Number.isSafeInteger(body[key]) || body[key] < 1) return false;
}
for (const key of SLACK_EXPECTED_KEYS.filter(
(key) =>
![
"slackGeneration",
"routeGeneration",
"membershipGeneration",
"serviceCredentialGeneration",
"modelCredentialGeneration",
"runtimeGeneration",
"bodyDigest",
"fence",
].includes(key)
)) {
if (
typeof body[key] !== "string" ||
body[key].length < 1 ||
body[key].length > 512
)
return false;
}
const issuedAt = Date.parse(body.issuedAt);
const expiresAt = Date.parse(body.expiresAt);
return (
Number.isFinite(issuedAt) &&
Number.isFinite(expiresAt) &&
expiresAt > issuedAt
);
}
function trustedKey(publicKeyPem, fingerprint) {
if (typeof publicKeyPem !== "string" || !SHA256.test(fingerprint ?? ""))
return null;
if (sha256(publicKeyPem) !== fingerprint) return null;
try {
const key = createPublicKey(publicKeyPem);
return key.asymmetricKeyType === "ed25519" ? key : null;
} catch {
return null;
}
}
function readProtectedJson(pathValue) {
if (!isAbsolute(pathValue) || !existsSync(pathValue)) return null;
try {
const entry = lstatSync(pathValue);
if (
entry.isSymbolicLink() ||
!entry.isFile() ||
(entry.mode & 0o022) !== 0 ||
entry.size < 2 ||
entry.size > 64 * 1024
)
return null;
return JSON.parse(readFileSync(pathValue, "utf8"));
} catch {
return null;
}
}
function descriptorCandidate(descriptorPath, descriptorRoot) {
const root = privateDirectory(descriptorRoot);
if (!root || !directChild(root, descriptorPath)) return null;
try {
const entry = lstatSync(descriptorPath);
if (
entry.isSymbolicLink() ||
!entry.isFile() ||
(entry.mode & 0o077) !== 0 ||
entry.size < 2 ||
entry.size > 64 * 1024
)
return null;
return JSON.parse(readFileSync(descriptorPath, "utf8"));
} catch {
return null;
}
}
export function deriveExpectedMcpTurnBinding({
descriptorPath,
descriptorRoot,
runtimeBindingPath,
}) {
const binding = readProtectedJson(runtimeBindingPath);
const descriptor = descriptorCandidate(descriptorPath, descriptorRoot);
if (
!validateMcpRuntimeBinding(binding) ||
!descriptor ||
!descriptorShape(descriptor.body)
)
return { ok: false, code: "runtime_binding_rejected" };
if (descriptor.body.schemaVersion === "sellable-agent-mcp-endpoint-run/v1") {
for (const key of [
"workspaceId",
"agentId",
"runtimeId",
"profileId",
"runtimeGeneration",
"serviceCredentialGeneration",
]) {
if (stableJson(descriptor.body[key]) !== stableJson(binding[key])) {
return { ok: false, code: "runtime_binding_mismatch" };
}
}
return {
ok: true,
expected: Object.fromEntries(
ENDPOINT_EXPECTED_KEYS.map((key) => [key, descriptor.body[key]])
),
};
}
for (const key of FIXED_TURN_BINDING_KEYS) {
if (stableJson(descriptor.body[key]) !== stableJson(binding[key])) {
return { ok: false, code: "runtime_binding_mismatch" };
}
}
if (
!binding.selectedChannelIds.includes(descriptor.body.channelId) ||
!binding.memberAllowlist.includes(descriptor.body.requesterId)
)
return { ok: false, code: "runtime_binding_mismatch" };
return {
ok: true,
expected: Object.fromEntries(
SLACK_EXPECTED_KEYS.map((key) => [key, descriptor.body[key]])
),
};
}
function validateDescriptor({
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
}) {
if (!exactKeys(descriptor, ["body", "signerGeneration", "signature"])) {
return { ok: false, code: "descriptor_schema_invalid" };
}
if (
!descriptorShape(descriptor.body) ||
!Number.isSafeInteger(descriptor.signerGeneration) ||
descriptor.signerGeneration < 1 ||
typeof descriptor.signature !== "string" ||
descriptor.signature.length < 32
)
return { ok: false, code: "descriptor_schema_invalid" };
const key = trustedKey(trustRootPublicKeyPem, trustRootFingerprint);
if (!key) return { ok: false, code: "descriptor_trust_rejected" };
let verified = false;
try {
verified = verify(
null,
Buffer.from(
`${DESCRIPTOR_SIGNING_DOMAIN}\0${stableJson({
body: descriptor.body,
signerGeneration: descriptor.signerGeneration,
})}`,
"utf8"
),
key,
Buffer.from(descriptor.signature, "base64url")
);
} catch {}
if (!verified) return { ok: false, code: "descriptor_signature_invalid" };
const nowMs = (
now instanceof Date ? now : new Date(now ?? Date.now())
).getTime();
const issuedAt = Date.parse(descriptor.body.issuedAt);
const expiresAt = Date.parse(descriptor.body.expiresAt);
if (
!Number.isFinite(nowMs) ||
nowMs < issuedAt - 5_000 ||
nowMs >= expiresAt
) {
return { ok: false, code: "descriptor_expired" };
}
const expectedKeys =
descriptor.body.schemaVersion === "sellable-agent-mcp-endpoint-run/v1"
? ENDPOINT_EXPECTED_KEYS
: SLACK_EXPECTED_KEYS;
if (!exactKeys(expected, expectedKeys)) {
return { ok: false, code: "descriptor_binding_mismatch" };
}
for (const keyName of expectedKeys) {
if (
stableJson(descriptor.body[keyName]) !== stableJson(expected[keyName])
) {
return { ok: false, code: "descriptor_binding_mismatch" };
}
}
return { ok: true, body: descriptor.body };
}
export function installMcpTurnDescriptor({
descriptorPath,
descriptorRoot,
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
}) {
const root = privateDirectory(descriptorRoot);
if (!root || !directChild(root, descriptorPath)) {
return { ok: false, code: "descriptor_path_rejected" };
}
try {
if (existsSync(descriptorPath))
return { ok: false, code: "descriptor_path_rejected" };
const valid = validateDescriptor({
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
});
if (!valid.ok) return valid;
const fd = openSync(
descriptorPath,
constants.O_CREAT |
constants.O_EXCL |
constants.O_WRONLY |
(constants.O_NOFOLLOW ?? 0),
0o600
);
try {
writeFileSync(fd, `${JSON.stringify(descriptor)}\n`, "utf8");
} finally {
closeSync(fd);
}
chmodSync(descriptorPath, 0o600);
return { ok: true };
} catch {
return { ok: false, code: "descriptor_path_rejected" };
}
}
/**
* Runtime refresh seam: validate first, then replace the direct-child private
* descriptor atomically. A proxy racing the rename observes either the old
* complete descriptor or the new complete descriptor, never partial bytes.
*/
export function replaceMcpTurnDescriptorAtomically({
descriptorPath,
descriptorRoot,
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
}) {
const root = privateDirectory(descriptorRoot);
if (!root || !directChild(root, descriptorPath)) {
return { ok: false, code: "descriptor_path_rejected" };
}
const valid = validateDescriptor({
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
});
if (!valid.ok) return valid;
try {
if (existsSync(descriptorPath)) {
const existing = lstatSync(descriptorPath);
if (
existing.isSymbolicLink() ||
!existing.isFile() ||
(existing.mode & 0o077) !== 0
) {
return { ok: false, code: "descriptor_path_rejected" };
}
}
const temporaryPath = join(
root,
`.${basename(descriptorPath)}.${process.pid}.${randomUUID()}.tmp`
);
let descriptorFd;
try {
descriptorFd = openSync(
temporaryPath,
constants.O_CREAT |
constants.O_EXCL |
constants.O_WRONLY |
(constants.O_NOFOLLOW ?? 0),
0o600
);
writeFileSync(descriptorFd, `${JSON.stringify(descriptor)}\n`, "utf8");
fsyncSync(descriptorFd);
closeSync(descriptorFd);
descriptorFd = undefined;
chmodSync(temporaryPath, 0o600);
renameSync(temporaryPath, descriptorPath);
const rootFd = openSync(root, constants.O_RDONLY);
try {
fsyncSync(rootFd);
} finally {
closeSync(rootFd);
}
return { ok: true };
} finally {
if (descriptorFd !== undefined) closeSync(descriptorFd);
rmSync(temporaryPath, { force: true });
}
} catch {
return { ok: false, code: "descriptor_path_rejected" };
}
}
function claimDescriptor(descriptorPath, root) {
if (!directChild(root, descriptorPath)) return null;
const claimedPath = join(
root,
`.${basename(descriptorPath)}.${process.pid}.${randomUUID()}.claimed`
);
try {
const link = lstatSync(descriptorPath);
if (link.isSymbolicLink() || !link.isFile() || (link.mode & 0o077) !== 0)
return null;
renameSync(descriptorPath, claimedPath);
return claimedPath;
} catch {
return null;
}
}
function downstreamMetadata(body) {
if (body.schemaVersion === "sellable-agent-mcp-endpoint-run/v1") {
return {
kind: "endpoint_run",
workspaceId: body.workspaceId,
agentId: body.agentId,
endpointId: body.endpointId,
revisionId: body.revisionId,
conversationId: body.conversationId,
runId: body.runId,
attemptId: body.attemptId,
claimId: body.claimId,
runtimeId: body.runtimeId,
profileId: body.profileId,
runtimeGeneration: body.runtimeGeneration,
profileGeneration: body.profileGeneration,
serviceCredentialGeneration: body.serviceCredentialGeneration,
toolPolicyGeneration: body.toolPolicyGeneration,
allowedTools: body.allowedTools,
allowedToolNames: body.allowedToolNames,
allowedToolDigest: body.allowedToolDigest,
fence: body.fence,
turnId: body.turnId,
bodyDigest: body.bodyDigest,
};
}
return {
channelId: body.channelId,
requesterId: body.requesterId,
providerRequestId: body.providerRequestId,
};
}
function burnNonce(consumedRoot, nonce) {
const root = privateDirectory(consumedRoot);
if (!root) return false;
const marker = join(root, `${sha256(nonce)}.consumed`);
let fd;
try {
fd = openSync(
marker,
constants.O_CREAT |
constants.O_EXCL |
constants.O_WRONLY |
(constants.O_NOFOLLOW ?? 0),
0o600
);
writeFileSync(fd, `${new Date().toISOString()}\n`, "utf8");
return true;
} catch {
return false;
} finally {
if (fd !== undefined) closeSync(fd);
}
}
const endpointSessions = new WeakMap();
export function createMcpEndpointSession() {
const handle = Object.freeze({ kind: "sellable-mcp-endpoint-session/v1" });
endpointSessions.set(handle, { activated: false, body: null });
return handle;
}
export function mcpEndpointSessionActivated(session) {
return endpointSessions.get(session)?.activated === true;
}
function endpointSessionBody(session) {
return endpointSessions.get(session)?.body ?? null;
}
function endpointSessionBodyMatches(left, right) {
return ENDPOINT_EXPECTED_KEYS.every(
(key) => stableJson(left[key]) === stableJson(right[key])
);
}
function activeEndpointSessionBody(session, now) {
const state = endpointSessions.get(session);
if (!state?.body) return { ok: false, code: "descriptor_missing" };
const nowMs = (
now instanceof Date ? now : new Date(now ?? Date.now())
).getTime();
if (!Number.isFinite(nowMs) || nowMs >= Date.parse(state.body.expiresAt)) {
return { ok: false, code: "descriptor_expired" };
}
return { ok: true, body: state.body };
}
function activateOrRefreshEndpointSession({
session,
descriptorPath,
descriptorRoot,
consumedRoot,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
}) {
const state = endpointSessions.get(session);
if (!state) return { ok: false, code: "endpoint_session_rejected" };
const root = privateDirectory(descriptorRoot);
if (!root || !directChild(root, descriptorPath)) {
return { ok: false, code: "descriptor_path_rejected" };
}
if (!existsSync(descriptorPath))
return activeEndpointSessionBody(session, now);
const claimedPath = claimDescriptor(descriptorPath, root);
if (!claimedPath) return { ok: false, code: "descriptor_claim_failed" };
try {
let descriptor;
try {
descriptor = JSON.parse(readFileSync(claimedPath, "utf8"));
} catch {
return { ok: false, code: "descriptor_schema_invalid" };
}
if (!expected) return { ok: false, code: "descriptor_binding_mismatch" };
const valid = validateDescriptor({
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
});
if (!valid.ok) return valid;
if (valid.body.schemaVersion !== "sellable-agent-mcp-endpoint-run/v1") {
if (state.body)
return { ok: false, code: "endpoint_session_binding_mismatch" };
return { ok: false, code: "endpoint_session_not_applicable" };
}
if (state.body && !endpointSessionBodyMatches(state.body, valid.body)) {
// Hermes deliberately reuses one stdio MCP transport across sequential
// endpoint runs. Rotate that transport in place after proving the next
// server-signed descriptor against the runtime binding. Returning a
// synthetic transport-expired error here made Hermes mark the Sellable
// MCP unavailable mid-conversation, so the following reviewed Calendar
// read never reached the backend. The nonce is burned before the session
// pointer moves, preserving the exact same single-use fence as first
// activation; a stale or replayed descriptor still fails closed.
if (!burnNonce(consumedRoot, valid.body.nonce)) {
return { ok: false, code: "descriptor_replayed" };
}
state.body = Object.freeze({ ...valid.body });
state.activated = true;
return { ok: true, body: state.body };
}
if (!burnNonce(consumedRoot, valid.body.nonce)) {
return { ok: false, code: "descriptor_replayed" };
}
state.body = Object.freeze({ ...valid.body });
state.activated = true;
return { ok: true, body: state.body };
} finally {
rmSync(claimedPath, { force: true });
}
}
export async function authorizeMcpToolCall({
descriptorPath,
descriptorRoot,
consumedRoot,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
request,
now,
callTool,
session = /** @type {any} */ (null),
}) {
if (
!request ||
request.method !== "tools/call" ||
!request.params ||
typeof request.params !== "object" ||
Array.isArray(request.params)
)
return { ok: false, code: "tool_request_invalid" };
if (session) {
const valid = activateOrRefreshEndpointSession({
session,
descriptorPath,
descriptorRoot,
consumedRoot,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
});
if (!valid.ok) return valid;
const downstream = {
...request,
params: {
...request.params,
_meta: { sellableAgent: downstreamMetadata(valid.body) },
},
};
return { ok: true, result: await callTool(downstream) };
}
const root = privateDirectory(descriptorRoot);
if (!root || !directChild(root, descriptorPath)) {
return { ok: false, code: "descriptor_path_rejected" };
}
const claimedPath = claimDescriptor(descriptorPath, root);
if (!claimedPath) return { ok: false, code: "descriptor_missing" };
try {
let descriptor;
try {
descriptor = JSON.parse(readFileSync(claimedPath, "utf8"));
} catch {
return { ok: false, code: "descriptor_schema_invalid" };
}
const valid = validateDescriptor({
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
});
if (!valid.ok) return valid;
if (!burnNonce(consumedRoot, valid.body.nonce)) {
return { ok: false, code: "descriptor_replayed" };
}
const downstream = {
...request,
params: {
...request.params,
_meta: {
sellableAgent: downstreamMetadata(valid.body),
},
},
};
const result = await callTool(downstream);
return { ok: true, result };
} finally {
rmSync(claimedPath, { force: true });
}
}
export async function authorizeMcpToolList({
descriptorPath,
descriptorRoot,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
request,
now,
callTool,
consumedRoot,
session = /** @type {any} */ (null),
}) {
if (!request || request.method !== "tools/list") {
return { ok: false, code: "tool_request_invalid" };
}
if (session) {
const valid = activateOrRefreshEndpointSession({
session,
descriptorPath,
descriptorRoot,
consumedRoot,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
});
if (!valid.ok) return valid;
const downstream = {
...request,
params: {
...(request.params ?? {}),
_meta: { sellableAgent: downstreamMetadata(valid.body) },
},
};
return { ok: true, result: await callTool(downstream) };
}
const descriptor = descriptorCandidate(descriptorPath, descriptorRoot);
if (!descriptor) return { ok: false, code: "descriptor_missing" };
const valid = validateDescriptor({
descriptor,
trustRootPublicKeyPem,
trustRootFingerprint,
expected,
now,
});
if (!valid.ok) return valid;
if (valid.body.schemaVersion !== "sellable-agent-mcp-endpoint-run/v1") {
return { ok: true, result: await callTool(request) };
}
const downstream = {
...request,
params: {
...(request.params ?? {}),
_meta: { sellableAgent: downstreamMetadata(valid.body) },
},
};
return { ok: true, result: await callTool(downstream) };
}
function parseDownstreamArgs(value) {
if (value === undefined || value === "") return [];
try {
const parsed = JSON.parse(value);
if (
!Array.isArray(parsed) ||
parsed.length > 32 ||
parsed.some(
(item) =>
typeof item !== "string" || item.length > 4096 || item.includes("\0")
)
)
return null;
return parsed;
} catch {
return null;
}
}
function parseJsonRpcLine(line) {
if (
typeof line !== "string" ||
Buffer.byteLength(line) > MAX_JSONRPC_LINE_BYTES
) {
return null;
}
try {
const message = JSON.parse(line);
return message &&
typeof message === "object" &&
!Array.isArray(message) &&
message.jsonrpc === "2.0"
? message
: null;
} catch {
return null;
}
}
function isHermesSlackToolCall(request) {
if (
request?.method !== "tools/call" ||
!request.params ||
typeof request.params !== "object" ||
Array.isArray(request.params)
)
return false;
const meta = request.params._meta;
if (!exactKeys(meta, ["sellableAgent"])) return false;
const actor = meta.sellableAgent;
const actorKeys =
actor && typeof actor === "object" ? Object.keys(actor) : [];
if (
!exactKeys(
actor,
actorKeys.includes("sessionId")
? ["requesterId", "channelId", "providerRequestId", "sessionId"]
: ["requesterId", "channelId", "providerRequestId"]
)
)
return false;
return Object.values(actor).every(
(value) => typeof value === "string" && SAFE_ID.test(value)
);
}
export function endpointHermesSessionId(body) {
if (body?.schemaVersion !== "sellable-agent-mcp-endpoint-run/v1") return null;
return `sellable_endpoint_${sha256(
`${body.conversationId}:${body.runId}:${body.attemptId}`
).slice(0, 32)}`;
}
export function endpointMcpDescriptorPath(descriptorPath, sessionId) {
if (
!isAbsolute(descriptorPath ?? "") ||
typeof sessionId !== "string" ||
!SAFE_ID.test(sessionId)
) {
return null;
}
return join(dirname(descriptorPath), `endpoint-${sha256(sessionId)}.json`);
}
function requestEndpointHermesSessionId(request) {
if (request?.method !== "tools/call" && request?.method !== "tools/list") {
return null;
}
const meta = request?.params?._meta;
if (!exactKeys(meta, ["sellableEndpoint"])) return null;
const endpoint = meta.sellableEndpoint;
if (!exactKeys(endpoint, ["sessionId"])) return null;
return typeof endpoint.sessionId === "string" &&
SAFE_ID.test(endpoint.sessionId)
? endpoint.sessionId
: null;
}
function isExactEndpointHermesSessionToolCall(request, body) {
if (!isHermesSlackToolCall(request)) return false;
const expectedSessionId = endpointHermesSessionId(body);
return Boolean(
expectedSessionId &&
request.params._meta.sellableAgent.sessionId === expectedSessionId
);
}
function messageIdKey(id) {
return id === undefined ? null : stableJson(id);
}
function writeJsonLine(stream, message) {
return new Promise((resolve, reject) => {
const bytes = `${JSON.stringify(message)}\n`;
const onError = (error) => {
stream.off("error", onError);
reject(error);
};
stream.once("error", onError);
const complete = () => {
stream.off("error", onError);
resolve();
};
if (stream.write(bytes)) complete();
else stream.once("drain", complete);
});
}
export async function runMcpContextProxyStdio({
input = process.stdin,
output = process.stdout,
errorOutput = process.stderr,
env = process.env,
spawnProcess = spawn,
} = {}) {
const descriptorPath = env.SELLABLE_AGENT_TURN_DESCRIPTOR_PATH;
const descriptorRoot =
descriptorPath && isAbsolute(descriptorPath)
? dirname(descriptorPath)
: null;
const consumedRoot = env.SELLABLE_AGENT_TURN_CONSUMED_ROOT;
const runtimeBindingPath = env.SELLABLE_AGENT_MCP_RUNTIME_BINDING_PATH;
const trustRootPath = env.SELLABLE_AGENT_MCP_TRUST_ROOT_PATH;
const trustRootFingerprint = env.SELLABLE_AGENT_MCP_TRUST_ROOT_FINGERPRINT;
const downstreamCommand = env.SELLABLE_AGENT_MCP_DOWNSTREAM_COMMAND;
const downstreamArgs = parseDownstreamArgs(
env.SELLABLE_AGENT_MCP_DOWNSTREAM_ARGS_JSON
);
if (
!descriptorRoot ||
!privateDirectory(descriptorRoot) ||
!privateDirectory(consumedRoot) ||
!isAbsolute(runtimeBindingPath ?? "") ||
!isAbsolute(trustRootPath ?? "") ||
!isAbsolute(downstreamCommand ?? "") ||
!SHA256.test(trustRootFingerprint ?? "") ||
!downstreamArgs
)
throw new Error("mcp_proxy_configuration_rejected");
let trustRootPublicKeyPem;
try {
const entry = lstatSync(trustRootPath);
if (
entry.isSymbolicLink() ||
!entry.isFile() ||
(entry.mode & 0o022) !== 0
) {
throw new Error("trust_root_rejected");
}
trustRootPublicKeyPem = readFileSync(trustRootPath, "utf8");
} catch {
throw new Error("mcp_proxy_trust_root_rejected");
}
if (!trustedKey(trustRootPublicKeyPem, trustRootFingerprint)) {
throw new Error("mcp_proxy_trust_root_rejected");
}
const child = spawnProcess(downstreamCommand, downstreamArgs, {
stdio: ["pipe", "pipe", "pipe"],
env,
shell: false,
});
const pending = new Map();
const childLines = createInterface({ input: child.stdout });
const inputLines = createInterface({ input });
child.stderr.on("data", () => {});
child.on("exit", (code) => {
for (const { reject } of pending.values()) {
reject(new Error(`mcp_downstream_exited:${code}`));
}
pending.clear();
});
const childReader = (async () => {
for await (const line of childLines) {
const message = parseJsonRpcLine(line);
if (!message) throw new Error("mcp_downstream_protocol_rejected");
const key = messageIdKey(message.id);
const waiter = key === null ? null : pending.get(key);
if (waiter) {
pending.delete(key);
waiter.resolve(message);
} else {
await writeJsonLine(output, message);
}
}
})();
const downstreamCall = async (request) => {
const key = messageIdKey(request.id);
if (key === null || pending.has(key)) {
throw new Error("mcp_request_id_rejected");
}
const response = new Promise((resolve, reject) => {
pending.set(key, { resolve, reject });
});
try {
await writeJsonLine(child.stdin, request);
} catch (error) {
pending.delete(key);
throw error;
}
return response;
};
const legacyEndpointSession = createMcpEndpointSession();
const endpointSessionsByHermesId = new Map();
for await (const line of inputLines) {
const request = parseJsonRpcLine(line);
if (!request) throw new Error("mcp_upstream_protocol_rejected");
const requestNow = Date.now();
for (const [sessionId, session] of endpointSessionsByHermesId) {
const body = endpointSessionBody(session);
if (!body || requestNow >= Date.parse(body.expiresAt)) {
endpointSessionsByHermesId.delete(sessionId);
}
}
const endpointHermesId = requestEndpointHermesSessionId(request);
const requestDescriptorPath = endpointHermesId
? endpointMcpDescriptorPath(descriptorPath, endpointHermesId)
: descriptorPath;
if (!requestDescriptorPath) {
await writeJsonLine(output, {
jsonrpc: "2.0",
id: request.id ?? null,
error: {
code: -32001,
message: "endpoint_session_rejected",
data: { code: "endpoint_session_rejected" },
},
});
continue;
}
let endpointSession = legacyEndpointSession;
if (endpointHermesId) {
endpointSession = endpointSessionsByHermesId.get(endpointHermesId);
if (!endpointSession) {
endpointSession = createMcpEndpointSession();
endpointSessionsByHermesId.set(endpointHermesId, endpointSession);
}
}
const candidate = existsSync(requestDescriptorPath)
? descriptorCandidate(requestDescriptorPath, descriptorRoot)
: null;
const activeBody = endpointSessionBody(endpointSession);
const endpointBody =
candidate?.body?.schemaVersion === "sellable-agent-mcp-endpoint-run/v1"
? candidate.body
: activeBody?.schemaVersion === "sellable-agent-mcp-endpoint-run/v1"
? activeBody
: null;
const endpointMode = Boolean(
mcpEndpointSessionActivated(endpointSession) || endpointBody
);
if (
endpointHermesId &&
endpointBody &&
endpointHermesSessionId(endpointBody) !== endpointHermesId
) {
await writeJsonLine(output, {
jsonrpc: "2.0",
id: request.id ?? null,
error: {
code: -32001,
message: "endpoint_session_binding_mismatch",
data: { code: "endpoint_session_binding_mismatch" },
},
});
continue;
}
if (endpointHermesId && !endpointMode) {
await writeJsonLine(output, {
jsonrpc: "2.0",
id: request.id ?? null,
error: {
code: -32001,
message: "descriptor_missing",
data: { code: "descriptor_missing" },
},
});
continue;
}
// The patched Hermes bridge adds request-scoped metadata from task-local
// ContextVars; the model controls only `arguments` and cannot author MCP
// `_meta`. Genuine Slack calls pass through with their actor identity.
// API endpoint calls select their own signed descriptor/session above.
if (
isHermesSlackToolCall(request) &&
!(
endpointMode &&
isExactEndpointHermesSessionToolCall(request, endpointBody)
)
) {
await writeJsonLine(child.stdin, request);
continue;
}
if (request.method === "tools/list" && endpointMode) {
const expected = existsSync(requestDescriptorPath)
? deriveExpectedMcpTurnBinding({
descriptorPath: requestDescriptorPath,
descriptorRoot,
runtimeBindingPath,
})
: { ok: true, expected: null };
const authorized = expected.ok
? await authorizeMcpToolList({
descriptorPath: requestDescriptorPath,
descriptorRoot,
consumedRoot,
trustRootPublicKeyPem,
trustRootFingerprint,
expected: expected.expected,
request,
now: new Date(),
callTool: downstreamCall,
session: endpointSession,
})
: expected;
if (authorized.ok) await writeJsonLine(output, authorized.result);
else {
await writeJsonLine(output, {
jsonrpc: "2.0",
id: request.id ?? null,
error: {
code: -32001,
message: authorized.code,
data: { code: authorized.code },
},
});
}
continue;
}
if (request.method !== "tools/call") {
await writeJsonLine(child.stdin, request);
continue;
}
// The existing Slack bridge remains the task-local authority when no
// server-minted endpoint descriptor is installed. Installing this proxy
// for endpoint runs must not weaken or fabricate that Slack path.
if (!existsSync(requestDescriptorPath) && !endpointMode) {
await writeJsonLine(child.stdin, request);
continue;
}
const expected = existsSync(requestDescriptorPath)
? deriveExpectedMcpTurnBinding({
descriptorPath: requestDescriptorPath,
descriptorRoot,
runtimeBindingPath,
})
: { ok: true, expected: null };
const authorized = expected.ok
? await authorizeMcpToolCall({
descriptorPath: requestDescriptorPath,
descriptorRoot,
consumedRoot,
trustRootPublicKeyPem,
trustRootFingerprint,
expected: expected.expected,
request,
now: new Date(),
callTool: downstreamCall,
...(endpointMode ? { session: endpointSession } : {}),
})
: expected;
if (authorized.ok) {
await writeJsonLine(output, authorized.result);
} else {
await writeJsonLine(output, {
jsonrpc: "2.0",
id: request.id ?? null,
error: {
code: -32001,
message: authorized.code,
data: { code: authorized.code },
},
});
}
}
child.stdin.end();
await childReader;
return { ok: true };
}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
runMcpContextProxyStdio().catch(() => {
process.stderr.write("sellable-agent MCP context proxy failed closed\n");
process.exitCode = 70;
});
}