Model or dataset
opentokenz/mcpx avatar
opentokenz/mcpx

mcpx is a gateway that gives a chat client a workspace, an edit guard and a session that survives a reconnect

MCPX 是运行在开发环境中的 MCP Runtime(网关)。ChatGPT、Claude、Cursor、Grok 及其他支持 Streamable HTTP 的 MCP 客户端,可以通过统一工具面理解项目、查看 Unified Diff、修改源码、运行任务、采集环境信息,并调用本地 MCP 与 Skill。

431 stars85 forksGoApache-2.0

At a glance

What is it?
A Go runtime that exposes 19 MCP tools over a single Streamable HTTP endpoint, keeps every stateful call keyed to a persisted session id, and separates freezing a file manifest from the confirmation that submits it. Builds from source with Go 1.26.1, updates itself by checksum, and serves only /mcp with no SSE fallback.
Who is it for?
Adopt it if you want one MCP endpoint that a chat client can resume across connections, with an edit guard and a persisted task log rather than a chat window with file access bolted on. Check two things before exposing it beyond localhost: the auth mode, because an empty configuration with no token behaves as open, and the command policy, because the sample configuration shown in the documentation is looser than the tightened one it suggests.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Nineteen tools, and the edit tool has no delete

The tool list is the interface, and it is the only authority. A tools/list call returns the names, descriptions, parameter schemas and annotations, and clients are told to treat that response as the single source of truth rather than anything cached elsewhere.

Twelve are core tools. workspace takes no arguments and lists registered workspaces so a client can pick one before opening a session. session creates, resumes or closes a remote session, and omitting the action defaults to open or resume. read assembles source context. edit creates, updates or renames files under a SHA revision guard with idempotent semantics, and it does not offer deletion at all.

That missing delete is the detail worth reading twice. Removal of a file is not a capability the model gets; it is a separate tool, move_out, which freezes a manifest first and requires a confirmation before anything happens. The tool list separates discovery, session handling, source reading, editing, planning and extension calls into twelve roles, and seven support tools sit on top for batching, observation and environment facts.

Two session identifiers exist and only one of them is for your work

The gateway distinguishes a transport-level identifier from a business one, and the difference matters more than it sounds.

Mcp-Session-Id is temporary. It belongs to the Streamable HTTP transport, carries connection and protocol state, and can change after a reconnect or a switch of client. remote_session_id is the persistent key: it lives in SQLite and is the primary key for workspaces, roles, edits, tasks, plans, operations, snapshots and artifacts.

Every stateful operation is keyed to the latter. The client is told to store and reuse the full remote_session_id, edit_id, plan_id, plan_task_id, execution_task_id, operation_id and artifact_id exactly as returned, and never to abbreviate them, guess them or reconstruct them from a log.

Two related boundaries are declared in the same place. Revision tokens for skills and MCP servers are no longer shown to the model at all, with the runtime revalidating consistency between describe and call. And plan tasks and execution tasks are separate namespaces, so there is no compatible generic task_id field to fall back on.

Moving files out takes a freeze step and a separate confirmation

The one destructive capability is split into two phases. A prepare action freezes an explicit manifest of files, directories and symlinks, which is the thing a human can read. A submit action carries only a confirmation_uuid.

The submit call therefore cannot express intent of its own. It references a manifest that was already fixed, so a model cannot describe one set of paths in the request and delete a different set at confirmation time. That is what semantic confirmation means here: the confirmation is bound to a frozen artifact rather than to a promise about what will happen.

The policy layer around it is configurable. Security covers OAuth, Bearer tokens, remote session ACL, command and file policies and this confirmation step. The sample configuration in the documentation is described as conservative, and the note attached to it says it differs from the generated default by tightening the decision for unknown commands to confirm.

Building from source needs Go 1.26.1, and the revision comes from your worktree

The build is three commands:

bash
git clone https://github.com/opentokenz/mcpx.git
cd mcpx
go build -o bin/mcpx ./cmd/mcpx-server

A local static build turns CGO off with CGO_ENABLED=0 set in front of the same build line. The module declares go 1.26.1, and the requirement section says to treat go.mod as authoritative for the exact version.

Version stamping has three sources, and the documentation is careful about which one wins. A normal build backfills the current git revision from Go build info, appending -dirty when the worktree has uncommitted changes. A real release takes its values from GoReleaser linker flags, which inject version, commit and a real build time. CI builds binaries with provenance and then checks with mcpx -version that the commit and date survived.

The dependency set explains the runtime choices: a pure-Go SQLite driver rather than cgo, the MCP Go SDK, Wails v3 for the Windows tray and GUI, JWT v5 and oauth2 for the auth modes.

Daemon mode stops the previous instance before it starts

