Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mcpx

A single-binary Zig CLI bridge with no runtime dependencies for calling Model Context Protocol HTTP servers directly.

Build

Zig 0.16.0 is required.

zig build -Doptimize=ReleaseSafe

The executable is written to zig-out/bin/mcpx.

Configuration

Create $XDG_CONFIG_HOME/mcpx/config.toml, or ~/.config/mcpx/config.toml when XDG_CONFIG_HOME is unset:

[[http]]
name = "search"
endpoint = "http://localhost:3000/mcp"

[[http]]
name = "github"
endpoint = "https://mcp.example.com/mcp"
timeout_secs = 60

[http.oauth]
client_id = "my-app"          # optional when register = true
scopes = "repo read"          # optional, space-separated
register = true               # RFC 7591 dynamic client registration

The default timeout is 30 seconds; timeout_secs = 0 is rejected. Pass -c <path> or --config=<path> to use another configuration file. Server entries are validated before any request: names must be unique and non-empty, endpoints must be absolute http/https URIs, and configured header names and values must be valid HTTP field content.

For an OAuth-configured server, mcpx honors WWW-Authenticate resource_metadata challenges or RFC 9728 protected-resource discovery, then tries RFC 8414 Authorization Server Metadata and OIDC Discovery. A challenge metadata URL is only followed when it stays on the resource server's own origin, and every advertised authorization server is tried in order. Issuer, authorization, token and registration URLs must use https, except on loopback hosts.

mcpx uses Authorization Code with PKCE (S256), opens the authorization URL with xdg-open on Linux, and waits up to 300 seconds for a redirect to an ephemeral 127.0.0.1 callback port. Other requests on that port, such as a browser favicon fetch, are answered and ignored. The URL is always printed to stderr so it can be opened manually. The callback state is compared in constant time, an error= response is reported with its description, and the authorization-server iss (when supplied or required) is verified before code exchange. Both authorization-code and refresh grants include the canonical MCP endpoint as RFC 8707 resource.

Dynamic registration (register = true) registers a public native client with token_endpoint_auth_method: none, so no client secret has to be stored.

Tokens and dynamically registered client credentials are keyed by validated issuer and stored separately in <config dir>/mcpx/tokens.toml. The directory is created with 0700 and the file is atomically replaced with owner-only 0600 permissions after grants and refreshes. Access tokens are refreshed when they are expired or within 60 seconds of expiry. To discard the effective session and force a new browser authorization, run:

mcpx auth <server>

When OAuth is configured, mcpx owns the Authorization header and ignores an Authorization value in [http.headers]. Static authorization headers remain supported for servers without an OAuth block.

Usage

mcpx servers
mcpx auth <server>
mcpx list <server>
mcpx call <server> <tool> [json_args]
mcpx skills <server> [tool]

mcpx servers appends [oauth] to OAuth-enabled entries. Unknown options are rejected rather than being treated as arguments.

mcpx skills prints a skill document, not just schemas: a preamble states how to reach the tools with mcpx call <server> <tool> '<json_arguments>', points at mcpx list, mcpx skills <tool> and mcpx auth, and explains the JSON argument rules and the 6 / 7 exit codes. Every tool ends with an ### Invocation block containing a runnable mcpx call command seeded with its required parameters. A -c PATH in effect is repeated in each printed command.

Exit codes

Code Meaning
0 Success
1 Unclassified failure
2 Usage or configuration error, including an unknown server or tool
3 Authentication or authorization failure
4 Protocol or JSON-RPC failure
5 Request timeout
6 The tool ran and reported isError
7 The tool needs more input (resultType: input_required)

A JSON-RPC error is reported on stderr with its code and a generic message. Remote response bodies, messages, and error data are hidden by default because they may contain submitted arguments or credentials. Set MCPX_DEBUG=1 to include that raw diagnostic content; mcpx prints a warning because this mode may expose secrets in terminals and CI logs.

mcpx negotiates MCP 2026-07-28 with server/discover and remains compatible with legacy 2025-03-26 initialize/session servers. It supports JSON and SSE responses and follows all tools/list pagination cursors.

Protocol compatibility

Protocol behavior comes from one version/capability table covering 2025-03-26, 2025-06-18, 2025-11-25, and 2026-07-28. mcpx attempts modern discovery first, honors -32022 supported-version responses by choosing the newest mutual version, and falls back to legacy initialize when server/discover is unavailable.

For 2026-07-28, requests include protocol/client _meta, Mcp-Method, and Mcp-Name where applicable. Modern requests do not use MCP sessions or legacy cancellation notifications. A result with resultType: input_required is printed intact and reported with exit code 7; mcpx does not yet conduct that follow-up interaction automatically.

Development

zig build test          # includes loopback HTTP integration tests
zig fmt --check src build.zig

Tool listings skip entries without a name and duplicate names, tool schema rendering is depth bounded, and responses are capped at 16 MiB (1 MiB for OAuth metadata) so a hostile server cannot exhaust memory.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages