> ## 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.

# LuaMCPServer

> Connect external tools via Model Context Protocol (MCP) servers

## Overview

`LuaMCPServer` allows you to connect external MCP (Model Context Protocol) servers to your agent. MCP servers provide additional tools that your agent can use at runtime, enabling integration with APIs, databases, documentation services, and more.

```typescript theme={null}
import { LuaMCPServer, env } from 'lua-cli';

const docsServer = new LuaMCPServer({
  name: 'docs',
  transport: 'streamable-http',
  url: 'https://mcp.example.com/mcp',
  headers: () => ({
    'Authorization': `Bearer ${env("MCP_API_KEY")}`
  })
});

export default docsServer;
```

<Note>
  **What is MCP?** The Model Context Protocol (MCP) is an open standard for connecting AI models to external tools and data sources. Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io).
</Note>

## Why MCP Servers?

<CardGroup cols={2}>
  <Card title="Extend Capabilities" icon="puzzle-piece">
    Add tools without writing code - use existing MCP servers
  </Card>

  <Card title="Standard Protocol" icon="plug">
    Compatible with any MCP-compliant server
  </Card>

  <Card title="Remote Integration" icon="globe">
    Connect to hosted MCP services via HTTP
  </Card>

  <Card title="Community Ecosystem" icon="users">
    Access growing library of hosted MCP servers
  </Card>
</CardGroup>

## Transport Types

MCP servers support two HTTP-based transport methods:

<Tabs>
  <Tab title="Streamable HTTP (Recommended)">
    **Best for:** Modern MCP servers, most use cases

    The modern MCP standard (spec 2025-03-26) with bidirectional communication.

    ```typescript theme={null}
    const server = new LuaMCPServer({
      name: 'my-server',
      transport: 'streamable-http',
      url: 'https://mcp.example.com/mcp',
      headers: () => ({
        'Authorization': `Bearer ${env("API_KEY")}`
      })
    });
    ```
  </Tab>

  <Tab title="SSE (Legacy)">
    **Best for:** Older MCP servers that don't support Streamable HTTP

    Uses Server-Sent Events for server-to-client streaming.

    ```typescript theme={null}
    const server = new LuaMCPServer({
      name: 'legacy-server',
      transport: 'sse',
      url: 'https://old-mcp.example.com/sse',
      headers: () => ({
        'Authorization': `Bearer ${env("API_KEY")}`
      })
    });
    ```
  </Tab>
</Tabs>

<Warning>
  **stdio transport not supported yet**: Local MCP servers (using `npx`, `node`, etc.) are not supported yet.
  Please use remote MCP servers with `streamable-http` or `sse` transport instead.
</Warning>

## Constructor

### new LuaMCPServer(config)

Creates a new MCP server configuration.

<ParamField path="config" type="LuaMCPServerConfig" required>
  MCP server configuration object
</ParamField>

## Configuration Parameters

### Required Fields

<ParamField path="name" type="string" required>
  Unique identifier for the MCP server

  **Format**: lowercase, hyphens allowed

  **Examples**: `'docs-server'`, `'api-gateway'`, `'database'`
</ParamField>

<ParamField path="transport" type="'streamable-http' | 'sse'" required>
  Transport protocol for communication

  * `'streamable-http'` - Modern MCP standard (recommended)
  * `'sse'` - Legacy Server-Sent Events transport
</ParamField>

<ParamField path="url" type="string | (() => string)" required>
  URL of the remote MCP server

  Can be a static string or a function that returns the URL at runtime using `env()`.

  **Examples**:

  * `'https://mcp.example.com/mcp'`
  * `() => env("MCP_SERVER_URL")`
</ParamField>

### Optional Fields

<ParamField path="headers" type="Record<string, string> | (() => Record<string, string>)">
  HTTP headers to send with requests

  Can be a static object or a function that returns headers at runtime using `env()`.

  **Example (static)**: `{ 'X-Custom-Header': 'value' }`

  **Example (dynamic)**: `() => ({ 'Authorization': \`Bearer \${env("API_KEY")}\` })\`
</ParamField>

<ParamField path="timeout" type="number">
  Timeout in milliseconds for server operations

  **Default**: `60000` (60 seconds)
</ParamField>

## Examples

### Documentation Server

```typescript theme={null}
import { LuaMCPServer, env } from 'lua-cli';

const docsServer = new LuaMCPServer({
  name: 'docs',
  transport: 'streamable-http',
  url: 'https://docs.example.com/mcp',
  headers: () => ({
    'Authorization': `Bearer ${env("DOCS_API_KEY")}`
  }),
  timeout: 30000
});

export default docsServer;
```

### API Gateway

```typescript theme={null}
import { LuaMCPServer, env } from 'lua-cli';

const apiServer = new LuaMCPServer({
  name: 'api-gateway',
  transport: 'streamable-http',
  url: 'https://api.example.com/mcp',
  headers: () => ({
    'Authorization': `Bearer ${env("API_TOKEN")}`,
    'X-Api-Version': '2024-01'
  }),
  timeout: 45000
});

export default apiServer;
```

### Database Service

```typescript theme={null}
import { LuaMCPServer, env } from 'lua-cli';

const dbServer = new LuaMCPServer({
  name: 'database',
  transport: 'streamable-http',
  url: 'https://db-mcp.example.com/mcp',
  headers: () => ({
    'Authorization': `Bearer ${env("DB_API_KEY")}`,
    'X-Database': 'production'
  }),
  timeout: 60000
});

export default dbServer;
```

### Dynamic URL with env()

```typescript theme={null}
import { LuaMCPServer, env } from 'lua-cli';

const server = new LuaMCPServer({
  name: 'dynamic-server',
  transport: 'streamable-http',
  url: () => env("MCP_SERVER_URL"),
  headers: () => ({
    'Authorization': `Bearer ${env("API_TOKEN")}`
  })
});

export default server;
```

### Legacy SSE Server

```typescript theme={null}
import { LuaMCPServer, env } from 'lua-cli';

const legacyServer = new LuaMCPServer({
  name: 'legacy-api',
  transport: 'sse',
  url: 'https://old-mcp.example.com/sse',
  headers: () => ({
    'Authorization': `Bearer ${env("API_KEY")}`
  })
});

export default legacyServer;
```

## Using with LuaAgent

MCP servers are added to your agent configuration:

```typescript theme={null}
import { LuaAgent, LuaSkill, env } from 'lua-cli';

const docsServer = new LuaMCPServer({
  name: 'docs',
  transport: 'streamable-http',
  url: 'https://docs.example.com/mcp',
  headers: () => ({
    'Authorization': `Bearer ${env("DOCS_API_KEY")}`
  })
});

const coreSkill = new LuaSkill({
  name: 'core-skill',
  description: 'Core functionality',
  tools: [...]
});

export const agent = new LuaAgent({
  name: 'docs-assistant',
  persona: 'You are an assistant with access to documentation.',
  skills: [coreSkill],
  
  // Add MCP servers
  mcpServers: [docsServer]
});
```

## Lifecycle Management

### Compile

During `lua compile`, MCP servers are:

1. Detected from your source code
2. Registered with the server (if new)
3. Assigned an ID stored in `lua.skill.yaml`
4. Configuration written to `dist/mcp-servers.json`

### Push

Push individual MCP server:

```bash theme={null}
lua push mcp
# Select server from list
```

Or push all components:

```bash theme={null}
lua push all --force
```

### Activate / Deactivate

MCP servers start inactive. Activate to make tools available:

```bash theme={null}
lua mcp activate
# Select server to activate

lua mcp deactivate
# Select server to deactivate
```

### List / Delete

```bash theme={null}
lua mcp list              # Show all MCP servers
lua mcp delete            # Remove an MCP server
```

## YAML Configuration

After compilation, `lua.skill.yaml` tracks MCP servers:

```yaml theme={null}
agent:
  agentId: your-agent-id
  persona: ...

