Skip to content

MCP Server

This document is intended for external users and explains how to configure CX's MCP Server with agents such as Claude Code and Codex.

What You Can Do

The current MCP Server provides the following tools:

  • get_context: View the currently connected source, user, tenant, and customer information.
  • list_devices: List devices visible to the current user.
  • list_programs: List programs visible to the current user.
  • get_device_status: Query the online status and version attributes of a single visible device.
  • get_device_detail: Query the details and latest attributes of a single visible device.
  • get_program_detail: Query the detailed content of a single visible program.
  • list_assets: List assets and groups visible to the current user.
  • get_entity_attributes: Query device, program, or asset attributes by explicitly specified keys.
  • list_program_targets: Query which visible devices or groups a program is currently deployed to.
  • list_device_programs: Query the programs currently associated with a visible device.
  • bind_device_by_ddc: Bind or create a device using a device dynamic code, optionally with a selected available device activation code ID.
  • describe_device_binding_semantics: Explain the activation code usage rules for binding devices via dynamic code in Cloud/LAN modes.
  • describe_activation_semantics: Explain activation code types, device activation codes, and cloud account token requirements.
  • list_activation_codes: Query visible activation codes for the cloud account. Use status: "usable" to filter for available device activation codes.
  • list_usable_device_auth_codes: Query currently available device activation codes that can be used for device binding.
  • get_activation_code: Query details of a single activation code.
  • activate_code: Activate a standard activation code.

The MCP Server accesses data using your login token, so different users will only see content they have permission to access.

Choosing a Connection Method

CX provides three MCP entry points:

  • In-App HTTP MCP: Suitable for directly connecting to an already running management/player app. The address is http://<device-LAN-IP>:9394/mcp.
  • Standalone HTTP MCP: Suitable for connecting to a persistently running cxmcp_http. The default address is http://127.0.0.1:9394/mcp.
  • stdio MCP: Suitable for local agents such as Claude Code and Codex to launch the cxmcp_stdio executable directly.

If the agent and the CX app are on the same LAN, prefer the in-app HTTP MCP. If you need a persistent server-side setup, use the standalone HTTP MCP. If you only want the agent to launch MCP on demand, use stdio MCP.

Starting cxserver

Start the local HTTP server:

bash
./run.sh

cxserver is only responsible for the local HTTP server and will not start MCP.

Starting HTTP MCP in the App

In the management or player app, go to the "Local Services" screen and turn on the MCP service switch. Once enabled, the interface will display something like:

text
http://192.168.1.10:9394/mcp

Agents on the same LAN should use this address to connect. Do not configure the in-app MCP as 127.0.0.1 unless the agent and the app are running on the same device.

Starting HTTP MCP

bash
cxmcp_http

Custom HTTP MCP address:

bash
cxmcp_http --host=127.0.0.1 --port=9394 --path=/mcp

Token and Source

Each MCP connection requires a valid login JWT.

HTTP MCP uses request headers:

text
Authorization: Bearer <jwt>
X-Mht-Source-Key: cloud

LAN local service uses:

text
Authorization: Bearer <lan-jwt>
X-Mht-Source-Key: lan
X-Mht-Lan-Host: http://127.0.0.1:9393

Some cloud account features (such as activation code / MHActivation tools) require a cloud account. When using LAN source, you need to provide an additional cloud account JWT for these features:

text
X-Mht-Cloud-Authorization: Bearer <cloud-jwt>

stdio MCP uses environment variables and command-line arguments. The examples use CX_MCP_* variable names, so you need to explicitly pass --token-env and --cloud-token-env:

bash
CX_MCP_TOKEN='<jwt>' /path/to/cxmcp_stdio \
  --source cloud \
  --token-env CX_MCP_TOKEN

LAN local service:

bash
CX_MCP_TOKEN_LAN='<lan-jwt>' /path/to/cxmcp_stdio \
  --source lan \
  --token-env CX_MCP_TOKEN_LAN \
  --lan-host http://127.0.0.1:9393

