{
  "markdown": "<div align=\"center\">\n\n# Universal Research MCP\n\n**Research memory with traceable sources, explicit write approval, and measured — not assumed — safety.**\n\n[![Version](https://img.shields.io/badge/version-v0.9.3-0b766e)](https://pypi.org/project/universal-research-mcp/0.9.3/)\n[![Python](https://img.shields.io/pypi/pyversions/universal-research-mcp.svg)](https://pypi.org/project/universal-research-mcp/0.9.3/)\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22118223.svg)](https://doi.org/10.5281/zenodo.22118223)\n[![CI](https://github.com/mp-juns/universal-research-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/mp-juns/universal-research-mcp/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-52617a)](LICENSE)\n\n[Architecture deep dive](docs/architecture-deep-dive.md) · [Benchmarks](#benchmarks--what-was-measured-how-and-what-each-result-licenses) · [Getting started](#getting-started--build-the-rag-store-connect-the-mcp) · [한국어 사용자 설명서](docs/user-guide.md)\n\n</div>\n\nResearch agents with long-lived memory fail in a specific way: they\n**assert recorded values whose evidence no longer holds** — the file\ndrifted, the claim was withdrawn, the source was never registered. This\nproject makes that failure mechanically checkable, fail-closed, and then\n**measures which parts of safety the mechanism actually provides**.\n\n## The structure, in one pass\n\n```\n append-only canonical ledger            derived, rebuildable RAG\n ─────────────────────────────           ─────────────────────────────\n data/events/daily/*/events.jsonl   →    SQLite FTS5 passage+event index\n data/events/sources.jsonl               (+ optional offline semantic view\n (path → SHA-256 at registration)         built FROM the lexical index)\n            │                                        │\n            │ registered hash + line range           │ BM25 candidates\n            ▼                                        ▼\n ┌─────────────────────────── MCP server (30 tools, stdio) ─────────────────────────┐\n │ memory_search_candidates → candidates only (\"a score is not evidence\")           │\n │ memory_fetch_evidence    → exact lines + integrity_status (matched/mismatched)   │\n │ memory_check_evidence_eligibility → fail-closed receipt; blocks silent omission  │\n │ research_prepare_ingest / research_commit_ingest → two-step, one-time HMAC       │\n │ governance_* (11 fixed roles; preflight only, never executes)                    │\n └──────────────────────────────────────────────────────────────────────────────────┘\n```\n\n- The ledger is the only authority; every index is a derived view that\n  refuses to build over a drifted registered source.\n- Retrieval is physically read-only (`sqlite mode=ro`, `query_only=ON`).\n- Writes need a pre-existing human approval record; model-side ingestion\n  additionally needs a one-time HMAC receipt issued **outside** the MCP.\n- The eligibility gate verifies the integrity of cited evidence and — as\n  of this release — fails closed when a material claim silently omits\n  evidence the session fetched and saw fail integrity.\n\nEvery one of those sentences is backed by a specific file and line:\n**[docs/architecture-deep-dive.md](docs/architecture-deep-dive.md)** walks\nthe goal, the ledger, the RAG construction, the RAG↔MCP chain, and each\ncontrol mechanism with code citations, including the boundaries that are\ndeliberately *not* enforced and say so in their docstrings.\n\n## Benchmarks — what was measured, how, and what each result licenses\n\nEvery study below was **preregistered before its runs** (protocol and\nanalysis code committed first; deviations disclosed in the protocol before\nthe affected runs), scored by an independent deterministic scorer\ncross-checked against a condition-blinded LLM judge (judge validity:\ntwo independent raters agreed with each other κ = 1.000 and with the judge\nκ = 0.865 on a 50-verdict blind sample), and reported as aggregates only.\nStatistical choices (Wilson/Newcombe CIs, mid-p McNemar, rule-of-three)\nare bound to hash-verified verbatim quotes from their source papers in\n[the citation manifests](benchmarks/protocols/).\n\n### 1 · Does the gate stop unsafe assertions? — yes, to zero, when invoked\n\n[![fig1](benchmarks/results/assets/fig1-unsafe-assertions.png)](benchmarks/results/integrity-claim-gate-paired-20260827.md)\n\n**Setup.** Two paired executions, one synthetic and one real. Synthetic: 24\ntasks × 2 arms × 3 reps (144 runs), each task planting one correct and one\naltered value in a corpus with an injected integrity fault (post-index\nmutation, line drift, stale index, withdrawn/missing/unregistered evidence,\nconflicts, plus negative controls). Real: 27 tasks over an actual\neight-month research project's ledger — **every fault occurred naturally**;\nnothing was mutated for the benchmark. Paired design so each task is its\nown control; the model (gpt-5.6-sol, medium) and prompts are identical\nacross arms except evidence access.\n**Why this setup.** Planted values make scoring deterministic (no judge\ndiscretion on the primary endpoint); natural faults answer the \"synthetic\nfaults are strawmen\" objection.\n**Result.** Hash-detectable fault stratum: filesystem 21–22/45 unsafe vs\ngated **0/45** (RD 0.49 [0.33, 0.63]); real corpus 23–26/27 vs **0/27**\n(RD 0.85 [0.64, 0.94]); clean coverage 21/21 in both arms.\n**What this licenses.** *When the eligibility workflow runs, unsafe\nassertions on integrity-broken evidence go to zero at no clean-coverage\ncost.* It does not license \"the MCP makes agents safe\" — see benchmark 4.\n\n### 2 · What does it cost? — retrieval effort, not blocking\n\n[![fig2](benchmarks/results/assets/fig2-utility-burden.png)](benchmarks/results/real-corpus-integrity-paired-20260828.md)\n\n**Setup.** Same paired runs, secondary endpoints: false blocks on\nanswerable tasks, uncached tokens, evidence-binding validity.\n**Result.** False blocks 9/54 on the real corpus — all nine traced to\nlegacy events recorded without source references (evidence-chain quality,\nnot the gate, is the binding constraint). Tokens ~1.4–1.9× filesystem.\nEvidence binding valid 81/81 in the gate arm vs 52/81 filesystem.\n**What this licenses.** *The gate's cost is retrieval chattiness and\nlegacy-chain gaps, not wrongful blocking of intact evidence.*\n\n### 3 · Where does the payload go? — search, not verification\n\n[![fig3](benchmarks/results/assets/fig3-payload-composition.png)](benchmarks/results/real-corpus-integrity-paired-20260828.md)\n\n**Setup.** Byte-level decomposition of all tool results in the real-corpus\ngate arm (81 runs, 29.4 MB), plus a same-day optimization pass re-run.\n**Result.** 93.4% of payload is candidate search; verification itself\n(fetch + eligibility) is 5.3%. The optimization pass halved transport\n(−49% payload) with fault-unsafe still 0.\n**What this licenses.** *Verification is cheap; retrieval dominates cost\nand is where optimization belongs.*\n\n### 4 · Does anyone actually call the gate? — no, not without policy\n\n[![fig4](benchmarks/results/assets/fig4-rebench.png)](benchmarks/results/rebench-ablation-v1-20260828.md)\n\n**Setup.** The scaffold-removal ablation (preregistered, 3 arms × 24 × 3 =\n216 runs): identical tasks with **no claim types, no scope preamble, no\ntool naming in any prompt** — the original scaffold is the treatment being\ntested. Arms: filesystem, MCP-attached-but-unprompted, and a cheap\nbaseline (one instruction + a registration-time hash manifest).\n**Why this setup.** Benchmark 1's 0/45 was measured under an operator\nprompt that told the model to use the workflow. A reviewer's question —\n\"if the gate isn't called, there is no protection\" — required measuring\nactivation itself, per the tool-usage-awareness literature.\n**Result.** The natural arm made **zero MCP calls in 72/72 runs** (all 30\ntools verifiably exposed): unsafe 24/45, identical to filesystem\n(RD exactly 0.000). The manifest baseline fixed only hash-visible faults\n(10/45) and misses everything semantic.\n**What this licenses.** *Effective protection = activation × enforcement,\nand un-prompted activation is 0%. Any headline safety claim for an agent\nmemory tool must be conditioned on activation.* This is the paper's\ncentral honest finding, not a defect disclosure.\n\n### 5 · Can deployable artifacts recover activation? — policy yes, schema no\n\n[![fig5](benchmarks/results/assets/fig5-layers.png)](benchmarks/results/rebench-ablation-v1.1-20260829.md)\n\n**Setup.** Preregistered amendment, 216 more runs: a repository\n`AGENTS.md` policy file (workflow mandate + session-scope preapproval), a\nproduct-only lever (activation triggers in the two tool descriptions), and\na clean rerun of the natural arm after a disclosed fixture-contamination.\n**Result.** Tool-description triggers: 0/45 activation — a dead lever.\n`AGENTS.md`: activation **42/45 (93%)**, unsafe halved to 12/45 — but all\n12 held *eligible* receipts: in 9 the model fetched the faulted source,\nsaw the mismatch, silently dropped it, and cited only intact evidence.\n**What this licenses.** *A one-file repository policy restores adoption;\ntool schemas alone do not. And a third protection layer exists — citation\ndiscipline — because the gate can only judge the citation set it is\ngiven.*\n\n### 6 · Enforcing citation discipline — information loses, enforcement wins\n\n[![fig6](benchmarks/results/assets/fig6-ladder.png)](benchmarks/results/rebench-v1.2-v1.3-citation-discipline-20260829.md)\n\n**Setup.** Two more preregistered steps (72 runs each). v1.2: the server\nlogs the session's fetches and the receipt *discloses* fetched-but-uncited\nmismatched evidence with an instruction to abstain or address it. v1.3:\nsame detection, but an active material claim **fails closed**\n(`OMITTED-MISMATCHED-EVIDENCE`); citing the mismatched reference lifts the\nblock.\n**Result.** Disclosure fired with perfect precision (13/45 fault, 0/21\nclean, 0/6 negative-control) and was **overridden in 9/13** — falsified by\nits own preregistered rule. Enforcement: unsafe **4/45** (bar ≤ 4 met),\n0/12 unsafe where the block fired, zero false blocks, clean 21/21. The\nresidual four are intact-hash semantic states (withdrawn, irrelevant) the\nintegrity gate is documented not to judge.\n**What this licenses.** *The measured ordering — information < instruction\n< enforcement — held at every layer tested. The enforcement ships in this\npackage and was verified live on the installed build.* Adversarial audit\nof the governance/ingest surface: 25/25 hostile inputs fail closed\n([audit](benchmarks/adversarial/audit-results-README.md)).\n\n### What none of this licenses\n\nGeneralization beyond one model family and one real corpus;\ndefense against faults whose hashes are intact (withdrawn, stale-but-valid,\nirrelevant evidence — measured to defeat every arm); anything about\ncorruption that precedes registration (both arms lose 6/6 by design);\nagent behavior under the multi-agent governance contracts (the controls\nfail closed under direct adversarial input, but no model-in-the-loop\ngovernance benchmark exists yet).\n\n## Getting started — two commands to a verified research memory\n\n```bash\npip install universal-research-mcp        # or: uv tool install universal-research-mcp\nuniversal-research quickstart ~/my-research --yes\n```\n\n`quickstart` takes a folder of Markdown documents and does the whole RAG\nsetup in one pass: initializes the store, registers every document's\nSHA-256, appends an operator-approved observation per document (the\n`--yes` is your human approval — without it, quickstart only prints a dry\nrun), and builds the search index. Re-running it only picks up new files.\nNo JSON authoring, no manual approval plumbing. No-install alternative,\nverified against the published package: `uvx --from universal-research-mcp\nuniversal-research quickstart … --yes`.\n\n### Connect your MCP host\n\nThe server is plain stdio — any MCP host launches the same command.\n\n**Claude Code**\n```bash\nclaude mcp add universal-research -- universal-research serve --root ~/my-research --no-auto-index\n```\n\n**Claude Desktop — one-click**: download\n[`universal-research-memory-0.9.3.mcpb`](https://github.com/mp-juns/universal-research-mcp/releases/download/v0.9.3/universal-research-memory-0.9.3.mcpb)\nand double-click (or Settings → Extensions → Install from file). Claude\nDesktop asks for your research folder and launches the server via uv; an\nempty folder is initialized automatically. Manual config alternative:\n\n**Claude Desktop / Cursor** (`claude_desktop_config.json` / `mcp.json`)\n```json\n{\n  \"mcpServers\": {\n    \"universal-research\": {\n      \"command\": \"universal-research\",\n      \"args\": [\"serve\", \"--root\", \"/home/you/my-research\", \"--no-auto-index\"]\n    }\n  }\n}\n```\n\n**Codex** (`~/.codex/config.toml`, or install the plugin from\n`plugin/universal-research-memory/`)\n```toml\n[mcp_servers.universal_research]\ncommand = \"universal-research\"\nargs = [\"serve\", \"--root\", \"/home/you/my-research\", \"--no-auto-index\"]\n```\n\n| host | support |\n| --- | --- |\n| Codex | officially tested (all benchmarks above ran here) |\n| any stdio MCP host | protocol-compatible |\n| Claude Code / Claude Desktop / Cursor | config verified, behavior unverified |\n| remote / hosted MCP | not offered (see `--public-demo` for the reviewed read-only path) |\n\n### The evidence loop your agent should run\n\nExecuted verbatim against a quickstart-built store before this section was\nwritten:\n\n1. `memory_search_candidates {query: \"dead-time correction\", mode: \"lexical\"}`\n   → returns the observation as a **candidate** (`candidate_only: true` —\n   a score is never evidence).\n2. `memory_fetch_evidence {path, start_line, end_line, event_id, expected_sha256}`\n   → `integrity_status: \"matched\"` and the exact cited lines; a drifted\n   file instead returns `mismatched` and withholds content.\n3. `memory_check_evidence_eligibility {claim, claim_type, materiality, evidence:[…]}`\n   → `status: \"eligible\"` for an intact single-source result claim, and\n   `blocked: OMITTED-MISMATCHED-EVIDENCE` if the session fetched a\n   mismatched source and silently dropped it.\n\n**Adoption note (measured, not advice).** In our ablation the model never\ncalled these tools without workspace policy. Add an `AGENTS.md` to the\nproject that mandates the loop above and preapproves the session scope for\nnon-interactive runs — that single file took gate activation from 0% to\n93% ([details](benchmarks/results/rebench-ablation-v1.1-20260829.md)).\n\n## Citation\n\nUse the concept DOI [`10.5281/zenodo.22118223`](https://doi.org/10.5281/zenodo.22118223)\nto cite the software across releases; it always resolves to the latest\narchived release, and each GitHub Release mints its own version DOI under it.\n\n## Development reference\n\n<details>\n<summary>Existing checks and release process</summary>\n\n```bash\npython -m pip install \".[test]\"\npython -m pytest -q\nruff check universal_research_mcp\nmypy --no-incremental --cache-dir=/dev/null universal_research_mcp\npython -m build\npython scripts/validate_distribution_artifact.py dist/*.whl\npython scripts/ci_smoke.py dist/*.whl\n```\n\nRelease workflows pin third-party actions to exact commits. A release wheel is\nbuilt once, checked on Linux/macOS/Windows, and that artifact is published\nthrough PyPI Trusted Publishing after its release gates succeed. These are\nengineering checks, separate from model experiments.\n\n</details>\n\nLicense: [MIT](LICENSE)\n\nmcp-name: io.github.mp-juns/universal-research-mcp\n",
  "bytes": 15398,
  "sha": "8f9911a01f399c539ff06fd351fdd1e9352137cd61e9756cdaddd8ad9364199f",
  "repo_slug": "mp-juns/universal-research-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_mp_juns_universal_research_mcp_e1ca9a79/readme"
}