ExMCP.Transport.Local (ex_mcp v0.9.2)

View Source

Unified BEAM transport for ExMCP, supporting both raw terms and JSON.

This module provides a high-performance transport for BEAM-based communication. It operates in two modes:

  • :native mode: Passes raw Elixir terms directly for maximum performance. This is ideal for trusted, local BEAM communication. It reports the :raw_terms capability.

  • :beam mode: Enforces MCP specification compliance by serializing all messages to/from JSON. This is safer for distributed or less-trusted scenarios.

The mode is selected automatically by the ExMCP.Client based on the transport specified (:native or :beam).

Features

  • Dual-mode operation (raw terms or JSON)
  • Direct process-to-process communication
  • Built-in fault tolerance
  • Low latency for local communication

Security Notice

⚠️ SECURITY WARNING: The :native mode is designed ONLY for trusted, local BEAM communication. It bypasses JSON validation. For distributed or untrusted scenarios, the :beam mode should be used.

Configuration

This transport is configured via ExMCP.Client.start_link/1:

# For native (raw term) mode
{:ok, client} = ExMCP.Client.start_link(
  transport: :native,
  service_name: :my_service
)

# For beam (JSON) mode
{:ok, client} = ExMCP.Client.start_link(
  transport: :beam,
  service_name: :my_service
)

Options:

  • :service_name - Required for client mode. The service to connect to.
  • :server - Required for client mode if connecting to a server process.
  • :timeout - Optional. Call timeout in milliseconds (default: 5000).

Summary

Types

t()

@type t() :: %ExMCP.Transport.Local{
  connected: boolean(),
  forwarder_pid: term(),
  mode: :beam | :native,
  role: :client | :server,
  server_pid: pid() | nil,
  subscriber: term(),
  timeout: pos_integer()
}

Functions

receive(transport)

receive_message(transport, timeout)

recv(transport, timeout)

send(transport, message)

subscribe(pid, state)

Subscribe to receive transport events (push model).

For the Local transport, the peer already sends {:transport_message, msg} to the client process. The Client GenServer handles these directly, so subscribe just signals that no receiver task is needed.