> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Use an MCP server

> Attach an external MCP server with LuaMCPServer, push it, activate it, and check its tools appear in a chat

After this guide, the model can call every tool an external [MCP server](/concepts/mcp-servers) advertises, with no tool code in your project. For a SaaS listed by `lua integrations available`, connect the [integration](/concepts/integrations) instead; it provisions and authenticates its own MCP server ([Integration MCP servers](/integrations/mcp)).

*Verified against lua-cli 3.33.0.*

**Before you begin**

* A project created with `lua init` and signed in with `lua auth configure` ([Install and sign in](/get-started/install)).
* The server's URL and transport: `streamable-http` (the current MCP standard) or `sse` for older servers. A local `stdio` process is not supported.
* Its token stored with `lua env production -k DOCS_MCP_TOKEN -v <token>`.

<Steps>
  <Step title="Declare the server">
    `headers` and `url` accept a function as well as a value; a function runs on the platform when the connection is built, so `env()` inside it reads the agent's environment and the token never lands in configuration. `timeout` is the deadline in milliseconds for each request to this server, tool calls included; unset, the platform's 60-second default applies. Listing the server's tools during a live turn has its own, shorter budget.

    ```ts src/mcp/DocsServer.ts theme={null}
    import { LuaMCPServer, env } from 'lua-cli';

    export default new LuaMCPServer({
      name: 'docs',
      transport: 'streamable-http',
      url: 'https://mcp.example.com/mcp',
      headers: () => ({ Authorization: `Bearer ${env('DOCS_MCP_TOKEN')}` }),
      timeout: 30000,
    });
    ```
  </Step>

  <Step title="Register it on the agent">
    Only servers referenced from `LuaAgent.mcpServers` are compiled.

    ```ts src/index.ts highlight={7} theme={null}
    import { LuaAgent } from 'lua-cli';
    import docsServer from './mcp/DocsServer';

    export default new LuaAgent({
      name: 'support-assistant',
      persona: 'You are the Acme support assistant. Search the product docs before answering.',
      mcpServers: [docsServer],
    });
    ```
  </Step>

  <Step title="Compile and push">
    `lua compile` bundles the project locally and counts what it found; the warning about a description is harmless in 3.33.0, whose `LuaMCPServer` accepts no such field.

    ```bash theme={null}
    lua compile
    ```

    ```text Output theme={null}
    🔨 Compiling...
    ⚠️  [mcp-server docs] MCP Server should have a description
    ✅ Compiled 23 primitives (1 agent, 2 skills, 8 tools, 3 webhooks, 3 jobs, 3 preprocessors, 2 postprocessors, 1 mcp-server) in 568ms
    ```

    MCP servers have no versions of their own. `lua push mcp` registers the server on the platform by name, or updates the record with that name, and prints `✅ MCP server "docs" pushed successfully`; nothing changes for end users yet. A later `lua push all` or `lua push mcp` updates an already-active server in place and keeps it active, so a new URL, header, or timeout applies from the agent's next turn. `--name` is required only when the agent declares more than one server.

    ```bash theme={null}
    lua push mcp --name docs --ci --force
    ```
  </Step>

  <Step title="Activate it">
    Activation is the live switch: the command prints `✅ MCP server "docs" activated successfully!`, and on the agent's next turn it connects, lists the server's tools, and offers them to the model. The server is recorded in the agent version, but not versioned on its own, and whether it is on sits outside the version: `lua version promote` never changes it.

    ```bash theme={null}
    lua mcp activate docs
    ```

    <Warning>
      Activation changes the production agent immediately, and sandbox chat sees the same state: there is no sandbox-only trial. `lua mcp deactivate docs` removes the tools again.
    </Warning>
  </Step>

  <Step title="Verify">
    List the servers, then ask the agent something only the server can answer.

    ```bash theme={null}
    lua mcp list
    lua chat -e production -m "Search the docs for how to reset a password"
    lua logs --type mcp --limit 10
    ```

    `lua mcp list` groups servers into active and inactive, with each server's transport, URL, and ID. The reply should draw on a tool from the server, and the log shows each call the model made against it.
  </Step>
</Steps>

## Options you may need

### Push and activate in one step

`lua push mcp --name docs --ci --force --auto-deploy` pushes the record and activates it; `lua push all` upserts every declared server but ignores `--auto-deploy` and activates nothing.

### Connect an older server over SSE

Set `transport: 'sse'` and point `url` at the server's SSE endpoint; `headers` and `timeout` work the same way.

### Manage servers an integration provisioned

Connecting a Unified.to integration creates and activates an MCP server named after the integration type. `lua mcp list` shows it alongside yours, and `lua integrations mcp list`, `lua integrations mcp activate --connection <id>`, and `lua integrations mcp deactivate --connection <id>` activate or deactivate it per connection. Don't hand-write a `LuaMCPServer` for a system the catalog covers.

## If it isn't working

<AccordionGroup>
  <Accordion title="No MCP servers found in compiled output.">
    **Cause** `lua push mcp` only sees servers registered on `LuaAgent.mcpServers`. **Fix** Import the server in `src/index.ts`, add it to `mcpServers`, and push again.
  </Accordion>

  <Accordion title="The model never uses the server's tools">
    **Cause** The server is inactive, or the token is missing in the environment the chat runs in. **Fix** Check `lua mcp list` for a green entry and `lua env production --list` for `DOCS_MCP_TOKEN`; then read `lua logs --type mcp --limit 10` for connection errors.
  </Accordion>

  <Accordion title="MCP Server should have a description">
    **Cause** The compiler expects a description, but the 3.33.0 typings have no such field on `LuaMCPServer`. **Fix** Ignore the warning; the server compiles, pushes, and activates without it.
  </Accordion>
</AccordionGroup>

## Next steps

<Columns cols={2}>
  <Card title="About MCP servers" href="/concepts/mcp-servers">Transports, lifecycle, and MCP servers versus skills and integrations.</Card>
  <Card title="LuaMCPServer reference" href="/reference/sdk/luamcpserver">Every configuration field.</Card>
  <Card title="lua mcp" href="/reference/cli/mcp">List, activate, deactivate, and delete servers.</Card>
  <Card title="Integration MCP servers" href="/integrations/mcp">Servers that arrive with a connected integration.</Card>
</Columns>
