Repository navigation
prd phase 2.3 callable functions
Status: not started. Research:
research-phase-2.3-sandbox.md. Technical design: to be written (design-phase-2.3-callable-functions.md) before implementation, per the feature-development workflow.
Some capabilities an agent needs are not available as MCP servers — they live behind cloud-vendor HTTP APIs (e.g. a document-translation API, an OCR service, an image generator, a proprietary search endpoint). Today there is no way to expose those to an agent tool through Harness Nexus: the proxy only aggregates upstream MCP servers. An admin who wants to give agents access to a vendor API has no in-product path and must run a separate MCP wrapper server. There needs to be a way for an admin to author a small function that calls the vendor API and expose it as an MCP tool, running safely on the Harness Nexus host.
Admin-authored JavaScript functions, stored and managed in Harness Nexus, compiled
and executed in a sandbox, and exposed as MCP tools alongside upstream tools
through the same profile-based proxy. The sandbox has no filesystem or
subprocess access and can only make network calls to an admin-specified host
allowlist, mediated by a host-injected ctx.fetch. Functions are bundled into
profiles like MCP servers, so an agent tool connecting with ?profile=<id> sees
both upstream tools and callable-function tools in one aggregated surface.
- As an admin, I want to author a JS function that calls a vendor API, so that agents can use it without a separate MCP server.
- As an admin, I want the function's network calls restricted to a host allowlist, so that a buggy or malicious script can't exfiltrate data.
- As an admin, I want the sandbox to have no filesystem or subprocess access, so that the host is protected.
- As an admin, I want to define the function's input schema, so that agents know what arguments to pass.
- As an admin, I want to set a per-call timeout, so that a hung vendor API doesn't block the proxy.
- As an admin, I want to bind a credential to a callable-function, so that it can authenticate to the vendor without the script seeing the secret.
- As an admin, I want to test-run a function from the UI before publishing, so that I can verify it works.
- As an admin, I want to disable a function without deleting it, so that I can take a broken tool offline temporarily.
- As a user, I want callable-functions included in a profile alongside MCP servers, so that my agent sees one unified tool set.
- As an agent tool, I want to call a callable-function the same way I call an upstream tool, so that the transport is transparent.
- As an admin, I want only admins to author functions, so that untrusted users can't run arbitrary sandboxed code.
- As an operator, I want each invocation audited, so that I can investigate sensitive API calls.
- As a developer, I want callable-functions to plug into the existing proxy without changing the upstream connection pool, so that the McpRegistry stays focused.
- As an admin, I want input validated before entering the sandbox, so that the script never sees malformed arguments.
- As an operator, I want a callable-function crash isolated, so that one bad script doesn't take down the proxy.
-
Sandbox:
isolated-vm(V8 native Isolate) — chosen overnode:vm(escapable),vm2(deprecated), andworker_threads(not a security boundary). Keeps V8 performance; fatal errors don't crash the host. Backup option:quickjs-emscriptenif native builds are a hard blocker. Seeresearch-phase-2.3-sandbox.md. -
Dedicated
CallableFunctionentity (not reuse of the deferredResourcemodule). Carriessource,inputSchema,allowedHosts,timeoutMs,scope,ownerId,status.ResourceKind = 'command'left as a forward-compat slot. -
ToolSourceabstraction: an interface (listTools,callTool) with two implementations —McpRegistry(existing upstream pool) and a newCallableRegistry(sandboxed scripts). The proxy merges both;callToolroutes by namespace prefix (<server>__→ McpRegistry,fn__→ CallableRegistry). McpRegistry's connection semantics stay untouched. -
Network via injected
ctx.fetch: the script receives only a host-proxied fetch that enforcesallowedHosts. The realfetchnever enters the sandbox. Credentials are decrypted host-side and added to outgoing headers by the proxy, so plaintext secrets stay outside the sandbox. -
Host-side input validation:
argsvalidated againstinputSchema(zod) before the sandbox runs; script-internal validation is not trusted. - Admin-only authoring: creation/mutation restricted to admins (consistent with the established 2.3 constraint). Scope still global/personal for profile referencing.
-
Profile integration:
profileEntryInputSchemaextended to accept callable-function entries;profileEntriesFor()returns callable-function ids alongsideserverIds;buildSessionregisters them on the same per-sessionSdkMcpServer. -
Config: new env fields
sandboxTimeoutMs,callableFunctionAllowedHosts(instance-level default), following the existingconfig.tspattern. - Migration: a new SQLite table for callable-functions.
- HTTP smoke tests: callable-function CRUD (admin-only), profile entry with a
callable-function, the function exposed as a tool via the proxy,
ctx.fetchallowlist enforcement (blocked host → error), timeout enforcement, crash isolation (one bad function doesn't break others). - Sandbox behavior tested at the API seam (call the tool, assert the response/error), not by inspecting sandbox internals.
- Prior art: the Phase 2.2 smoke tests for profile routing and
/mcpproxy gating.
- A full code editor with syntax checking in the UI (a textarea + test-run is sufficient for 2.3).
- Non-admin authoring of functions.
- Functions that need filesystem or subprocess access (deliberately impossible).
- Reusing the
Resourceaggregate / building the generic Resource module. - Sharing callable-functions via the ECC/Superpower import pipeline.
- Per-call credential selection beyond a single bound credential.
- Suggested sub-phasing: 2.3.1 core (entity + CRUD + executor + ToolSource integration + smoke tests, no UI) then 2.3.2 UI (management page + profile picker). Confirm scope when starting.
- The full technology comparison (isolated-vm vs QuickJS-WASM vs others) and the
network-access design are in
research-phase-2.3-sandbox.md.