Repository navigation
Integrations Wassette
Experimental: this works and is tested, but may change and gets less hardening than the stable core. Tested in CI: Wassette's tools and arguments as its source names them, served to the real MCP gateway and decided by a real signer under this page's policy. Checked once by hand against the Wassette 0.8.0 binary (the run below), not in CI (#312).
Wassette is an MCP server from Microsoft that runs each tool as a WebAssembly component in Wasmtime. A component can use only the files, hosts and environment variables its permissions allow. Wassette's built-in tools load components and grant those permissions while it runs. Put Wassette behind the MCP gateway and every call the agent makes to it, built-in or component, is decided, recorded and completed by the signer, and a policy can hold each load and grant for a person.
| Wassette | Tracekit | |
|---|---|---|
| What it does | Runs each tool in a Wasm sandbox limited to that component's permissions | Decides each call before it reaches Wassette, holds loads and grants for a person, and signs a record of every call, approval and result |
| Where | An MCP server: stdio (wassette run) or Streamable HTTP (wassette serve) |
The MCP gateway in front of it, and a signer outside the agent |
| What a third party can check later | Its logs | A signed, hash-chained bundle, verified offline |
Wassette (0.8.0) serves MCP two ways, and the gateway reaches both:
| Wassette | Gateway upstream |
|---|---|
wassette run: stdio |
command: [wassette, run]: the gateway starts it, as its own user |
wassette serve --streamable-http: Streamable HTTP at http://127.0.0.1:9001/mcp (--bind-address changes it) |
url: http://127.0.0.1:9001/mcp |
The gateway sends plain http only to localhost, 127.0.0.1 or ::1, so run wassette serve on the gateway's host
(or in its pod), on its default loopback address. Agents connect to the gateway, never to Wassette: an agent that can
reach Wassette itself calls around the gateway.
Choose how to run Wassette by whether the agent may change its tools.
List the components and their permissions in a Wassette provisioning manifest, and turn the built-in tools off:
# wassette-manifest.yaml
version: 1
components:
- uri: file:///opt/wassette/fetch_rs.wasm # a component you reviewed; oci:// and https:// also work
name: fetch
permissions:
network:
allow:
- host: api.github.comwassette serve --streamable-http --manifest wassette-manifest.yaml --disable-builtin-tools# mcp-gateway.yaml (the rest as in the MCP gateway's docs)
upstreams:
- name: wassette
url: http://127.0.0.1:9001/mcp-
--manifestloads the listed components with their permissions when Wassette starts. Wassette exits if one fails to load (--continue-on-provisioning-failureserves the rest). Onlywassette servetakes it. -
--disable-builtin-toolsdrops the built-in tools from the tool list and refuses a call to one withBuilt-in tools are disabled. Bothrunandservetake it.
The agent then sees only the components' tools, and their permissions change only when you edit the manifest and restart Wassette. Tracekit decides and records every call to them.
When the agent loads components and asks for permissions as it works (Wassette's default), keep the built-in tools and have the policy hold the ones that widen what a component may do. They are, as Wassette names them:
| Built-in tool | Arguments | Effect |
|---|---|---|
load-component |
path: a file://, oci:// or https:// URI |
adds a component and its tools |
grant-storage-permission |
component_id, details: {uri: "fs://…", access: ["read"] or ["read", "write"]}
|
lets it read or write a path |
grant-network-permission |
component_id, details: {host}
|
lets it reach a host |
grant-environment-variable-permission |
component_id, details: {key}
|
lets it read an environment variable |
unload-component, revoke-storage-permission, revoke-network-permission, revoke-environment-variable-permission, reset-permission
|
removes a component or a permission | |
list-components, get-policy, search-components
|
reads |
The upstream is command: [wassette, run], or url: as above with wassette serve --streamable-http. Add one rule
to the signer's policy (here /etc/tracekit/policy.yaml, which reaches the server pack as packs/server.yaml,
policy):
version: 'wassette-1'
description: the server pack, with Wassette's component loads and permission grants held for a person
extends: packs/server.yaml
ask:
- id: WASSETTE-GRANT
tool: '(mcp:[^/]+/|mcp__.+__)?(load-component|grant-[a-z-]+-permission)'
pattern: '^'
approval: {executor: t2}
reason: loading a Wassette component or granting it a permission-
toolmatches the name the gateway decides (mcp:wassette/grant-network-permission), whatever you call the upstream, and the names other MCP clients give the same tool (mcp__wassette__grant-network-permissionin Claude Code). -
executor: t2: the gateway runs the signer's copy of the approved arguments (approvals). - The other tools run and are recorded; the server pack flags every MCP call (
TK-F006).
Each load and grant then waits for a person, answered from outside the agent:
tracekit approvals show apr-… # the component and the path, host or variable, in full
tracekit approvals approve apr-… # or: tracekit approvals reject apr-…
The approval is bound to that call's exact arguments and used once. A rejected or unanswered one (approval_wait_s)
is an isError result for the agent, and Wassette never sees the call. A run against Wassette 0.8.0 with this policy:
wassette__load-component {"path": "file:///…/fetch_rs.wasm"}
held, approved -> {"status":"component loaded successfully","id":"fetch_rs","tools":["fetch"]}
wassette__grant-network-permission {"component_id": "fetch_rs", "details": {"host": "example.com"}}
held, rejected -> Tool call blocked by policy: WASSETTE-GRANT, TK-F006: approval rejected
wassette__fetch {"url": "https://example.com/"}
allowed (flagged TK-F006) -> {"err":"ErrorCode::HttpRequestDenied"}
-
Records: every call to Wassette as
mcp:<upstream>/<tool>, with its decision, any approval and its result (sourcegateway, tier T2), and each tool listing as untrusted input, as for any MCP gateway upstream. A bundle shows each load and grant, the rule that held it (WASSETTE-GRANT) and who approved it; its arguments (the component, the path, host or variable) are committed to, not stored in the bundle (format v2). -
Records as
ok: a component's own failure that Wassette returns as a normal result. A request to a host the component may not reach comes back as{"err":"ErrorCode::HttpRequestDenied"}withisErrorfalse. -
Doesn't see: what a component does inside Wassette (the files it reads, the requests it makes), or permissions
set another way: the manifest, the
wassette permissioncommand, the component's policy file, or an MCP client connected to Wassette directly. The manifest isn't signed into the run. - A grant outlives its call. Wassette saves it with the component, so it applies to every later call of that component, from every agent and run behind the gateway, after restarts too, until it is revoked.
-
New tools appear on the next listing. After a load, Wassette sends
notifications/tools/list_changed, which the gateway doesn't relay (MCP gateway limits); the agent sees the new tools the next time its client lists them.
Limits lists these with what to do.
Generated from docs/ at v1.4.1. Edit the docs in the repository, not here.
Get started
- Quickstart: the v2 signer
- Quickstarts
- Quickstart: Claude Agent SDK
- Quickstart: a custom agent
- Quickstart: LangChain and LangGraph
- Quickstart: MCP client
- Quickstart: OpenAI Agents SDK
- Coding agents other than Claude Code
- tracekit doctor
- Walkthrough: Tracekit end to end
How it works
- How Tracekit works
- Overview
- The life of a tool call
- The evidence format
- Verification and assurance
- Witnesses and monitoring
- Policy
- Approvals
- Detection and containment
- Capture and completeness
- Custody
- Provenance and tracekit why
- Deployment and isolation
- Storage, durability and performance
- Integrations
- Security model
- Architecture
- tracekit why: architecture
Integrations
- Integrations
- Adapters
- OpenTelemetry
- Remote clients
- Kubernetes agent-sandbox
- agentgateway
- agentsh and Tracekit
- Browser Use
- Claude Agent SDK
- Claude Code's sandbox
- Codex's sandbox
- CrewAI
- Docker MCP Gateway
- E2B
- Falco
- Gemini CLI's sandbox
- Google ADK
- Haystack
- LangChain v1
- LiteLLM
- LlamaIndex
- MCP client
- microsandbox
- Microsoft Agent Framework
- OpenAI Agents SDK
- NVIDIA OpenShell
- Pydantic AI
- sandbox-runtime's proxy on its own
- Strands Agents
- Tetragon
- Vercel AI SDK
- Wassette
Policy and approvals
- Policy reference
- Approvals
- Findings
- Reading the model's reasoning
- Incidents and containment
- Webhooks
Deploy and operate
- Deploying the signer
- The signer as a container
- The signer on Kubernetes
- The compose stack
- Identity
- Tool executor
- MCP gateway
- LLM gateway
- Egress observation
- Witnesses
- Log monitor
- Record-key issuer
- Signer observability
- Viewer
- tracekit why: causal investigation and replay
- Migrating
- Platforms
Verify the evidence
- Reading a v2 verify report
- Evidence format v2
- Auditor guide
- Sample evidence bundle
- Signing
- What Tracekit guarantees
Security and privacy
- Threat model: the v2 signer
- Threat model: the v1 laptop signer
- HTTP security checklist
- Threat-model review packet
- Privacy
- Known limits and trade-offs
- What's stable
Compliance
- Compliance mapping
- EU AI Act
- ISO/IEC 42001
- NIST AI RMF and the Generative AI Profile
- OWASP Top 10 lists for LLM and agentic applications
Evaluation
Demos
- Demos
- Agent approvers within bounds
- Completeness and tamper evidence
- Detection and containment
- Network coverage: an egress observer
- Guardrails: allow, deny, or ask a person
- MCP tools, gated and recorded
- Prompt injection held by provenance
- Why: which input caused the action
Help