enquire-mcp API reference - v3.12.0-rc.19
    Preparing search index...

    Function contextPack

    • Token-budgeted vault context export — runs hybrid retrieval, gathers note bodies + backlinks + recent dailies, packs to a token budget, and returns one ready-to-paste markdown blob. With subqueries[], it executes at most MAX_RESEARCH_SUBQUERIES extra searches sequentially, reserves the best available unique evidence candidate per atomic sub-question, then fills remaining slots with RRF. The default single-query path is unchanged.

      The MCP-native answer to Smart Connections' "Send to Smart Context" pattern, but works in any chat (Claude / Cursor / Codex / web UI) by producing a plain-text bundle. Saves the agent from orchestrating 5 separate tool calls.

      Budget enforcement: each note's body is truncated to ~50% of remaining budget so room remains for backlinks + dailies; oversize bodies get a […truncated…] marker. As a final defense-in-depth, the assembled bundle is hard-capped at budget_tokens × 4 chars and marked […budget cap reached…] if truncated. Top-3 included notes get 1-line backlink summaries when include_backlinks is true.

      Parameters

      • vault: Vault

        The vault.

      • args: ContextPackArgs

        ContextPackArgs. query required + non-empty.

      • ctx: {
            embedFile: string;
            feedback?: { scores: ReadonlyMap<string, number>; weight: number };
            ftsIndex: FtsIndex | null;
            hnsw?: HnswSearchContext | null;
            recency?: { staleDays: number; weight: number };
            reranker?: { alias?: string; topN?: number };
            rerankerOverride?: {
                score(query: string, passages: readonly string[]): Promise<number[]>;
            };
        }

        Server-side context — the SAME shape as searchHybrid's ctx, forwarded verbatim to the inner retrieval. v3.11.6-rc.14: pre-rc.14 only ftsIndex/embedFile were accepted, so a server started with --enable-reranker / --use-hnsw / --recency-weight / --feedback-weight silently packed context in PLAIN RRF order while obsidian_search ranked with the enabled enhancements — an "enabled but not wired" divergence (the CRL-1/M5 class). Now the full ctx flows through, so the pack's top-10 is ranked exactly like obsidian_search would rank it.

        • embedFile: string

          Path to the .embed.db (file may or may not exist — checked at call time).

        • Optionalfeedback?: { scores: ReadonlyMap<string, number>; weight: number }

          v3.11.0 — optional opt-in closed-loop feedback re-ranking. When weight > 0 AND scores is non-empty, the final fused order is re-sorted by a blend of relevance rank and each note's feedback score (useful/(useful+notUseful+1), from obsidian_mark_useful via the FeedbackStore). weight = 0 / empty scores is a provable no-op. Applied AFTER recency so a "human said this helped" signal is the final tie-break. scores is keyed by relPath.

        • ftsIndex: FtsIndex | null

          FTS5 index, if --persistent-index is enabled at server start.

        • Optionalhnsw?: HnswSearchContext | null

          v2.13.0 — optional HNSW context for the embeddings-search arm. When passed, the embedding-side k-NN goes through the in-memory HNSW approximate nearest-neighbor index instead of the O(n) brute-force cosine in EmbedDb.search(). Built on serve start; lives in ServerDeps.hnswContext. Null/undefined → brute-force fallback.

        • Optionalrecency?: { staleDays: number; weight: number }

          v3.10 (rc.5) — optional opt-in recency re-ranking. When weight > 0, the final fused order is re-sorted by a blend of relevance rank and the note's live-mtime recency (see recencyScore in staleness.ts). weight = 0 (or undefined) is a no-op — the default keeps ranking purely relevance-driven. staleDays is the recency half-life (the age at which recency = 0.5).

        • Optionalreranker?: { alias?: string; topN?: number }

          v2.9.0 — optional cross-encoder reranker config. When set, the top-N hits from RRF (default 50) are re-scored by a BGE-style cross-encoder and re-sorted before truncation. Adds ~30-50ms per query on M1 CPU for a 50-candidate set.

          alias resolves to a RERANKER_MODELS entry. topN defaults to 50. Lazy-loaded from the local transformers.js cache. Runtime callers are offline-enforced; pre-cache with enquire-mcp install-model <alias>. Failures are swallowed and surface via signal_errors.reranker so the whole search doesn't break on a model load issue.

        • OptionalrerankerOverride?: { score(query: string, passages: readonly string[]): Promise<number[]> }

          v2.9.0 — test-only injection point. When set, this pre-loaded reranker is used instead of lazy-loading via loadReranker(alias). Lets unit tests validate the rerank-and-resort plumbing without pulling in the real ML model. Unused in production callers.

      Returns Promise<ContextPackResult>

      A ContextPackResult with the packed bundle + meta.

      If query is empty / whitespace-only.

      const pack = await contextPack(
      vault,
      {
      query: "How do I tune the hybrid retrieval?",
      subqueries: ["Which rankers contribute?", "How is the final order fused?"],
      budget_tokens: 3000,
      include_backlinks: true,
      recent_dailies: 3
      },
      { ftsIndex, embedFile: "/path/to/vault.embed.db" }
      );
      console.log(pack.bundle); // ready to paste into any chat