Skip to main content

⚠️ Note: The rest of this repository (code, comments, scripts, docs, commits, issues) is written in French. Only this README is in English.

mcp-loom-mcp

version

M8ven Score M8ven Score

⚠️ WORK IN PROGRESS — NOT READY FOR PRODUCTION (updated 2026-10-26)

Loom is under repair and being re-measured. Do not use in production.

  • No token savings have been demonstrated to date. The old figures (saved_pct 94–99%, bench-report.json, bench_results.json, REPORT_FINAL.md) measured the anchor size alone: they are invalid.
  • Current real measurement (LM Studio, small local models, small documents): Loom costs more tokens than the baseline (fixed anchor overhead + tool schemas). The large-context test with a cloud model has not been done yet.
  • Decision criterion frozen before the bench: same success rate with ≥ 35% fewer total tokens (in+out), retrieval and tool tax included. Otherwise: pivot or stop.
  • Code state (measured 2026-10-25, see PROGRESS.md): 83 passed / 19 failed / 1 collection error across 103 test functions in 20 files. Most failures come from a code refactor that was not followed by a test update, plus 4 real anchor regressions (port kind, rare kinds, dates). verify, redact, audit and sandbox exist and their tests pass.
  • The server exposes 17 MCP tools — this section used to list 13. The tool table below is now the measured list.

"Weave the context without cutting the thread." A portable MCP server that keeps the LLM context small by moving it out of the prompt — never by summarizing it.


Dashboard

Loom dashboard (demo mode)

Dashboard in --demo mode (python dash/server.py --demo, port set by LOOM_DASH_PORT, default 8775). The figures on screen (for example "85% saved") are synthetic demo data, not measurements — see the work-in-progress notice above.

Installation

The registry publication is pending. The repository, the PyPI distribution and the npm package all carry the same name — mcp-loom-mcp — and the packages are built, tagged and ready to publish (v0.1.3). The names mcp-loom and loom-mcp belong to other projects on those registries — on PyPI a server for Loom's internal GraphQL API, on npm an unrelated DuckDB proxy — and a registry never releases a name. That is why the repository was renamed from Mcp-Loom (the old URL redirects automatically).

The registry commands below are the final ones, but they return a 404 until the first publish. Install from source in the meantime: pip install "mcp-loom-mcp @ git+https://github.com/MlkBlk-IT/mcp-loom-mcp.git".

# PyPI
uv tool install mcp-loom-mcp          # or: pip install mcp-loom-mcp

# npm
npx -y mcp-loom-mcp
Registry Package Page
PyPI mcp-loom-mcp pypi.org/project/mcp-loom-mcp
npm mcp-loom-mcp npmjs.com/package/mcp-loom-mcp

The package installs the loom-mcp console script (the server MCP clients spawn) and the loom admin CLI. Point your MCP client at loom-mcp:

{
  "mcpServers": {
    "loom": {
      "command": "loom-mcp"
    }
  }
}

From source

pip install "mcp-loom-mcp @ git+https://github.com/MlkBlk-IT/mcp-loom-mcp.git"

From source, with the dev extras

git clone https://github.com/MlkBlk-IT/mcp-loom-mcp.git
cd mcp-loom-mcp
python -m venv .venv
.\.venv\Scripts\Activate.ps1        # Windows
pip install -e ".[dev]"

Admin CLI

The same operations are available on the command line, built on top of the MCP tools:

loom health      # drawer health status
loom stats       # token stats for a session
loom vacuum      # compact the SQLite drawer
loom search      # FTS5 search over stored chunks

Transports

Transport Command Target client
stdio loom-mcp Claude Desktop, IDEs, any stdio client

The HTTP transport (streamable-http) and token authentication are not yet tested end to end.

Building and publishing this package: see PUBLISHING.md.


The problem

An LLM agent burns its tokens on bulky context: raw logs, 100 files read, tool outputs. Loom takes that volume out of the prompt and files it in a local drawer. The model keeps a short, dense anchor plus stable IDs. When it needs the detail, it asks Loom back — byte for byte.

Method Loss
Move (Loom) — "the log is in drawer #7" zero — the content exists, retrievable
Summarize (the others) — "the log says the build failed" possible loss — exact numbers vanish

Loom moves nothing else. That is the whole thesis of the project.


Current state

v0.1.1 — working core, honest test state. 17 MCP tools exposed, a reproducible benchmark on a 21-file corpus, and a test suite that is not green: 83 passed / 19 failed / 1 collection error (measured 2026-10-25 — PROGRESS.md). Phase 2 (HTTP transport, rate-limiting and audit wired to the last 5 tools) in progress.


Architecture

LLM context
     │
     │  ctx_store / ctx_store_file / ctx_store_cmd
     ▼
┌──────────────────────────────────────────┐
│  ANCHORING      anchors.py + compress.py │  ← extracted invariants, condensed anchor
│  REDUCTION      profile.py               │  ← strict / balanced / aggressive
│  GUARANTEE      verify.py                │  ← safety net: nothing disappears
│  ENCRYPTION     crypto.py                │  ← Fernet (column) / SQLCipher (DB)
│  REDACTION      redact.py                │  ← secrets masked before storage
│  TRUST          sandbox.py + ratelimit.py│  ← isolated execution + rate limiting
│  TRACEABILITY   audit.py                 │  ← structured JSONL logs
└──────────────────────────────────────────┘
     │
     │  SQLite + FTS5 (store.py)
     ▼
   LOCAL DRAWER  (~/.loom/loom.db)

Modules

Module Role
server.py FastMCP server — 17 tools, thin layer, zero business logic
anchors.py Invariant extractor (numbers, paths, URLs, versions, hashes, ports, constraints)
compress.py Anchor + chunk construction, byte-identical guarantee
store.py SQLite drawer + FTS5 index: chunks, anchors, invariants
verify.py Coverage check — proof that nothing was lost
profile.py 3 profiles: strict (zero-loss), balanced, aggressive (opt-in lossy)
tokenizer.py Token counting (tiktoken cl100k_base, heuristic fallback)
crypto.py Dual-mode encryption: SQLCipher (DB) or Fernet (columns)
redact.py Secret masking (Bearer, sk-, password=, secret=, token=)
sandbox.py Execution sandbox (Windows Job Object / bwrap-firejail Linux), fail-closed
ratelimit.py Token bucket per session / IP
audit.py structlog JSONL audit logs, 30-day rotation
session.py UUIDv7 sessions, TTL, purge, isolation

Exposed MCP tools (17)

Tool Role
ctx_store Moves bulky content into the drawer → anchor + IDs + savings report
ctx_store_file Same, reading server-side (the volume never transits through the prompt)
ctx_store_cmd Same, from a command — opt-in (LOOM_STORE_CMD=1) and sandboxed
ctx_get Retrieves a chunk, byte for byte
ctx_search FTS5 search over stored chunks → chunk_id, score, snippet
ctx_check Verifies no critical invariant was lost (the safety net)
ctx_verify Coverage verification, per session or global
ctx_stats Tokens before/after, hit rate, ratio
ctx_profile Switch profile: strict | balanced | aggressive
ctx_list_sessions Lists sessions (including expired)
ctx_purge_session Purges one session
ctx_purge_expired Purges expired sessions (TTL)
ctx_transfer Transfers chunks between two sessions
ctx_vacuum Compacts the SQLite database
ctx_rebuild_index Rebuilds the search index
ctx_vector_stats Statistics of the vector index
ctx_health Drawer health status

Administration operations (purge, vacuum, health, list_sessions) are also available as CLI: python -m loom <cmd>.


Profiles

Profile Behavior Loss
strict Widened anchor, all invariants visible none — default mode
balanced Tightened anchor, priority invariants kept none on stored content
aggressive Minimal anchor the anchor becomes lossy — explicit opt-in, always reported

Metrics — and what they actually mean

This is the most important part of the project: badly named metrics make a benchmark lie. Here is the exact meaning of each measure.

Metric Definition What it does not say
saved_pct Tokens saved in the anchor (what the model sees in context) Not the total stored volume — chunks are on demand
coverage Fraction of invariants visible in the anchor without retrieval 25% coverage is not a loss: the rest is retrievable
retrievable Fraction of content retrievable via chunks Always 1.0 in the measurements below
lossless No critical invariant lost Verified by verify.py, not assumed
gain_net (anchor tokens + needed chunk tokens) / original tokens Measured on 10 planted facts per file
identical Legacy field, not tracked since bench v2 Always false in bench_results.json — do not read proof into it

Proven feasibility — measured benchmark

Corpus: 21 real files (6.87 MB — code review, config, incident, doc, analysis, session, migration) × 3 sizes × 3 profiles = 63 measurements, 1,405,483 tokens processed per profile. Tokenizer tiktoken:cl100k_base. Corpus reproducible via scripts/make_dataset.py.

Averages per profile (21 files)

Profile Tokens saved Anchor coverage Compression latency Retrieval Lossless Critical invariants lost
strict 83.33% 67.04% 144.6 ms 28.7 ms ✅ 0
balanced 89.55% 53.84% 144.9 ms 28.6 ms ✅ 0
aggressive 94.17% 40.77% 145.1 ms 28.0 ms ✅ 0

retrievable = 1.0 and critical_missing_retrievable = 0 across all 63 measurements.

Breakdown by size

Profile Small (13.6 k tok.) Medium (168.3 k tok.) Large (1,223.6 k tok.)
strict 56.68% · 99.34% cov. · 4.4 ms 94.33% · 76.78% cov. · 52.7 ms 98.99% · 24.99% cov. · 376.7 ms
balanced 72.51% · 94.56% cov. · 4.4 ms 96.54% · 56.29% cov. · 53.1 ms 99.60% · 10.68% cov. · 377.4 ms
aggressive 84.29% · 80.03% cov. · 4.4 ms 98.37% · 38.16% cov. · 52.7 ms 99.86% · 4.12% cov. · 378.2 ms

Reading: latency is dominated by invariant extraction (regex), not by anchor size — hence near-identical latencies across profiles on the same file. On a 1.2 M-token file, the strict anchor drops to ~25% visible coverage but 100% of the content stays retrievable: exactly the intended trade-off.

Reproduce

.venv/Scripts/python.exe bench_dataset.py   # → bench_results.json (63 measurements)

Proven artifacts

Artifact File Proof
MCP server src/loom/server.py 17 tools, 416 lines
Safety net src/loom/verify.py coverage + invariants not lost
Encryption src/loom/crypto.py PBKDF2-HMAC-SHA256 600k iterations → Fernet (AES-128-CBC + HMAC)
Sandbox src/loom/sandbox.py Windows Job Object (CPU, RAM, process count) / bwrap Linux
Redaction src/loom/redact.py 5 pattern families, LOOM_REDACT=1 by default
Corpus dataset/ 21 files, 6.87 MB, 7 types × 3 sizes
Benchmark bench_results.json 63 measurements, real tokenizer
Tests tests/ 103 test functions in 20 files — 83 pass, 19 fail, 1 collection error

Test suite

The suite is not green. Measured on 2026-10-25 — full breakdown in PROGRESS.md:

$ .venv/Scripts/python.exe -m pytest -q --ignore=tests/test_allowed_dirs.py
103 test functions in 20 files  ->  83 passed, 19 failed
  • 1 collection error — tests/test_allowed_dirs.py imports loom.server._path_allowed, a helper that was replaced by an inline LOOM_ALLOWED_DIRS check. The test is stale, the code is newer.
  • 19 failures — 15 come from a code refactor that was not followed by a test update (renamed APIs, removed kwargs, the tool list growing from 13 to 17), and 4 are real anchor regressions (port kind no longer produced, rare kinds no longer reaching the strict anchor, dates still extracted as numbers).
  • verify, redact, audit and sandbox exist and their tests pass.

The safety-net subset (green)

File Tests Guarantee
test_safety_net.py 16 Byte-identical chunks, strict not lossy, edge-case coverage
test_anchor_vectors.py 9 Invariant extraction on reference vectors
test_compress_anchor.py 4 Anchor + chunk construction, invariant budget
test_roundtrip.py 4 Store → retrieve byte-identical on a real SQLite drawer
test_server_integration.py 4 Full MCP round-trip (store/get/check/profile)
test_stdio_server.py 1 The server actually responds over STDIO transport

3 real bugs found by the tests (they would never have surfaced otherwise):

  1. FastMCP 4.x no longer accepts readOnlyHint= as a kwarg → worked around with annotations=ToolAnnotations(...).
  2. chunk_id typed int while MCP clients send strings → tolerant str | int signature.
  3. Chunk splitting was losing bytes (strip("\n")) → broke the "byte-identical" promise. Fixed, with safety net + parameterized test cases.

Configuration (environment variables)

Variable Default Effect
LOOM_DB ~/.loom/loom.db SQLite drawer path
LOOM_DB_PASSWORD (empty) Enables encryption (Fernet or SQLCipher)
LOOM_REDACT 1 Secret masking (0 = disabled)
LOOM_STORE_CMD 0 Enables ctx_store_cmd (sandboxed)
LOOM_TTL_DAYS 30 Session expiry
LOOM_RATE_LIMIT (on) Token bucket per session / IP
LOOM_RPM / LOOM_BURST — Token-bucket rate and burst
LOOM_LOG_LEVEL INFO Log verbosity

Known limitations

  • ctx_store_cmd is not sandboxed on every platform: it refuses to run if no sandbox is available (fail-closed).
  • Redaction breaks byte-identity of masked zones — an accepted trade-off, reported in the report.
  • No full database encryption on Windows: SQLCipher has no prebuilt wheel (C build failure) → fallback to column-level Fernet, with the FTS5 index remaining in clear for search.
  • chmod 600 is ignored on NTFS → protect the drawer directory manually.
  • HTTP transport (streamable-http) and token authentication are not yet tested end to end.
  • Rate-limiting and audit are wired to 8 of the 17 tools; 9 remain to be wired.

Methodology

  • Safety net first: the invariant extractor and verifier were written before the compression logic. If the verifier cannot prove something survived, the tool refuses to compress.
  • Deterministic extraction: regex and heuristics only, never an LLM. A verifier that depends on an LLM cannot prove coverage.
  • Honest measurement: every report gives before/after tokens counted by a real tokenizer, never estimated.
  • Audit before action: reproducible benchmark, versioned corpus, per-session report in docs/.
  • Portable by construction: SQLite + FTS5, no proprietary SDK, no paid API.

What this project demonstrates

  1. Moving ≠ summarizing — lossy compression is a choice, not a technical necessity. Loom proves it with retrievable = 1.0 across 63 measurements.
  2. The token budget is an architecture problem, not a prompt problem — the right answer is an indexed local drawer, not a shorter prompt.
  3. Honest metrics do more work than flattering metrics — naming coverage "visible in the anchor" instead of "covered" prevents a benchmark that lies.
  4. An AI project can be 100% CPU and 100% local — Python + SQLite, no GPU, no paid API.

Author

Malik — IT Support student (DEP), self-taught Focus: Sysadmin + Cyber + AI + Cloud


⚡ Built on CPU. Proven on disk. ⚡

Metadata

Release files for mcp-loom-mcp 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-loom-mcp 0.1.3
File Size Uploaded Provenance Actions
mcp_loom_mcp-0.1.3.tar.gz 93.0 kB Without provenance Details for mcp_loom_mcp-0.1.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mcp-loom-mcp 0.1.3
File Interpreter ABI Platform Actions
mcp_loom_mcp-0.1.3-py3-none-any.whl Python 3 none any Details for mcp_loom_mcp-0.1.3-py3-none-any.whl

Total release size: 148.6 kB

Release files / mcp_loom_mcp-0.1.3.tar.gz

Download URL mcp_loom_mcp-0.1.3.tar.gz
Size 93.0 kB
Tags Source
SHA-256 checksum
How to use checksums
390ef4ef6c0a8abc754919d1e49f366c502226e52e6307391abf8b20758c9c3c
BLAKE2b-256 checksum
How to use checksums
2b7d25dd533f1e5f1fd378561fa14c684cc9875ec412446cdb5e9229058dec86
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / mcp_loom_mcp-0.1.3-py3-none-any.whl

Download URL mcp_loom_mcp-0.1.3-py3-none-any.whl
Size 55.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c90c3b5ce6645d08fa8b4be73bae00032cc23c4a7c4dca6638660e6370a08b74
BLAKE2b-256 checksum
How to use checksums
af95aa70b477d7d07543eea98f505a889ada3aaf66f235e5adce9528d53c744e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for mcp-loom-mcp 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page