MCP servers
Edit on GitHubOrrery 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).
commandstarts a local server over stdio, in the workspace root, with the profile'senv(see Profiles).- A server sets
commandorurl, 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" }urlreaches 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.headersgo on every request. A value written"$VAR"is read from the profile'senv, 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 (orreryororrery 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>. oauthapplies tourlservers only; a local server takes its credentials from the profile'senv.
Keep a big server's tools out of every prompt
[mcp_servers.github]
command = "github-mcp-server"
args = ["stdio"]
deferred = truedeferred = truemakes the server's tools searchable rather than declared: the model finds them withtools.searchinstead 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,urlorheadersasks again.
Prompts and resources
- A server's prompts become commands named like its tools: type
/mcp.github.review 42in 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 resourcesand 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] connectornames 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 toolsmcp 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.