When using LAN source and needing activation code / MHActivation tools, provide an additional cloud account token and pass it explicitly to the CLI:

bash
CX_MCP_TOKEN_LAN='<lan-jwt>' CX_MCP_CLOUD_TOKEN='<cloud-jwt>' /path/to/cxmcp_stdio \
  --source lan \
  --token-env CX_MCP_TOKEN_LAN \
  --cloud-token-env CX_MCP_CLOUD_TOKEN \
  --lan-host http://127.0.0.1:9393

It is recommended to pass tokens via environment variables and never commit JWTs to repositories or shared configurations.

Docker stdio MCP

The Docker version of cxmcp_stdio can replace native executable installation. It is still a stdio MCP and must be run with docker run -i — do not use -d, and no port mapping is required. Replace <cxmcp-stdio-image> with the actual image name provided by your OEM or deployment environment.

Cloud:

bash
docker run -i --rm \
  -e CX_MCP_TOKEN='<jwt>' \
  <cxmcp-stdio-image> \
  --source cloud \
  --token-env CX_MCP_TOKEN

LAN:

bash
export CX_MCP_LAN_HOST='http://host.docker.internal:9393'

docker run -i --rm \
  -e CX_MCP_TOKEN_LAN='<lan-jwt>' \
  -e CX_MCP_CLOUD_TOKEN='<cloud-jwt>' \
  <cxmcp-stdio-image> \
  --source lan \
  --token-env CX_MCP_TOKEN_LAN \
  --cloud-token-env CX_MCP_CLOUD_TOKEN \
  --lan-host "$CX_MCP_LAN_HOST"

On Docker Desktop (macOS/Windows), containers accessing the host's cxserver should use host.docker.internal instead of 127.0.0.1. On Linux Docker without host.docker.internal, add the following when running:

bash
--add-host=host.docker.internal:host-gateway

Claude Code Configuration

If the token, source, or LAN host changes, it is recommended to remove the old configuration first, then re-add it to avoid stale headers or environment variables:

bash
claude mcp remove cx-cloud -s local
claude mcp remove cx-lan -s local
claude mcp remove cx-cloud-stdio -s local
claude mcp remove cx-lan-stdio -s local

HTTP Cloud

bash
export CX_MCP_TOKEN='<jwt>'

claude mcp add --transport http \
  cx-cloud http://127.0.0.1:9394/mcp \
  --header "Authorization: Bearer $CX_MCP_TOKEN" \
  --header "X-Mht-Source-Key: cloud"

HTTP LAN

bash
export CX_MCP_TOKEN_LAN='<lan-jwt>'
export CX_MCP_CLOUD_TOKEN='<cloud-jwt>'
export CX_MCP_LAN_HOST='http://127.0.0.1:9393'

claude mcp add --transport http \
  cx-lan http://127.0.0.1:9394/mcp \
  --header "Authorization: Bearer $CX_MCP_TOKEN_LAN" \
  --header "X-Mht-Source-Key: lan" \
  --header "X-Mht-Lan-Host: $CX_MCP_LAN_HOST" \
  --header "X-Mht-Cloud-Authorization: Bearer $CX_MCP_CLOUD_TOKEN"

X-Mht-Cloud-Authorization is only needed when the LAN source requires access to cloud account features. It can be omitted for regular LAN device/program queries.

stdio Cloud

bash
claude mcp add cx-cloud-stdio \
  -e CX_MCP_TOKEN='<jwt>' \
  -- /path/to/cxmcp_stdio --source cloud --token-env CX_MCP_TOKEN

stdio LAN

bash
claude mcp add cx-lan-stdio \
  -e CX_MCP_TOKEN_LAN='<lan-jwt>' \
  -e CX_MCP_CLOUD_TOKEN='<cloud-jwt>' \
  -- /path/to/cxmcp_stdio \
    --source lan \
    --token-env CX_MCP_TOKEN_LAN \
    --cloud-token-env CX_MCP_CLOUD_TOKEN \
    --lan-host http://127.0.0.1:9393

You can also put the LAN host in an environment variable:

bash
export CX_MCP_LAN_HOST='http://127.0.0.1:9393'

claude mcp add cx-lan-stdio \
  -e CX_MCP_TOKEN_LAN='<lan-jwt>' \
  -e CX_MCP_CLOUD_TOKEN='<cloud-jwt>' \
  -- /path/to/cxmcp_stdio \
    --source lan \
    --token-env CX_MCP_TOKEN_LAN \
    --cloud-token-env CX_MCP_CLOUD_TOKEN \
    --lan-host "$CX_MCP_LAN_HOST"

Verify:

bash
claude mcp list
claude mcp get cx-lan

Once inside Claude Code, run:

text
/mcp

Confirm that cx-lan or cx-cloud is connected and you can see the tools.

Codex Configuration

Codex uses ~/.codex/config.toml to configure MCP servers. HTTP MCP can use url, and stdio MCP can use command/args/env.

If the source or LAN host changes, it is recommended to delete the corresponding [mcp_servers.<name>] block from ~/.codex/config.toml, then rewrite it.

HTTP Cloud

toml
[mcp_servers.cx_cloud]
url = "http://127.0.0.1:9394/mcp"
bearer_token_env_var = "CX_MCP_TOKEN"
http_headers = { "X-Mht-Source-Key" = "cloud" }

Set the environment variable before launching Codex:

bash
export CX_MCP_TOKEN='<jwt>'
codex

HTTP LAN

toml
[mcp_servers.cx_lan]
url = "http://127.0.0.1:9394/mcp"
bearer_token_env_var = "CX_MCP_TOKEN_LAN"
http_headers = { "X-Mht-Source-Key" = "lan", "X-Mht-Lan-Host" = "http://127.0.0.1:9393", "X-Mht-Cloud-Authorization" = "Bearer <cloud-jwt>" }

If you prefer not to write the cloud account JWT into config.toml, you can omit X-Mht-Cloud-Authorization for now, or use stdio MCP to pass CX_MCP_CLOUD_TOKEN via env.

stdio Cloud

toml
[mcp_servers.cx_cloud_stdio]
command = "/path/to/cxmcp_stdio"
args = ["--source", "cloud", "--token-env", "CX_MCP_TOKEN"]
env = { "CX_MCP_TOKEN" = "<jwt>" }

stdio LAN

toml
[mcp_servers.cx_lan_stdio]
command = "/path/to/cxmcp_stdio"
args = ["--source", "lan", "--token-env", "CX_MCP_TOKEN_LAN", "--cloud-token-env", "CX_MCP_CLOUD_TOKEN", "--lan-host", "http://127.0.0.1:9393"]
env = { "CX_MCP_TOKEN_LAN" = "<lan-jwt>", "CX_MCP_CLOUD_TOKEN" = "<cloud-jwt>" }

To switch the LAN host, simply change the value of --lan-host. Codex args do not perform shell variable expansion, so do not write $CX_MCP_LAN_HOST here:

toml
[mcp_servers.cx_lan_stdio]
command = "/path/to/cxmcp_stdio"
args = ["--source", "lan", "--token-env", "CX_MCP_TOKEN_LAN", "--cloud-token-env", "CX_MCP_CLOUD_TOKEN", "--lan-host", "http://127.0.0.1:9393"]
env = { "CX_MCP_TOKEN_LAN" = "<lan-jwt>", "CX_MCP_CLOUD_TOKEN" = "<cloud-jwt>" }

Docker stdio Cloud

toml
[mcp_servers.cx_cloud_stdio_docker]
command = "docker"
args = [
  "run", "-i", "--rm",
  "-e", "CX_MCP_TOKEN",
  "<cxmcp-stdio-image>",
  "--source", "cloud",
  "--token-env", "CX_MCP_TOKEN"
]
env = { "CX_MCP_TOKEN" = "<jwt>" }

Docker stdio LAN

toml
[mcp_servers.cx_lan_stdio_docker]
command = "docker"
args = [
  "run", "-i", "--rm",
  "--add-host=host.docker.internal:host-gateway",
  "-e", "CX_MCP_TOKEN_LAN",
  "-e", "CX_MCP_CLOUD_TOKEN",
  "<cxmcp-stdio-image>",
  "--source", "lan",
  "--token-env", "CX_MCP_TOKEN_LAN",
  "--cloud-token-env", "CX_MCP_CLOUD_TOKEN",
  "--lan-host", "http://host.docker.internal:9393"
]
env = { "CX_MCP_TOKEN_LAN" = "<lan-jwt>", "CX_MCP_CLOUD_TOKEN" = "<cloud-jwt>" }

Verify:

bash
codex mcp list
codex mcp get cx_lan

Remove:

bash
codex mcp remove cx_cloud
codex mcp remove cx_lan
codex mcp remove cx_cloud_stdio
codex mcp remove cx_lan_stdio

If your current Codex version does not have the mcp remove command, you can directly edit ~/.codex/config.toml and delete the corresponding configuration block.

Other Agents

If the agent supports Streamable HTTP MCP:

  • URL: http://127.0.0.1:9394/mcp
  • Header: Authorization: Bearer <jwt>
  • Cloud Header: X-Mht-Source-Key: cloud
  • LAN Header: X-Mht-Source-Key: lan
  • LAN Header: X-Mht-Lan-Host: http://127.0.0.1:9393
  • LAN Optional Cloud Header: X-Mht-Cloud-Authorization: Bearer <cloud-jwt>

If the agent supports stdio MCP:

  • Command: /path/to/cxmcp_stdio
  • Cloud args: --source cloud --token-env CX_MCP_TOKEN
  • LAN args: --source lan --token-env CX_MCP_TOKEN_LAN --cloud-token-env CX_MCP_CLOUD_TOKEN --lan-host http://127.0.0.1:9393
  • Cloud Env: CX_MCP_TOKEN=<jwt>
  • LAN Env: CX_MCP_TOKEN_LAN=<lan-jwt>
  • LAN Optional Env: CX_MCP_CLOUD_TOKEN=<cloud-jwt>
  • The LAN host can be placed in your own environment variable, but the startup argument must still be passed explicitly: --lan-host "$CX_MCP_LAN_HOST"
  • Docker Command: docker
  • Docker args: run -i --rm -e CX_MCP_TOKEN <cxmcp-stdio-image> --source cloud --token-env CX_MCP_TOKEN

Frequently Asked Questions

Connection failures or tool call errors

Check:

  • Whether the token has expired.
  • Whether the HTTP mode is using the Authorization: Bearer <jwt> format.
  • Whether the token belongs to the current source.
  • Whether LAN mode has X-Mht-Source-Key: lan and X-Mht-Lan-Host configured.
  • Whether stdio LAN has --lan-host configured, or whether it is explicitly passed via --lan-host "$CX_MCP_LAN_HOST" in shell examples.
  • Whether, when using LAN source to call activation code / MHActivation tools, an additional cloud account token has been configured: HTTP via X-Mht-Cloud-Authorization, stdio via CX_MCP_CLOUD_TOKEN.

Configuration changes not taking effect

Remove the old MCP server first, then reconfigure. This is especially important when the source, LAN host, or command path changes — overwriting is not recommended.

Using LAN and Cloud simultaneously

It is recommended to configure them as two separate MCP servers, for example:

  • cx_cloud
  • cx_lan

They can use the same HTTP MCP URL but require different tokens and source configurations.

Security Notes

  • Do not commit JWTs to repositories.
  • For local testing, prefer environment variables or local private configuration files.
  • HTTP MCP binds to 127.0.0.1 by default — do not casually expose it to the public internet.
  • For stdio mode, it is recommended to use the CX_MCP_TOKEN environment variable to pass the token; --token is only recommended for temporary debugging.
  • The LAN source's CX_MCP_CLOUD_TOKEN is a cloud account JWT and must also not be committed to repositories or shared configurations.
  • The current version does not support refresh tokens; you will need to provide a new JWT after the token expires.