MCP Tools
Norn can list and call Model Context Protocol tools directly inside .norn sequences. The VS Code extension and CLI use the same MCP parser, target resolver, session manager, and tool-call runtime.
A server can be declared in two places: in the agent sidecar that uses it, or in norn.config.json for the whole project. Both work everywhere, and a sidecar declaration wins over a config entry of the same name.
Declare a Server in a Sidecar
A .nornai file declares the servers it uses beside the models it uses, with every input written down and credentials left as environment references. Blocks go above the first agent block. .nornagent is the same language and works identically — see AI Agents.
mcp LocalTools
transport stdio
command node ./tools/mcp-server.js # or {{$env.MCP_COMMAND}} for a whole command line
cwd ./tools # optional; relative to this sidecar
env TOOL_MODE readonly # optional; passed to the child process
session run # run (default) | agent | call
end mcp
mcp RemoteTools
transport http
url {{$env.REMOTE_MCP_URL}} # the MCP endpoint, path included
header Authorization: Bearer {{$env.REMOTE_MCP_TOKEN}}
timeout 60000 # milliseconds
end mcp command is a single line resolved before it is split. Norn substitutes its variables first and only then separates the executable from its arguments, so one reference such as command {{$env.MCP_COMMAND}} can supply the executable and every argument together — the same way in VS Code and in the CLI. Quotes, whether you author them or they arrive with the resolved value, keep whitespace inside one argument. No shell is involved: the executable is spawned directly, so pipes, redirection, and && are not interpreted. A bare name is looked up on PATH, a relative path resolves against the sidecar that declared it, and a command that resolves to nothing is reported as an empty command for that alias instead of a failed spawn.
env <NAME> <value> is a repeatable stdio-only directive. Norn passes each entry to the spawned child process and preserves the inherited process environment. The variable name and meaning are defined by that MCP server; TOOL_MODE above is illustrative, not a Norn setting.
header is written the way you would write an HTTP header anywhere else. The value is the rest of the line taken verbatim, so Bearer {{$env.REMOTE_MCP_TOKEN}} needs no quotes — and quotes you add become part of the token. The colon is optional, and IntelliSense inserts it for you.
Use {{$env.NAME}} for environment-backed values. Norn checks the selected .nornenv first and then the process environment. A reference that cannot be resolved fails by name before Norn connects to anything, and resolved server configuration never enters a trace, a recording, or --json output.
transport stdio makes Norn spawn the server process when its authored session scope opens. transport http only dials an existing server. Norn never starts an HTTP server, and a refused connection reports the URL it tried.
Configure norn.config.json
A server used across a whole project can live in the mcp.servers section of norn.config.json instead. The alias names under servers are the names you reference in run mcp list and run mcp call.
{
"version": 1,
"mcp": {
"servers": {
"localTools": {
"transport": "stdio",
"command": ["node", "./tools/mcp-server.js"]
},
"remoteTools": {
"transport": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer {{$env.mcpToken}}"
},
"timeoutMs": 5000
}
}
}
} stdio launches a local MCP server process. http connects to a hosted MCP endpoint. Relative paths resolve from the location of norn.config.json, and the nearest config file to the active .norn file wins.
List and Call Tools
test sequence ToolCheck
var tools = run mcp list localTools
assert tools.count > 0
# Replace summarize_text with a tool advertised by your server.
var result = run mcp call localTools summarize_text(text: "hello world")
assert result.isError == false
end sequence run mcp list <alias> returns an array of tool definitions. run mcp call <alias> <tool>(...) accepts named arguments or positional arguments bound in the tool's input-schema order, and returns a result object you can assert on or capture into variables.
Aliases resolve through the agent sidecars the .norn file imports directly, then through norn.config.json. VS Code offers both after run mcp list and run mcp call, naming the file each one was declared in.
After a successful run mcp list <alias>, Norn caches the discovered tool metadata in .norn-cache beside whatever declared the server — the sidecar for a declared block, the config file otherwise. VS Code can then suggest cached tool names and named parameter properties for later run mcp call lines.
Result Shape
MCP tool calls return a deterministic result envelope with these commonly used fields:
content- raw MCP content blocksstructuredContent- parsed structured tool output when providedtext- concatenated text blocks for quick assertionsisError- whether the tool reported an errorserverandtool- the resolved alias and tool name
var result = run mcp call remoteTools summarize_text("hello world")
assert result.isError == false
assert result.text contains "hello"
assert result.structuredContent.summary exists If a tool advertises an outputSchema, Norn validates structuredContent against it before the result is exposed to the sequence.
Deterministic Session Behavior
- With the default
session run, one client session is reused for the same resolved server target throughout the outer sequence run. - Imported or nested sequences reuse that session only when their own scope resolves to the same origin, alias, and server configuration.
- All MCP sessions are closed automatically when the outermost sequence finishes or fails.
tools/listpagination is drained automatically throughnextCursor.
Choosing What State Is Shared
A declared server can say how long its session lives, which decides what state travels between the things that use it:
session run— the default. One session for the whole sequence run, so every step and every agent shares the server's state. Deliberate for an orchestration: five agents testing one website are one testing session.session agent— one session per agent invocation. This is how an agent asks not to inherit state it never earned, such as another agent's login.session call— one session per tool call. Correct only for stateless servers; a browser given this gets a fresh browser per call, so a click cannot land on the page the previous call navigated to.
A deterministic run mcp step has no agent invocation boundary. For direct sequence steps, session agent therefore behaves as run-scoped; session call still closes the client after each MCP operation.
MCP Tools for AI Agents
The same server resolution, transport, session, and schema-validation runtime backs tools used by AI agents. An agent is granted a whole server with mcp <Alias>, or named tools with tools <Alias>.<tool>. Agent-facing binary MCP content is summarized instead of being sent to a text-only model. See AI Agents.
Because deterministic steps and agent grants resolve through the same alias rules, run mcp list can verify that a server connects and advertises tools before any model is involved.
VS Code Setup
The quickest way to get a declared server in front of you is Create agentic flow starter in the Project Setup section of the Norn sidebar. It writes a .nornai sidecar containing a placeholder mcp block and a commented-out tool grant, so the shape is there before you supply a real server. Replace or delete the block; no agent can reach it until you grant a tool.
norn.config.json is written by hand. It is backed by a JSON schema in VS Code, so alias naming, local versus remote transport fields, and optional settings all get completion and validation as you type.