Run your first component
Every act subcommand accepts the same three forms of reference: a local path, an HTTP(S) URL,
or an OCI registry ref. We’ll use the published SQLite component at actpkg.dev/library/sqlite.
Inspect
Section titled “Inspect”act info actpkg.dev/library/sqlite --toolsPrints the component’s metadata (name, version, description), its declared capabilities,
and every tool it exposes.
Call a tool directly
Section titled “Call a tool directly”mkdir -p /tmp/actdemo
act call actpkg.dev/library/sqlite query \ --args '{"sql": "SELECT sqlite_version()"}' \ --session-args '{"database_path": "/tmp/actdemo/app.sqlite"}' \ --allow 'fs=/tmp/actdemo/**'[ { "sqlite_version()": "3.51.3" }]act call instantiates the component, runs one tool, prints the result, and exits.
Two things in that command are worth unpacking:
--session-args—sqliteis a stateful component: it holds an open database connection, so it exportssession-providerand takes its connection parameters at session open rather than per call. Onact call, this flag opens a session-of-1, runs the call, and closes it. Ask any component what it accepts withact session open-args-schema <component>.--allow 'fs=…'— the component declares awasi:filesystemcapability, and nothing reaches the filesystem until you grant it.fs=/tmp/actdemo/**grants that directory read-write and nothing else;:rowould make it read-only. Note it covers the whole directory, not just the database file: SQLite also writes a.locksidecar next to it. Grant too little and the audit trail tells you exactly what was refused — and which flag would grant it.
Serve it to an agent
Section titled “Serve it to an agent”act run actpkg.dev/library/sqlite --mcp \ --session-args '{"database_path": "/tmp/actdemo/app.sqlite"}' \ --allow 'fs=/tmp/actdemo/**'Exposes the component over MCP stdio. Plug into Claude Code, Claude Desktop, Cursor, or any MCP
client. With --session-args the host pre-opens one session and hides the session machinery
from the client entirely.
act run actpkg.dev/library/sqlite --mcp --http -l "[::1]:3000" \ --session-args '{"database_path": "/tmp/actdemo/app.sqlite"}' \ --allow 'fs=/tmp/actdemo/**'The same MCP server on an HTTP listener, at /mcp. Use it for a remote or containerised agent.
See Transports.
Wire it into your agent
Section titled “Wire it into your agent”Rather than typing that command, put it in your MCP client’s config. In Claude Code that is
.mcp.json at the root of the project:
{ "mcpServers": { "sqlite": { "command": "npx", "args": [ "@actcore/act", "run", "actpkg.dev/library/sqlite", "--mcp", "--session-args", "{\"database_path\": \"/tmp/actdemo/app.sqlite\"}", "--allow", "fs=/tmp/actdemo/**" ] } }}Each flag is its own array element, and the JSON value passed to --session-args is a string,
so its quotes are escaped. If you have act on $PATH, use "command": "act"
and drop the leading "@actcore/act" argument.
The equivalent one-liner, if you would rather not edit the file by hand:
claude mcp add sqlite -- npx @actcore/act run actpkg.dev/library/sqlite --mcp \ --allow 'fs=/tmp/actdemo/**'For a component you serve over HTTP instead, point the client at the endpoint:
{ "mcpServers": { "sqlite": { "type": "http", "url": "http://[::1]:3000/mcp" } }}Why this file is worth committing
Section titled “Why this file is worth committing”.mcp.json lives in the repository, so the grant travels with the project. Everyone who
opens it gets the same component at the same version with the same capability ceiling — rather
than each developer running an npx tool with ambient access to their whole machine and hoping
it behaves. A reviewer can read the diff and see exactly what a new tool is allowed to touch.
Where did the .wasm go?
Section titled “Where did the .wasm go?”act cached it to ~/.cache/act/components/. Subsequent runs skip the network. act store list
shows what’s cached, act store gc prunes it.
Why did the command need a grant?
Section titled “Why did the command need a grant?”The SQLite component declares a wasi:filesystem capability. At runtime you must grant it —
otherwise the component can open no files at all. The declaration is a ceiling: you can’t
grant more than the component asked for, and the component can’t reach past what you granted.
The default policy mode is ask, so an interactive run prompts you on first access instead of
requiring the flag up front. A headless run with no prompt channel degrades to deny — which is
why scripted invocations like the ones above pass --allow explicitly. See
Policy & sandbox.
- Build a component in Rust
- Configure host policy — filesystem, network, and socket grants
- Profiles — save these grants for SQLite in
~/.config/act/config.toml