feat(modules): pin the tinymcp v0.3.1 module, and correct what step two of the extraction actually sheds - #5689
Conversation
Add the Model Context Protocol client module to the module registry, providing lazy-loaded support for MCP server connections, transports, and the write-audit log. The module is declared lazy because most sessions never dial an MCP server, avoiding unnecessary downloads and dynamic loading for hosts without configured or installed servers. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Expand the scope note on the mcp feature gate to document that the tinymcp module extraction, while creating a compilation boundary, does not reduce the kernel profile's dependency count because reqwest and rusqlite are already shared with other always-on domains. Add the status of the extraction's second step, which is registry-entered but not yet wired due to missing contract additions in tinymcp-bus. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
The comment describing the tinymcp path dependency and the planned transition to a loadable module has been rewritten to accurately describe the current situation. The old comment incorrectly promised that dropping the path dependency would remove reqwest and rusqlite from the build, but analysis shows those dependencies have other consumers in the tree, so the boundary only provides compilation isolation rather than a dependency shed. The new comment also lists the specific items the host still needs from the library that the v0.3.1 release does not yet publish, and notes the additional `data_dir` seam required for per-workspace storage. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a detailed history comment to the kernel-floor limits file documenting that the tinymcp registry entry corrects a previous prediction about dependency reduction. The entry clarifies that removing the tinymcp path dependency does not lower the ratchet because its dependencies are shared with the kernel surface, as confirmed by simulation and cargo tree analysis. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
|
Upstream requirements filed as tinyhumansai/tinymcp#4 — the members, types and the per- |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review. 📝 WalkthroughWalkthroughThe PR adds a lazily loaded Changestinymcp registry and dependency documentation
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: 🔵 Low · up to The PR makes TINYMCP available for explicit native-module loading while retaining lazy loading and artifact integrity checks. Authorization for callers that can request the module and use its interface is not established, so the change is mergeable with explicit owner awareness and follow-up on those permission boundaries. Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What this is
Step two of the tinymcp extraction, as far as it can honestly go today: the
TINYMCPmodule record lands, and three pieces of documentation that predictedthe rest of step two are corrected against measurement.
tinymcpcut v0.3.1 on 2026-08-22, publishing artifacts for all eleven hostkeys
modules::platformknows about. So the registry entry is unblocked and ishere. Cutting the
tinymcppath dependency is not —tinymcp-busv0.3.1does not publish everything the host reaches for, and that is upstream work in
tinyhumansai/tinymcpthat has to land and be released first. The details arebelow and are also written into
Cargo.tomlnext to the dependency, so the nextperson reads them where the decision lives.
The headline number is not the one the plan predicted
scripts/kernel-floor.limits' 2026-08-22 entry said step two would drop the pathdependency "at which point the MCP transport stack leaves the always-on graph
entirely. Lower it in that PR."
Measured, it does not.
scripts/dep-sim.py --cut tinymcp:-1 package / -1 name / 0 native builds, and the package that leaves istinymcpitself with nothing beneath it.reqwestandrusqlitedo not go,because in this profile they are not tinymcp's to take:
rusqlitehas sixparents (
openhuman,tinyagents,tinychannels,tinycortex,tinymcp,tinymemory-core) andreqwesthas ten. Confirmed withcargo tree --no-default-features --features flows -e normal -i rusqlite/-i reqwest.So the ratchet is not lowered here — nothing was shed. It is not lowered in
the follow-up either, beyond that
-1. The corrected prediction is recorded as adated History entry rather than by editing the old one away; this is the same
lesson the TinyMemory port produced, and it is worth it staying findable: a module
boundary buys a compilation boundary, not a dependency shed, whenever the
module's dependencies are already shared with kernel surface.
Kernel floor before and after this PR: 286 / 268 / 2, unchanged.
scripts/check-kernel-floor.shpasses.What blocks cutting the path dependency
Verified against the code, not assumed.
tinymcp-busv0.3.1 has a completenames::METHODS(28 members),CONTRACT_VERSIONand payload types — the surveystarted optimistic. What it is missing:
Members that do not exist
OAuthComplete(state, code). The contract hasOAuthBeginonly. The loopbackcallback route calls
oauth_complete, which does the token exchange and thereconnect, and resolves
state → server_idthrough a module-private pending map.Not reconstructible from
Connect.connect_installed_servers) and the reconnectsupervisor (
Supervisor::tick). Neither is a member, and the module does notrun either internally —
tinybus_module/mod.rs'ssetup()builds the service,serves it, requests the name and returns. Its
lazy = falsecomment ("a hostthat loaded this module wants its servers connected") is aspirational; nothing
implements it. The supervisor's
probe_aliveliveness check has no wireequivalent either, so a host-side reimplementation over
Statuspolling wouldbe strictly worse than what it replaces.
ConnectedServerOverview. The type is exported bytinymcp-bus but nothing on the interface returns it — an exported type with no
wire path. The orchestrator prompt and the agent tool registry both read it, and
composing it from
Status+InstalledList+ N ×ListToolsis an N+1.Types the contract does not publish
ServerDetail(returned byRegistryGet,SetupGet,ConfigAssist) is definedinside
tinymcp/src/tinybus_module/service.rs.AuthDetection/AuthKind(returned byDetectAuth) live intinymcp/src/registry/oauth/types.rs.Four of the 28 members return types a host cannot name. They are decodable with
hand-written mirror structs, which is exactly the "parallel type set with no
check" that
tinymcp-bus's own module docs forbid.Smaller, but each one real
registry::curation::{tag_official, float_official_first}— applied host-sideafter a search; not in the contract, and
RegistrySearchdeliberately does notapply them ("applied by
crate::registry::curationon top of this, by a callerthat wants them").
render_tool_resultandredact_endpoint— both intinymcp::transport, not inthe contract.
gitbooksconsumesresult.rendered;StaticCallToolreturns theraw reply only.
src/core/observability.rs'sclassifies_mcp_connect_401_as_needs_authis alive test anchored on
tinymcp::Error::Unauthorized'sDisplay.tinymcp-busexports no error type, so the classifier's coupling would become anuntethered string literal — the wording-drift leak AGENTS.md specifically says
this test exists to prevent.
And one architectural item, which is the largest
mcp::hostkeys aHashMap<PathBuf, McpHost>by workspace, one store perworkspace. A loaded module receives one
data_dirin its load-time configblob. This is not a test-only concern: login rewrites the active-user marker and
reloads config in-process (
desktop::app_state::ops::activate_revalidated_user_dir),moving
workspace_dirfromusers/localtousers/<id>, and logout reverses it —so an ordinary desktop session opens at least two. Without a per-
data_dirobjectseam of the shape
modules::memoryalready uses (Open(dir) -> object_path), apost-login RPC would be answered silently from the pre-login store.
What is in this PR
TINYMCPinsrc/openhuman/modules/registry.rs, pinning v0.3.1 with digeststaken verbatim from the release's
checksum.tomlfor the eleven host keysplatform::candidates_forcan ask for (the fedora/archlinux archives the releasealso publishes are ignored, since nothing asks for them).
LoadPolicy::Lazy—a host that never dials an MCP server should not pay a download and a
dlopen;the doc comment says why that differs from the module's own
lazy = falsehint.Cargo.tomlcomment above the dependency, replaced with what is actuallytrue and what actually blocks.
AGENTS.md'smcpgate scope note, extended rather than rewritten: the old"sheds zero dependencies" finding stands, and the new measurement showing the
module extraction does not change it is added beside it.
scripts/kernel-floor.limitsHistory entry described above.Known follow-up, not silently dropped
src/openhuman/modules/mcp.rs(the host call client) and the move ofsrc/openhuman/mcp/**onto it are not in this PR. Writing a client whose"every declared member is called by this client" test forces calls to members
whose reply types cannot be named would mean inventing the twin types the contract
forbids, and would trade compile-time failures for
MemberNotFoundat runtime —the failure mode AGENTS.md already documents for the memory module.
One more thing worth fixing upstream while the release is being re-cut: the v0.3.1
archives contain
libtinymcp.so, butmodules::ops::platform_library_nameexpectslibtinymcp_module.so. Downloads still work (tinybus finds the library itself),but the warm-start
installed_artifactfast path never matches, so the modulere-downloads on every process start.
Verification
GGML_NATIVE=OFF cargo check --no-default-features --features mcp— cleanGGML_NATIVE=OFF cargo check --no-default-features(the disabled build, the onlystub-drift catcher) — clean
cargo test --liboveropenhuman::modules::registry— 9/9, includingobject-path derivation, lowercase-hex digests, archive naming, version-in-name,
the tag URL, and full host-key coverage
cargo test --lib --features "$(bash scripts/ci/product-features.sh)" --no-default-featuresover
openhuman::mcp::+openhuman::modules::— 266 passed, 0 failedcargo test --lib --no-default-features core::(the disabled-build test suite,which CI's smoke lane does not run) — 574 passed, 0 failed
scripts/check-kernel-floor.sh— passes at 286/268/2node scripts/ci/check-feature-forwarding.mjs— passescargo fmt --check— cleanscripts/dep-sim.py --cut-nothing --expect-names 268in the Feature-Gate Smokelane is deliberately not touched. That number moves whenever
scripts/kernel-floor.limitsdoes, and neither moves here, because this PR shedsnothing — the
-1arrives with the PR that actually cuts the path dependency.(#5688 takes it to 269 for
tinyjuice-bus; on a conflict keep both history linesand let whichever lands second reconcile the number.)
Conflicts
PR #5688 (
module-bus-wiring, the tinydocs/tinyvoice/tinyjuice/tinyruntime batch)is in flight and touches
Cargo.toml,src/openhuman/modules/registry.rs,scripts/kernel-floor.limitsandAGENTS.md. Conflicts are expected and resolveby keeping both sides. Note #5688 raises the
flowsfloor to 287/269/2 fortinyjuice-bus; whichever lands second should keep both History entries and takethe lower limit line.