mcpServers:
  - name: docs
    mcpServerId: mcp_abc123
  - name: api-gateway
    mcpServerId: mcp_def456
```

<Note>
  The YAML only stores `name` and `mcpServerId`. The full configuration (url, headers, etc.) lives in your source code.
</Note>

## Best Practices

<AccordionGroup>
  <Accordion title="Use env() for Secrets">
    Always use `env()` for API keys and tokens

    ```typescript theme={null}
    // ✅ Good - resolved at runtime
    headers: () => ({
      'Authorization': `Bearer ${env("API_KEY")}`
    })

    // ❌ Bad - hardcoded secret
    headers: {
      'Authorization': 'Bearer sk_live_xxxx'
    }
    ```
  </Accordion>

  <Accordion title="Set Appropriate Timeouts">
    Adjust timeout based on expected operation duration

    ```typescript theme={null}
    // Quick operations
    timeout: 10000  // 10 seconds

    // Database queries
    timeout: 30000  // 30 seconds

    // Heavy processing
    timeout: 120000 // 2 minutes
    ```
  </Accordion>

  <Accordion title="Use Streamable HTTP for New Integrations">
    Prefer `streamable-http` transport for new MCP server integrations

    ```typescript theme={null}
    // ✅ Recommended - modern standard
    transport: 'streamable-http'

    // Use only for legacy servers
    transport: 'sse'
    ```
  </Accordion>

  <Accordion title="Activate Only What You Need">
    Keep unused servers deactivated to reduce overhead

    ```bash theme={null}
    # Activate only when needed
    lua mcp activate docs-server

    # Deactivate when done
    lua mcp deactivate docs-server
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Server not found after push">
    Make sure the server is activated:

    ```bash theme={null}
    lua mcp list      # Check status
    lua mcp activate  # Activate if needed
    ```
  </Accordion>

  <Accordion title="Connection timeout">
    Check the URL is accessible and increase timeout:

    ```typescript theme={null}
    const server = new LuaMCPServer({
      transport: 'streamable-http',
      url: 'https://...',
      timeout: 120000  // Increase timeout
    });
    ```
  </Accordion>

  <Accordion title="Authentication failed">
    Verify your API key is correct and set in environment:

    ```bash theme={null}
    # Check environment variable is set
    lua env production

    # Set the variable
    lua env production -k API_KEY -v "your-api-key"
    ```
  </Accordion>

  <Accordion title="stdio transport error">
    Local MCP servers (stdio) are no longer supported. Migrate to remote servers:

    ```typescript theme={null}
    // ❌ No longer supported
    transport: 'stdio',
    command: 'npx',
    args: [...]

    // ✅ Use remote transport instead
    transport: 'streamable-http',
    url: 'https://mcp.example.com/mcp',
    headers: () => ({ ... })
    ```
  </Accordion>
</AccordionGroup>

## Related APIs

<CardGroup cols={2}>
  <Card title="LuaAgent" href="/api/luaagent" icon="robot">
    Agent configuration with MCP servers
  </Card>

  <Card title="LuaSkill" href="/api/luaskill" icon="puzzle-piece">
    Custom tool collections
  </Card>

  <Card title="Environment" href="/api/environment" icon="key">
    Managing environment variables
  </Card>

  <Card title="MCP Command" href="/cli/mcp-command" icon="terminal">
    CLI management commands
  </Card>
</CardGroup>

## See Also

* [MCP Servers Overview](/overview/mcp-servers) - Conceptual introduction
* [MCP Command](/cli/mcp-command) - CLI management
* [LuaAgent](/api/luaagent) - Adding MCP servers to your agent
* [Use Lua with Claude & Cursor](/mcp-for-builders) - Connect Lua's docs to your AI coding assistant
