ESC
Start typing to search...

MCP Servers

Extend your Teleton Agent with external tools by connecting Model Context Protocol (MCP) servers. This guide covers both transport types, all configuration methods, scope control, and troubleshooting.

What is MCP?

The Model Context Protocol (MCP) is an open standard that lets AI agents call external tool servers. Teleton supports MCP natively, so you can plug in any compatible server and its tools become available to the agent immediately.

Teleton supports two MCP transport types:

TransportHow it worksWhen to use
StdioRuns an npm package as a child process; communicates over stdin/stdoutMost community MCP servers distributed as npm packages
HTTP (Streamable HTTP + SSE fallback)Connects to an HTTP endpoint. Tries StreamableHTTPClientTransport first; falls back to SSE automatically if the server does not support Streamable HTTP.Remote or self-hosted MCP servers exposed over the network

Every tool from a connected MCP server is automatically registered in the agent's ToolRegistry with a namespaced prefix: mcp_{serverName}_{toolName}. If Tool RAG is enabled, the new tools are indexed there as well.

Step 1 -- Add Servers via the CLI

The fastest way to add an MCP server is with teleton mcp add.

Add a stdio server (npm package)

Add an SSE server (HTTP endpoint)

List and remove servers

Automatic name derivation

When you omit --name, Teleton derives a short name from the package:

PackageDerived name
@modelcontextprotocol/server-filesystemfilesystem
@anthropic/mcp-server-brave-searchbrave-search

Step 2 -- Configuration in config.yaml

Every server added via the CLI or WebUI is persisted in config.yaml under the mcp.servers map. You can also edit this file directly.

config.yaml
mcp:
  servers:
    # Stdio server -- runs as a child process
    filesystem:
      command: "npx @modelcontextprotocol/server-filesystem /tmp"
      scope: "admin-only"
      enabled: true

    # SSE server -- connects to a remote HTTP endpoint
    weather:
      url: "http://localhost:3000"
      env:
        API_KEY: "sk_live_xxx"
      scope: "always"

Server configuration fields

FieldTypeRequiredDescription
commandstring*Shell command for a stdio server. Teleton splits this string on spaces to derive the binary and its arguments.
argsstring[]NoExplicit arguments array. When provided, overrides the automatic splitting of command.
envRecord<string, string>NoEnvironment variables passed to the stdio child process.
urlstring*SSE/HTTP endpoint URL. Use this instead of command for remote servers.
scopeenumNoWhere the server's tools are available. Default: "always". See Scope System.
enabledbooleanNoSet to false to disable a server without removing it. Default: true.

* Each server must have either command or url, but not both.

Step 3 -- Manage Servers from the WebUI

The WebUI dashboard provides a visual interface for managing MCP servers at /api/mcp.

REST endpoints

MethodEndpointDescription
GET/api/mcp/List all servers with connection status, tool count, and tool names
POST/api/mcp/Add a server. Body: { name, package, args?, url?, scope?, env? }
DELETE/api/mcp/:nameRemove a server by name

What the MCP page shows

For each server, the WebUI displays: server name, transport type (stdio or SSE), connection status, tool count, individual tool names, scope, and environment variable key names (values are hidden).

Restart required

Changes made via the CLI or WebUI require an agent restart to take effect. The agent reads the MCP configuration at startup and establishes connections at that time.

Tool Naming Convention

Every tool registered from an MCP server is prefixed with the server name to avoid collisions:

Naming pattern
mcp_{serverName}_{originalToolName}

For example, if the server named filesystem exposes a tool called read_file, it becomes available to the agent as:

Example
mcp_filesystem_read_file

The agent's LLM sees these prefixed names in its tool list and calls them automatically when relevant to a user request.

Scope System

The scope field controls where a server's tools can be invoked. This lets you restrict powerful tools to specific contexts.

