zenyard-relay
zenyard-relay connects an MCP server running on a user's machine to the
Zenyard backend, even when that machine is behind a NAT or firewall. It
dials out to the backend so the server can be reached without exposing any
inbound ports.
Run one zenyard-relay serve process per MCP server you want to expose.
Each process is a transparent passthrough — it forwards traffic between the
backend and the MCP server unchanged. Multiple servers on the same machine
appear to the backend as a single device.
The MCP server can run as a local subprocess (stdio) or a remote HTTP
endpoint (streamable-http).
Install
The relay ships as a Python wheel built by maturin;
the wheel installs the native zenyard-relay binary into the environment's
bin/ (or Scripts\ on Windows):
pip install zenyard-relay
Or build from source with a stable Rust toolchain (≥ 1.75):
cargo build --release
The binary lands at target/release/zenyard-relay. Wheels for the common
platforms are published from .github/workflows/ci.yml (tests gate the
wheel publish step).
One-time device setup
serve runs without any config file as long as --control-endpoint (or
--api-url) and the ZENYARD_RELAY_TOKEN env var are supplied. For
convenience, a shared ~/.zenyard/relay.json can hold the control endpoint
(and optionally the token) so individual sidecars don't have to pass it on
the command line:
zenyard-relay config init # optional; writes a starter ~/.zenyard/relay.json
zenyard-relay config path # prints the config path
zenyard-relay config validate # validates the file
zenyard-relay relay-id # prints this device's relay id (generating one if missing)
~/.zenyard/relay.json example:
{
"config": {
"control_endpoint": "wss://relay.zenyard.dev/relay/control",
"device_description": "user-laptop (Linux)"
}
}
Plugins that already have the backend HTTP API URL configured can pass it
as-is — the relay swaps http/https for ws/wss and appends the
fixed /relay/control path:
zenyard-relay serve --id <ID> --api-url http://localhost:30465/ ...
The same field is accepted in relay.json as "api_url" (mutually
exclusive with "control_endpoint").
The auth token is preferred from ZENYARD_RELAY_TOKEN (keeps secrets out
of the JSON file); config.token is the fallback.
Sidecar contract
zenyard-relay serve --id <UPSTREAM_ID> [--display-name <NAME>] [--description <TEXT>] [--tag K=V...]
[--control-endpoint <URL> | --api-url <URL>]
[--config <PATH>] [--log-level <LEVEL>] [--log-format <FMT>]
(--command <CMD> [--arg <V>...] [--env K=V...] [--cwd <DIR>])
| (--url <URL> [--header "Name: value"...])
--control-endpoint / --api-url may be omitted when ~/.zenyard/relay.json
(or the file pointed at by --config) supplies one. ZENYARD_RELAY_TOKEN
in the environment is preferred over config.token.
Example — stdio upstream:
zenyard-relay serve --id fs --display-name "Filesystem" \
--command npx --arg -y --arg @modelcontextprotocol/server-filesystem --arg /tmp
Example — remote upstream:
zenyard-relay serve --id api --display-name "Example API" \
--url https://api.example.com/mcp \
--header "Authorization: Bearer ghp_..."
After connecting, the sidecar sends a single Hello frame carrying the
connection identity (relay_id / upstream_id) and the initial metadata
snapshot (display_name / description / tags). It then reads stdin
line-by-line for update ops that mutate the announced metadata:
{"op":"update", "display_name":"Echo (renamed)"}
{"op":"update", "tags":{"file":"sample.exe"}}
{"op":"update", "description":"Decompilation tools for sample.exe"}
Each update op replaces the supplied fields and re-sends
UpstreamUpdated. The sidecar logs lifecycle events (connections, sessions,
auth failures) to stderr per --log-level / --log-format, and exits when
stdin closes.
For "same resource → same upstream across restarts" semantics, derive
--id deterministically from the resource (e.g.
ida-<sha256(idb_path)>). Conflicting live claims on the same id from
two sidecars trigger takeover at the backend: the newer connection wins,
the older one's sessions continue until they close naturally.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Ok |
| 1 | Generic error |
| 2 | Invalid configuration / fatal auth rejection |
| 3 | Superseded — another relay took over this (relay_id, upstream_id) |
License
This project is licensed under the GNU Affero General Public License v3.0 only.
See the LICENSE file in this repository for the full license text.
Release files for zenyard-relay 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| zenyard_relay-0.1.2.tar.gz | 94.4 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| zenyard_relay-0.1.2-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| zenyard_relay-0.1.2-py3-none-musllinux_1_2_x86_64.whl | Python 3 | none | Linux musl 1.2+ x86-64 | Details |
| zenyard_relay-0.1.2-py3-none-musllinux_1_2_aarch64.whl | Python 3 | none | Linux musl 1.2+ ARM64 | Details |
| zenyard_relay-0.1.2-py3-none-manylinux_2_28_aarch64.whl | Python 3 | none | Linux glibc 2.28+ ARM64 | Details |
| zenyard_relay-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details |
| zenyard_relay-0.1.2-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| zenyard_relay-0.1.2-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size:33.0 MB
Release files / zenyard_relay-0.1.2.tar.gz
| Download URL | zenyard_relay-0.1.2.tar.gz |
|---|---|
| Size | 94.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7d0270e1656ce506157c996e75963624541687817bef65218473807d214ec091
|
|
BLAKE2b-256 checksum How to use checksums |
fa3679b94919a6f0995151e5a17645ce05ccfb06408b1866fda23cd31b77de06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / zenyard_relay-0.1.2-py3-none-win_amd64.whl
| Download URL | zenyard_relay-0.1.2-py3-none-win_amd64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
605215ecaedb5b0881512987953ce078023257e6efe95858f59c4be950eb6e63
|
|
BLAKE2b-256 checksum How to use checksums |
c671d0f5dcb49eec1b36b562fcc26047a76bd2786ba0391cbe0e4bab187536c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / zenyard_relay-0.1.2-py3-none-musllinux_1_2_x86_64.whl
| Download URL | zenyard_relay-0.1.2-py3-none-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 5.0 MB |
| Tags | Linux musl 1.2+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
5871ab69ae38ac3eb0ce882acfbcbc77c98ad626dab1725f36e08ce04958e42e
|
|
BLAKE2b-256 checksum How to use checksums |
83559e10ad17ebbd43a244434a1c25599901b0882f868b6068d3d71fd95dee30
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / zenyard_relay-0.1.2-py3-none-musllinux_1_2_aarch64.whl
| Download URL | zenyard_relay-0.1.2-py3-none-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 4.6 MB |
| Tags | Linux musl 1.2+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
7629a3321f56dd18e80df8920fdaf6365215b241e174e7c7d03c5f5cb7f03e23
|
|
BLAKE2b-256 checksum How to use checksums |
c900a02ce254ca56114c29b067409e4228d6e8af6b7356624cb166160ec6f83d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / zenyard_relay-0.1.2-py3-none-manylinux_2_28_aarch64.whl
| Download URL | zenyard_relay-0.1.2-py3-none-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 4.5 MB |
| Tags | Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
ad89de4055c7a16d2b03172c7a9861e10fe3c59cb6dc8a9dcd4700c4e964c42d
|
|
BLAKE2b-256 checksum How to use checksums |
3165275190071ae36b2b32e1d484d53a5b63b2f8da855716ed92db3e9277a90d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / zenyard_relay-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | zenyard_relay-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 4.8 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
1c3d79022a6d0bc976b2b6bc17ee7af178a42ec1361b4348ba9e44093bda5408
|
|
BLAKE2b-256 checksum How to use checksums |
2e7027049c3abb36c1252c4a5f123c9a61ad631dc7d5bcf8194a3004a61bd591
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / zenyard_relay-0.1.2-py3-none-macosx_11_0_arm64.whl
| Download URL | zenyard_relay-0.1.2-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 4.6 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
de84f85f36106a1e3dfc8b73e47e10a395e889011c94fc0e297ccc0b27036b3f
|
|
BLAKE2b-256 checksum How to use checksums |
50725f5b0668759e50acdff7c0ca4c327170a0b2c372209470f0eb263264cc6d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / zenyard_relay-0.1.2-py3-none-macosx_10_12_x86_64.whl
| Download URL | zenyard_relay-0.1.2-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 4.8 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
275f081de892e4c7bca126af47608f16a1cc3ddc888d758789d51d32f2ff5926
|
|
BLAKE2b-256 checksum How to use checksums |
44a2406b837cf80a1a90929a70afc2d802c50ed4a44dfb9bc06e1e69885a7836
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency log