MCP servers
Docs/Extend/MCP servers

MCP servers

Edit on GitHub
docs-site/extend/mcp.md

Orrery speaks the Model Context Protocol. An existing MCP server works unmodified, behind the same policy check as every other tool.

Declare one

[mcp_servers.github]
command = "github-mcp-server"
args = ["stdio"]

Each server is an extension with the id mcp.<name>, and its tools are mcp.<name>.<tool>: mcp.github.search_issues. A rule names them like any tool, tool(mcp.github.search_issues).

  • command starts a local server over stdio, in the workspace root, with the profile's env (see Profiles).
  • A server sets command or url, never both. One with neither, or both, is reported and skipped, and the message names both keys.

Reach a remote server

[mcp_servers.linear]
url = "https://mcp.example.com/mcp"
headers = { Authorization = "$LINEAR_TOKEN" }
  • url reaches the server over streamable HTTP. A server that only speaks the older SSE transport is detected and reached that way; there is nothing to set.
  • headers go on every request. A value written "$VAR" is read from the profile's env, then the process, so the file holds only the variable's name. A header naming an unset variable is reported and the server skipped.
  • The request goes through the network permission like any other: a rule must allow the host, net(mcp.example.com).
  • orrery mcp tools <name> starts local servers only. A remote one is reached from a session (orrery or orrery run), where its network grant applies.

Sign in with OAuth

[mcp_servers.linear]
url = "https://mcp.example.com/mcp"
oauth = true
  • With oauth = true, Orrery signs in to the server the MCP way (OAuth 2.1 with PKCE, discovered from the server).
  • The tokens are kept by Orrery with your other sign-ins, never in config.toml, and are renewed when they expire.
  • Until you have signed in, a call to one of its tools fails with: OAuth login: run orrery mcp login <name>.
  • oauth applies to url servers only; a local server takes its credentials from the profile's env.

Keep a big server's tools out of every prompt

[mcp_servers.github]
command = "github-mcp-server"
args = ["stdio"]
deferred = true
  • deferred = true makes the server's tools searchable rather than declared: the model finds them with tools.search instead of reading every description in every prompt.
  • Its tools are still behind the same policy check. A server's tool list is kept on disk, keyed by how the server is declared, so a deferred or lazy server is not started just to list its tools. Changing its command, args, url or headers asks again.

Prompts and resources

  • A server's prompts become commands named like its tools: type /mcp.github.review 42 in the TUI. Words after the command fill the prompt's arguments in order, the last taking the rest. The server fills the prompt in and its text is sent as your next message.
  • The same line works without a screen: orrery run -p "/mcp.github.review 42" sends the filled-in prompt. A prompt no server offers, or a required argument left out, is refused with the usage and exit code 2; nothing is sent to the model.
  • A server's resources are listed with /mcp resources and read with /mcp read <server> <uri>, which prints the text in the thread.

Replace the connector

[mcp]
connector = "my-mcp-layer"
  • How servers are reached is a part. The default connects them in process; [mcp] connector names an extension that connects them instead.
  • What keeps a server safe does not change: its mcp.<name> id, its permission rules, the audit, and the check on a tool list that grows mid-session.

From the TUI, /mcp add writes the same table to your user layer, and /mcp remove <name> deletes it. A server connects when a session starts, so an added one is there after a restart.

A workspace can declare servers in its own .orrery/config.toml; they load only once you trust the workspace.

Check it

Two questions, kept apart on purpose:

orrery mcp list            # what is declared, by which layer. Starts nothing.
orrery mcp tools github    # connect to one and list its tools

mcp tools prints each tool by the name a policy rule would use.

Limit which servers a profile runs

[profile.review]
extensions = ["mcp.github"]

A profile that names mcp.* ids runs only those servers.

Keep secrets out of the file

Give the server its token through the profile's env, as a reference:

[profile.default]
env = { GITHUB_TOKEN = "$GITHUB_TOKEN" }

The process environment wins over the profile's.