condensate docs
Build and connect / Condensate

Connect tools and hooks

Expose tools through MCP and apply harness policy through hook events.

Middleware lets a compatible agent harness reach tools through a common MCP endpoint and send lifecycle events to policy hooks. It is useful when you want to connect an existing harness while keeping its own model loop.

Two connections, two responsibilities
Tool access
HarnessRequests a tool
MCP endpointChecks and routes the call
UpstreamExecutes the tool
Policy hooks
Harness eventTriggers a wired hook
PolicyProduces a verdict
Hook shimReturns it to the harness
MCP routes tool calls. Hooks carry lifecycle events and decisions. Both paths must be configured in the client harness.

Connect an upstream tool server

Start with an HTTP MCP server you already run. Replace the example URL with that server's address. Middleware also supports stdio upstreams; this example uses HTTP to keep the connection visible.

export CONDENSATE_HOST=127.0.0.1
export CONDENSATE_MCP_UPSTREAMS='[{"name":"tools","url":"http://127.0.0.1:9000/mcp","auth":"none"}]'
export CONDENSATE_LOCAL_PRINCIPAL_ID=local-dev
export CONDENSATE_LOCAL_API_KEY="$(openssl rand -hex 32)"

bun apps/middleware/backend/index.ts

Run this from the repository root. The backend's default port is 4787. The key authenticates your client to middleware. In this example, auth: "none" describes the connection from middleware to the upstream server; choose the appropriate authentication for your own upstream.

Inspect the tool catalog

In another terminal, set CONDENSATE_LOCAL_API_KEY to the same key used by the backend. Then request the catalog:

curl --fail-with-body http://127.0.0.1:4787/mcp \
  -H "x-condensate-key: $CONDENSATE_LOCAL_API_KEY" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

A successful JSON-RPC response contains result.tools. Aggregated tool names take the form <upstream>__<tool>, so a read tool on the tools upstream becomes tools__read.

Configure your harness's HTTP MCP client with:

SettingValue
URLhttp://127.0.0.1:4787/mcp
Headerx-condensate-key: YOUR_LOCAL_KEY

The client configuration format depends on the harness. Use its supported HTTP MCP setup rather than copying one client's configuration into another.

Add lifecycle hooks

MCP supplies tool access. A hook integration separately connects the harness's events to middleware policy. The hook shim translates the event, receives a verdict, and returns it using the harness's own contract.

Required policy checks fail closed; optional enhancements can fail open according to their hook implementation. The TypeSafe-backed steering judge participates in this policy path as a classifier. The task's generative model and Condensate's model router are separate components.

Batch tool work with code mode

Code mode provides tool-catalog search, generated TypeScript signatures, and a QuickJS execution sandbox. A program can call several tools and return a concise result, avoiding a separate model round trip for every intermediate value.

Without batching:
model → tool A → model → tool B → model → tool C → model

With a code-mode program:
model → program calls A, B, C → selected result → model

This is an execution sketch, not code to paste into the sandbox. Code mode is off by default and gated by CONDENSATE_CODE_MODE and CONDENSATE_CODE_MODE_PRINCIPALS. Calls through its call(tool, args) bridge pass through normal MCP policy and accounting. Native SDK namespaces have their own paths and caps.

Choose the right connection

Use middleware to add a tool and policy layer to an existing harness. Use the runtime SDK when your application needs durable Condensate threads, event recovery, and task controls.

Condensate developer documentation · Source ba6d28952e