Add an MCP server
For a server you want across projects, store one reusable definition in the central library and select it by name.
1. Write a safe definition#
Use ${REF} for secrets:
# github-server.toml
type = "http"
url = "https://api.githubcopilot.com/mcp/"
[headers]
Authorization = "Bearer ${GITHUB_TOKEN}"2. Add it to the library#
$ agentstack lib add-server github --file ./github-server.toml
$ agentstack lib add-server github --file ./github-server.toml --write
$ agentstack lib listThe preview validates the definition and shows the destination. The secret value never enters the library. lib list then shows it under Servers, and closes with a What is dead in here section listing every library entry with no recorded usage — a new one starts there, as no data.
If you ranagentstack initfirst, pick a name it did not already import.initputs each imported server in your first linked library source, solib add-server githubafterwards can land a secondgithubin a different source. That is not an error and nothing is overwritten — sources resolve in order and the first match wins, so the new one silently shadows the imported one.agentstack lib sourcesprints the order and aShadowed namessection naming what is hidden, andlocal:github-style qualified names reach the shadowed copy. See Link a library repo. Adding the same name twice in the same source is refused outright:'github' is already in the central library — pass --replace to overwrite.
3. Select it in a project#
This goes in the project's manifest, .agentstack/agentstack.toml. Add the [toolsets.backend] table, and replace the existing default_toolset value — TOML allows the key only once, and init already wrote default_toolset = "default". (Keep the old value instead if you would rather select this toolset explicitly with --toolset backend.)
default_toolset = "backend"
[toolsets.backend]
servers = ["github"]Then:
$ agentstack lock # preview
$ agentstack lock --write
$ agentstack trust .
$ agentstack secret set GITHUB_TOKEN
$ agentstack statustrust . and secret set both need a terminal, and say so rather than guessing: refusing to trust: stdin is not a terminal and secret set needs a terminal to prompt for the value. The non-interactive forms are:
$ agentstack trust --preview # JSON review surface; read `surface_digest` from it
$ agentstack trust . --yes --consented <surface_digest> # the value already includes sha256:
$ agentstack secret set GITHUB_TOKEN --value <VALUE> # OS keychain
$ agentstack secret set GITHUB_TOKEN --value <VALUE> --env-file # project env filetrust --preview emits JSON on its own (there is no --json flag) and its surface_digest value already carries the sha256: prefix, so pass it verbatim — a second sha256: is refused. The grant refuses too unless that digest still matches the bytes on disk.
Two stores, and on some machines only one of them works. --value alone writes to the OS keychain; --env-file writes the project env file next to the manifest. A headless box, a container, or a Linux machine with no secret service has no keychain to write to, and there --env-file is the working path rather than a fallback. Inline values can land in shell history either way — prefer the prompt when you have a terminal.
The next trusted agent connection opens the default and can discover the server's tools through tools_search. The server definition is not copied into project MCP configs in the live lane.
Because nothing is written for a server served live, more why is the place that answers "where did this come from, and who gets it":
$ agentstack more why github
github (MCP server)
from the central library · init:local
pinned sha256:b720188932b4…
approved yes · you said yes 0s ago
live Claude Code · Codex CLI
written Claude Code — in its own config, which AgentStack does not manage
scope runs `/usr/bin/env` · reads GITHUB_TOKEN
used never activated from here yet
full detail: agentstack explain githubOther starting points#
| What you have | Command |
|---|---|
| A catalog name | agentstack search <name> then agentstack add from <id> |
| A native server already configured | agentstack adopt to preview importing it |
| A server only this project needs | agentstack add server ... |
| An existing manifest definition to reuse | agentstack lib add-server <name> --from-manifest |
After any selected server change, use the same lock-then-trust loop. Run agentstack apply --write only when status reports a rendered compatibility lane that requires native files.
Next: Central library · Secrets · Server reference
Source of truth: docs/howto/add-a-server.md — this page is generated from it.