
moca-mcp
io.github.openmoca/moca-mcp
Search and cite MOCA knowledge packages, verified and with citation records, on your machine.
Documentation
moca-mcp: the MOCA MCP server
The MCP server for MOCA knowledge packages, in one
download with nothing else to install. Connect a .moca file to Claude
Desktop, Claude Code, VS Code, Cursor or any MCP client, and ask questions
about it with citations you can check.
It is built on the .NET MOCA Reader. Every result is a citation record: the text plus its package, version, digest, signature status, reviews, freshness and evidence.
Install
Download the file for your computer from the latest release and unzip it:
| Computer | File |
|---|---|
| Windows (Intel or AMD) | moca-mcp-win-x64.zip |
| Windows on Arm | moca-mcp-win-arm64.zip |
| Mac with Apple silicon | moca-mcp-osx-arm64.zip |
| Mac with an Intel processor | moca-mcp-osx-x64.zip |
| Linux (x64 or Arm) | moca-mcp-linux-x64.zip, moca-mcp-linux-arm64.zip |
It holds one program, moca-mcp (moca-mcp.exe on Windows). It needs no
.NET, Node.js or anything else installed.
Or, with .NET 10: dotnet tool install -g OpenMoca.Mcp.
The first run: unsigned builds
The builds are not code-signed yet, so your computer warns you the first time. Signing is planned.
- macOS says the developer cannot be verified. In Finder, right-click
moca-mcp, choose Open, then Open again. Or, in Terminal:xattr -d com.apple.quarantine /path/to/moca-mcp. - Windows SmartScreen says it protected your PC. Choose More info, then Run anyway.
Each release lists the SHA-256 of every file, so you can check what you downloaded.
Connect a package
Claude Desktop keeps its servers in claude_desktop_config.json. To open
it, go to Settings, then Extensions (under Desktop app). At the
bottom of that page, choose Manage, then Edit Config under
Local MCP servers. The file is in ~/Library/Application Support/Claude/
on a Mac and %APPDATA%\Claude\ on Windows.
Add the server, save, and quit and restart Claude. This serves every package in a folder (see A folder of packages):
{
"mcpServers": {
"moca": {
"command": "/path/to/moca-mcp",
"args": ["--library", "/path/to/packages",
"--trust-root", "/path/to/trust-root.json",
"--audience", "public"]
}
}
}
- If the file has no
mcpServersyet, add it as shown, inside the outer{ }and beside any settings already there, with a comma between them. - To serve one package, put its path in place of
"--library", "/path/to/packages". - Use full paths. On Windows, the command is
moca-mcp.exe, and each\is written twice:"C:\\Users\\you\\moca\\moca-mcp.exe".
Other clients take the same command and arguments. For Claude Code:
claude mcp add acme-support -- /path/to/moca-mcp /path/to/acme-support.moca --trust-root /path/to/trust-root.json
Then ask: "Using acme-support, how long do customers have to ask for a refund? Cite the page."
ChatGPT and Claude.ai on the web call MCP servers from their own cloud, so they cannot reach a server on your computer: they need a hosted MCP server.
A folder of packages
Keep your packages in one folder, packed (.moca) or unpacked, and serve the
whole folder:
moca-mcp --library ~/moca --trust-root ~/moca/trust-root.json
- Only the manifests are read at start, so a folder of hundreds of packages starts at once. Each package is read and verified the first time a question needs it, then kept in memory for the session.
- Ask about one package at a time. The assistant lists the packages with
moca_list_packages, then names the ones it wants inmoca_search. - Indexes are found by name.
acme.moca.idx, oracme.<model>.moca.idx, besideacme.mocaor theacmefolder, is used for that package. Either can be a folder, or a Zip with.zipon the end, as downloaded. - Versions are handled for you. When a package supersedes another, both load together, so the older one is always reported as superseded.
- Composed packages find their members in the same folder.
--watchpicks up packages you add, change or remove while it runs.
Search by meaning
With a standard embedding model installed, packages whose index was built with it are searched by words and meaning together (hybrid): a question finds the page that answers it even when they share no words.
moca-mcp models list # the standard models, and which are installed
moca-mcp models add bge-small-en-v1.5 # download once, checked against its pinned SHA-256
| Model | Size | Best for |
|---|---|---|
bge-small-en-v1.5 | 33 MB | English, a good default |
all-MiniLM-L6-v2 | 22 MB | English, the smallest and fastest |
nomic-embed-text-v1.5 | 131 MB | English, long pages |
multilingual-e5-small | 117 MB | Many languages, French included |
Models go in ~/.moca/models (or --models, or MOCA_MODELS) and load the
first time a search needs them. Build an index with the same model using
moca-index build <package> -o <package>.moca.idx --model bge-small-en-v1.5
and put it beside the package. A package whose model is not installed is
still searched by words, and moca_list_packages names the model to add.
Usage
moca-mcp [package...] [--library folders...] [--trust-root file] [--audience public,internal] [options]
| Option | Does |
|---|---|
<package> | A package folder or .moca file, loaded at start. Write package=index to search through a sidecar index |
--library <folders...> | Folders of packages, loaded on first use |
--trust-root <file> | Verifies publisher and review attestations. Without it, nothing is reported as signed or reviewed, and no package can supersede or contest another |
--audience <list> | The audiences served, such as public. The assistant cannot widen it. Pages with no audience label are left out |
--allow-unlabelled | With --audience, also serve pages that have no audience label |
--include-excluded | Also serve out-of-force, superseded and deprecated content, flagged as such |
--allow-unsigned-relations | Apply supersedes and conflictsWith from unsigned packages. Only for a library of your own packages |
--members <folders...> | Where a composed package's members are, if not in the library |
--overlay <layer=file...> | Structure overlays, as the application or organisation layer |
--watch | Follow changes to the library folders |
--preload | Load the library at start, not on first use |
--max-packages <n> | Most packages a library lists (default 1,000) |
--max-depth <n> | How deep to look in a library folder (default 3) |
--models <folder> | Where the standard embedding models are installed (default ~/.moca/models) |
--max-loaded-pages <n> | Memory budget: pages kept loaded at once (default 25,000, about 750 MB). The least recently used package is unloaded beyond it |
Invalid packages are skipped and reported on standard error;
moca_list_packages says why.
Tools and resources
| Tool | Returns |
|---|---|
moca_list_packages | Every package the server can serve, loaded or not: id, version, title, description; for a loaded package its digest, signature, capabilities, page count and search mode |
moca_search | Citation records, compact by default; detail: "full" for whole records. packages limits it to some packages; mode is lexical, semantic or hybrid. Out-of-force, superseded and deprecated content is left out unless the host starts the server with --include-excluded: the assistant cannot ask for it |
moca_structure | Structure answers: concept, requires, required_by, parts, narrower, broader, related, sequence or nodes, each naming its layer |
moca_get_node | One citation record with the page's full text |
moca_package_info | One package's manifest, digest, signers, attestations, members, profiles and the Reader's findings: why it is, or is not, trusted |
Every tool is marked read-only, and no tool takes a file path: the assistant
can only choose among the packages you serve. Input is bounded and checked
before anything runs. Every page of a loaded package is also a resource at
moca://node/<URL-encoded versioned reference>. The audience filter and the
default retrieval policy apply to tools and resources alike.
Package text is returned as data inside citation records. Tool descriptions tell the model to quote and cite it, not follow it (Reader contract §12).
Build on it
OpenMoca.Mcp.Server is the server as a .NET library, for your own host:
var moca = await MocaMcpServer.CreateAsync(
new MocaMcpOptions { Audiences = ["public"] },
new FolderPackageSource(new FolderPackageSourceOptions { Folders = ["/srv/moca"] }));
var server = McpServer.Create(new StdioServerTransport("moca"), moca.ServerOptions);
moca.Attach(server);
await server.RunAsync();
- Your own embedder:
MocaMcpOptions.Embedderstakes any ReaderIEmbedder, such as a hosted model through Microsoft.Extensions.AI. - Your own package source: implement
IPackageSource(list packages from their manifests, open one when it is needed, report changes). The server verifies every package it opens, wherever it came from. - Search hooks:
MocaMcpOptions.SearchHookstakes the Reader's ingress and egress hooks, which may narrow or reorder a search, never widen it. - Dependency injection:
services.AddMocaMcp(options).WithPackageSource<MySource>(), thenMocaMcpServerFactory. - Logging: any
ILogger.
Privacy Policy
moca-mcp collects nothing and sends nothing anywhere.
- No network calls. The server reads only the packages, library folders,
trust root, overlays, sidecar indexes and installed models you name or set
up.
moca-mcp models addis the one command that downloads: the model files you ask for, from Hugging Face, checked against their pinned SHA-256. It never fetches anything a package names, and it has no telemetry, analytics or update check. - Your questions stay with you. Searches and the nodes returned go only to the MCP client that asked, over stdio on your own machine. The server keeps no record of them.
- Logs are local and about packages only. It writes to standard error which packages it loaded, their digests, and any problems found in them, never the queries.
The AI assistant you connect it to has its own privacy terms: what it does with the text it receives is governed by them, not by this server.
Develop
Clone moca-spec beside this repository
(or set MOCA_SPEC_DIR), then:
dotnet build moca-mcp-dotnet.slnx
dotnet test --project tests/OpenMoca.Mcp.Tests
Expected answers. tests/parity holds calls over moca-spec's examples
and the answers every build must give: tool definitions, results, resources
and refusals. The tests start the built server and compare. When a tool or a
parameter changes on purpose, add a case, record the answers, and read the
difference before committing it:
dotnet test --project tests/OpenMoca.Mcp.Tests -- --filter-method "*Record_expected_answers" --explicit only
Scale. bench/ measures the library scan, loading, memory and search
time the default limits rest on; see bench/README.md.
The tool and resource definitions are in src/OpenMoca.Mcp/definitions.json.
Release
Push a vX.Y.Z tag. The release workflow builds the six self-contained files,
attaches them with their SHA-256 sums to a GitHub release, and publishes the
OpenMoca.Mcp .NET tool and the OpenMoca.Mcp.Server library to NuGet.
Licence
Apache-2.0. See LICENSE and NOTICE. "OpenMOCA" is a trade mark; see the trade mark policy.
OpenMoca.Mcp# nuget: OpenMoca.Mcp