okf-mcp 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a730c3c4e2bc94cfdc83704f96ae40425cce8e561e8bb77f84abd153607c81d3
4
- data.tar.gz: a1651babe0d4dd972d0d83590aafddba43f411a7f70f2047b92933b8f4dbc281
3
+ metadata.gz: 44ae2c50c714bc127ac861756a46e998d20f4310c77165ddcb616f7600c75517
4
+ data.tar.gz: 9fec8976e46b7bbe983bd0261eba453a4b25c700dcde8085df36f7a0df3f924a
5
5
  SHA512:
6
- metadata.gz: d979addc867e9ee49f0fe3a5090915c63b3b9da55d92e89863e461022ce1316e110e80f5b4ceee6f4076a5171be3fad3691aa10fd732144b6e0dcf5ec0711c25
7
- data.tar.gz: 4b52f99b0b429c500acd8fc2af91614f8a0dad69f6d8877533a701aa66421cac9cf1351e35b7b4eaa463e06a8af86506cb8af366cf21e4d6ebc2a74dea3ee8ce
6
+ metadata.gz: 7989702891ac272f637306102cadbd68f9e14f458b5cf81b373b681e3f9a8970fc248526f65038c449d498508820e143a2c9795b074ce456e3372882fd51889a
7
+ data.tar.gz: 0a9f01ba82b4bf10592c23666051617f9be55f80848925cbd029a8ad7e42753d3f597491ea71e45f2a97c817c6d8acbf9203890d4b7afd28a17a6dd4c526207a
@@ -0,0 +1,9 @@
1
+ # Capabilities
2
+
3
+ What this server offers a host, and what implements each of them. This area is
4
+ the catalog an agent reads instead of opening `lib/okf/mcp/server.rb` to find
5
+ out whether something already exists.
6
+
7
+ * [The fourteen tools](tools.md) - Every tool: what it answers, the kernel call behind it, and the CLI verb it is kin to.
8
+ * [Resources and prompts](resources-and-prompts.md) - What the protocol offers that a tool does not: bundles and concepts as resources, completions, and the two consuming prompts.
9
+ * [Transports](transports.md) - stdio, Streamable HTTP, and any Rack 3 server — one definition behind all three.
@@ -0,0 +1,45 @@
1
+ ---
2
+ type: Capability
3
+ title: Resources, completions and prompts
4
+ description: What the protocol offers that a tool call does not — bundles and concepts as addressable resources, argument completion, and the two prompts shipped in-gem and read at get-time.
5
+ tags: [mcp, resources, prompts, completion]
6
+ generated:
7
+ by: human:maintainer
8
+ at: 2026-08-19T12:00:00Z
9
+ resource: lib/okf/mcp/resources.rb
10
+ ---
11
+
12
+ # Resources: addressable, not just callable
13
+
14
+ A tool is something a host *invokes*; a resource is something it can *attach*.
15
+ Both bundles and concepts are exposed as resources, so a host can put a concept
16
+ into a conversation without spending a tool call on it.
17
+
18
+ `Resources.list` enumerates served bundles, `templates` declares the concept
19
+ template, and `read` resolves one URI. The URI grammar is parsed by hand rather
20
+ than templated — see
21
+ [the server definition](../structure/server-definition.md) for why the SDK's
22
+ matcher cannot do it.
23
+
24
+ `Resources.complete` backs argument completion, which is what makes a concept
25
+ id typeable in a host that offers completion at all. `concept_ids` and
26
+ `prefixed` are its two halves.
27
+
28
+ # Prompts: the consuming pair
29
+
30
+ Two, shipped as markdown in `lib/okf/mcp/prompts/` and named by
31
+ `Server::PROMPTS`:
32
+
33
+ | prompt | for |
34
+ | ------ | --- |
35
+ | `search` | answering a question from a bundle, token-lean: the map, then the finder, then only the winning bodies |
36
+ | `consume` | using a bundle as context for a task |
37
+
38
+ They are read at get-time by `Server.prompt_text`, so booting never pays for
39
+ their bodies and editing one is not a code change. They are written in **tool
40
+ vocabulary** — they name the tools above, not CLI verbs — because the host
41
+ reading them has no shell.
42
+
43
+ `test/integration/prompts_test.rb` walks both, and
44
+ `test/integration/resources_test.rb` and `completions_test.rb` cover the
45
+ resource surface.
@@ -0,0 +1,73 @@
1
+ ---
2
+ type: Capability
3
+ title: The fourteen tools
4
+ description: Every tool this server defines — what it answers, what it is kin to on the CLI, and the builder that constructs it — as one table, so nothing gets rebuilt for want of knowing it exists.
5
+ tags: [mcp, tools, catalog, search, retrieval]
6
+ generated:
7
+ by: human:maintainer
8
+ at: 2026-08-19T12:00:00Z
9
+ resource: lib/okf/mcp/server.rb
10
+ ---
11
+
12
+ # The catalog
13
+
14
+ Fourteen, and the number is a decision rather than a resting point: tool-list
15
+ weight is a real cost on every host, so adding one is a design decision. Check
16
+ this table first — `dirs` + `index` + `search` compose to most retrieval, and
17
+ the commonest mistake is building a fifteenth tool for something three of these
18
+ already answer together.
19
+
20
+ Every one is a **read-only lens**: `readOnlyHint` and a `title` on all fourteen,
21
+ `additionalProperties: false` on every input schema, and a declared output shape
22
+ looked up by name (`read_concept` alone has none — it answers markdown).
23
+
24
+ | tool | answers | builder |
25
+ | ---- | ------- | ------- |
26
+ | `list_bundles` | what exists: every bundle this server knows — slug, title, root, concept count | `list_bundles_tool` |
27
+ | `dirs` | the first move: a bundle's shape, one row per directory | `dirs_tool` |
28
+ | `index` | the §8 index map, one directory at a time: authored `index.md` bodies, rollups, listings | `index_tool` |
29
+ | `search` | find concepts: every term must match (AND) across title, id, tags, type and body | `search_tool` |
30
+ | `read_concept` | one concept's full markdown, frontmatter and body, live from disk | `read_concept_tool` |
31
+ | `catalog` | per-concept metadata for a whole bundle, projectable down to the fields asked for | `catalog_tool` |
32
+ | `tags` | the tag index: every tag with its count and concepts, ordered by count | `tags_tool` |
33
+ | `types` | the type index: every type with its count and concepts, ordered by count | `types_tool` |
34
+ | `stats` | bundle rollups in one answer: concepts, dirs, types, cross-links, distinct tags | `stats_tool` |
35
+ | `log` | the append-only history: every `log.md`, root scope first | `log_tool` |
36
+ | `validate` | the spec §11 conformance verdict, with every error | `validate_tool` |
37
+ | `lint` | the curation report: reachability, backlog, completeness, freshness, provenance | `lint_tool` |
38
+ | `graph` | the knowledge graph in three bounded views — never with concept bodies | `graph_tool` |
39
+ | `references` | the `references/` tree (§6.3): every file, its citers, and every pointer that resolves to nothing | `references_tool` |
40
+
41
+ Each builder lives in [the server definition](../structure/server-definition.md)
42
+ and calls the kernel. None of them analyses anything itself.
43
+
44
+ # Kin to a CLI verb, and that is the point
45
+
46
+ Every row above has a counterpart in `okf <verb>`, and the answers are the same
47
+ because both call the same kernel method. That is the
48
+ [kernel-first rule](../design/kernel-first.md) doing its job: a host and a
49
+ terminal cannot disagree about whether a bundle is conformant.
50
+
51
+ So the way to add a capability is usually **not** to add a tool here. It is to
52
+ add it to the kernel, where the CLI, the graph server, the TUI and this shell
53
+ all reach it.
54
+
55
+ # What every list answer carries
56
+
57
+ `total` appears on every list answer and means one thing everywhere: **how many
58
+ rows the request matched, before any `limit` cut them**. There is no silent
59
+ truncation anywhere in this gem, and a new tool that returns rows owes the same
60
+ field with the same meaning.
61
+
62
+ Domain failures become tool errors carrying the kernel's own sentences — never
63
+ a bare `-32603` — and both channels always: the JSON text an older client reads
64
+ and the same object as `structuredContent`.
65
+
66
+ `test/unit/bundle_catalog_test.rb` fails if this table and the tools
67
+ `server.rb` defines ever disagree, in either direction.
68
+
69
+ # The doctrine is elsewhere
70
+
71
+ *Why* each tool exists, what was rejected, and the reasoning behind the
72
+ bounded-output rules is [the tool set](../design/the-tool-set.md). This table
73
+ is the catalog; that concept is the argument. Neither restates the other.
@@ -0,0 +1,39 @@
1
+ ---
2
+ type: Capability
3
+ title: Three transports, one definition
4
+ description: stdio by default, Streamable HTTP behind `--http`, and any Rack 3 server through `OKF::MCP.app` — all three built at one seam so they cannot compose the server differently.
5
+ tags: [mcp, transports, stdio, http, rack]
6
+ generated:
7
+ by: human:maintainer
8
+ at: 2026-08-19T12:00:00Z
9
+ resource: lib/okf/mcp/app.rb
10
+ ---
11
+
12
+ # The three
13
+
14
+ | transport | how | who owns it |
15
+ | --------- | --- | ----------- |
16
+ | stdio | the default for `okf mcp` | `CLI#serve_stdio` |
17
+ | Streamable HTTP | `okf mcp --http` — the WEBrick bridge, stateless JSON mode | [`HTTP`](../structure/http-bridge.md) |
18
+ | any Rack 3 server | `run OKF::MCP.app` in a `config.ru` | [`App`](../structure/doors.md) |
19
+
20
+ stdio is the default because it is what an agent host launches; nothing has to
21
+ be bound, and there is no port to collide.
22
+
23
+ # One construction site
24
+
25
+ All three reach the transport through `App.build` / `App.transport`. This is
26
+ worth protecting: the moment two callers construct their own, they begin to
27
+ disagree about `allowed_hosts`, `allowed_origins` or the engine, and the
28
+ disagreement shows up as a security difference between `--http` and a Rack
29
+ deployment rather than as a test failure.
30
+
31
+ `test/integration/http_harness.rb` is the same idea one layer up — the three
32
+ HTTP test files share it so they cannot drift in how they compose the bridge.
33
+
34
+ # No rackup file of its own
35
+
36
+ This gem ships no `config.ru`. The reader's server is the reader's dependency:
37
+ `OKF::MCP.app` is a complete Rack application, and naming a server here would
38
+ add a dependency to satisfy a convenience. The bridge behind `--http` uses
39
+ WEBrick, which arrives through okf rather than being named in this gemspec.
@@ -0,0 +1,11 @@
1
+ # Design
2
+
3
+ The rules a change has to keep. `AGENTS.md` states them as a contract in a
4
+ handful of lines; this is where each one's argument lives, so that a rule
5
+ questioned is a rule you can re-read rather than re-derive.
6
+
7
+ * [The tool set, and why it is this one](the-tool-set.md) - The doctrine: what each tool exists for, the bounded-output argument, and the posture the whole surface takes.
8
+ * [The inherited Ruby floor](ruby-floor.md) - 2.7, the `mcp` SDK's, not okf's 2.4 — and what that admits and forbids.
9
+ * [Two runtime dependencies](runtime-dependencies.md) - Exactly `mcp` and `okf`, with floors that track what the suite proves.
10
+ * [Kernel-first](kernel-first.md) - This shell restates nothing the kernel can answer, which is what stops the CLI and MCP answers drifting apart.
11
+ * [One entry point](one-entry-point.md) - `okf mcp` through the plugin seam, and why the executable was removed before the first release.
@@ -0,0 +1,42 @@
1
+ ---
2
+ type: Constraint
3
+ title: Kernel-first — this shell restates nothing
4
+ description: Logic a tool needs lands in the kernel and is read from there, so a host's answer and a terminal's answer cannot drift apart; the corollary is that most new capabilities are not new tools.
5
+ tags: [architecture, kernel, drift, constraint]
6
+ generated:
7
+ by: human:maintainer
8
+ at: 2026-08-19T12:00:00Z
9
+ resource: lib/okf/mcp/server.rb
10
+ ---
11
+
12
+ # The rule
13
+
14
+ Every tool is a library call. Logic a tool needs that the kernel does not have
15
+ yet — `Bundle#tag_groups`, `Bundle#stats`, the cutoff grammar — is added *to
16
+ the kernel* and read from there, never implemented in this shell.
17
+
18
+ The reason is drift, and it is not hypothetical: the CLI, the graph server, the
19
+ TUI and this gem all answer the same questions about the same bundles. The
20
+ moment two of them compute an answer independently, they begin to disagree
21
+ under conditions nobody tested, and the disagreement surfaces as a user
22
+ reporting that `okf lint` and their agent say different things.
23
+
24
+ # The corollary that saves the most work
25
+
26
+ **Most new capabilities are not new tools here.** If a host needs something,
27
+ ask first whether the kernel could answer it — because if it could, the CLI and
28
+ the TUI want it too, and one kernel method serves all four surfaces.
29
+
30
+ This is also the repository's standing rule, stated at the seam: every
31
+ user-facing capability lands in the base gem first, and no addon owns semantics
32
+ the base lacks.
33
+
34
+ # What legitimately lives here
35
+
36
+ Three things, and it is a short list: **schema** (input shapes, declared output
37
+ shapes), **bounded-output arithmetic** (`total`, the log slicing, projection),
38
+ and **protocol translation** (tool errors carrying the kernel's own sentences,
39
+ both content channels, resource URIs). None of them is analysis.
40
+
41
+ If a change adds a fourth kind, that is the signal to stop and ask whether it
42
+ belongs in the kernel instead.
@@ -0,0 +1,36 @@
1
+ ---
2
+ type: Constraint
3
+ title: One entry point, and no executable
4
+ description: "`okf mcp` through the kernel's plugin seam is the only door; the `exe/` that only aliased it was removed before the first release, and adding one back needs an argument stronger than symmetry."
5
+ tags: [cli, plugin, packaging, constraint]
6
+ generated:
7
+ by: human:maintainer
8
+ at: 2026-08-19T12:00:00Z
9
+ resource: lib/okf/plugin.rb
10
+ ---
11
+
12
+ # No `exe/`
13
+
14
+ `lib/okf/plugin.rb` registers `okf mcp` with the kernel's command registry, and
15
+ that is the gem's entire entry surface. `spec.executables` is empty by
16
+ omission, and `test/unit/packaging_test.rb` and `test/integration/cli_plugin_test.rb`
17
+ hold the line from opposite ends — one that nothing ships, one that the verb
18
+ works when spawned as a real process.
19
+
20
+ The removed executable did nothing but call the same `CLI.run`. It went before
21
+ the first release, while dropping a name still cost nobody anything. What it
22
+ would have cost forever: a second name to install, document, keep working and
23
+ keep in step with the verb's argument grammar.
24
+
25
+ `okf-tui` made the same call for the same reason, and `okf-pro` made it for a
26
+ sharper one — its hook wrapper has to recognise exactly one `okf` binary.
27
+
28
+ # The dispatcher adds nothing
29
+
30
+ Between `okf mcp` and `OKF::MCP::CLI.run` there is argv and the streams, and
31
+ nothing else. That is what makes the plugin seam honest: a verb behaves like a
32
+ built-in because it *is* dispatched like one, and nothing about being an addon
33
+ shows up in how it is invoked or how it exits.
34
+
35
+ Adding a binary back needs an argument stronger than symmetry with gems that
36
+ have one.
@@ -0,0 +1,43 @@
1
+ ---
2
+ type: Constraint
3
+ title: The floor is 2.7, and it is inherited
4
+ description: The `mcp` SDK's floor, taken rather than chosen — so okf's 2.4 API list does not bind here, and nothing past 2.7 may appear in lib/ or test/.
5
+ tags: [ruby, floor, constraint]
6
+ generated:
7
+ by: human:maintainer
8
+ at: 2026-08-19T12:00:00Z
9
+ resource: okf-mcp.gemspec
10
+ ---
11
+
12
+ # 2.7, from the SDK
13
+
14
+ The floor is the `mcp` gem's, inherited rather than argued. That makes it
15
+ different in kind from okf's 2.4, which is a *position* — the tool should run
16
+ on the Ruby an OS already ships. Nothing here can run below what the SDK
17
+ supports, so there is no version of this gem that reaches okf's floor.
18
+
19
+ # What it admits, and what it still forbids
20
+
21
+ A sibling's floor is its own: **okf's 2.4 API list — `@okf design/ruby-floor` —
22
+ does not bind here.** `filter_map`, `tally`, `Dir.glob(base:)`, `transform_keys`,
23
+ `Struct.new(keyword_init:)` and numbered block params are all available and
24
+ used.
25
+
26
+ What is forbidden is anything *past* 2.7, in `lib/` **and** in `test/`:
27
+ endless method definitions, hash-literal shorthand (`{x:}`), `Data.define`,
28
+ `it` as a block parameter, and the rest of 3.x. RuboCop's `TargetRubyVersion`
29
+ catches syntax; it does not catch APIs, so a 3.x method that parses fine on 2.7
30
+ is the failure mode to watch.
31
+
32
+ The suite is the check that matters — CI runs 2.7 through the current stable,
33
+ one job for this gem, and a 3.x-only spelling fails on the oldest column. That
34
+ is the same rule the [dependency floors](runtime-dependencies.md) are held to:
35
+ the floor tracks what the suite proves.
36
+
37
+ # The trap the floor sets in the HTTP bridge
38
+
39
+ `ThreadError` on a mutex in trap context is a 2.7 behaviour, and it is why the
40
+ signal trap in [the HTTP bridge](../structure/http-bridge.md) hands teardown to
41
+ a thread instead of doing it inline. That is a floor constraint expressed as
42
+ code, and it is the one place the floor is load-bearing rather than merely
43
+ declared.
@@ -0,0 +1,45 @@
1
+ ---
2
+ type: Constraint
3
+ title: Exactly two runtime dependencies
4
+ description: "`mcp` and `okf`, nothing else — rack and webrick arrive through okf and must never be named here — with both floors held to one rule: the floor tracks what the suite proves."
5
+ tags: [dependencies, gemspec, constraint]
6
+ generated:
7
+ by: human:maintainer
8
+ at: 2026-08-19T12:00:00Z
9
+ resource: okf-mcp.gemspec
10
+ ---
11
+
12
+ # The two
13
+
14
+ `mcp` (the official SDK) and `okf` (the kernel). That is the whole list, and
15
+ `test/unit/gemspec_test.rb` pins it.
16
+
17
+ **rack and webrick arrive via okf.** Naming either one here would be the
18
+ mistake that looks like diligence: this gem uses both — the Rack seam and the
19
+ WEBrick bridge — but it uses them *because okf already depends on them*, and a
20
+ second declaration is a second version constraint to keep in sync with a gem
21
+ that owns the answer.
22
+
23
+ A third runtime dependency is a design decision, held to the same bar the
24
+ kernel holds its own: argue it, do not add it for convenience — and
25
+ [kernel-first](kernel-first.md) is usually the reason one is not needed.
26
+
27
+ # The floor tracks what the suite proves
28
+
29
+ One rule covers both, and it is the reason the pins are not round numbers.
30
+
31
+ **`mcp` is pinned pessimistically (`~>`)**, and the suite fails the day the
32
+ lockfile resolves past it. The listen and modern-path tests exercise the
33
+ SEP-2575 wire, which 1.0 and 1.1 never served — against those versions the
34
+ tests fail, so the floor cannot admit them. The floor is not a guess about
35
+ compatibility; it is the oldest version the tests actually pass on.
36
+
37
+ **The `okf` floor may lead the kernel checkout but never lag it.** It names the
38
+ kernel version that ships what this shell rides — `Search.prepare/with/across`,
39
+ registry groups, project-local discovery, `dirs`, `Bundle#directories`, the
40
+ slug grammar. An earlier floor once admitted a kernel this code raises
41
+ `NoMethodError` against, because `Bundle#directories` did not exist there: the
42
+ gem installed cleanly and broke on the first `dir` refusal.
43
+
44
+ That is the failure the rule closes, and why the floor moves when the code
45
+ starts calling something new — in the same commit, not at the next release.