ScopeDirect MessagesGroup ChatsAdmin Only
always (default)YesYesNo
dm-onlyYesNoNo
group-onlyNoYesNo
admin-onlyYesYesYes -- only admin users

Connection Flow

Understanding the startup sequence helps when debugging connection issues.

  1. Connect -- On agent startup, each enabled server is connected with a 30-second timeout. Stdio servers are spawned as child processes; SSE servers receive an HTTP connection.
  2. List tools -- Teleton requests the list of available tools from each connected server.
  3. Register -- Each tool is registered in the ToolRegistry with the mcp_{server}_{tool} prefix.
  4. Index -- If Tool RAG is enabled, new tools are added to the RAG index so the agent can discover them semantically.
  5. Fail gracefully -- If a server fails to connect within 30 seconds, the error is logged and the server is skipped. Other servers are not affected.

Security and Environment Sandboxing

Teleton takes care to limit what stdio child processes can access.

Safe environment variables

Host environment variables are handled with an allowlist/blocklist approach:

Allowlist (forwarded automatically):

  • PATH
  • HOME
  • NODE_PATH
  • LANG
  • TERM

Blocklist (always blocked, even if declared in env):

  • LD_PRELOAD
  • NODE_OPTIONS
  • LD_LIBRARY_PATH
  • DYLD_INSERT_LIBRARIES
  • ELECTRON_RUN_AS_NODE

Any additional variables (beyond the allowlist) must be declared explicitly in the server's env configuration. Blocked variables are rejected even when explicitly declared, preventing privilege escalation via library injection.

Package name validation

Package names are validated against the pattern @a-zA-Z0-9._/-. Shell metacharacters and other special characters are rejected, preventing command injection via package names.

Full Example

Below is a complete configuration with multiple MCP servers of different types and scopes.

config.yaml
mcp:
  servers:
    # File system access -- admin only
    filesystem:
      command: "npx @modelcontextprotocol/server-filesystem /home/data"
      scope: "admin-only"
      enabled: true

    # Web search -- available everywhere
    brave-search:
      command: "npx @anthropic/mcp-server-brave-search"
      env:
        BRAVE_API_KEY: "BSA_xxxxxxxxxxxx"
      scope: "always"

    # Remote weather API via SSE
    weather:
      url: "http://localhost:3000"
      env:
        API_KEY: "sk_live_xxx"
      scope: "always"

    # Temporarily disabled
    experimental:
      command: "npx @example/experimental-server"
      enabled: false

After saving the file, restart the agent. On startup you will see log lines for each MCP server connecting and registering its tools:

Expected log output
[MCP] Connecting to "filesystem" (stdio)... OK (3 tools)
[MCP] Connecting to "brave-search" (stdio)... OK (1 tool)
[MCP] Connecting to "weather" (sse)... OK (5 tools)
[MCP] Skipping "experimental" (disabled)

The agent now has access to tools like mcp_filesystem_read_file, mcp_brave-search_web_search, and mcp_weather_get_forecast.

Troubleshooting

Connection timeout (30s exceeded)

  • Verify the npm package exists: run the command value manually in a terminal.
  • For SSE servers, confirm the URL is reachable: curl -I http://localhost:3000.
  • Check that required environment variables are set in the env block.

Tools not appearing after adding a server

  • An agent restart is required after any MCP configuration change.
  • Run teleton mcp list to confirm the server is in the config.
  • Check that enabled is not set to false.

Permission denied / tools not callable

  • Verify the scope setting matches the context (DM vs. group vs. admin).
  • If using admin-only, confirm the user sending the message is in the admin list.

Environment variable not reaching the server

  • Only variables listed in the server's env block are forwarded beyond the automatic allowlist (PATH, HOME, NODE_PATH, LANG, TERM). The blocklist variables (LD_PRELOAD, NODE_OPTIONS, LD_LIBRARY_PATH, DYLD_INSERT_LIBRARIES, ELECTRON_RUN_AS_NODE) are always rejected.