# Connect MCP servers

> Give the agent the tools of any MCP server, local over stdio or remote over HTTP with OAuth, using elelem-mcp.


At the end of this guide elelem will start your MCP servers, list their
tools next to its own, and sign in to remote servers that need OAuth. The
Model Context Protocol (MCP) is a standard way for a program to offer tools
to an agent. `elelem-mcp` is the client side.

## Before you start

- elelem and `elelem-builtins` installed, with a working provider. See
  [the Quickstart](/docs/quickstart/).
- An MCP server to connect. This guide uses Playwright's, which needs
  Node.js for `npx`.

## 1. Install and load elelem-mcp

```bash
gem install elelem-mcp
```

elelem does not load integration gems on its own. Add a one-line plugin
file that requires it:

```bash
mkdir -p ~/.agents/plugins
echo 'require "elelem/mcp"' > ~/.agents/plugins/mcp.rb
```

Every session now loads `elelem-mcp`. To use it in one project only, put
the file in that project's `.agents/plugins/` instead.

## 2. Add a stdio server

Most MCP servers are programs that talk JSON-RPC over stdin and stdout.
elelem reads servers from `~/.agents/mcp.json` and `.agents/mcp.json` in
the current directory. Both are read and merged; when both define a server
with the same name, the project file wins.

Create `.agents/mcp.json`:

```json
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest"]
    }
  }
}
```

Each entry under `mcpServers` is a name and how to start the server:

- `command` is the program to run.
- `args` is its argument list.
- `env` is an optional hash of extra environment variables. A value can
  refer to your environment as `${NAME}`.

```json
{
  "mcpServers": {
    "github": {
      "command": "github-mcp-server",
      "args": ["stdio"],
      "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" }
    }
  }
}
```

If `GITHUB_TOKEN` is not set, the server does not start and elelem prints
`MCP failed: Missing environment variable: GITHUB_TOKEN`.

> **Note:** Stdio entries accept only `command`, `args`, and `env`. Do not
> add `"type": "stdio"`, which some other clients use. `elelem-mcp` 0.2.0
> rejects it, and the server fails with `unknown keyword: :type`.

## 3. Check the tools

```bash
elelem chat -p ollama
```

```text
> /tools
```

MCP tools are named `SERVER_TOOL`: the Playwright server's `browser_navigate`
becomes `playwright_browser_navigate`. If a name collides with a tool that
is already registered, the existing tool wins.

elelem starts the servers in the background so the prompt appears right
away. If `/tools` does not list them yet, wait a moment and run it again.
Servers are stopped when elelem exits.

Ask for something that needs the server:

```text
> open https://example.com and tell me the page title
```

When a server reports an error, the model gets it as a failed tool result.
Structured results (`structuredContent`) are passed through as-is;
otherwise the text parts of the result are joined.

## 4. Add a remote server over HTTP

For a server reachable by URL, set `type` to `http`:

```json
{
  "mcpServers": {
    "docs": {
      "type": "http",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer ${DOCS_TOKEN}" }
    }
  }
}
```

`headers` is optional and supports `${NAME}` like `env` does. elelem sends
JSON-RPC requests as `POST` to `url`, accepts JSON or server-sent event
replies, and keeps the `Mcp-Session-Id` the server returns.

## 5. Sign in with OAuth

If an HTTP server answers `401 Unauthorized`, elelem runs the OAuth flow
and retries once. Leave `headers` out for these servers.

1. It reads `/.well-known/oauth-protected-resource` from the server's
   host to find the authorization server, then that server's
   `/.well-known/oauth-authorization-server`.
2. It registers itself as a client named `elelem`. The authorization
   server must support dynamic client registration.
3. It opens the sign-in page with `xdg-open`, `open`, or `start`. If none
   works, it prints `Open this URL in your browser: ...`.
4. It waits up to 120 seconds for the redirect on
   `http://127.0.0.1:18273/callback`, then exchanges the code using PKCE.

Tokens and the client registration are saved in
`~/.config/elelem/tokens/`, readable only by you. Expired tokens are
refreshed on their own; if the refresh fails, elelem asks you to sign in
again. To force a fresh sign-in, delete the files in that directory.

## Limitations

- If one server fails to start, elelem prints `MCP failed: ...` and adds
  no MCP tools from any server for that session.
- Servers load in the background. In a one-shot `elelem ask`, the first
  model call can happen before the MCP tools are registered.
- OAuth discovery uses the server's scheme and host only. A server on a
  non-default port has to serve the metadata on the default port.
- Only MCP tools are supported, not resources or prompts.

## What you built

elelem now starts the servers listed in `mcp.json`, adds their tools to
the agent, fills secrets from your environment, and signs in to OAuth
servers in your browser.

## Next steps

- [Use agent skills](/guides/agent-skills/) for instructions the model
  loads on demand.
- [Write a tool plugin](/guides/write-a-tool/) when the tool you want is
  10 lines of Ruby.
- Read the [elelem-mcp](/plugins/mcp/) page.


Canonical: https://elelem.sh/guides/mcp-servers/

