Your bundles, served to any agent: okf-mcp 1.0.0
🇧🇷 Ler em portuguêsNew here: okf is a Ruby gem for the Open Knowledge Format, where a bundle is a directory of markdown files and each file is a concept, one idea carrying frontmatter and links to its neighbours (start here).
Everything okf could do for your knowledge, it could only do where a shell runs: the CLI answers in a terminal, the skill drives that CLI inside a coding agent, the graph serves a browser. okf-mcp 1.0.0 adds the surface that needed none of that: any host speaking the Model Context Protocol, Claude Desktop, Claude Code, or whatever your team runs next, reads the bundles on your machine directly.
One gem install, and the host is connected
$ gem install okf-mcp
That is the whole installation. The gem registers an okf mcp verb with the CLI you already have (it shows up in okf help under installed extensions), and pointing a host at it is one config block:
{
"mcpServers": {
"okf": { "command": "okf", "args": ["mcp"] }
}
}
With no arguments the server offers every bundle in your registry, project-local registries included, under the same names: the @slug you type at the CLI is the bundle argument every tool takes. One identity across all four surfaces, so "the handbook" is handbook everywhere.
Arguments close the list instead of opening it. okf mcp <dir> @slug serves exactly what you named, and no tool call, no resource URI, and no group expansion can widen the set afterwards. A served set you chose at boot stays the set you chose.
Answers sized to the question
The ten tools map the CLI's read verbs: list_bundles, dirs, index, search, read_concept, catalog, log, validate, lint, graph. The list is less interesting than the discipline behind it: every answer is bounded for a context window, and every bound counts the thing that grows.
The clearest example is log. Asked "what changed recently", a first cut returned a whole 119,863-byte history behind a total: 1, because the total counted log files. The released tool returns the newest three date groups per file and names how many each holds, which cut that same answer to 13,491 bytes and cut a whole evaluation session roughly in half. Elsewhere the same rule: search caps at 20 ranked rows, catalog pages, rollups cap with a named remainder, and a byte budget covers every answer, announcing itself with truncated when it cuts. Your agent pays for what the question needs, not for the age of your project.
The failures hold the same line. A dir that names no directory is refused with advice, never answered with a zero that reads like a fact, because "the bundle root holds nothing" is a wrong answer an agent will happily repeat. And nine of the ten tools declare a result schema and return structured content beside the text, so a host consumes fields instead of parsing prose. The tenth, read_concept, returns markdown, which is already its structure.
The map your host can pin
Tools are what the model decides to call. Resources are what you attach: every served bundle's root map is okf://<slug>, every concept is okf://<slug>/<id>, with completions so the URIs are browsable. Pinning a bundle's map at the start of a session costs a few hundred tokens and saves the orientation round trips.
The server also ships two prompts, the retrieval doctrine the skill teaches, rewritten in the tools' own vocabulary: orient with dirs, descend with index, search for pointed questions, read only the winners. A Desktop host never sees the skill, so the playbook travels with the server.
Live answers, not snapshots
The server holds one parsed bundle per root and re-reads only when the files on disk actually change, so the body a tool returns is always the file as it is right now, at less than a per-request scan. The registry gets the same treatment: register, rename, or repoint a bundle while the server runs and the served set follows, no restart. A search index over a set is dropped the moment any member changes, on the rule the graph hub already follows: a held index outliving its bundle is a wrong answer, not a slow one.
Read-only, on purpose
All ten tools are read-only and say so in their annotations. Authoring stays with the skill, where a filesystem, the CLI, and a human editor are actually present. The default transport is stdio, one process per host, nothing on the network; okf mcp --http serves Streamable HTTP for hosts that connect to a URL, and there the posture matches the graph server: --bind 0.0.0.0 publishes every served bundle to anything that can reach the port, and the boot line warns you in those words instead of printing a URL that looks safe to share.
What okf 1.13.0 carries under it
okf-mcp rides okf 1.13.0, and the kernel release matters on its own.
Every read surface now refuses a symlink that points outside the bundle. Before the fix, a concept or an index.md that was really a symlink to somewhere else on the machine was followed on read and served verbatim, over the graph server, okf render, and the new MCP surface alike. Reads now resolve the real path and refuse a target outside the bundle root. If you serve bundles anywhere at all, this release is worth taking for that line alone.
A directory actually named root/ is addressable again. The views accept root as a convenient spelling of the bundle root, and that convenience used to shadow a real directory of the same name, answering with the wrong concepts and exit 0. The real directory wins now, in every view, and okf dirs counts it the same way --dir reads it.
The repository also became a monorepo, one directory per gem, which is what lets okf-mcp and future siblings ship beside the core without touching it. The published gem is unchanged in kind; the full details are in the changelog.
Try it
$ gem install okf okf-mcp
$ okf registry set handbook ./docs
$ okf mcp
Point any MCP-capable host at okf mcp and ask it what your team knows. The MCP server docs cover the tools, the resources, and the HTTP transport; the bundles never leave your machine.