Skip to main content
Glama

google-surf-mcp

English | Korean

npm version npm downloads ci MCP Toplist google-surf-mcp MCP server

Web searches, papers, and GitHub repositories are stored as PKM, ontology, and lineage. The view above is generated with project_memory(action="export", export_format="html", export_view="graph", all_projects=true).

"Turn Google Search, Papers, and Codebases into an Automatic Local Knowledge Graph and lineage for AI Agents with Zero API Key, Zero External Server."

Google Surf stores search and extraction results in a project-scoped local knowledge graph.

As you search, papers, code, web sources, session intent, plans, experiments, and decisions accumulate in a personal PKM. New research searches stored knowledge and fresh web results together, reducing repeated work while continuing to discover new information.

Projects remain isolated by default. Only verifiable links such as matching DOIs, repository URLs, or explicit aliases are added, so knowledge from one project can be reused in another without merging the original records.

Retrieval runs exact search, BM25, vector search, code and graph search, and live web independently, then combines them with RRF and one shared reranker.

Live web + Papers + Codebases + Project memory
                        ↓
Exact + BM25 + Vector + Code graph + Graph PPR
                        ↓
              RRF + Shared reranker
                        ↓
        Results with evidence and provenance

Seven tools are available by default: search / search_parallel / extract / scholar_search / project_memory_search / project_memory / health.

Research mode and automatic capture are enabled by default. Set SURF_RESEARCH=false to use search and extraction without opening the database or graph sidecar; the project memory tools are not registered in that mode.

With research mode disabled, live search and search_parallel results still use a lightweight in-memory reranker. It fuses the provider order with query BM25 rank through RRF without loading the vector model or opening local storage.

Browser search needs no API key. SearchApi can be configured as an optional primary provider or fallback.

Core features

  • Web, paper, and codebase search: Google web search is the default, while Scholar is used for paper-specific metadata. SearchApi can act as an optional primary provider or fallback.

  • Web and academic document extraction: HTML and PDF extraction returns available titles, authors, DOIs, publication metadata, and body text. search and search_parallel can include abstracts or full bodies.

  • Automatic project memory: Search results, extracted bodies, and code repositories are stored in the current project. Unread results remain metadata; extracted content becomes active RAG evidence.

  • Structured codebase search: Tree-sitter links files, symbols, imports, and calls from local projects and relevant GitHub repositories. Exact, BM25, vector, and graph search retrieve the code.

  • Graph hybrid retrieval: Fresh web results, papers, stored content, codebases, and the project graph are searched independently. Exact, BM25, vector, and PPR candidates are combined through RRF and one shared reranker.

  • Ontology and data lineage: Web sources, papers, code, plans, experiments, and decisions become typed entities and relations. Evidence paths run from source through documents, chunks, symbols, evidence, and assertions.

  • Cross-project knowledge reuse: Projects remain isolated but selected projects can be searched together. Only verifiable links connect matching entities.

  • Durable research history: Session intent, plans, experiments, failures, and decisions supplied by the MCP host are stored as revisions and linked to their supporting evidence.

  • Local graph analysis and export: PageRank, PPR, connected components, and Louvain communities run without a separate Neo4j server. Results export to HTML, Graphviz, D3 JSON, and Neo4j import formats.

Related MCP server: G-Search MCP

  • API-key-free system Chrome search

  • Dedicated logged-out profile that never reads or copies the user's Chrome profile

  • Multi-strategy SERP parsing with geometric verification

  • Sponsored block and knowledge panel removal

  • CAPTCHA detection and environment-specific recovery

  • Parser self-healing and context fallback

Numbers

Search speed

result

search

4.0-5.1s/query

scholar_search

3.8-5.6s/query

Live web search reranker check

32 held-out queries

nDCG@5

MRR

Precision@5

Provider order

0.8949

0.8203

0.6375

BM25 + RRF

0.8971

0.8203

0.6500

  • web search responses with BM25+RRF reduce large retrieval payloads by up to 75%. Measured across three uncached queries per provider on a workstation with a 1Gb/s connection. Network and Google response time vary.

Tech Stack

  • Runtime: Node.js, TypeScript, Model Context Protocol SDK

  • Web search: System Chrome + CDP, Playwright compatibility fallback, SearchApi fallback

  • Web extraction: Mozilla Readability, Turndown

  • PDF extraction: LiteParse/PDFium, optional OCR, pdf-lib metadata parsing

  • Code collection: Local project roots and gated GitHub sparse download

  • Code parsing: Tree-sitter for files, symbols, imports, and call relations

  • Code search: Exact lookup, BM25, Multilingual E5 vector search, and graph PPR

  • Local database: Embedded SurrealDB on RocksDB

  • Hybrid retrieval: Live web, papers, project memory, and codebase results combined through RRF

  • Ranking: Reciprocal Rank Fusion and shared vector reranking

  • Graph analysis: Graphology, PageRank, PPR, connected components, and Louvain communities

  • Knowledge model: Versioned ontology, data lineage, cross-project schema and entity linking

  • Recovery: CAPTCHA recovery, Playwright pool fallback, and deterministic parser self-healing

Install

Requires Node 20.18.1+. Browser mode also requires Google Chrome or Chromium.

npx google-surf-mcp   # actual MCP - register in client config

First tool call auto-bootstraps the warm profile (you may see Chrome open briefly).

Or local clone:

git clone https://github.com/HarimxChoi/google-surf-mcp
cd google-surf-mcp
npm install

If auto-bootstrap fails (rare), run it manually:

npm run bootstrap

Override paths if needed:

CHROME_PATH=/path/to/chrome SURF_TZ=America/New_York npm run bootstrap

Optional Codex output protection

Google Surf can install an opt-in Codex hook that ranks oversized Bash output before it reaches the model. The host still executes the command; the hook only applies stateless source-order, exact, and BM25 ranking with RRF. It opens neither the Google Surf database nor a browser and does not store command output.

npx -y google-surf-mcp@latest hooks install --host codex

Restart Codex, then open /hooks to review and trust the definitions. Shell output is reranked from 1,500 characters, with a default 1,500-character display budget that expands up to 3,000 for distinct query-matching evidence records or blocks. An explicit override may exceed 3,000; there is no cumulative per-turn output limit. Two identical or near-duplicate searches and explicit foreground polling loops are blocked. Existing write_stdin polls for an already-running unified command remain controlled by the Codex runtime, not this hook.

JSON/JSONL summaries use compact records with input-relative JSON pointers, ancestor identity/condition references and original result values. Markdown table rows retain headers and adjacent context, including source lines. Selected records and their required context must fit together; the renderer reports omissions instead of slicing records. Plain logs retain block reranking. Selection is deterministic and lexical, without a model, database or extra subprocess. Context extraction uses structural/field-name heuristics, not semantic understanding; unselected fields remain in the original input. These excerpts do not replace experiment logs or SSOT history. Input-relative pointers are not persistent retrieval handles. Existing installed hook bundles require an update to use changed code.

npx -y google-surf-mcp@latest hooks status --host codex
npx -y google-surf-mcp@latest hooks update --host codex
npx -y google-surf-mcp@latest hooks uninstall --host codex

Use with Claude Code

Paste this into your ~/.claude.json:

{
  "mcpServers": {
    "google-surf": {
      "command": "npx",
      "args": ["-y", "google-surf-mcp"]
    }
  }
}

Restart Claude Code. All seven tools, including project_memory_search and project_memory, are available by default.

For other MCP clients, use the same JSON shape in their config file.

Search providers

Browser search remains the default. SearchApi can be selected as the primary provider or used only when browser search fails.

value

behavior

browser

Default. Uses system Chrome with a dedicated logged-out profile, keeps native search windows hidden, and does not require SEARCH_API. Multiple MCP sessions share one local browser broker.

searchapi

Uses SearchApi as the primary provider and does not initialize Chrome for that tool.

fallback

Tries the current browser tier once, then uses SearchApi on browser errors, CAPTCHA/rate limits, profile failure, or parser degradation. It does not wait for human CAPTCHA recovery. Successful and normal empty browser responses are not repeated.

SURF_SEARCH_PROVIDER controls search and search_parallel. SURF_SCHOLAR_PROVIDER controls scholar_search. SearchApi modes require your own SearchApi account, key, and available credits.

SURF_BROWSER_ENGINE=auto selects native Chrome on a local desktop and the Playwright compatibility path in cloud or remote-debug mode. Native mode uses a normal hidden Chrome window, not headless Chrome. Set native or playwright to pin the engine.

{
  "mcpServers": {
    "google-surf": {
      "command": "npx",
      "args": ["-y", "google-surf-mcp"],
      "env": {
        "SEARCH_API": "your-searchapi-key",
        "SURF_SEARCH_PROVIDER": "fallback",
        "SURF_SCHOLAR_PROVIDER": "searchapi"
      }
    }
  }
}

Local clone variant:

{
  "mcpServers": {
    "google-surf": {
      "command": "node",
      "args": ["/abs/path/to/google-surf-mcp/build/index.js"]
    }
  }
}

Tools

  • search(query, limit?, extract_mode?, extract_limit?, response_content?, max_chars?) - primary single-query tool for live discovery and reading. When new sources must be found and read, set extract_mode in this call instead of downloading PDFs, cloning repositories, or calling extract separately. Use extract only when the exact public URL is already known and no discovery is needed. With project_id, stored project knowledge is fused with live results, but the call never becomes local-only. limit is 1-20. Extraction defaults to none; extract_limit is 1-10 with default 5. response_content defaults to summary to bound one-call output.

  • scholar_search(query, limit?) - Google Scholar metadata search, max 10 papers. Supports browser, SearchApi primary, and fallback modes.

  • search_parallel(queries[], limit?, extract_mode?, extract_limit?, response_content?, max_chars?) - primary multi-query tool for broad live discovery and reading through a continuous four-tab queue. Set extract_mode in the same call when public web pages, PDFs, papers, or GitHub repositories must be read. Use local PDF tools only for local files or visual layout work, and clone repositories only for editing, building, testing, or full Git history. limit is 1-20 per query. The call-wide extract_limit defaults to 12 and allows up to 20 for abstract; full defaults to and allows 10. response_content defaults to summary to bound one-call output.

  • Integrated search extraction reports requested, applied, skipped, truncated, and total_chars. remaining_urls can be passed to extract without repeating the search.

  • extract(url, max_chars?, mode?, response_content?) - secondary extraction tool for an exact public URL when no new discovery is required. If sources still need to be found, use search or search_parallel with extract_mode instead.

    • mode="full" (default): reads up to 1000000 characters for research capture. Research mode stores deterministic 4000-character chunks; response_content="full" returns up to 50000 characters and summary returns a 1500-character evidence excerpt.

    • mode="abstract": ~1500-char survey (PDF page 1 or HTML meta description). Document metadata is included and stored with the survey when research mode is enabled.

    • mode="metadata": metadata without body text. Returns available title, authors, publication, dates, DOI, description, keywords, canonical URL, and PDF properties including page count.

    • GitHub repository URLs read the README in metadata mode. Abstract and full use the same download gate and differ only in indexed source depth.

    • Response: content fields plus available document metadata. Failures return { error }, never throw.

  • project_memory_search(query, query_variants?, project_id?, include_project_ids?, all_projects?, limit?, request_id?, response_deadline_ms?) - searches stored local knowledge only. Up to 19 optional variants run inside one broker request with batched query embeddings, RRF fusion, evidence-seeded graph expansion, and one final rerank against query. The response contains only bounded query-focused summaries from the final ranking; stored bodies stay in the database. A caller-supplied request_id makes a long query observable and cooperatively cancellable through project_memory. If a deadline arrives after retrieval has produced candidates, the completed lanes return as an explicitly partial result instead of being discarded. It never opens a browser or calls Google or SearchApi.

  • project_memory(action, ...) - manages durable project knowledge when SURF_RESEARCH=true.

    • action="search": compatibility alias for project_memory_search.

    • action="project_update": updates an existing project name, purpose, constraints, or protected parents as a revision-checked profile revision.

    • action="context": separates the durable project purpose, confirmed session intent, provisional recent query, current plan, scientific experiment state, and observed process liveness.

    • action="get": returns exact typed or legacy records through bounded UTF-8 byte spans. Set body_bytes=0 for metadata only and use next_body_offset for lossless paging.

    • action="show": always returns a bounded summary with counts and active record IDs. detail_level="full" is accepted for compatibility but never dumps every record body. Use project_memory_search for relevant bodies or target_id for one assertion or entity.

    • action="record": stores the submitted body and returns only its ID, revision, and status. Receipts distinguish the original application from an idempotent replay.

    • action="query_status" / action="query_cancel": inspects or cooperatively stops a local retrieval identified before execution by request_id.

    • action="export": writes a standalone interactive HTML explorer, Graphviz DOT, D3 node-link JSON, or a Neo4j import bundle under <research-root>/exports.

  • health() - server status, including the local research runtime.

Need

Tool

Search only previously stored research and project memory

project_memory_search

Find new information on the web

search

Compare new web results with stored project knowledge

search with project_id

Run several new web queries

search_parallel

Replayable research collection

google-surf-collect runs a versioned JSON specification through one persistent MCP session. A specification can mix live search jobs with local-only project_memory_search jobs. Live jobs can extract bodies in the same call, while local jobs reuse indexed project knowledge without opening Google.

npx google-surf-collect examples/research-collection.example.json

From a source checkout:

npm run build
npm run research:collect -- examples/research-collection.example.json

A project workflow can also record durable sessions and plans, rebuild approved code roots, search the resulting local knowledge, and export its graph:

npm run research:collect -- examples/project-memory-workflow.example.json

project_memory collection jobs allow record, rebuild, and export. Destructive forget operations are not accepted by the collection schema. Project-level project_id is inherited by every job unless an all-project export is requested.

The output is append-only JSONL. Its manifest records the normalized specification hash, package version, Git commit, Node runtime, platform, project setup, and server health. Every search, record, rebuild, and export result records the stable job id, exact tool arguments, attempt, timestamps, elapsed time, response, and error state. Successful jobs are skipped on resume; failed jobs are retried. A changed specification requires a new output file. Set project_name with project_id when the runner should create a missing project; existing projects are reused.

Set retrieval_mode to live when prior project RAG state must not affect live result ranking. Results are still captured under project_id. Use hybrid when the collection intentionally ranks new web evidence together with stored project knowledge. API keys and environment variable values are never written to the collection log.

This makes the collection procedure and returned snapshot replayable and auditable. Live web results can still change with time, locale, network route, and upstream ranking.

Graph hybrid RAG with ontology and lineage

flowchart TB
    subgraph SOURCES["1. Search and research"]
        direction LR
        LIVE["Live web<br/>Google browser • SearchApi fallback"]
        PAPER["Pages and papers<br/>extract • Scholar metadata"]
        PROJECT_INPUT["Code and project records<br/>local roots • GitHub • host-provided session/plan"]
    end

    INGEST["2. Deterministic capture<br/>normalize • deduplicate • content hash<br/>repository source gate • Tree-sitter"]

    subgraph KNOWLEDGE_BASE["3. SurrealDB knowledge base"]
        direction LR
        CONTENT["Content and code index<br/>exact • BM25 • HNSW vector<br/>documents • chunks • symbols"]
        PROV["Data lineage and provenance<br/>source → evidence → assertion<br/>valid time • recorded time • correction"]
        ONTOLOGY["Versioned ontology<br/>core/project term revisions<br/>entity type • relation • alias • merge/split"]
        MEMORY["Project memory<br/>session intent • plan revisions<br/>experiments • decisions"]
    end

    subgraph INTELLIGENCE["4. Graph intelligence"]
        direction LR
        SCHEMA["Cross-project schema linking<br/>type and relation alignment<br/>stable identifier → identity bridge"]
        SIDECAR["Typed graph sidecar<br/>PageRank • Louvain • query-time PPR"]
    end

    FUSION["5. Hybrid retrieval<br/>live • exact • BM25 • vector • graph<br/>deterministic RRF • shared reranker • fresh-web floor"]
    RESULTS["Results + provenance<br/>short storage receipt"]

    LIVE --> INGEST
    PAPER --> INGEST
    PROJECT_INPUT --> INGEST
    INGEST --> CONTENT
    INGEST --> PROV
    INGEST --> ONTOLOGY
    INGEST --> MEMORY
    ONTOLOGY --> SCHEMA
    CONTENT --> SIDECAR
    PROV --> SIDECAR
    MEMORY --> SIDECAR
    SCHEMA --> SIDECAR
    LIVE --> FUSION
    CONTENT --> FUSION
    SIDECAR --> FUSION
    FUSION --> RESULTS
    RESULTS -. "automatic search/extract capture" .-> INGEST

    classDef inputStyle fill:#eef6ff,stroke:#2563eb,color:#172554
    classDef processStyle fill:#fff7ed,stroke:#ea580c,color:#431407
    classDef storageStyle fill:#ecfdf5,stroke:#059669,color:#052e16
    classDef intelligenceStyle fill:#f5f3ff,stroke:#7c3aed,color:#2e1065
    classDef outputStyle fill:#f8fafc,stroke:#475569,color:#0f172a
    class LIVE,PAPER,PROJECT_INPUT inputStyle
    class INGEST processStyle
    class CONTENT,PROV,ONTOLOGY,MEMORY storageStyle
    class SCHEMA,SIDECAR intelligenceStyle
    class FUSION,RESULTS outputStyle

One local knowledge base

One SurrealDB instance is the authority for three distinct layers:

  • Catalog: stable identities, revisions, project membership, ontology, provenance, and temporal links.

  • Payloads: exact bodies, source snapshots, manifests, and artifact references. Identical content is stored once and can be fetched by ID and byte span.

  • Derived views: exact, BM25, vector, code, and graph indexes plus the compact current-project view. These are versioned by source hash and can be rebuilt.

A single local research broker owns the embedded RocksDB connection. Multiple MCP sessions connect through authenticated local IPC, run bounded reads concurrently, and serialize writes without opening another database process. Original evidence and historical occurrences remain addressable even when bodies, embeddings, or graph structures are deduplicated.

Durable records and incremental indexing

project_memory writes project profiles, plans, experiments, attempts, measurements, artifacts, documents, decisions, and sessions as typed records. A stable asset ID receives revisions; an uncertain retry with the same idempotency key returns the committed revision with idempotent_replay=true and applied_this_request=false. body_path streams bodies up to 256 MiB, artifact manifests are paginated instead of sliced, and get/get_batch return exact typed or legacy records through bounded body spans. Compact write receipts report accepted bytes, references, revision, and the exact readback handle without echoing the submitted body.

sync accepts registered roots or explicit changed and removed paths. Unchanged roots and parent identities remain intact, a no-op does not rewrite derived indexes, and a one-file change publishes only the affected generation. Code, retrieval, and graph publication run under one durable job ID. job_wait uses a revision cursor, job_cancel stops at a safe stage boundary, and unfinished jobs resume after process restart. Under the worker soft-memory limit, foreground requests finish first; rebuildable index jobs checkpoint at a durable stage boundary and resume in the replacement worker without cancelling the committed record.

The versioned ontology preserves entity type and relation changes as revisions. Schema linking aligns project-specific types and relations with the shared schema. Entity linking connects the same paper, repository, or entity only when verifiable identifiers such as a DOI, repository URL, or explicit alias match. Ambiguous candidates are not linked automatically.

Data and research lineage

  • Source lineage: source → document → chunk → evidence → assertion

  • Code lineage: repository → directory → file → symbol → import/call

  • Research lineage: session → intent → plan revision → experiment → decision

This preserves the evidence behind claims and decisions while retaining corrected or superseded history.

Graph retrieval

Graphology builds a typed graph projection from SurrealDB and computes PageRank, connected components, and Louvain communities. At retrieval time, related nodes seed PPR-based multi-hop search. Live web, exact, BM25, vector, and graph candidates are combined through deterministic RRF and one shared reranker.

Local multi-query retrieval batches query embeddings, keeps exact, BM25, and vector lanes independent through RRF, expands the graph once, hydrates selected chunks once, and reranks once. Graph-only all-project searches use a lightweight memory-node index and verified identity aliases to select at most four graph scopes instead of constructing every project graph at query time.

If query embedding fails or returns no vector, local search returns its lexical/graph ranking without retrying the model in reranking. Timing fields are non-overlapping wall-clock partitions: embedding_ms plus retrieval_ms reaches the end of retrieval, and rerank_ms covers the remaining response work. Retrieval may overlap embedding, so retrieval_ms is not standalone database execution time. A supplied response_deadline_ms starts after broker admission; the transport watchdog retains its five-minute queue/IPC allowance in addition to that deadline. Native queries that outlive a partial response retain their broker read slot until they settle.

Research retrieval check

The 60-query regression fixture compares the lexical baseline with the complete local RAG path. To separate retrieval changes from HNSW approximation, the check pins one embedding thread and uses exhaustive vector scoring. The table reports the median of three fresh-process runs:

60 controlled queries

Recall@10

nDCG@10

MRR@10

Lexical baseline

0.3333

0.3333

0.3333

Exact + BM25 + Vector + Graph RRF

0.9833

0.8194

0.7668

+ shared reranker

0.9833

0.8194

0.7668

All retrieved targets passed exact provenance readback. The conservative reranker preserved the fused order on this fixture; this check does not claim production search quality or a reranker gain.

npm run research:vector-backends -- --rows 5000 compares physical representations with deterministic test vectors. The sample below excludes E5 model loading and should be rerun on the target machine:

Backend

Input rows

Stored vectors

Insert

Query p95

Recall

HNSW

5,000

5,000

1292.1 ms

10.77 ms

1.000

Compact

5,000

1,250

357.1 ms

3.96 ms

1.000

Exhaustive

5,000

5,000

1197.1 ms

289.79 ms

1.000

The default remains HNSW for full-chunk semantic coverage. Compact indexes one representative chunk per source; it used less memory and matched aggregate recall in this short-record fixture, but can miss rare details near the tail of long sources.

Broker and durability check

Latest 100-query local soak

Result

Browser broker launches

0

Active database owner restarts

0

Query RSS delta

+10.9 MiB

Peak observed research worker RSS

375.5 MiB

Idle drain and transparent reopen

Passed

No-op sync / one-file incremental sync

Passed / Passed

npm run research:reopen-probe also verifies byte-exact body paging, a paginated 225-reference artifact manifest, and a pending rebuild that resumes after process restart and becomes searchable. The soak runs with the vector model disabled to isolate broker, database, and query lifecycle memory; vector backends are measured separately above.

Project isolation and knowledge reuse

project_id selects where new results are stored. include_project_ids expands the read scope without changing the write target. Original records remain isolated by project, while verified schema and entity links allow papers, code, and experiment results to be reused across selected projects.

Interactive graph and export

Use project_memory(action="export", export_format="html", export_view="graph"). The returned standalone HTML opens locally without a server and contains three coordinated views. Use project_id for one project, include_project_ids for a selected combined graph, or all_projects=true for every project.

  • PKM groups the integrated project graph by community and sizes nodes by PageRank.

  • Lineage separates source and code lineage from session, intent, plan, experiment, and decision lineage while keeping both flows aligned by stage.

  • Ontology shows core types and relations, aligned shared schema, and typed instances. A verified identity layer appears only when stable identifiers or explicit aliases prove a cross-project match.

Search, type filters, one to three hop local focus, pan, zoom, and the provenance inspector work inside the file. Large graphs use a deterministic semantic projection that balances node type, PageRank, degree, and community coverage. The viewer reports source and displayed counts, replaces internal IDs with local aliases, disambiguates repeated labels, and does not embed source IDs, local paths, node bodies, plan text, or evidence quotes.

The project menu switches between every project embedded in the export and an integrated All projects view. Use all_projects=true when exporting to include every named project in the local database, or use project_id and include_project_ids for a bounded set. Clicking empty canvas space clears local node focus. PNG exports the current canvas, while JSON exports the current tab, project, type filters, and local focus using only the anonymized viewer payload. The standalone file has a nonce-bound script CSP, makes no network connections, and permits source links only for stripped public HTTP or HTTPS URLs.

Neo4j export

Use project_memory(action="export", export_format="neo4j", export_view="graph"). The returned directory contains nodes.csv, relationships.csv, constraints.cypher, load.cypher, manifest.json, and README.txt. PageRank, community, ontology, lineage, project IDs, source IDs, and evidence IDs are preserved. Node bodies, plan text, and evidence quotes are not exported.

For a new or empty local database, run the Neo4j offline importer from the export directory:

neo4j-admin database import full --nodes=nodes.csv --relationships=relationships.csv neo4j

For an existing local database, copy both CSV files to the Neo4j import directory, then run:

cypher-shell -f constraints.cypher
cypher-shell -f load.cypher

The offline importer creates typed node labels and relationship types. The online loader uses SurfNode and SURF_RELATION, retaining the original kinds and relationship types as properties. neo4j-admin database import full is intended for a new or empty database; use LOAD CSV for an existing database. See the official Neo4j import and LOAD CSV documentation. Bolt is a connection protocol, not an export file format, so this command does not connect to or modify a Neo4j server.

Storage scope and security

Research mode is enabled by default. search, search_parallel, scholar_search, and extract results are captured automatically. Session intent, plans, experiments, and decisions are stored only when the MCP host sends them through project_memory; versioning, ontology mapping, and lineage linking then run automatically. Retrieval mode is server configuration, not a per-call argument.

Image retrieval, image embeddings, and visual reranking are not part of research memory. OCR is used only to recover searchable text from scanned PDF pages.

Credential and private-key files are excluded from body indexing. HTML exports omit source IDs, local paths, node bodies, plan text, and evidence quotes. The viewer initiates no network requests and opens stripped public HTTP or HTTPS source links only after user action.

Project and assertion deletion require a count preview and confirmation token. They create reversible tombstones and preserve evidence and correction history. Fact correction takes only target_id, replacement, and reason; the prior assertion remains as bitemporal history. Plan revisions are append-only. Experiments are bound to the active revision and must be finished explicitly as success, failed, or inconclusive. Logs are not used to infer an outcome. Receipts list stored categories only:

Project: Graph memory | Session: temporal graph research | Stored: paper 1 (Graphiti), repo 1 (getzep), search summaries 3 | Status: ready

Set SURF_RESEARCH=false to keep the database and sidecar closed and omit project_memory_search and project_memory. Obsidian and Notion sync are not included and will remain project-level opt-in when added.

Local operations CLI

These commands use the same authenticated research broker as MCP sessions. They do not open another embedded database owner or browser:

npx google-surf-mcp doctor --json
npx google-surf-mcp daemon start --background --no-window
npx google-surf-mcp memory get --project PROJECT --record RECORD --json
npx google-surf-mcp memory sync --project PROJECT --manifest changes.json --json
npx google-surf-mcp memory current --project PROJECT --json
npx google-surf-mcp job wait --project PROJECT --id JOB --after-revision 0 --json
npx google-surf-mcp job cancel --project PROJECT --id JOB --reason "operator request" --json
npx google-surf-mcp daemon drain --json

doctor is passive: it reports process identity, versions, capabilities, queue counters, memory counters, cache bytes, current lifecycle state, foreground/background ownership, checkpoint-drain state, and the exact blockers preventing worker recycling without opening the database, vector model, or graph. The broker drains after meaningful work is idle even if an MCP client remains connected; active requests and commits postpone the drain, while rebuildable background jobs checkpoint at safe stage boundaries under memory pressure. The next request reconnects transparently.

Env vars

var

default

notes

SEARCH_API

unset

SearchApi API key. Required only when either provider setting is searchapi or fallback. Sent as a bearer token and never placed in the request URL.

SEARCHAPI_API_KEY

unset

Alias for SEARCH_API.

SURF_SEARCH_PROVIDER

browser

Provider for search and search_parallel: browser, searchapi, or fallback.

SURF_SCHOLAR_PROVIDER

browser

Provider for scholar_search: browser, searchapi, or fallback.

SURF_BROWSER_ENGINE

auto

Browser engine: auto, native, or playwright. Native Chrome performs the request before read-only CDP attachment.

CHROME_PATH

auto-detected

absolute path to Chrome binary

SURF_PROFILE_ROOT

~/.google-surf-mcp

where the warm profile lives

SURF_RESEARCH

true

enables local project memory, capture, indexing, project_memory_search, and project_memory; set false for search and extraction only

SURF_RETRIEVAL_MODE

hybrid

research search route: live or hybrid; used only when SURF_RESEARCH=true

SURF_RESEARCH_ROOT

<profile>/research

embedded SurrealDB data directory

SURF_RESEARCH_DB_ENDPOINT

unset

optional remote SurrealDB endpoint; requires wss/https, except ws/http is allowed for localhost

SURF_RESEARCH_DB_NAMESPACE

google_surf

SurrealDB namespace used by the research catalog

SURF_RESEARCH_DB_DATABASE

research

SurrealDB database used by the research catalog

SURF_RESEARCH_DB_TOKEN

unset

bearer token for a remote research database; alternatively set SURF_RESEARCH_DB_USERNAME and SURF_RESEARCH_DB_PASSWORD

SURF_RESEARCH_VECTOR_MODEL

Xenova/multilingual-e5-small

local 384-dimensional model used by HNSW vector retrieval and final reranking. The default model revision is pinned; off disables the vector lane.

SURF_RESEARCH_VECTOR_LOW_MEMORY

true

disables the ONNX CPU memory arena and memory pattern; set false to trade higher peak memory for faster initial indexing

SURF_RESEARCH_VECTOR_THREADS

4

ONNX intra-op thread count, clamped to 1-16

SURF_RESEARCH_VECTOR_BACKEND

hnsw

vector representation: hnsw, content-deduplicated compact, or bounded exhaustive

SURF_RESEARCH_REPO_AUTO

true

automatically sparse-index at most one small, relevant GitHub repository per search call

SURF_RESEARCH_REPO_AUTO_MAX_MB

20

maximum searchable source-text size for automatic GitHub indexing; assets are excluded

SURF_RESEARCH_REPO_AUTO_MAX_FILES

2000

maximum searchable source file count for automatic GitHub indexing

SURF_RESEARCH_BROKER_IDLE_MS

60000

drain delay after the last meaningful work, even when clients remain connected; active requests and background jobs postpone drain

SURF_RESEARCH_READ_CONCURRENCY

4

maximum concurrent broker reads; identical in-flight reads share one operation

SURF_RESEARCH_QUERY_TIMEOUT_MS

120000

timeout per embedded SurrealDB query, clamped to 1-600 seconds; a timed-out retrieval lane is reported as partial while other lanes still return

SURF_RESEARCH_GRAPH_CACHE_MAX_MB

64

byte budget for in-process graph projections and analysis artifacts

SURF_RESEARCH_WORKER_SOFT_MEMORY_MB

2048

RSS threshold that requests an immediate idle drain after active work completes

SURF_RERANK_TRIGGER_CHARS

1500

shell-output interception threshold (inclusive); sensitive output is sanitized even below this threshold

SURF_RERANK_MAX_CHARS

adaptive: 1500–3000

optional explicit shell-summary limit, including values above 3000; default is min(3000, ceil(1500 + 750*log2(max(1,n)))) for distinct query-matching records/blocks, not repeated output volume

GITHUB_TOKEN

unset

optional GitHub token that raises API limits for repository inspection

SURF_RESEARCH_CODE_WORKERS

auto, max 4

Tree-sitter worker count for initial code structure indexing

SURF_LOCALE

en-US

browser locale

SURF_TZ

system tz

e.g. America/New_York

SURF_HEADLESS

true

Controls Playwright extraction, compatibility, and recovery paths. Native search keeps a normal system Chrome window hidden and shows it only for CAPTCHA recovery.

SURF_REMOTE_DEBUG

false

set true on a headless server with remote DevTools. CAPTCHA path emits the DevTools port and throws instead of spawning a window; attach chrome://inspect from a local machine over SSH port-forward to solve.

SURF_CAPTCHA_TIMEOUT_MS

180000

lifetime of the background human-recovery window. MCP calls return immediately and do not wait for this timeout.

SURF_IDLE_CLOSE_MS

30000

idle ms before closing the sequential ctx and pool. 0 disables idle auto-close. Lower = faster cleanup, higher = warmer cache for spaced-out calls.

SURF_ALLOW_PRIVATE

false

set true to allow extract to fetch private/loopback addresses (localhost, 127.0.0.1, 10.x, 192.168.x, 169.254.x, etc). Default blocks them as an SSRF guard.

SURF_EXTRACT_MAX_CHARS

50000

full extraction limit (200-50000); abstract defaults to 1500 and per-call max_chars overrides both

SURF_EXTRACT_OCR

false

OCR scanned/image PDFs via Tesseract (slower; off by default)

SURF_CLOUD_MODE

false

headless/serverless mode: TLS bypass + --no-sandbox + --disable-dev-shm-usage + worker pool disabled + fail-fast on CAPTCHA

SURF_CASCADE_DISABLED

false

pin a single stealth mode (chosen by SURF_USE_STEALTH) instead of the 3-tier auto-cascade

SURF_USE_STEALTH

true

initial stealth tier; only consulted when SURF_CASCADE_DISABLED=true

SURF_HUMANLIKE_MODE

background

off / background (fire-and-forget after returning results) / inline (await before returning, slower)

SURF_RATE_LIMIT_PER_MIN

10

internal cap on Google-facing requests per minute

SURF_CACHE_TTL_SEARCH_MS

86400000

search cache TTL (24h); 0 disables caching

SURF_CACHE_MAX_ENTRIES

1000

LRU cap per cache namespace

SURF_CACHE_ROOT

<profile>/cache

cache directory

SURF_INSECURE_TLS

=SURF_CLOUD_MODE

--ignore-certificate-errors (auto-on in cloud mode)

SURF_NO_SANDBOX

=SURF_CLOUD_MODE

--no-sandbox (auto-on in cloud mode)

SURF_TELEMETRY

false

set true to enable jsonl event logging (search outcomes, cache hits/misses, tool errors, parser staleness) under {SURF_TELEMETRY_ROOT}. Designed as the input feed for the self-healing pipeline. Off by default.

SURF_TELEMETRY_ROOT

<profile>/telemetry

directory for jsonl telemetry files. UTC-dated one file per day (YYYY-MM-DD.jsonl).

SURF_SELF_HEALING

true

per-strategy outcome tracking + persisted reordering. Healing must win by 3 outcomes before reorder kicks in, so single-call flapping is impossible. Set false to pin the default strategy order.

SURF_SELF_HEALING_FILE

<profile>/.heal/strategy-order.json

persistence path for healing state. Atomic tmp+rename writes; debounced 5s.

SURF_LLM_HEAL

false

opt-in for LLM-assisted selector repair in the workflow-only repairWithLLM helper. Off by default, so no third-party LLM request fires.

SURF_LLM_PROVIDER

anthropic

LLM repair provider: anthropic or orcarouter.

SURF_LLM_MODEL

provider default

model for LLM-assisted repair. Defaults to claude-sonnet-4-6 for Anthropic and orcarouter/auto for OrcaRouter.

ANTHROPIC_API_KEY

unset

Anthropic key used only when LLM repair is enabled with the Anthropic provider.

ORCAROUTER_API_KEY

unset

OrcaRouter key used only when LLM repair is enabled with the OrcaRouter provider.

ORCA_KEY

unset

Alias for ORCAROUTER_API_KEY.

OrcaRouter

SURF_LLM_HEAL=true
SURF_LLM_PROVIDER=orcarouter
ORCAROUTER_API_KEY=...
SURF_LLM_MODEL=orcarouter/auto

Troubleshooting

  • Native search keeps the current session open and shows Chrome when a CAPTCHA appears. Solve it in that window and retry; the next call verifies the page, restores the hidden window guard, and continues with the same session. SearchApi fallback remains available through SURF_SEARCH_PROVIDER=fallback and SURF_SCHOLAR_PROVIDER=fallback.

  • Playwright CAPTCHA recovery has 4 modes (picked automatically from env):

    • default (local desktop): OS notification fires, headed Chrome opens, and the call returns; solve it and retry

    • SURF_HEADLESS=false: headed Chrome opens without a notification; solve it and retry

    • SURF_REMOTE_DEBUG=true: DevTools port + instructions printed, attach chrome://inspect locally to solve

    • SURF_CLOUD_MODE=true: fail-fast with CAPTCHA_REQUIRED error

  • Headed Chrome opens to a plain search box instead of CAPTCHA: just type any query in the box and press Enter. Subsequent calls work.

  • "Chrome not found": install Chrome or set CHROME_PATH.

  • Stale selectors: runtime per-strategy reorder (SURF_SELF_HEALING, deterministic) plus a manually dispatched repair workflow (SURF_LLM_HEAL optional, human review required, never auto-merged).

  • Playwright searches feel slower than expected: check health().pool.fallback. true means the worker pool is using a single context. Native search uses one authenticated local browser broker across MCP sessions. The broker keeps one hidden Chrome process with up to four reusable tabs for search, search_parallel, and scholar_search. Query starts are staggered. A CAPTCHA shows and preserves that session for user recovery, then the window guard is restored on the next call. A browser crash starts a new session on the next call.

  • SSRF: extract blocks localhost, private IPs, AWS metadata by default. Set SURF_ALLOW_PRIVATE=true to allow them.

  • Cache cleanup: npm run cache:clear removes search/extract and downloaded vector-model caches. It does not remove the research DB.

  • The local research DB is not application-encrypted. Use OS account permissions and disk encryption such as BitLocker or FileVault when the machine or backups need at-rest protection.

Changelog

See CHANGELOG.md.

License

MIT

Available Tools

7 tools
extractKnown URL ExtractA

SECONDARY KNOWN-URL CONTENT EXTRACTION TOOL. Use only when the exact public URL is already known and no new web discovery is required. If sources still need to be found, use search or search_parallel with extract_mode instead. For semantic reading of a public PDF or GitHub repository, use this tool before local download or parsing. Local PDF tools are for local files, forms, OCR recovery, or visual layout inspection; general repository tools are for editing, building, testing, or full Git history. Fetch one public URL and return clean content. With research enabled, one local broker lets multiple MCP sessions query the same knowledge base concurrently and orders writes safely. For GitHub repository URLs, metadata reads the README; abstract and full use the same bounded download gate and differ only in indexed source depth. HTML via Mozilla Readability; academic PDFs (arxiv/biorxiv/Nature/OpenReview/NeurIPS/JMLR/PMLR/Springer/PubMed-via-PMC) auto-detected via Content-Type, %PDF magic, citation_pdf_url meta, and per-domain URL rules. Tiered depth: mode="metadata" returns document metadata without body text, mode="abstract" returns about 1500 chars for relevance checks, and mode="full" reads the full bounded source. response_content controls whether the response contains a 1500-character summary or up to 50000 characters. PDF and landing-page metadata are merged when available. With research enabled, abstract and full PDF reads are stored as searchable evidence with bibliographic metadata and provenance. Best-effort: failures return an errorInfo instead of throwing.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesPublic http(s) URL. Loopback/private IPs blocked unless SURF_ALLOW_PRIVATE=true.
modeNoExtraction depth. `full` = whole article body (default; uses Playwright if needed). `abstract` = cheap survey: PDF page 1 OR HTML meta description (~1500 chars); use to triage relevance before paying for full text. `metadata` = document metadata without body text: title, authors, publication details, dates, DOI, keywords, canonical URL, and PDF properties when available. Academic PDFs (arxiv/biorxiv/Nature/OpenReview/NeurIPS/JMLR/PMLR/Springer/PubMed-via-PMC) are auto-detected; abstract mode skips Playwright for them.full
max_charsNoMaximum returned characters when response_content=full. Defaults to 1500 for abstract and 50000 for full.
project_idNoProject memory id.
session_idNoStable host task id. Reuses the same project session after restart.
memory_handleNoReuse the handle returned by a prior project-aware call.
session_intentNoCurrent durable task intent. A changed value creates an immutable revision.
response_contentNoControls only the returned body. full returns up to max_chars; summary returns a 1500-character evidence excerpt. Research storage keeps the full captured text in deterministic chunks.full

Output Schema

ParametersJSON Schema
NameRequiredDescription
doiNo
urlNo
metaNo
yearNo
errorNo
titleNo
is_pdfNo
lengthNo
memoryNo
authorsNo
contentNo
creatorNo
excerptNo
subjectNo
keywordsNo
languageNo
producerNo
truncatedNo
created_atNo
elapsed_msNo
page_countNo
descriptionNo
modified_atNo
publicationNo
published_atNo
canonical_urlNo
memory_handleNo
source_lengthNo
extraction_qualityNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite annotations already providing some signals, the description adds substantial behavioral detail: best-effort failures return errorInfo instead of throwing, PDF and GitHub URL handling are explained, research-enabled memory writes are disclosed, and mode/response_content behavior is specified. This goes well beyond the annotation surface and gives the agent a realistic model of side effects and failure behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose and usage, then organized into behavior, modes, and failure semantics. It is dense but mostly relevant; a few sentences, such as the local broker concurrency note, feel tangential and partly overlap with what the schema already conveys. This prevents a 5 but is still well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 8 parameters, an output schema, and meaningful side-effect behavior, the description is complete: it covers when to use it, when not to, mode semantics, output size controls, PDF and GitHub behavior, memory/research implications, and error handling. Nothing critical for correct invocation or selection is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: it explains what each mode returns, how response_content interacts with max_chars, how PDF auto-detection works, and how memory/research parameters relate to stored evidence. It does not substantially clarify project_id, session_id, memory_handle, or session_intent beyond the schema, so a 4 is appropriate rather than 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'SECONDARY KNOWN-URL CONTENT EXTRACTION TOOL' and states 'Fetch one public URL and return clean content,' giving a specific verb, resource, and scope. It also explicitly distinguishes this tool from search and search_parallel, so an agent can tell it apart from siblings without guessing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage guidance is explicit and actionable: 'Use only when the exact public URL is already known and no new web discovery is required.' It names alternatives with conditions ('use search or search_parallel with extract_mode instead') and even clarifies when local PDF and repository tools should be preferred. This leaves little room for misrouting.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

healthMCP Health CheckA
Read-onlyIdempotent

MCP server status: cascade mode + transitions, rate-limiter usage, cache size, config. Call this if searches start failing or returning empty -- check cascade.totalCaptchas and rateLimiter.queueSize, and reduce search volume if they are high.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
poolNo
cacheNo
errorNo
configNo
cascadeNo
versionNo
researchNo
telemetryNo
rateLimiterNo
selfHealingNo
nativeBrowserNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is covered. The description adds value by explaining what status fields the agent should inspect and how to interpret them (thresholds/actions), which is useful behavioral context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences and every part earns its place: the field list gives what the tool reports, and the second sentence gives the trigger condition and expected action. It is front-loaded with the core status purpose before the usage guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given this is a zero-parameter health-check tool, the annotations cover read-only/idempotent behavior, and an output schema exists, the description is complete. It even goes beyond the minimum by telling the agent when to call it and what to do with the returned values.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no input semantics for the description to clarify. The description instead compensates by naming the output fields that matter (cascade.totalCaptchas, rateLimiter.queueSize), which adds context beyond the empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies a health-check/status resource and enumerates the fields it exposes (cascade mode, transitions, rate-limiter usage, cache size, config). It lacks an explicit action verb like 'get' or 'return', but 'MCP server status' plus the title makes the purpose unambiguous and distinguishable from the search-oriented siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to call the tool: 'if searches start failing or returning empty'. It also gives follow-up guidance, telling the agent to check cascade.totalCaptchas and rateLimiter.queueSize and reduce search volume if they are high. This is a clear, actionable usage rule, and it implicitly separates this diagnostic tool from the search tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

project_memoryProject MemoryA

PROJECT MEMORY MANAGEMENT. With research enabled, one local broker lets multiple MCP sessions query the same knowledge base concurrently and orders writes safely. It links session intent, immutable plan revisions, experiments, decisions, versioned ontology, and bitemporal data lineage; corrections can use entity merge or split without discarding history. Use project_update for revision-checked changes to an existing project profile; context reads that same versioned profile. Use query_status/query_cancel with a caller-supplied search request_id to inspect or cooperatively stop a long retrieval. Use context for the bounded current project view; current to generate a compact CURRENT.md; get/get_batch for exact records and body spans; record/record_batch for durable idempotent writes; timeline/diff for history; sync for declared source deltas; job_status/job_wait/job_cancel for background progress and safe stage-boundary cancellation; verify for preservation levels; snapshot/snapshot_import/snapshot_rollback for versioned offline transfer and append-only recovery; doctor for passive diagnostics; rebuild for derived indexes; export for graph views; and forget for reversible deletion. Typed record writes return compact receipts and never echo submitted bodies. action=search remains a compatibility alias, but project_memory_search should be used for local knowledge retrieval. Ontology revisions use supersedes_term_id. Corrections preserve bitemporal data lineage and support assertion replacement plus entity merge or split. rebuild indexes approved local roots and code structure into a reproducible snapshot; export writes an interactive HTML viewer, Graphviz DOT, D3 JSON, or a Neo4j import bundle. HTML always includes PKM, Lineage, and Ontology tabs, an embedded-project selector, empty-canvas focus reset, and visible PNG or JSON download. forget previews impact before reversible project or assertion deletion. Search, search_parallel, scholar_search, and extract automatically capture sources and provenance; project_memory manages their durable structure.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNoComplete UTF-8 record body. Typed writes preserve it losslessly and return byte counts plus an exact get route.
nameNoProject name for create/project_update, or entity name lookup for show.
afterNo
as_ofNoFor context, reconstruct the project and plan view at this effective or recorded time.
limitNoMaximum local RAG results for action=search.
queryNoRequired for action=search. Searches stored local knowledge only and does not start live web discovery.
rootsNoApproved local roots and optional path-independent role/alias manifest. sync merges roots by default; removal is explicit.
titleNoPlan title, experiment name, or decision title.
actionYesTyped project-memory operation. create: project_id and name required. project_update: versioned profile update with expected_revision and idempotency_key. get/get_batch: exact IDs and bounded body spans; body_bytes=0 returns metadata only. record/record_batch: typed durable writes with idempotency_key. context/current/timeline/diff: compact current or historical views. query_status/query_cancel: inspect or cooperatively cancel caller-identified local retrieval. sync/rebuild: incremental source and derived indexing. job_status/job_wait/job_cancel: durable background work. snapshot/snapshot_import/snapshot_rollback: offline transfer and append-only recovery. export: HTML, DOT, JSON, or Neo4j. forget: reversible deletion preview and confirmation. Unrelated local questions use project_memory_search.
beforeNo
fieldsNoTyped structured fields stored with the record revision. measurement requires metric, value, unit, evaluator_contract, dataset, split, tokenizer, context_length, targets, carrier_precision, and source_locator; byte_ledger requires byte_components, denominator, and scope. Put unknown required values in missing_fields.
intentNoDurable intent for record_type=session.
job_idNo
reasonNoRequired reason for any correction.
statusNoUse success, failed, or inconclusive to finish an experiment. Omit or use running when starting it.
aliasesNoOntology term aliases, or aliases moved during entity_split.
dry_runNo
filtersNoOptional project, source, type, role, lane, and recorded-time filters. Excluded lanes are not executed.
metricsNoTerminal experiment metrics.
purposeNo
queriesNoIndependent questions returned as separate ranked groups inside one broker request.
recordsNo
summaryNoExperiment result or decision summary.
versionNoOntology revision number. Defaults to 1 or the superseded term version plus one.
asset_idNoStable logical identity. Revisions remain under this ID.
git_rootNoOptional Git root recorded with a rebuild snapshot.
revisionNo
valid_toNoCorrected assertion valid-time end.
artifactsNoLegacy experiment artifact paths. Typed writes should use artifact_references; no values are silently sliced.
body_pathNoLocal UTF-8 file for a streamed versioned body attachment up to 256 MiB. Use instead of body; only a compact receipt is returned.
operationNoTyped durable write operation. Use with asset_kind and idempotency_key.
protectedNo
record_idNoKnown exact record or alias ID for get, diff, or verify.
root_modeNo
target_idNoAssertion or entity id for show or correction.
asset_kindNo
body_bytesNoUTF-8 bytes to return. Use 0 for metadata-only readback; use a positive value and next_body_offset for exact paging.
hypothesisNoHypothesis when starting an experiment.
project_idNoStable project id. For search, this is the write-isolated primary scope. Omit to list projects or use all_projects.
record_idsNo
request_idNoCaller-chosen ID for one local query. Supply it before a long request so project_memory query_status/query_cancel can inspect or cancel the same operation.
source_idsNoEntity ids merged into target_id by entity_merge.
valid_fromNoCorrected assertion valid-time start.
access_tierNoOperational access tier. It does not rank scientific quality.
body_offsetNo
export_viewNoInitial HTML tab or non-HTML export scope. graph is PKM; ontology shows types, shared schema, verified identity links, and typed instances; lineage shows aligned data and research lineage.graph
forget_modeNoPreview first. Apply requires its confirm_token. Restore reverses deletion.
record_typeNoRequired for record. session stores intent; plan creates an immutable revision; experiment starts or finishes a run; decision links a conclusion; ontology creates a versioned type or relation; correction replaces an assertion or merges/splits entities.
replacementNoNew assertion value, or new entity name for entity_split.
set_currentNoFor plan writes, select this revision as current. Defaults to true; use false for historical imports.
to_revisionNo
all_projectsNoSearch or export every active named project. Excludes Inbox and cannot be combined with project ids.
budget_bytesNo
detail_levelNoFor show with project_id and no target_id, both values return a bounded summary. full is retained only for compatibility and never returns every durable record body.summary
effective_atNo
evidence_idsNoEvidence retained on a corrected assertion.
cancel_reasonNo
change_reasonNoReason for a new plan revision.
changed_pathsNoExplicit root-relative files or collection boundaries to re-read. Existing roots and all unlisted entries are preserved.
confirm_tokenNoToken returned by the matching forget preview.
experiment_idNoExperiment to finish or associate with a decision.
export_formatNoVisualization file format. html writes one offline explorer with PKM, Lineage, Ontology, project selection, and current-view PNG or anonymized JSON download; d3 writes node-link JSON; dot writes Graphviz DOT; neo4j writes an import-ready CSV and Cypher bundle.d3
from_revisionNo
memory_handleNoExisting project session handle for a session intent revision.
ontology_kindNoOntology term kind for record_type=ontology.
removed_pathsNoExplicit root-relative entries to remove from the active snapshot. Historical snapshots remain addressable.
snapshot_pathNo
after_revisionNo
artifact_limitNo
missing_fieldsNo
query_variantsNoOptional local retrieval variants for action=search. They run inside one broker request and are fused before one rerank.
since_revisionNo
artifact_offsetNo
correction_kindNoCorrection operation. Defaults to assertion.
idempotency_keyNoStable operation key. Reuse it after an uncertain response.
source_sequenceNo
wait_timeout_msNo
plan_revision_idNoPlan revision associated with an experiment or decision.
source_referenceNo
user_constraintsNo
correction_reasonNo
expected_revisionNoOptimistic concurrency revision. Stale values return a conflict.
supersedes_term_idNoPrior ontology term replaced by this revision.
verification_levelNo
artifact_referencesNo
include_project_idsNoAdditional read-only projects for one local search or integrated visualization export.
protected_parent_idsNo
response_deadline_msNoCaller-selected 1-300 second response deadline. Returns available lane results or QUERY_TIMEOUT with request_id. Native reads remain tracked until they settle; stored evidence and writes are unaffected.
response_budget_bytesNoExplicit result-array byte budget. Without an override, summaries adapt to unique result, question and source-family counts. Stored bodies and retrieval scope are not truncated by this budget; envelope metadata is separate.
based_on_experiment_idNoExperiment that motivated a plan revision.

Output Schema

ParametersJSON Schema
NameRequiredDescription
jobNo
diffNo
metaNo
errorNo
indexNo
plansNo
queryNo
doctorNo
entityNo
forgetNo
groupsNo
memoryNo
recordNo
contextNo
currentNo
projectNo
receiptNo
recordsNo
resultsNo
sessionNo
entitiesNo
importedNo
projectsNo
receiptsNo
snapshotNo
timelineNo
assertionNo
decisionsNo
elapsed_msNo
job_countsNo
plan_countNo
experimentsNo
entity_countNo
query_statusNo
verificationNo
memory_handleNo
session_countNo
visualizationNo
decision_countNo
document_countNo
assertion_countNo
correction_countNo
experiment_countNo
search_event_countNo
source_entry_countNo
active_source_snapshotNo
entity_operation_countNo
citation_observation_countNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are all false (readOnlyHint=false, openWorldHint=false, idempotentHint=false), so they declare nothing positive and the description carries the burden. It adds meaningful behavioral context: concurrent querying with safe write ordering, 'Typed record writes return compact receipts and never echo submitted bodies,' corrections that 'preserve bitemporal data lineage and support assertion replacement plus entity merge or split,' forget that 'previews impact before reversible project or assertion deletion,' and that search-family tools 'automatically capture sources and provenance.' No contradiction with annotations. Small deduction for not covering auth requirements, rate limits, or failure semantics beyond hints like QUERY_TIMEOUT.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and every sentence carries information, but it is a very long wall of text with essentially no paragraph breaks for scannability. The central routing sentence is a massive run-on listing 15+ action mappings in one clause ('Use context for the bounded current project view; current to generate a compact CURRENT.md; get/get_batch for exact records and body spans; record/record_batch for durable idempotent writes; ...'). The core concept is front-loaded well, but an agent parsing this would benefit from bullets or segmentation. Appropriately sized for the tool's complexity, poorly structured for consumption.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 90-parameter destination tool with an output schema, this is near-complete: it covers the broker/concurrency model, what the store links, a full action routing table, behavior of writes, correction semantics, export output characteristics, and sibling differentiation. The output schema means return values need no explanation. Deductions for not addressing access control/permissions, rate limits, or multi-step error-recovery flows beyond idempotency-key mentions. Given the enormous scope, the coverage is strong but not exhaustive.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 66%, so the schema already documents most parameters and the baseline is 3. The description adds value mostly at the action-routing level (which parameter combinations belong to which action) and via behavioral notes like 'Ontology revisions use supersedes_term_id' and export format specifics (HTML always includes PKM, Lineage, and Ontology tabs). However, it does not deeply compensate for the remaining undocumented ~34% of parameters; many parameter meanings are only discoverable through the schema or the action enum's own long description. Marginal addition over the schema, hence a 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific role: a local broker that lets multiple MCP sessions query the same knowledge base concurrently while ordering writes safely, and it enumerates what the store links (session intent, plan revisions, experiments, decisions, versioned ontology, bitemporal lineage). It also distinguishes itself from siblings by explicitly naming project_memory_search as the sibling for local knowledge retrieval. Slight deduction because the tool is a 25-plus-action dispatcher, so the 'purpose' is necessarily broad rather than a single verb+resource.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides an explicit routing map for nearly every action: 'Use project_update for revision-checked changes...', 'Use context for the bounded current project view; current to generate a compact CURRENT.md; get/get_batch for exact records...', plus job_*, snapshot_*, doctor, rebuild, export, and forget. It also gives a negative rule: 'action=search remains a compatibility alias, but project_memory_search should be used' and 'Unrelated local questions use project_memory_search.' This is model-guidance of the highest quality.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_parallelParallel Web Search and ExtractA

PRIMARY MULTI-QUERY LIVE DISCOVERY AND CONTENT INGESTION TOOL. ALWAYS PERFORMS MULTIPLE LIVE WEB SEARCHES. With research enabled, one local broker lets multiple MCP sessions query the same knowledge base concurrently and orders writes safely. Use this tool only when 2-12 new external queries are required. Providing project_id adds stored evidence but never makes the searches local-only. When the task requires broad discovery plus reading public web pages, PDFs, papers, or GitHub repositories, set extract_mode=abstract or full in this call. Do not download public PDFs, clone repositories, or invoke local parsers first. Select extract_mode=full, not abstract, when the user asks to read originals, full text, document bodies, or code, or to compare source contents. Use extract separately only when the exact public URL is already known and no new discovery is required. Use general repository tools only for editing, building, testing, or full Git history. For stored project knowledge without live web discovery, use project_memory_search. Each query limit accepts integers from 1 to 20. Call-wide extract_limit accepts 1-20 with default 12 for abstract, and 1-10 with default 10 for full. Final results use one call-wide bounded response budget after ranking; at most 36 ranked rows are returned across query groups and full captured bodies remain local. Use extract on one selected URL when longer response text is explicitly required. The response includes applied, skipped, truncated, total_chars, and a bounded remaining_urls list. GitHub none mode reads the README; abstract and full can sparse-index eligible repositories with Tree-sitter. With research enabled and project_id set, each query fuses live, exact, BM25, vector, code, and graph lanes through RRF and one reranker. With research disabled, each query independently fuses provider order and query BM25 rank through a lightweight in-memory RRF reranker without opening local storage or loading the vector model. research_context returns prior project searches; capture retains data lineage and include_project_ids uses versioned ontology and verified cross-project schema/entity links. Extracted bodies become evidence while unread hits remain metadata. Native Chrome uses one authenticated local broker across MCP sessions and keeps one hidden process with up to four reusable tabs. Query starts are staggered and each tab continuously consumes the remaining queue. SearchApi fallback replaces failed queries individually.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results per query. Integer 1-20, default 10.
queriesYes2-12 independent live queries.
max_charsNoMaximum returned characters per extracted result in response_content=full. Defaults to 1500 for abstract and 50000 for full.
project_idNoProject memory id.
session_idNoStable host task id. Reuses the same project session after restart.
extract_modeNoContent depth in this search call. Use none only when titles and snippets are enough, abstract for relevance evidence, and full when the user asks to read originals, full text, document bodies, or code, or to compare source contents. Use abstract or full here instead of following search with separate extraction, PDF download, or repository clone. For GitHub results, none reads the README; abstract and full use the same repository eligibility gate but index different source amounts.none
extract_limitNoCall-wide maximum unique result URLs to extract. Integer 1-20, default 12 for abstract; full defaults to and allows at most 10.
memory_handleNoReuse the handle returned by a prior project-aware call.
session_intentNoCurrent durable task intent. A changed value creates an immutable revision.
response_contentNoControls only returned bodies. summary is the default and returns 1500-character evidence excerpts; full returns up to max_chars. Research storage keeps the full captured text in deterministic chunks.summary
include_project_idsNoAdditional read-only projects joined through ontology-aligned schema and identity links. New records stay in project_id.

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
errorNo
memoryNo
resultsNo
elapsed_msNo
memory_handleNo
research_contextNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are minimal (readOnlyHint false, openWorldHint true, idempotentHint false), so the description carries the full burden. It discloses writes ('orders writes safely'), concurrency ('one local broker lets multiple MCP sessions query the same knowledge base concurrently'), fallback behavior ('SearchApi fallback replaces failed queries individually'), and result bounds ('at most 36 ranked rows are returned'). This far exceeds what annotations provide and is fully consistent with them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single dense paragraph exceeding 300 words. While every sentence adds substantive information, the lack of paragraph breaks or bullets makes it harder to scan. The content is front-loaded with the primary purpose, but the wall of text could be better structured without losing information. It is not concise, though it is thorough.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 11 parameters, an output schema, and complex behavioral nuances (research modes, extract modes, browser fallback, response budgets), the description covers all essential aspects. It explains return fields ('applied, skipped, truncated, total_chars, and a bounded remaining_urls list'), clarifies modes, and addresses edge cases like project_id not making searches local-only. An agent can confidently invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and parameter descriptions are already detailed. The description adds meaningful context beyond the schema, such as clarifying the relationship between extract_mode and extract_limit, explaining that 'Use abstract or full here instead of following search with separate extraction, PDF download, or repository clone,' and detailing the response budget. This adds value beyond the schema, though not every nuance is covered.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear statement of what the tool does: 'PRIMARY MULTI-QUERY LIVE DISCOVERY AND CONTENT INGESTION TOOL. ALWAYS PERFORMS MULTIPLE LIVE WEB SEARCHES.' It also distinguishes itself from siblings by specifying when to use it: 'Use this tool only when 2-12 new external queries are required.' This makes its purpose unambiguous and clearly differentiated from extract, project_memory_search, and repository tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage guidance: 'Use this tool only when 2-12 new external queries are required,' 'Use extract separately only when the exact public URL is already known and no new discovery is required,' and 'Use general repository tools only for editing, building, testing, or full Git history.' It also names alternatives like project_memory_search for stored knowledge without live discovery. This is comprehensive and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv1.1.3
    • Changedextract1 field changed
      • changedOutput schema / properties / error / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "code": {
        -        "type": "string"
        -      },
        -      "message": {
        -        "type": "string"
        -      },
        -      "retry_after_ms": {
        -        "type": "number"
        -      },
        -      "retryable": {
        -        "type": "boolean"
        -      },
        -      "user_action": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "code",
        -      "message",
        -      "retryable"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "cancel_reason": {
        +        "type": "string"
        +      },
        +      "code": {
        +        "type": "string"
        +      },
        +      "message": {
        +        "type": "string"
        +      },
        +      "phase": {
        +        "type": "string"
        +      },
        +      "request_id": {
        +        "type": "string"
        +      },
        +      "retry_after_ms": {
        +        "type": "number"
        +      },
        +      "retryable": {
        +        "type": "boolean"
        +      },
        +      "user_action": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "code",
        +      "message",
        +      "retryable"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedhealth3 fields changed
      • addedOutput schema / properties / error / properties / cancel_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / phase
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / request_id
        Added value: +{
        +  "type": "string"
        +}
    • Changedproject_memory84 fields changed
      • addedInput schema / properties / access_tier
        Added value: +{
        +  "description": "Operational access tier. It does not rank scientific quality.",
        +  "enum": [
        +    "hot",
        +    "warm",
        +    "cold"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / action / description
        Previous value: -"create: project_id and name required. show: inspect a known project, assertion, entity, or durable record. search: compatibility alias for project_memory_search. record: project_id and record_type required. rebuild: project_id required; roots optional. export: project_id, include_project_ids, or all_projects=true required. forget: project_id and forget_mode required; apply also requires confirm_token."New value: +"Typed project-memory operation. create: project_id and name required. project_update: versioned profile update with expected_revision and idempotency_key. get/get_batch: exact IDs and bounded body spans; body_bytes=0 returns metadata only. record/record_batch: typed durable writes with idempotency_key. context/current/timeline/diff: compact current or historical views. query_status/query_cancel: inspect or cooperatively cancel caller-identified local retrieval. sync/rebuild: incremental source and derived indexing. job_status/job_wait/job_cancel: durable background work. snapshot/snapshot_import/snapshot_rollback: offline transfer and append-only recovery. export: HTML, DOT, JSON, or Neo4j. forget: reversible deletion preview and confirmation. Unrelated local questions use project_memory_search."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "create",
        -  "show",
        -  "search",
        -  "record",
        -  "rebuild",
        -  "export",
        -  "forget"
        -]New value: +[
        +  "create",
        +  "project_update",
        +  "show",
        +  "search",
        +  "record",
        +  "record_batch",
        +  "get",
        +  "get_batch",
        +  "context",
        +  "timeline",
        +  "diff",
        +  "sync",
        +  "job_status",
        +  "job_wait",
        +  "job_cancel",
        +  "query_status",
        +  "query_cancel",
        +  "verify",
        +  "current",
        +  "snapshot",
        +  "snapshot_import",
        +  "snapshot_rollback",
        +  "doctor",
        +  "rebuild",
        +  "export",
        +  "forget"
        +]
      • addedInput schema / properties / after
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / after_revision
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / artifact_limit
        Added value: +{
        +  "maximum": 1000,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / artifact_offset
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / artifact_references
        Added value: +{
        +  "items": {
        +    "properties": {
        +      "artifact_id": {
        +        "maxLength": 500,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "available": {
        +        "type": "boolean"
        +      },
        +      "content_hash": {
        +        "maxLength": 200,
        +        "type": "string"
        +      },
        +      "location": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "media_type": {
        +        "maxLength": 200,
        +        "type": "string"
        +      },
        +      "member": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "observed_at": {
        +        "format": "date-time",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +        "type": "string"
        +      },
        +      "path": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "role": {
        +        "maxLength": 200,
        +        "type": "string"
        +      },
        +      "size": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "verification": {
        +        "enum": [
        +          "declared",
        +          "present",
        +          "hash_verified",
        +          "restore_tested",
        +          "replayed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "artifact_id"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 50000,
        +  "type": "array"
        +}
      • changedInput schema / properties / artifacts / description
        Previous value: -"Experiment artifact paths or identifiers."New value: +"Legacy experiment artifact paths. Typed writes should use artifact_references; no values are silently sliced."
      • changedInput schema / properties / artifacts / maxItems
        Previous value: -100New value: +50000
      • addedInput schema / properties / as_of
        Added value: +{
        +  "description": "For context, reconstruct the project and plan view at this effective or recorded time.",
        +  "format": "date-time",
        +  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +  "type": "string"
        +}
      • addedInput schema / properties / asset_id
        Added value: +{
        +  "description": "Stable logical identity. Revisions remain under this ID.",
        +  "maxLength": 500,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / asset_kind
        Added value: +{
        +  "enum": [
        +    "project",
        +    "plan",
        +    "task",
        +    "method",
        +    "experiment",
        +    "attempt",
        +    "arm",
        +    "measurement",
        +    "byte_ledger",
        +    "artifact",
        +    "document",
        +    "decision",
        +    "session"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / before
        Added value: +{
        +  "type": "string"
        +}
      • changedInput schema / properties / body / description
        Previous value: -"Plan body for record_type=plan."New value: +"Complete UTF-8 record body. Typed writes preserve it losslessly and return byte counts plus an exact get route."
      • changedInput schema / properties / body / maxLength
        Previous value: -50000New value: +4194304
      • addedInput schema / properties / body_bytes
        Added value: +{
        +  "description": "UTF-8 bytes to return. Use 0 for metadata-only readback; use a positive value and next_body_offset for exact paging.",
        +  "maximum": 1048576,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / body_offset
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / body_path
        Added value: +{
        +  "description": "Local UTF-8 file for a streamed versioned body attachment up to 256 MiB. Use instead of body; only a compact receipt is returned.",
        +  "maxLength": 4000,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / budget_bytes
        Added value: +{
        +  "maximum": 1000000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • addedInput schema / properties / cancel_reason
        Added value: +{
        +  "maxLength": 500,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / changed_paths
        Added value: +{
        +  "description": "Explicit root-relative files or collection boundaries to re-read. Existing roots and all unlisted entries are preserved.",
        +  "items": {
        +    "properties": {
        +      "path": {
        +        "maxLength": 2000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "root": {
        +        "maxLength": 32,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "root",
        +      "path"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 100000,
        +  "type": "array"
        +}
      • addedInput schema / properties / correction_reason
        Added value: +{
        +  "maxLength": 2000,
        +  "type": "string"
        +}
      • addedInput schema / properties / dry_run
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / effective_at
        Added value: +{
        +  "format": "date-time",
        +  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +  "type": "string"
        +}
      • addedInput schema / properties / expected_revision
        Added value: +{
        +  "description": "Optimistic concurrency revision. Stale values return a conflict.",
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / fields
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Typed structured fields stored with the record revision. measurement requires metric, value, unit, evaluator_contract, dataset, split, tokenizer, context_length, targets, carrier_precision, and source_locator; byte_ledger requires byte_components, denominator, and scope. Put unknown required values in missing_fields.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / filters
        Added value: +{
        +  "description": "Optional project, source, type, role, lane, and recorded-time filters. Excluded lanes are not executed.",
        +  "properties": {
        +    "kinds": {
        +      "items": {
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "maxItems": 20,
        +      "type": "array"
        +    },
        +    "recorded_after": {
        +      "format": "date-time",
        +      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +      "type": "string"
        +    },
        +    "recorded_before": {
        +      "format": "date-time",
        +      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +      "type": "string"
        +    },
        +    "retrieval_lanes": {
        +      "items": {
        +        "enum": [
        +          "exact",
        +          "bm25",
        +          "vector",
        +          "graph"
        +        ],
        +        "type": "string"
        +      },
        +      "maxItems": 4,
        +      "type": "array"
        +    },
        +    "roles": {
        +      "items": {
        +        "enum": [
        +          "experiment_record",
        +          "result",
        +          "method",
        +          "log",
        +          "paper",
        +          "plan",
        +          "config",
        +          "source",
        +          "report",
        +          "other"
        +        ],
        +        "type": "string"
        +      },
        +      "maxItems": 10,
        +      "type": "array"
        +    },
        +    "source_families": {
        +      "items": {
        +        "enum": [
        +          "document",
        +          "code",
        +          "graph"
        +        ],
        +        "type": "string"
        +      },
        +      "maxItems": 3,
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / from_revision
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / idempotency_key
        Added value: +{
        +  "description": "Stable operation key. Reuse it after an uncertain response.",
        +  "maxLength": 500,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / job_id
        Added value: +{
        +  "maxLength": 500,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / missing_fields
        Added value: +{
        +  "items": {
        +    "maxLength": 500,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 1000,
        +  "type": "array"
        +}
      • changedInput schema / properties / name / description
        Previous value: -"Project name for create, or entity name lookup for show."New value: +"Project name for create/project_update, or entity name lookup for show."
      • addedInput schema / properties / operation
        Added value: +{
        +  "description": "Typed durable write operation. Use with asset_kind and idempotency_key.",
        +  "enum": [
        +    "create",
        +    "patch",
        +    "append_evidence",
        +    "relocate",
        +    "correct"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / protected
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / protected_parent_ids
        Added value: +{
        +  "items": {
        +    "maxLength": 500,
        +    "type": "string"
        +  },
        +  "maxItems": 10000,
        +  "type": "array"
        +}
      • addedInput schema / properties / purpose
        Added value: +{
        +  "maxLength": 10000,
        +  "type": "string"
        +}
      • addedInput schema / properties / queries
        Added value: +{
        +  "description": "Independent questions returned as separate ranked groups inside one broker request.",
        +  "items": {
        +    "properties": {
        +      "id": {
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "limit": {
        +        "maximum": 20,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "query": {
        +        "maxLength": 400,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "query_variants": {
        +        "items": {
        +          "maxLength": 400,
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 19,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "query"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 20,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / record_id
        Added value: +{
        +  "description": "Known exact record or alias ID for get, diff, or verify.",
        +  "maxLength": 500,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / record_ids
        Added value: +{
        +  "items": {
        +    "maxLength": 500,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 100,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / records
        Added value: +{
        +  "items": {
        +    "properties": {
        +      "access_tier": {
        +        "enum": [
        +          "hot",
        +          "warm",
        +          "cold"
        +        ],
        +        "type": "string"
        +      },
        +      "aliases": {
        +        "items": {
        +          "maxLength": 2000,
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 1000,
        +        "type": "array"
        +      },
        +      "artifact_references": {
        +        "items": {
        +          "properties": {
        +            "artifact_id": {
        +              "maxLength": 500,
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "available": {
        +              "type": "boolean"
        +            },
        +            "content_hash": {
        +              "maxLength": 200,
        +              "type": "string"
        +            },
        +            "location": {
        +              "maxLength": 2000,
        +              "type": "string"
        +            },
        +            "media_type": {
        +              "maxLength": 200,
        +              "type": "string"
        +            },
        +            "member": {
        +              "maxLength": 2000,
        +              "type": "string"
        +            },
        +            "observed_at": {
        +              "format": "date-time",
        +              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +              "type": "string"
        +            },
        +            "path": {
        +              "maxLength": 2000,
        +              "type": "string"
        +            },
        +            "role": {
        +              "maxLength": 200,
        +              "type": "string"
        +            },
        +            "size": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "verification": {
        +              "enum": [
        +                "declared",
        +                "present",
        +                "hash_verified",
        +                "restore_tested",
        +                "replayed"
        +              ],
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "artifact_id"
        +          ],
        +          "type": "object"
        +        },
        +        "maxItems": 50000,
        +        "type": "array"
        +      },
        +      "asset_id": {
        +        "maxLength": 500,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "body": {
        +        "maxLength": 4194304,
        +        "type": "string"
        +      },
        +      "body_path": {
        +        "maxLength": 4000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "correction_reason": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "effective_at": {
        +        "format": "date-time",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +        "type": "string"
        +      },
        +      "evidence_ids": {
        +        "items": {
        +          "maxLength": 500,
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 50000,
        +        "type": "array"
        +      },
        +      "expected_revision": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "fields": {
        +        "additionalProperties": {},
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "idempotency_key": {
        +        "maxLength": 500,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "kind": {
        +        "enum": [
        +          "project",
        +          "plan",
        +          "task",
        +          "method",
        +          "experiment",
        +          "attempt",
        +          "arm",
        +          "measurement",
        +          "byte_ledger",
        +          "artifact",
        +          "document",
        +          "decision",
        +          "session"
        +        ],
        +        "type": "string"
        +      },
        +      "missing_fields": {
        +        "items": {
        +          "maxLength": 500,
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 1000,
        +        "type": "array"
        +      },
        +      "operation": {
        +        "enum": [
        +          "create",
        +          "patch",
        +          "append_evidence",
        +          "relocate",
        +          "correct"
        +        ],
        +        "type": "string"
        +      },
        +      "protected": {
        +        "type": "boolean"
        +      },
        +      "set_current": {
        +        "type": "boolean"
        +      },
        +      "source_reference": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "source_sequence": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "operation",
        +      "idempotency_key"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 100,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / removed_paths
        Added value: +{
        +  "description": "Explicit root-relative entries to remove from the active snapshot. Historical snapshots remain addressable.",
        +  "items": {
        +    "properties": {
        +      "path": {
        +        "maxLength": 2000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "root": {
        +        "maxLength": 32,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "root",
        +      "path"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 100000,
        +  "type": "array"
        +}
      • addedInput schema / properties / request_id
        Added value: +{
        +  "description": "Caller-chosen ID for one local query. Supply it before a long request so project_memory query_status/query_cancel can inspect or cancel the same operation.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / response_budget_bytes
        Added value: +{
        +  "description": "Explicit result-array byte budget. Without an override, summaries adapt to unique result, question and source-family counts. Stored bodies and retrieval scope are not truncated by this budget; envelope metadata is separate.",
        +  "maximum": 1000000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • addedInput schema / properties / response_deadline_ms
        Added value: +{
        +  "description": "Caller-selected 1-300 second response deadline. Returns available lane results or QUERY_TIMEOUT with request_id. Native reads remain tracked until they settle; stored evidence and writes are unaffected.",
        +  "maximum": 300000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • addedInput schema / properties / revision
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / root_mode
        Added value: +{
        +  "enum": [
        +    "merge",
        +    "replace",
        +    "remove"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / roots / description
        Previous value: -"Approved local roots to index. Omit to rebuild derived state from stored sources."New value: +"Approved local roots and optional path-independent role/alias manifest. sync merges roots by default; removal is explicit."
      • addedInput schema / properties / roots / items / properties / manifest
        Added value: +{
        +  "items": {
        +    "properties": {
        +      "aliases": {
        +        "items": {
        +          "maxLength": 2000,
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 100,
        +        "type": "array"
        +      },
        +      "path": {
        +        "maxLength": 2000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "role": {
        +        "enum": [
        +          "experiment_record",
        +          "result",
        +          "method",
        +          "log",
        +          "paper",
        +          "plan",
        +          "config",
        +          "source",
        +          "report",
        +          "other"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "role"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 100000,
        +  "type": "array"
        +}
      • addedInput schema / properties / roots / items / properties / role
        Added value: +{
        +  "enum": [
        +    "experiment_record",
        +    "result",
        +    "method",
        +    "log",
        +    "paper",
        +    "plan",
        +    "config",
        +    "source",
        +    "report",
        +    "other"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / roots / maxItems
        Previous value: -8New value: +64
      • addedInput schema / properties / set_current
        Added value: +{
        +  "description": "For plan writes, select this revision as current. Defaults to true; use false for historical imports.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / since_revision
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / snapshot_path
        Added value: +{
        +  "maxLength": 4000,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / source_reference
        Added value: +{
        +  "maxLength": 2000,
        +  "type": "string"
        +}
      • addedInput schema / properties / source_sequence
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / to_revision
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / user_constraints
        Added value: +{
        +  "items": {
        +    "maxLength": 2000,
        +    "type": "string"
        +  },
        +  "maxItems": 1000,
        +  "type": "array"
        +}
      • changedInput schema / properties / valid_from / pattern
        Previous value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"New value: +"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
      • changedInput schema / properties / valid_to / pattern
        Previous value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"New value: +"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
      • addedInput schema / properties / verification_level
        Added value: +{
        +  "enum": [
        +    "declared",
        +    "present",
        +    "hash_verified",
        +    "restore_tested",
        +    "replayed"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / wait_timeout_ms
        Added value: +{
        +  "maximum": 60000,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedOutput schema / properties / context
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / current
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / diff
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / doctor
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / error / properties / cancel_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / phase
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / request_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / groups
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / imported
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / job
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / query_status
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / receipt
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / receipts
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / records
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / body_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / index_freshness
        Added value: +{
        +  "enum": [
        +    "current",
        +    "stale"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / record_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / revision_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / source_span
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "end": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "start": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "start",
        +    "end"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / snapshot
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / timeline
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / verification
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
    • Changedproject_memory_search29 fields changed
      • addedInput schema / properties / filters
        Added value: +{
        +  "description": "Optional project, source, type, role, lane, and recorded-time filters. Excluded lanes are not executed.",
        +  "properties": {
        +    "kinds": {
        +      "items": {
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "maxItems": 20,
        +      "type": "array"
        +    },
        +    "recorded_after": {
        +      "format": "date-time",
        +      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +      "type": "string"
        +    },
        +    "recorded_before": {
        +      "format": "date-time",
        +      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
        +      "type": "string"
        +    },
        +    "retrieval_lanes": {
        +      "items": {
        +        "enum": [
        +          "exact",
        +          "bm25",
        +          "vector",
        +          "graph"
        +        ],
        +        "type": "string"
        +      },
        +      "maxItems": 4,
        +      "type": "array"
        +    },
        +    "roles": {
        +      "items": {
        +        "enum": [
        +          "experiment_record",
        +          "result",
        +          "method",
        +          "log",
        +          "paper",
        +          "plan",
        +          "config",
        +          "source",
        +          "report",
        +          "other"
        +        ],
        +        "type": "string"
        +      },
        +      "maxItems": 10,
        +      "type": "array"
        +    },
        +    "source_families": {
        +      "items": {
        +        "enum": [
        +          "document",
        +          "code",
        +          "graph"
        +        ],
        +        "type": "string"
        +      },
        +      "maxItems": 3,
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / queries
        Added value: +{
        +  "description": "Independent questions returned as separate ranked groups inside one broker request.",
        +  "items": {
        +    "properties": {
        +      "id": {
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "limit": {
        +        "maximum": 20,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "query": {
        +        "maxLength": 400,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "query_variants": {
        +        "items": {
        +          "maxLength": 400,
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 19,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "query"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 20,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / properties / query / description
        Previous value: -"Natural-language query over indexed local project knowledge."New value: +"One natural-language query over indexed local project knowledge. Use queries instead for independent grouped answers."
      • addedInput schema / properties / request_id
        Added value: +{
        +  "description": "Caller-chosen ID for one local query. Supply it before a long request so project_memory query_status/query_cancel can inspect or cancel the same operation.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / response_budget_bytes
        Added value: +{
        +  "description": "Explicit result-array byte budget. Without an override, summaries adapt to unique result, question and source-family counts. Stored bodies and retrieval scope are not truncated by this budget; envelope metadata is separate.",
        +  "maximum": 1000000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • addedInput schema / properties / response_deadline_ms
        Added value: +{
        +  "description": "Caller-selected 1-300 second response deadline. Returns available lane results or QUERY_TIMEOUT with request_id. Native reads remain tracked until they settle; stored evidence and writes are unaffected.",
        +  "maximum": 300000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "query"
        -]
      • addedOutput schema / properties / context
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / current
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / diff
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / doctor
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / error / properties / cancel_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / phase
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / request_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / groups
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / imported
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / job
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / query_status
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / receipt
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / receipts
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / records
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / body_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / index_freshness
        Added value: +{
        +  "enum": [
        +    "current",
        +    "stale"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / record_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / revision_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / source_span
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "end": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "start": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "start",
        +    "end"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / snapshot
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / timeline
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / verification
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
    • Changedscholar_search3 fields changed
      • addedOutput schema / properties / error / properties / cancel_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / phase
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / request_id
        Added value: +{
        +  "type": "string"
        +}
    • Changedsearch8 fields changed
      • addedOutput schema / properties / error / properties / cancel_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / phase
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / request_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / body_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / index_freshness
        Added value: +{
        +  "enum": [
        +    "current",
        +    "stale"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / record_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / revision_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / source_span
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "end": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "start": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "start",
        +    "end"
        +  ],
        +  "type": "object"
        +}
    • Changedsearch_parallel8 fields changed
      • addedOutput schema / properties / error / properties / cancel_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / phase
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / error / properties / request_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / body_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / index_freshness
        Added value: +{
        +  "enum": [
        +    "current",
        +    "stale"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / record_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / revision_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / source_span
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "end": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "start": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "start",
        +    "end"
        +  ],
        +  "type": "object"
        +}
  2. 3 tool updatesv1.0.6
    • Changedproject_memory4 fields changed
      • addedInput schema / properties / detail_level
        Added value: +{
        +  "default": "summary",
        +  "description": "For show with project_id and no target_id, both values return a bounded summary. full is retained only for compatibility and never returns every durable record body.",
        +  "enum": [
        +    "summary",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / decision_count
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / experiment_count
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / plan_count
        Added value: +{
        +  "type": "number"
        +}
    • Changedproject_memory_search3 fields changed
      • addedOutput schema / properties / decision_count
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / experiment_count
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / plan_count
        Added value: +{
        +  "type": "number"
        +}
    • Changedsearch2 fields changed
      • changedInput schema / properties / response_content / default
        Previous value: -"full"New value: +"summary"
      • changedInput schema / properties / response_content / description
        Previous value: -"Controls only the returned body. full returns up to max_chars; summary returns a 1500-character evidence excerpt. Research storage keeps the full captured text in deterministic chunks."New value: +"Controls only the returned body. summary is the default and returns a 1500-character evidence excerpt; full returns up to max_chars. Research storage keeps the full captured text in deterministic chunks."
  3. 5 tool updatesv1.0.4
    • Changedhealth1 field changed
      • addedOutput schema / properties / nativeBrowser
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
    • Changedproject_memory1 field changed
      • addedInput schema / properties / query_variants
        Added value: +{
        +  "description": "Optional local retrieval variants for action=search. They run inside one broker request and are fused before one rerank.",
        +  "items": {
        +    "maxLength": 400,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 19,
        +  "type": "array"
        +}
    • Changedproject_memory_search1 field changed
      • addedInput schema / properties / query_variants
        Added value: +{
        +  "description": "Optional retrieval variants executed inside this one broker request. Exact identifiers and quoted phrases are added deterministically, candidates are fused with RRF, and the primary query is reranked once. Do not make repeated terminal or tool calls for query variants.",
        +  "items": {
        +    "maxLength": 400,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 19,
        +  "type": "array"
        +}
    • Changedsearch1 field changed
      • changedInput schema / properties / extract_mode / description
        Previous value: -"Content depth in this search call. Use abstract or full during research instead of following search with separate extract calls. For GitHub results, none reads the README; abstract and full use the same repository eligibility gate but index different source amounts."New value: +"Content depth in this search call. Use none only when titles and snippets are enough, abstract for relevance evidence, and full when the user asks to read originals, full text, document bodies, or code, or to compare source contents. Use abstract or full here instead of following search with separate extraction, PDF download, or repository clone. For GitHub results, none reads the README; abstract and full use the same repository eligibility gate but index different source amounts."
    • Changedsearch_parallel1 field changed
      • changedInput schema / properties / extract_mode / description
        Previous value: -"Content depth in this search call. Use abstract or full during research instead of following search with separate extract calls. For GitHub results, none reads the README; abstract and full use the same repository eligibility gate but index different source amounts."New value: +"Content depth in this search call. Use none only when titles and snippets are enough, abstract for relevance evidence, and full when the user asks to read originals, full text, document bodies, or code, or to compare source contents. Use abstract or full here instead of following search with separate extraction, PDF download, or repository clone. For GitHub results, none reads the README; abstract and full use the same repository eligibility gate but index different source amounts."
  4. 6 tool updatesv1.0.2
    • Changedextract4 fields changed
      • changedInput schema / properties / max_chars / description
        Previous value: -"Truncate body to this many chars. Defaults to 1500 for abstract and 50000 for full."New value: +"Maximum returned characters when response_content=full. Defaults to 1500 for abstract and 50000 for full."
      • addedInput schema / properties / response_content
        Added value: +{
        +  "default": "full",
        +  "description": "Controls only the returned body. full returns up to max_chars; summary returns a 1500-character evidence excerpt. Research storage keeps the full captured text in deterministic chunks.",
        +  "enum": [
        +    "summary",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / source_length
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
    • Changedproject_memory2 fields changed
      • addedOutput schema / properties / results / items / properties / source_length
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
    • Changedproject_memory_search2 fields changed
      • addedOutput schema / properties / results / items / properties / source_length
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
    • Changedscholar_search1 field changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max papers (default 10)."New value: +"Maximum papers. Integer 1-10, default 10."
    • Changedsearch6 fields changed
      • changedInput schema / properties / extract_limit / description
        Previous value: -"Maximum unique result URLs to extract. For parallel search this is one call-wide limit, not a per-query limit."New value: +"Maximum unique result URLs to extract. Integer 1-10, default 5."
      • changedInput schema / properties / limit / description
        Previous value: -"Max results (default 10)."New value: +"Maximum results. Integer 1-20, default 10."
      • changedInput schema / properties / max_chars / description
        Previous value: -"Maximum characters per extracted result. Defaults to 1500 for abstract and 50000 for full."New value: +"Maximum returned characters per extracted result in response_content=full. Defaults to 1500 for abstract and 50000 for full."
      • addedInput schema / properties / response_content
        Added value: +{
        +  "default": "full",
        +  "description": "Controls only the returned body. full returns up to max_chars; summary returns a 1500-character evidence excerpt. Research storage keeps the full captured text in deterministic chunks.",
        +  "enum": [
        +    "summary",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / source_length
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
    • Changedsearch_parallel8 fields changed
      • removedInput schema / properties / extract_limit / default
        Removed value: -5
      • changedInput schema / properties / extract_limit / description
        Previous value: -"Maximum unique result URLs to extract. For parallel search this is one call-wide limit, not a per-query limit."New value: +"Call-wide maximum unique result URLs to extract. Integer 1-20, default 12 for abstract; full defaults to and allows at most 10."
      • changedInput schema / properties / extract_limit / maximum
        Previous value: -10New value: +20
      • changedInput schema / properties / limit / description
        Previous value: -"Max results per query."New value: +"Maximum results per query. Integer 1-20, default 10."
      • changedInput schema / properties / max_chars / description
        Previous value: -"Maximum characters per extracted result. Defaults to 1500 for abstract and 50000 for full."New value: +"Maximum returned characters per extracted result in response_content=full. Defaults to 1500 for abstract and 50000 for full."
      • addedInput schema / properties / response_content
        Added value: +{
        +  "default": "summary",
        +  "description": "Controls only returned bodies. summary is the default and returns 1500-character evidence excerpts; full returns up to max_chars. Research storage keeps the full captured text in deterministic chunks.",
        +  "enum": [
        +    "summary",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / source_length
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
  5. 8 tool updatesv1.0.0
    • Changedextract23 fields changed
      • removedInput schema / properties / max_chars / default
        Removed value: -8000
      • changedInput schema / properties / max_chars / description
        Previous value: -"Truncate body to this many chars (default 8000, set via SURF_EXTRACT_MAX_CHARS)."New value: +"Truncate body to this many chars. Defaults to 1500 for abstract and 50000 for full."
      • addedInput schema / properties / memory_handle
        Added value: +{
        +  "description": "Reuse the handle returned by a prior project-aware call.",
        +  "format": "uuid",
        +  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +  "type": "string"
        +}
      • changedInput schema / properties / mode / description
        Previous value: -"Extraction depth. `full` = whole article body (default; uses Playwright if needed). `abstract` = cheap survey: PDF page 1 OR HTML meta description (~1500 chars); use to triage relevance before paying for full text. `metadata` = page count only (PDF). Academic PDFs (arxiv/biorxiv/Nature/OpenReview/NeurIPS/JMLR/PMLR/Springer/PubMed-via-PMC) are auto-detected; abstract mode skips Playwright for them."New value: +"Extraction depth. `full` = whole article body (default; uses Playwright if needed). `abstract` = cheap survey: PDF page 1 OR HTML meta description (~1500 chars); use to triage relevance before paying for full text. `metadata` = document metadata without body text: title, authors, publication details, dates, DOI, keywords, canonical URL, and PDF properties when available. Academic PDFs (arxiv/biorxiv/Nature/OpenReview/NeurIPS/JMLR/PMLR/Springer/PubMed-via-PMC) are auto-detected; abstract mode skips Playwright for them."
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "Project memory id.",
        +  "maxLength": 64,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / session_id
        Added value: +{
        +  "description": "Stable host task id. Reuses the same project session after restart.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / session_intent
        Added value: +{
        +  "description": "Current durable task intent. A changed value creates an immutable revision.",
        +  "maxLength": 2000,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedOutput schema / properties / authors
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / canonical_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / created_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / creator
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / description
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / doi
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / keywords
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / language
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / modified_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / producer
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / publication
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / published_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / subject
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / year
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
    • Changedhealth1 field changed
      • addedOutput schema / properties / research
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
    • Addedproject_memory
    • Addedproject_memory_search
    • Changedscholar_search7 fields changed
      • addedInput schema / properties / memory_handle
        Added value: +{
        +  "description": "Reuse the handle returned by a prior project-aware call.",
        +  "format": "uuid",
        +  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +  "type": "string"
        +}
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "Project memory id.",
        +  "maxLength": 64,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / session_id
        Added value: +{
        +  "description": "Stable host task id. Reuses the same project session after restart.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / session_intent
        Added value: +{
        +  "description": "Current durable task intent. A changed value creates an immutable revision.",
        +  "maxLength": 2000,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / research_context
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "prior_searches": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "query": {
        +            "type": "string"
        +          },
        +          "relation": {
        +            "enum": [
        +              "same",
        +              "related",
        +              "recent"
        +            ],
        +            "type": "string"
        +          },
        +          "results": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "searched_at": {
        +            "type": "string"
        +          },
        +          "surface": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "query",
        +          "relation",
        +          "searched_at",
        +          "results"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 3,
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "prior_searches"
        +  ],
        +  "type": "object"
        +}
    • Changedsearch37 fields changed
      • addedInput schema / properties / extract_limit
        Added value: +{
        +  "default": 5,
        +  "description": "Maximum unique result URLs to extract. For parallel search this is one call-wide limit, not a per-query limit.",
        +  "maximum": 10,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / extract_mode
        Added value: +{
        +  "default": "none",
        +  "description": "Content depth in this search call. Use abstract or full during research instead of following search with separate extract calls. For GitHub results, none reads the README; abstract and full use the same repository eligibility gate but index different source amounts.",
        +  "enum": [
        +    "none",
        +    "abstract",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / include_project_ids
        Added value: +{
        +  "description": "Additional read-only projects joined through ontology-aligned schema and identity links. New records stay in project_id.",
        +  "items": {
        +    "maxLength": 64,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 8,
        +  "type": "array"
        +}
      • addedInput schema / properties / max_chars
        Added value: +{
        +  "description": "Maximum characters per extracted result. Defaults to 1500 for abstract and 50000 for full.",
        +  "maximum": 50000,
        +  "minimum": 200,
        +  "type": "integer"
        +}
      • addedInput schema / properties / memory_handle
        Added value: +{
        +  "description": "Reuse the handle returned by a prior project-aware call.",
        +  "format": "uuid",
        +  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +  "type": "string"
        +}
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "Project memory id.",
        +  "maxLength": 64,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / session_id
        Added value: +{
        +  "description": "Stable host task id. Reuses the same project session after restart.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / session_intent
        Added value: +{
        +  "description": "Current durable task intent. A changed value creates an immutable revision.",
        +  "maxLength": 2000,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / research_context
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "prior_searches": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "query": {
        +            "type": "string"
        +          },
        +          "relation": {
        +            "enum": [
        +              "same",
        +              "related",
        +              "recent"
        +            ],
        +            "type": "string"
        +          },
        +          "results": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "searched_at": {
        +            "type": "string"
        +          },
        +          "surface": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "query",
        +          "relation",
        +          "searched_at",
        +          "results"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 3,
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "prior_searches"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / results / items / properties / authors
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / canonical_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / content
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / created_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / creator
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / document_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / doi
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / excerpt
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / extract_error
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / extraction_quality
        Added value: +{
        +  "enum": [
        +    "full_text",
        +    "abstract",
        +    "meta_abstract",
        +    "metadata_only"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / fresh_web
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / is_pdf
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / keywords
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / language
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / length
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / modified_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / page_count
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / producer
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / project_ids
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / publication
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / published_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / retrieval_families
        Added value: +{
        +  "items": {
        +    "enum": [
        +      "exact",
        +      "bm25",
        +      "vector",
        +      "graph"
        +    ],
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / score
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / source_family
        Added value: +{
        +  "enum": [
        +    "live",
        +    "document",
        +    "code",
        +    "graph"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / subject
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / year
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
    • Removedsearch_extract
    • Changedsearch_parallel43 fields changed
      • addedInput schema / properties / extract_limit
        Added value: +{
        +  "default": 5,
        +  "description": "Maximum unique result URLs to extract. For parallel search this is one call-wide limit, not a per-query limit.",
        +  "maximum": 10,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / extract_mode
        Added value: +{
        +  "default": "none",
        +  "description": "Content depth in this search call. Use abstract or full during research instead of following search with separate extract calls. For GitHub results, none reads the README; abstract and full use the same repository eligibility gate but index different source amounts.",
        +  "enum": [
        +    "none",
        +    "abstract",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / include_project_ids
        Added value: +{
        +  "description": "Additional read-only projects joined through ontology-aligned schema and identity links. New records stay in project_id.",
        +  "items": {
        +    "maxLength": 64,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 8,
        +  "type": "array"
        +}
      • addedInput schema / properties / max_chars
        Added value: +{
        +  "description": "Maximum characters per extracted result. Defaults to 1500 for abstract and 50000 for full.",
        +  "maximum": 50000,
        +  "minimum": 200,
        +  "type": "integer"
        +}
      • addedInput schema / properties / memory_handle
        Added value: +{
        +  "description": "Reuse the handle returned by a prior project-aware call.",
        +  "format": "uuid",
        +  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +  "type": "string"
        +}
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "Project memory id.",
        +  "maxLength": 64,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / queries / description
        Previous value: -"2-10 queries to run concurrently."New value: +"2-12 independent live queries."
      • addedInput schema / properties / queries / items / maxLength
        Added value: +400
      • addedInput schema / properties / queries / items / minLength
        Added value: +1
      • changedInput schema / properties / queries / maxItems
        Previous value: -10New value: +12
      • changedInput schema / properties / queries / minItems
        Previous value: -1New value: +2
      • addedInput schema / properties / session_id
        Added value: +{
        +  "description": "Stable host task id. Reuses the same project session after restart.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / session_intent
        Added value: +{
        +  "description": "Current durable task intent. A changed value creates an immutable revision.",
        +  "maxLength": 2000,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / memory_handle
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / research_context
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "prior_searches": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "query": {
        +            "type": "string"
        +          },
        +          "relation": {
        +            "enum": [
        +              "same",
        +              "related",
        +              "recent"
        +            ],
        +            "type": "string"
        +          },
        +          "results": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "searched_at": {
        +            "type": "string"
        +          },
        +          "surface": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "query",
        +          "relation",
        +          "searched_at",
        +          "results"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 3,
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "prior_searches"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / properties / results / items / properties / provider / enum
        Previous value: -[
        -  "browser",
        -  "searchapi"
        -]New value: +[
        +  "browser",
        +  "searchapi",
        +  "local"
        +]
      • addedOutput schema / properties / results / items / properties / results / items / properties / authors
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / canonical_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / content
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / created_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / creator
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / document_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / doi
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / excerpt
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / extract_error
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / extraction_quality
        Added value: +{
        +  "enum": [
        +    "full_text",
        +    "abstract",
        +    "meta_abstract",
        +    "metadata_only"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / fresh_web
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / is_pdf
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / keywords
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / language
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / length
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / modified_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / page_count
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / producer
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / project_ids
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / publication
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / published_at
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / retrieval_families
        Added value: +{
        +  "items": {
        +    "enum": [
        +      "exact",
        +      "bm25",
        +      "vector",
        +      "graph"
        +    ],
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / score
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / source_family
        Added value: +{
        +  "enum": [
        +    "live",
        +    "document",
        +    "code",
        +    "graph"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / subject
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / results / items / properties / year
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
  6. 3 tool updatesv0.8.0
    • Addedscholar_search
    • Changedsearch_extract1 field changed
      • changedInput schema / properties / max_chars / description
        Previous value: -"Truncate each result body. Default depends on mode: ~1500 for abstract, 8000 for full."New value: +"Truncate each result body. Default depends on mode: ~1500 for abstract, 8000 for full (SURF_EXTRACT_MAX_CHARS, capped at 20000 here)."
    • Changedsearch_parallel3 fields changed
      • addedOutput schema / properties / results / items / properties / degraded_reasons
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / fallback_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / provider
        Added value: +{
        +  "enum": [
        +    "browser",
        +    "searchapi"
        +  ],
        +  "type": "string"
        +}
  7. 1 tool updatev0.6.8
    • Changedextract1 field changed
      • changedInput schema / properties / max_chars / description
        Previous value: -"Truncate body to this many chars (default 8000)."New value: +"Truncate body to this many chars (default 8000, set via SURF_EXTRACT_MAX_CHARS)."
  8. 5 tool updatesv0.6.5
    • Addedextract
    • Addedhealth
    • Addedsearch
    • Addedsearch_extract
    • Addedsearch_parallel
  9. 5 tool updatesv0.6.1
    • Removedextract
    • Removedhealth
    • Removedsearch
    • Removedsearch_extract
    • Removedsearch_parallel
  10. 1 tool updatev0.5.6
    • Changedhealth3 fields changed
      • addedOutput schema / properties / pool
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / selfHealing
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / telemetry
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
  11. 5 tool updatesv0.5.2
    • Addedextract
    • Addedhealth
    • Addedsearch
    • Addedsearch_extract
    • Addedsearch_parallel
  12. 5 tool updatesv0.5.1
    • Removedextract
    • Removedhealth
    • Removedsearch
    • Removedsearch_extract
    • Removedsearch_parallel
  13. 5 tool updatesv0.4.8
    • Addedextract
    • Addedhealth
    • Addedsearch
    • Addedsearch_extract
    • Addedsearch_parallel

TDQS

A4.4/5.0

Scored across 7 tools

Disambiguation5/5

Each tool has a clearly scoped role: search for single-query live lookup, search_parallel for multi-query lookup, extract for known-URL reading, scholar_search for paper metadata, and project_memory_search for local-only retrieval. Even potential overlaps like search's extract_mode vs extract are explicitly separated by whether discovery is still needed.

Naming Consistency3/5

Naming is reasonably readable but not consistent: some tools are bare verbs (search, extract), some are noun+search (scholar_search, project_memory_search), and health is a standalone noun while project_memory is a broad domain name. There is no uniform verb_noun or noun_verb convention across the surface.

Tool Count5/5

Seven tools is well-scoped for the server's purpose: live web search, parallel search, extraction, scholar metadata, local memory search, memory management, and health. Each tool occupies a distinct place, and the count is within the ideal range without redundant or missing entries.

Completeness5/5

The surface covers the full workflow: discover via search, extract via extract or search mode, search scholar metadata, retrieve from local project memory, and manage that memory's full lifecycle. Project_memory is especially thorough, offering writes, updates, timelines, deletion, rollback, snapshots, and diagnostics, so agents should not hit dead ends.

Maintenance

ActivityActive
ResponsivenessSlow

Related MCP Connectors

Related MCP Servers