AI-native MCP toolchain for Cangjie developers.
Exposes a curated set of Cangjie-aware tools to any MCP-compatible LLM client — Claude Desktop, Cursor, Windsurf, Continue, OpenAI Agents, Cherry Studio, and friends — so the model can search the standard library, run cjpm / cjlint / cjfmt, scaffold a new project, look up the central registry, or read a source file, all without leaving the chat.
cjdrift is one binary that ships as a Cangjie 1.1.3 third-party
library. You can import it into your own project, embed the MCP
server into a larger app, or run it as a standalone cjdrift command
that talks to the LLM over stdio.
The Cangjie ecosystem has a lot of moving parts: cjc, cjpm, cjlint,
cjfmt, cjcov, cjtrace-recover, std.ast, the central registry at
pkg.cangjie-lang.cn, the cangjie-tpc and cj-awesome package
indexes, the docs site at cangjie-lang.cn/docs, the HCIA-Cangjie
developer certification, the language server, and so on. When you ask
an LLM to "add a function that reads JSON from a file", the model has
to remember all of these moving parts and guess at API names.
cjdrift gives the LLM tools for every one of those parts:
| When the LLM needs to ... | It calls |
|---|---|
| ... find a Cangjie stdlib API | cangjie_apis |
| ... read the long-form docs for one API | cangjie_doc |
| ... find an idiomatic snippet for a task | cangjie_patterns |
... run cjpm build / cjpm test |
cangjie_run |
... run cjlint and get a structured list |
cangjie_lint |
... format a file with cjfmt |
cangjie_fmt |
| ... look up a package on the registry | cangjie_pkg_search |
| ... start a new project | cangjie_scaffold |
| ... understand a compiler / runtime error | cangjie_explain |
| ... read a source file | cangjie_read_file |
| ... write a file | cangjie_write_file |
| ... list a directory | cangjie_list_dir |
Every tool is read-only by default. The only state-changing tool
(cangjie_write_file) requires an explicit confirm: true from the
model, which the MCP client surfaces to the human before invoking.
# from your Cangjie project directory
cjpm add cjdriftOr, if you want the binary too:
git clone https://gitcode.com/jiangzeyu-2026/cjdrift
cd cjdrift
cjpm build
./target/release/cjdrift server # run the MCP server
./target/release/cjdrift version # print the version
./target/release/cjdrift tools # list built-in tool names
./target/release/cjdrift search "ArrayList"
./target/release/cjdrift explain "cannot find symbol"Edit ~/Library/Application Support/Claude/claude_desktop_config.json
(macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"cjdrift": {
"command": "cjpm",
"args": ["run", "--", "server"],
"cwd": "/path/to/cjdrift"
}
}
}Restart Claude Desktop. You should see the 11 cangjie_* tools in the
tool palette.
Both follow the same MCP config format. In ~/.cursor/mcp.json (or
~/.codeium/mcp.json):
{
"mcpServers": {
"cjdrift": {
"command": "cjpm",
"args": ["run", "--", "server"]
}
}
}Add to ~/.continue/config.json:
{
"experimental": {
"modelContextProtocolServers": [
{
"name": "cjdrift",
"transport": {
"type": "stdio",
"command": "cjpm",
"args": ["run", "--", "server"]
}
}
]
}
}If you are building a Cangjie IDE plugin, an in-house agent platform, or just want to drive cjdrift from your own code:
import cjdrift
main(): Int64 {
// The default registry exposes all 11 built-in tools over stdio.
return cjdrift.runDefaultServer()
}For finer control, build a registry with only the tools you need:
import cjdrift.core.{Server, ServerConfig, ToolRegistry, Transport}
import cjdrift.tools.{CjapiTool, CjlintTool, ExplainTool}
import cjdrift.knowledge.{ApiIndexLoader, builtinIndex, Explainer}
import std.io.{InputStream, OutputStream}
main(): Int64 {
let registry = ToolRegistry()
let idx = ApiIndexLoader().load()
registry.register(CjapiTool(idx))
registry.register(CjlintTool())
registry.register(ExplainTool(Explainer()))
let transport = Transport(InputStream.stdin(), OutputStream.stdout())
let server = Server(ServerConfig(), registry, transport)
return server.run()
}See docs/tools.md for the full input schema and
return shape of every tool. Here is a one-liner for each:
- cangjie_apis — Fuzzy search the offline API index. Returns matches ranked by exact / prefix / substring hit on the type, member, package or signature fields.
- cangjie_doc — Look up the full record for one entry, with a few related entries from the same package.
- cangjie_patterns — Search a small library of short idiomatic snippets ("how do I write a unit test?", "how do I parse JSON?", "how do I spawn a future?").
- cangjie_run — Run an allow-listed
cjpm/cjpm/cjc/cjlint/cjfmtsubcommand and capture stdout, stderr, exit code, and elapsed time. Anything outside the allow-list is refused for safety. - cangjie_lint — Run
cjlint, parse its JSON report, and group findings by rule so the LLM sees patterns instead of one-off warnings. - cangjie_fmt — Run
cjfmtin dry-run mode (default) to emit a unified diff, or in write mode to rewrite a file in place. - cangjie_pkg_search — Search the Cangjie central registry with an offline seed list as a safety net.
- cangjie_scaffold — Generate a ready-to-build project for one of
three kinds:
executable,library,mcp-server. - cangjie_explain — Heuristic explanations for common compiler / runtime error messages, with concrete fix suggestions.
- cangjie_read_file / cangjie_write_file — Read or write a
file under a configured project root. Write requires
confirm: true. - cangjie_list_dir — List a directory under a configured project root.
+----------------------------+
| MCP client (Claude etc.) |
| |
| LLM <-> JSON-RPC over stdio|
+-------------+--------------+
|
v
+----------------------------+
| cjdrift server (this) |
| |
| Transport Protocol |
| Server Registry |
| |
| Tool Tool Tool ... |
+-------------+--------------+
|
+-------------------+-------------------+
v v v
stdio / fs / cjpm cjlint cjfmt network
process (via std.process) (registry)
The codebase is layered so that you can swap the transport (stdio,
WebSocket, in-memory), the toolset, or the knowledge backend
independently. See docs/arch.md for the full
architecture write-up.
cjdrift is a developer's tool, not a security boundary. The LLM
ultimately decides which tools to call and what to do with the
results. We layer three safety mechanisms on top of whatever the MCP
client already provides:
- Allow-list for
cangjie_run. Only build, test, run, update, clean, lint, fmt, check, info, version. Nocjpm add, no shell. confirm: trueforcangjie_write_file. The model must explicitly opt in. The MCP client then surfaces a human prompt.- Path containment for
cangjie_*_fileandcangjie_list_dir. Paths are resolved against a configuredroot, and..segments are rejected unless the caller explicitly opts in.
- SDK: cjdrift 0.1.0 targets Cangjie 1.1.3 (STS). It is built and tested on Linux x86-64, macOS aarch64, and Windows x86-64.
- MCP protocol: cjdrift speaks MCP
2025-06-18. Earlier2024-11-05clients work; later versions will work as long as the spec stays backwards-compatible (which Anthropic has promised). - MCP clients: Claude Desktop 0.7+, Cursor 0.40+, Windsurf 1.5+, Continue 0.9+, OpenAI Agents SDK 0.3+.
# Build and run all unit tests
cjpm test
# Run the server in dev mode (foreground)
cjpm run -- server
# Build a release binary
cjpm build -i
cjpm bundle
# Publish to the central registry
cp cangjie-repo.toml.example cangjie-repo.toml # then fill in your token
cjpm publishApache-2.0. See LICENSE.
- The Cangjie team at Huawei for an unusually well-thought-out language and a generous SDK.
- The Anthropic team for the MCP spec, which is the most pleasant tool protocol I have used.
- The contributors to
cangjie-tpcandcj-awesomefor documenting the ecosystem so thoroughly.