Skip to main content
NorenDocs← Main siteSandbox

MCP integration

Noren integrates the Model Context Protocol (MCP) for tool discovery and invocation. The same Tool trait backs native Rust implementations and external MCP servers reached over JSON-RPC; the daemon and its clients list and invoke tools through a single surface.

Wire shapes

Noren's MCP types match the published MCP shapes verbatim, so a tool catalogue is portable between Noren and any other MCP-aware host.

ToolSpec {
  name:        "echo",
  description: "Returns the provided `text` argument verbatim.",
  inputSchema: {
    "type": "object",
    "properties": { "text": { "type": "string" } },
    "required": ["text"],
    "additionalProperties": false
  }
}

ToolCallResult {
  content: [ Content::Text { text: "…" }, Content::Json { value: {…} } ],
  isError: false
}

Native tools

Native tools are Rust types implementing the Tool trait and registered with ToolRegistry at daemon startup. The registry exposes list_specs for catalogue queries and call(name, arguments) for invocation.

Two native tools are bundled with the daemon:

  • echo returns its text argument verbatim. Performs schema validation (missing or non-string text is rejected). Serves as the reference implementation for argument validation against the registry.
  • clock takes no arguments; returns { "epoch_ms": <u64> }. Provides a daemon liveness probe that does not require additional capability grants.

Calling a tool

noren tools list --json

# Grant the per-tool capability first.
noren capabilities grant tool.call.echo

# Then call the tool with JSON arguments.
noren tools call echo --args '{"text":"hi"}'
# → hi

Every tools/call requires the capability tool.call.<name> in the issuer's active set. Capability checks are audited via the same CapabilityCheck event used by agent dispatch; the audit row carries an agent_id of tool:<name> so operators can distinguish tool calls from agent dispatches.

External MCP servers

External MCP servers extend the catalogue without modifying the daemon. Configure them in ~/.noren/secrets.toml:

[[mcp.server]]
name    = "filesystem"
command = "npx"
args    = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/notes"]
env     = { LOG_LEVEL = "info" }

On startup the daemon spawns each configured server, performs the MCP handshake (initialize → notifications/initialized → tools/list), and merges the discovered tools into the same ToolRegistry the native tools live in. Per-server failures are fail-soft: a server that fails to start or returns an error during handshake is logged and skipped without preventing the daemon from coming up.

Transport

Noren uses line-delimited JSON-RPC 2.0 over the spawned process's stdin/stdout. Each request carries a stable id; the daemon correlates responses by id and discards unrecognised messages. Child processes are started with kill_on_drop(true), so an unclean daemon exit also terminates the child and prevents orphan tool processes.

Security

External MCP servers execute with the operator's privileges and have access to whatever the daemon's user account can reach. The capability gate (tool.call.<name>) controls invocation through the daemon but cannot constrain server behavior post-invocation. Operators should review external servers before configuration and select the narrowest-scoped server appropriate for the task.

Related

  • Capability tokens: the gate on every tools/call.
  • Audit log: where every capability check and every tool call lands.
  • CLI: tools list and tools call.