Foreground and background are one flag apart. Foreground is ./bin/mcpx. Background is ./bin/mcpx -d, which writes daemon state to ~/.mcpx/mcpx-daemon.json and logs to ~/.mcpx/logs/mcpx-daemon.log.

The behaviour to know about is what happens on the next start. Starting a foreground service or another background instance causes the gateway to first stop an old background process that is still recorded as alive in that state file. So a second start is not a second listener competing for port 9090; the first one is shut down first.

The runtime directory is created on first start under ~/.mcpx, and MCPX_HOME relocates it. The contents are listed explicitly: config.yaml for the listener, auth, security policy and workspaces, .mcp.json for upstream MCP servers, logs/ for JSONL audit records, skills/ as an optional local skill root, workspaces.example.yaml, state/mcpx.db for the index of sessions, edits, tasks, plans, operations, snapshots and artifacts, and tasks/ for persistent terminal logs.

The default listen address is the loopback only, at http://127.0.0.1:9090/mcp.

Workspace registration survives an unmounted disk but cleans up a deleted one

Registration is a separate command that does not start the service:

bash
./bin/mcpx workspace register /path/to/your/project

The interesting logic is what happens at the next startup, when each registered root path is validated. If the parent directory is not available yet, such as an external disk that is not mounted, startup waits for the path to appear. When the wait times out, the registration is kept and a warning is logged, because a temporarily unavailable path is not the same as a deleted one.

A different case is handled the other way. If the parent exists but the target directory is gone, or exists and is not a directory, that entry is removed from config.yaml. The stated reason is convenience: a disposable worktree that you deleted does not need manual cleanup.

So one class of missing path is treated as transient and the other as permanent, decided by whether the parent survives. That distinction is the whole design, and it is the piece to test before you rely on it with a mounted volume.

Self-update verifies a checksum then replaces the running binary, and there is no /sse

The update command has three forms, a check with no install, a plain update, and an update pinned to a version:

bash
./bin/mcpx update --check
./bin/mcpx update
./bin/mcpx update --version 0.9.6

What it does is described step by step: pick the GitHub Release artifact for the current platform, verify the SHA-256 listed in checksums.txt, then verify the version of the downloaded binary before replacing the executable. Access to the GitHub API can be authenticated with GITHUB_TOKEN.

Verifying the checksum and then verifying the version are two different checks, and the second one catches a case the first cannot: a correct file that is the wrong version.

The transport boundary is narrower than the tool list suggests. Only the Streamable HTTP /mcp endpoint is served. There is deliberately no legacy HTTP plus SSE /sse or /message compatibility endpoint, so a client that has not moved to Streamable HTTP has no path in. The command surface beyond the server includes mcpx stop, mcpx desktop for a tray and GUI on Windows only, mcpx observe as a read-only terminal observer of workspace events, mcpx oauth-register, and the workspace register command. Common service flags are -addr, -log-level, -log-format, -d and -version.

Editorial conclusion

Adopt it if you want one MCP endpoint that a chat client can resume across connections, with an edit guard and a persisted task log rather than a chat window with file access bolted on. Check two things before exposing it beyond localhost: the auth mode, because an empty configuration with no token behaves as open, and the command policy, because the sample configuration shown in the documentation is looser than the tightened one it suggests. Build from source rather than trusting a downloaded binary if you can, and note that only /mcp is served, so any client that still speaks the older HTTP plus SSE transport will not connect.

Frequently asked questions

What tools does mcpx expose over MCP?

Nineteen in total: twelve core tools including workspace, session, read, edit, move_out, observe, progress, execute, plan, artifact, skill_tool and mcp_tool, plus seven support tools for batching, operation management and environment reads.

What is the difference between Mcp-Session-Id and remote_session_id in mcpx?

Mcp-Session-Id is a temporary transport identifier that can change on reconnect or when the client changes. remote_session_id is persisted in SQLite and is the primary key for workspaces, roles, edits, tasks, plans, operations, snapshots and artifacts.

How do I build mcpx from source?

Clone the repository, change into the mcpx directory, then run go build -o bin/mcpx ./cmd/mcpx-server. The module declares Go 1.26.1, and a static local build sets CGO_ENABLED=0 in front of the same command.

Does mcpx support the older HTTP plus SSE MCP transport?

No. It serves only the Streamable HTTP /mcp endpoint, and the documentation states there is no legacy /sse or /message compatibility endpoint. The default listen address is http://127.0.0.1:9090/mcp.

How does the mcpx update command verify what it downloads?

It selects the GitHub Release artifact for the platform, checks the SHA-256 against checksums.txt, then verifies the version of the downloaded binary before replacing the executable. GITHUB_TOKEN authenticates the GitHub API when needed.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. opentokenz/mcpx on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/opentokenz-mcpx.svg)](https://hysenlabs.com/projects/opentokenz-mcpx)