import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; import { type RagContentBlock, type RagTextContentBlock } from './error-utils.js'; import type { IngestDataInput, ListFilesInput, QueryDocumentsInput, RAGServerConfig, SyncStartInput, SyncStatusInput } from './types.js'; type QueryContent = [RagTextContentBlock, ...RagContentBlock[]]; export declare class RAGServer { private readonly server; private readonly vectorStore; private readonly embedder; private readonly chunker; private readonly parser; private readonly dbPath; /** * Allowed document roots, REALPATH-normalized — the security boundary handed * to `DocumentParser`. `list_files` scanning and display use the normal-path * `rawBaseDirs` below instead. */ private readonly baseDirs; /** * Normal-path (resolve()) roots, index-aligned with `baseDirs`, for * user-facing `list_files` scan/display. Falls back to `baseDirs` for legacy * `{ baseDir }` callers. See {@link BaseDirsConfig} for the path policy. */ private readonly rawBaseDirs; /** Legacy single-root accessor for `rawBaseDirs`. Derived from `rawBaseDirs[0]`. */ private readonly rawBaseDir; private readonly cacheDir; private readonly scanExclusion; private readonly configWarnings; /** * When non-null the server is in degraded mode: `status` stays callable so the * user can diagnose over MCP, while root-dependent tools must reject first. */ private readonly configError; private readonly minChunkLength; /** * Configured byte ceiling for one ingested file. The parser enforces it for * parsing; sync also needs it before hashing, where nothing else bounds the * read. */ private readonly maxFileSize; private readonly device; private readonly storeImages; /** Configured reranker command. Undefined leaves query_documents unchanged. */ private readonly rerankCommand; private readonly rerankTimeoutMs; /** * The one current-or-latest sync job this process retains. A new `sync_start` * replaces a terminal record, so the older id becomes unknown; there is no * history, persistence or recovery. */ private syncJob; /** * True while one external mutation is in flight (SYNC-007). A request-scoped * mutation clears it when the request completes; a sync keeps it until its * job reaches a terminal state. */ private mutationInFlight; constructor(config: RAGServerConfig); /** * Fail-fast guard for root-dependent tools in degraded mode: reject before any * DB / embedder / parser access. Throws the stored error so the dispatcher * mapper owns the code, rather than hand-building one here. * * `status` deliberately does not call this — it stays callable and reports the * error in a diagnostic block, so recovery does not need stderr. */ private assertConfigOk; /** Every handler funnels through here, so the warning shape lives in one place. */ private withWarnings; /** * Take the single external-mutation slot, or describe the overlap. * * Returns `null` when the slot was free. Otherwise an ordinary result with * `isError: true` rather than a thrown error, naming the holding job id and * pointing at `sync_status` — the only way to learn when to retry. */ private acquireMutation; private releaseMutation; /** * Set up MCP handlers */ private setupHandlers; /** * Initialization */ initialize(): Promise; /** * query_documents tool handler */ /** Hands the finished results to the configured command and takes its answer. */ private applyReranker; handleQueryDocuments(args: QueryDocumentsInput): Promise<{ content: QueryContent; }>; /** * `options.skipOptimize` is internal: sync compacts once per run, so its reuse * of this handler must not compact once per file (a 100-file sync would * otherwise perform 101 compactions). The tools omit it and compact per call. */ handleIngestFile(raw: unknown, options?: { skipOptimize?: boolean; images?: boolean; }): Promise<{ content: RagTextContentBlock[]; }>; /** What one ingest source contributed, before rows are built and stored. */ private prepareRawDataIngest; private prepareSourceFileIngest; /** * Restore the pre-ingest state after a failed insert. A rollback that itself * fails is reported as its own error, because the prior data may now be gone. */ private rollbackIngest; private prepareIngestSource; private ingestFile; /** * Saves raw content under raw-data and re-enters `handleIngestFile`. HTML is * reduced to its main content and converted to Markdown first, so chunking * sees prose rather than markup. */ handleIngestData(args: IngestDataInput): Promise<{ content: RagTextContentBlock[]; }>; /** * Scans the normal-path roots (`this.rawBaseDirs`) so scanned paths match the * resolve()-stored DB keys (see {@link BaseDirsConfig}). * * Multi-root contract: a top-level `baseDir` is still reported as * `rawBaseDirs[0]` for clients written against the single-root shape; * duplicate paths across roots collapse to the first occurrence in root * order; raw-data and orphaned DB entries stay under `sources` with no * producing root. */ handleListFiles(input?: ListFilesInput): Promise<{ content: RagTextContentBlock[]; }>; /** * status tool handler */ handleStatus(): Promise<{ content: RagTextContentBlock[]; }>; /** * delete_file tool handler * Deletes chunks from VectorDB and physical raw-data files * Supports both filePath (for ingest_file) and source (for ingest_data) */ handleDeleteFile(raw: unknown): Promise<{ content: RagTextContentBlock[]; }>; /** * Context expansion around a chunkIndex, not a search tool. Mirrors * handleDeleteFile's filePath-XOR-source resolution. */ handleReadChunkNeighbors(raw: unknown): Promise<{ content: RagTextContentBlock[]; }>; /** Resolve the shared filePath/source reference without changing its DB-key spelling. */ private resolveDocumentTarget; /** * Registers the one current job and answers with its id without waiting: the * caller polls `sync_status`. * * The scheduled promise is deliberately floating — an unexpected rejection is * captured into the job record rather than escaping, and the run holds the * external-mutation guard until it is terminal. */ handleSyncStart(input: SyncStartInput): Promise<{ content: RagTextContentBlock[]; }>; /** * Read-only, so it stays callable while a sync holds the mutation guard. Any * id but the current one is unknown — replaced by a newer `sync_start`, or * lost with a previous server process. */ handleSyncStatus(input: SyncStatusInput): Promise<{ content: RagTextContentBlock[]; }>; /** Patch the current job, ignoring a write aimed at a record already replaced. */ private updateSyncJob; /** * One sync job's body: supply the real collaborators to the shared core and * fold its result into the pollable record. Planning and the * stop-on-first-error policy stay in the core, so path classification and * depth match the CLI exactly. */ private runSyncJob; /** * Sync's `ingestFile` uses the same typed operation as `ingest_file`, keeping * its backup and rollback semantics. A zero-chunk file is rejected before the * delete, so prior rows survive, and is reported as `empty`. * * The planner's resolved profile is expressed through the same `visual` / * `visualQuality` arguments a direct `ingest_file` call uses, so inheritance * reuses the configured cache and device rather than a second VLM route. * * Per-file compaction is skipped because the sync core runs one `optimize()` * for the whole run. A rollback still compacts — that path restores rows and * then aborts, so no later `optimize()` follows. */ private ingestFileForSync; /** * Serve this instance's tool registration over `transport` — the registration * itself, not a copy, since `this.server` is private. `run()` passes stdio; a * test passes an in-memory pair. * * One instance serves at most one client: the job record and the mutation slot * are per-process, so a multiplexing transport would share one caller's write * lock with every other caller. */ connect(transport: Transport): Promise; /** * Start the server */ run(): Promise; /** * Stop the server and release resources */ close(): Promise; } export {}; //# sourceMappingURL=index.d.ts.map