# Connect an MCP host

> Register the server in Claude Code, Codex, Gemini CLI, OpenCode, or pi, and choose how credentials reach it.

Canonical URL: https://www.slivingdoc.dev/docs/guides/mcp-hosts/ · Version: 0.1 · Updated: 2026-09-21

Full site index: https://www.slivingdoc.dev/llms.txt

An MCP host starts the server as a child process and speaks MCP JSON-RPC
over standard input and output. Every host below runs the same command —
`npx -y slivingdoc serve` — and differs only in where that command is
written down and how the configuration and credentials reach it: the
bucket as `SLIVINGDOC_BUCKET`, the store as the region or the endpoint,
and the keys through the AWS chain.

Two things hold for all of them:

- Standard output carries protocol messages only. Logs go to standard
  error, so a chatty log level never corrupts the protocol.
- With no `--workspace-root`, the server takes its own session directory
  and names it in the server instructions and in every tool result. The
  agent omits `path`, or sends an empty string. Add
  `"--workspace-root", "/srv/notes"` to the arguments when humans and
  agents should share one fixed directory — see
  [Share a directory with humans](/docs/guides/shared-directory/).

> **Note:** Host commands, flags, and file locations belong to each host
> vendor, not to slivingdoc. They are the ones that change; check the
> vendor's own documentation if a command below is rejected.

## Claude Code

```text
claude mcp add slivingdoc \
  --env SLIVINGDOC_BUCKET=my-notes \
  --env AWS_ACCESS_KEY_ID=<your-access-key-id> \
  --env AWS_SECRET_ACCESS_KEY=<your-secret-access-key> \
  -- npx -y slivingdoc serve
```

Each `--env` goes after the server name and before the `--` separator.
Everything after `--` is the command Claude Code will run.

Without a scope flag the entry is local: yours, in this project only,
recorded in `~/.claude.json`. Add `--scope project` to write a shared
`.mcp.json` in the project root, or `--scope user` to make it available
in every project.

Verify with `claude mcp list`, which prints the connection state of each
server, or `/mcp` inside a session.

## Codex

```text
codex mcp add slivingdoc \
  --env SLIVINGDOC_BUCKET=my-notes \
  --env AWS_ACCESS_KEY_ID=<your-access-key-id> \
  --env AWS_SECRET_ACCESS_KEY=<your-secret-access-key> \
  -- npx -y slivingdoc serve
```

The entry is stored in `~/.codex/config.toml` under
`[mcp_servers.slivingdoc]`. A trusted project can scope it instead to
`.codex/config.toml` in the project.

Verify with `codex mcp list`, or `/mcp` inside a session.

## Gemini CLI

```text
gemini mcp add -s user \
  -e SLIVINGDOC_BUCKET=my-notes \
  -e AWS_ACCESS_KEY_ID=<your-access-key-id> \
  -e AWS_SECRET_ACCESS_KEY=<your-secret-access-key> \
  slivingdoc npx -- -y slivingdoc serve
```

The argument order differs from the two hosts above: the server name
comes first, then the command, then its arguments. The `--` separator
keeps Gemini CLI from reading `-y` as one of its own options.

`-s user` writes the entry to `~/.gemini/settings.json`, under
`mcpServers`. Drop it for the default project scope, which writes
`.gemini/settings.json` in the project instead.

Verify with `gemini mcp list`, or `/mcp` inside a session. A local server
reports as connected only from a trusted folder.

## OpenCode

OpenCode is configured by file. Put this in `opencode.json` at the
project root, or in `~/.config/opencode/opencode.json` to have it
everywhere:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "slivingdoc": {
      "type": "local",
      "command": ["npx", "-y", "slivingdoc", "serve"],
      "enabled": true,
      "environment": {
        "SLIVINGDOC_BUCKET": "my-notes",
        "AWS_ACCESS_KEY_ID": "<your-access-key-id>",
        "AWS_SECRET_ACCESS_KEY": "<your-secret-access-key>"
      }
    }
  }
}
```

`type` and `command` are required; `enabled` and `environment` are
optional. The `$schema` line is what makes an editor validate and
complete the file.

Verify with `opencode mcp list`.

## pi

pi has no built-in MCP support. Its vendor suggests an extension, and the
`pi-mcp-adapter` package in pi's own package catalogue is that
extension:

```text
pi install npm:pi-mcp-adapter
```

The adapter reads a standard `.mcp.json` from the project root, among
other locations, so the raw form below is the configuration to write.
Restart pi after installing it.

## Any host: the raw `mcpServers` form

Hosts that take the common JSON shape need no command at all. This is the
configuration every one of them accepts:

```json
{
  "mcpServers": {
    "slivingdoc": {
      "command": "npx",
      "args": ["-y", "slivingdoc", "serve"],
      "env": {
        "SLIVINGDOC_BUCKET": "my-notes",
        "AWS_PROFILE": "notes"
      }
    }
  }
}
```

## Credentials

slivingdoc has no authentication layer of its own. `serve`, `pull`, and
`commit` build the S3 client the same way, and credentials come from the
AWS SDK default credential chain, resolved at startup:

1. Environment variables — `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`,
   and `AWS_SESSION_TOKEN`.
2. The shared configuration and credentials files (`~/.aws/credentials`,
   `~/.aws/config`), honouring `AWS_PROFILE`.
3. Ambient identity — SSO sessions, ECS and EKS task roles, and the EC2
   instance metadata service.

slivingdoc's own flags shape _where_ the client points — `--bucket`,
`--prefix`, `--region`, `--endpoint` — never _who it is_. No flag carries
a credential, and an `--endpoint` URL with user information in it is
refused, so a secret can never echo into a diagnostic.

There are three ways to deliver credentials, and the choice is a
deployment decision:

- **Inherit.** The process inherits the environment of whatever launched
  it. A shell with an exported profile or an active SSO session needs
  nothing else. This covers `slivingdoc pull` and `commit` run by hand,
  and a `serve` whose host was started from that shell.
- **Inject.** Most hosts accept an environment block per server — the
  `--env` flags and `env` objects above. Use it when the host is not
  launched from a credentialed shell (a GUI application, a service
  manager), or to point at a local S3-compatible store.
- **Ambient.** On EC2, ECS, or EKS, an attached role satisfies the chain
  with no configuration at all. This is the cleanest server deployment.

> **Tip:** Prefer injecting `AWS_PROFILE` over pasting static keys. Host
> configuration files tend to be synced and backed up, while a profile
> keeps the secret in `~/.aws/credentials`.

Credentials stay inside the slivingdoc process. They never cross the MCP
protocol — the client sees only `notes_pull`, `notes_commit`, and their
result envelopes — and the redaction layer keeps key material out of
every error and log line as defence in depth.

> **Warning:** `serve` resolves the chain once and holds the session.
> With short-lived STS or SSO credentials, an expired login surfaces as a
> redacted startup refusal from the compatibility probe, not as a
> mid-operation error. Restart the server after renewing the session.

## Next

- [Quickstart](/docs/quickstart/) — the first pull, edit, and commit.
- [MCP tools](/docs/reference/mcp-tools/) — the two tools, their inputs,
  and their results.
- [Use the CLI without a host](/docs/guides/cli/) — the same two
  operations by hand.
