@wei840222/qmd 2026.8.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +1373 -0
  2. package/LICENSE +45 -0
  3. package/README.md +1439 -0
  4. package/THIRD_PARTY_NOTICES.md +31 -0
  5. package/bin/qmd +192 -0
  6. package/dist/ast.d.ts +65 -0
  7. package/dist/ast.js +334 -0
  8. package/dist/bench/bench.d.ts +35 -0
  9. package/dist/bench/bench.js +338 -0
  10. package/dist/bench/cjk-baseline.d.ts +36 -0
  11. package/dist/bench/cjk-baseline.js +111 -0
  12. package/dist/bench/fixture.d.ts +2 -0
  13. package/dist/bench/fixture.js +84 -0
  14. package/dist/bench/score.d.ts +38 -0
  15. package/dist/bench/score.js +107 -0
  16. package/dist/bench/types.d.ts +110 -0
  17. package/dist/bench/types.js +8 -0
  18. package/dist/cli/build-info.json +4 -0
  19. package/dist/cli/embed-lock.d.ts +24 -0
  20. package/dist/cli/embed-lock.js +94 -0
  21. package/dist/cli/embedding-owner.d.ts +10 -0
  22. package/dist/cli/embedding-owner.js +20 -0
  23. package/dist/cli/formatter.d.ts +120 -0
  24. package/dist/cli/formatter.js +355 -0
  25. package/dist/cli/mcp-pid.d.ts +25 -0
  26. package/dist/cli/mcp-pid.js +86 -0
  27. package/dist/cli/qmd.d.ts +72 -0
  28. package/dist/cli/qmd.js +4806 -0
  29. package/dist/cli/version.d.ts +42 -0
  30. package/dist/cli/version.js +80 -0
  31. package/dist/collections.d.ts +200 -0
  32. package/dist/collections.js +433 -0
  33. package/dist/db.d.ts +65 -0
  34. package/dist/db.js +143 -0
  35. package/dist/diagnostics.d.ts +62 -0
  36. package/dist/diagnostics.js +260 -0
  37. package/dist/embedding/config.d.ts +52 -0
  38. package/dist/embedding/config.js +229 -0
  39. package/dist/embedding/identity.d.ts +58 -0
  40. package/dist/embedding/identity.js +321 -0
  41. package/dist/embedding/local-identity.d.ts +1 -0
  42. package/dist/embedding/local-identity.js +15 -0
  43. package/dist/embedding/local.d.ts +34 -0
  44. package/dist/embedding/local.js +290 -0
  45. package/dist/embedding/openai.d.ts +79 -0
  46. package/dist/embedding/openai.js +477 -0
  47. package/dist/embedding/owner.d.ts +13 -0
  48. package/dist/embedding/owner.js +36 -0
  49. package/dist/embedding/provider.d.ts +68 -0
  50. package/dist/embedding/provider.js +16 -0
  51. package/dist/embedding/remote-chunking.d.ts +22 -0
  52. package/dist/embedding/remote-chunking.js +83 -0
  53. package/dist/embedding/remote-embedding.d.ts +15 -0
  54. package/dist/embedding/remote-embedding.js +77 -0
  55. package/dist/hybrid-llm.d.ts +18 -0
  56. package/dist/hybrid-llm.js +53 -0
  57. package/dist/index.d.ts +244 -0
  58. package/dist/index.js +418 -0
  59. package/dist/llm.d.ts +566 -0
  60. package/dist/llm.js +1847 -0
  61. package/dist/maintenance.d.ts +33 -0
  62. package/dist/maintenance.js +52 -0
  63. package/dist/mcp/origin-guard.d.ts +67 -0
  64. package/dist/mcp/origin-guard.js +137 -0
  65. package/dist/mcp/server.d.ts +116 -0
  66. package/dist/mcp/server.js +919 -0
  67. package/dist/paths.d.ts +1 -0
  68. package/dist/paths.js +4 -0
  69. package/dist/remote-llm.d.ts +52 -0
  70. package/dist/remote-llm.js +464 -0
  71. package/dist/search/cjk-analyzer.d.ts +33 -0
  72. package/dist/search/cjk-analyzer.js +158 -0
  73. package/dist/search/cjk-index.d.ts +104 -0
  74. package/dist/search/cjk-index.js +1031 -0
  75. package/dist/search/jieba-loader.d.ts +23 -0
  76. package/dist/search/jieba-loader.js +79 -0
  77. package/dist/search/query-expansion.d.ts +23 -0
  78. package/dist/search/query-expansion.js +43 -0
  79. package/dist/search/zh-dict.txt +624013 -0
  80. package/dist/store.d.ts +1218 -0
  81. package/dist/store.js +6076 -0
  82. package/dist/trust.d.ts +152 -0
  83. package/dist/trust.js +249 -0
  84. package/package.json +139 -0
  85. package/scripts/build.mjs +83 -0
  86. package/scripts/check-package-grammars.mjs +29 -0
  87. package/scripts/package-smoke.mjs +205 -0
  88. package/scripts/sync-zh-dict.mjs +187 -0
  89. package/scripts/test-all.mjs +45 -0
  90. package/skills/qmd/SKILL.md +324 -0
  91. package/skills/qmd/references/mcp-setup.md +119 -0
  92. package/skills/release/SKILL.md +141 -0
  93. package/skills/release/scripts/install-hooks.sh +38 -0
  94. package/skills/release/scripts/release-context.sh +129 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Maintenance - Database cleanup operations for QMD.
3
+ *
4
+ * Wraps low-level store operations that the CLI needs for housekeeping.
5
+ * Takes an internal Store in the constructor — allowed to access DB directly.
6
+ */
7
+ import type { Store } from "./store.js";
8
+ import { type CleanupStats } from "./store.js";
9
+ export declare class Maintenance {
10
+ private store;
11
+ constructor(store: Store);
12
+ /** Run VACUUM on the SQLite database to reclaim space */
13
+ vacuum(): void;
14
+ /** Remove content rows that are no longer referenced by any document */
15
+ cleanupOrphanedContent(): number;
16
+ /** Remove vector embeddings for content that no longer exists */
17
+ cleanupOrphanedVectors(): number;
18
+ /** Clear the LLM response cache (query expansion, reranking) */
19
+ clearLLMCache(): number;
20
+ /** Delete documents marked as inactive (removed from filesystem) */
21
+ deleteInactiveDocs(): number;
22
+ /** Clear all vector embeddings (forces re-embedding) */
23
+ clearEmbeddings(): void;
24
+ /** Compact FTS5 so deleted rows leave documents_fts_data (#550). */
25
+ optimizeFts(): void;
26
+ /** Preview what {@link run} would remove, without writing. */
27
+ preview(): CleanupStats;
28
+ /**
29
+ * Full cleanup: cache, orphaned vectors, inactive docs, orphaned content,
30
+ * FTS optimize, vacuum. Same sequence as `qmd cleanup`.
31
+ */
32
+ run(): CleanupStats;
33
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Maintenance - Database cleanup operations for QMD.
3
+ *
4
+ * Wraps low-level store operations that the CLI needs for housekeeping.
5
+ * Takes an internal Store in the constructor — allowed to access DB directly.
6
+ */
7
+ import { vacuumDatabase, cleanupOrphanedContent, cleanupOrphanedVectors, deleteLLMCache, deleteInactiveDocuments, clearAllEmbeddings, optimizeDocumentsFts, previewCleanup, runCleanup, } from "./store.js";
8
+ export class Maintenance {
9
+ store;
10
+ constructor(store) {
11
+ this.store = store;
12
+ }
13
+ /** Run VACUUM on the SQLite database to reclaim space */
14
+ vacuum() {
15
+ vacuumDatabase(this.store.db);
16
+ }
17
+ /** Remove content rows that are no longer referenced by any document */
18
+ cleanupOrphanedContent() {
19
+ return cleanupOrphanedContent(this.store.db);
20
+ }
21
+ /** Remove vector embeddings for content that no longer exists */
22
+ cleanupOrphanedVectors() {
23
+ return cleanupOrphanedVectors(this.store.db);
24
+ }
25
+ /** Clear the LLM response cache (query expansion, reranking) */
26
+ clearLLMCache() {
27
+ return deleteLLMCache(this.store.db);
28
+ }
29
+ /** Delete documents marked as inactive (removed from filesystem) */
30
+ deleteInactiveDocs() {
31
+ return deleteInactiveDocuments(this.store.db);
32
+ }
33
+ /** Clear all vector embeddings (forces re-embedding) */
34
+ clearEmbeddings() {
35
+ clearAllEmbeddings(this.store.db);
36
+ }
37
+ /** Compact FTS5 so deleted rows leave documents_fts_data (#550). */
38
+ optimizeFts() {
39
+ optimizeDocumentsFts(this.store.db);
40
+ }
41
+ /** Preview what {@link run} would remove, without writing. */
42
+ preview() {
43
+ return previewCleanup(this.store.db);
44
+ }
45
+ /**
46
+ * Full cleanup: cache, orphaned vectors, inactive docs, orphaned content,
47
+ * FTS optimize, vacuum. Same sequence as `qmd cleanup`.
48
+ */
49
+ run() {
50
+ return runCleanup(this.store.db);
51
+ }
52
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * origin-guard.ts — DNS-rebinding protection for the HTTP MCP transport.
3
+ *
4
+ * Binding to localhost keeps *remote* clients out, but it does not keep a web
5
+ * page out. A page served from `attacker.example` can re-point that hostname at
6
+ * `127.0.0.1` after load (DNS rebinding); the browser then treats
7
+ * `http://attacker.example:8181` as same-origin with the page and hands the
8
+ * response body to attacker JavaScript. The only server-side signal that
9
+ * distinguishes such a request from a legitimate local client is the `Origin`
10
+ * and `Host` headers, so the MCP spec requires local HTTP servers to validate
11
+ * them.
12
+ *
13
+ * The predicates here are pure so they can be unit-tested without a socket;
14
+ * `startMcpHttpServer` applies them to every request before routing.
15
+ */
16
+ /**
17
+ * Hostnames that resolve to this machine's loopback interface.
18
+ *
19
+ * `0.0.0.0` is deliberately excluded: browsers happily route it to loopback on
20
+ * Linux and macOS, which makes it a rebinding-free path to local servers, so an
21
+ * `Origin: http://0.0.0.0:8181` is treated as untrusted like any other.
22
+ */
23
+ export declare function isLoopbackHostname(hostname: string): boolean;
24
+ export type OriginGuard = {
25
+ /** All checks disabled (`QMD_ALLOWED_ORIGINS=*`). */
26
+ disabled: boolean;
27
+ /** Extra origins accepted beyond the loopback defaults, normalized. */
28
+ allowedOrigins: string[];
29
+ /** Extra `Host` values accepted beyond the loopback defaults, lowercased. */
30
+ allowedHosts: string[];
31
+ /** Whether the `Host` header is checked at all — see `resolveOriginGuard`. */
32
+ enforceHost: boolean;
33
+ };
34
+ /**
35
+ * Build the guard for a server bound to `host`.
36
+ *
37
+ * `Host` validation is enforced whenever the bind address names a concrete
38
+ * interface, since the legitimate `Host` header is then known (loopback, or the
39
+ * bind address itself). For a wildcard bind — `--host 0.0.0.0`, e.g. Docker —
40
+ * any of the container's names may legitimately appear, so the check is only
41
+ * enforced when the operator supplies an explicit allowlist. `Origin`
42
+ * validation always applies; browsers are the threat, and they always send it.
43
+ */
44
+ export declare function resolveOriginGuard(options: {
45
+ host: string;
46
+ allowedOrigins?: string[];
47
+ allowedHosts?: string[];
48
+ env?: NodeJS.ProcessEnv;
49
+ }): OriginGuard;
50
+ export type GuardVerdict = {
51
+ ok: true;
52
+ } | {
53
+ ok: false;
54
+ reason: string;
55
+ };
56
+ /**
57
+ * Validate a request's `Origin` and `Host` headers against the guard.
58
+ *
59
+ * A missing `Origin` is allowed: non-browser clients (curl, the MCP SDK's HTTP
60
+ * client, editors) omit it, and browsers cannot. The header is the signal that
61
+ * a request came from page JavaScript, so its *absence* is not suspicious while
62
+ * a foreign *value* is conclusive.
63
+ */
64
+ export declare function checkRequestOrigin(headers: {
65
+ origin?: string | undefined;
66
+ host?: string | undefined;
67
+ }, guard: OriginGuard): GuardVerdict;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * origin-guard.ts — DNS-rebinding protection for the HTTP MCP transport.
3
+ *
4
+ * Binding to localhost keeps *remote* clients out, but it does not keep a web
5
+ * page out. A page served from `attacker.example` can re-point that hostname at
6
+ * `127.0.0.1` after load (DNS rebinding); the browser then treats
7
+ * `http://attacker.example:8181` as same-origin with the page and hands the
8
+ * response body to attacker JavaScript. The only server-side signal that
9
+ * distinguishes such a request from a legitimate local client is the `Origin`
10
+ * and `Host` headers, so the MCP spec requires local HTTP servers to validate
11
+ * them.
12
+ *
13
+ * The predicates here are pure so they can be unit-tested without a socket;
14
+ * `startMcpHttpServer` applies them to every request before routing.
15
+ */
16
+ /** Wildcard bind addresses — the request's legitimate `Host` is unknowable. */
17
+ const WILDCARD_BIND_HOSTS = new Set(["", "0.0.0.0", "::", "[::]", "*"]);
18
+ /**
19
+ * Hostnames that resolve to this machine's loopback interface.
20
+ *
21
+ * `0.0.0.0` is deliberately excluded: browsers happily route it to loopback on
22
+ * Linux and macOS, which makes it a rebinding-free path to local servers, so an
23
+ * `Origin: http://0.0.0.0:8181` is treated as untrusted like any other.
24
+ */
25
+ export function isLoopbackHostname(hostname) {
26
+ const h = hostname.trim().toLowerCase().replace(/^\[|\]$/g, "");
27
+ if (h === "localhost" || h.endsWith(".localhost"))
28
+ return true;
29
+ if (h === "::1" || h === "0:0:0:0:0:0:0:1")
30
+ return true;
31
+ // IPv4-mapped IPv6 (::ffff:127.0.0.1) and the whole 127.0.0.0/8 range.
32
+ const v4 = h.startsWith("::ffff:") ? h.slice(7) : h;
33
+ return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v4);
34
+ }
35
+ /** Parse an `Origin` header into its hostname, or undefined if unusable. */
36
+ function originHostname(origin) {
37
+ try {
38
+ const url = new URL(origin.trim());
39
+ if (url.protocol !== "http:" && url.protocol !== "https:")
40
+ return undefined;
41
+ return url.hostname;
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
46
+ }
47
+ /** Normalize an origin for comparison against the allowlist. */
48
+ function normalizeOrigin(origin) {
49
+ try {
50
+ return new URL(origin.trim()).origin.toLowerCase();
51
+ }
52
+ catch {
53
+ return undefined;
54
+ }
55
+ }
56
+ /** Parse a `Host` header (`name`, `name:port`, `[::1]:port`) into a hostname. */
57
+ function hostHeaderHostname(host) {
58
+ try {
59
+ return new URL(`http://${host.trim()}`).hostname;
60
+ }
61
+ catch {
62
+ return undefined;
63
+ }
64
+ }
65
+ function splitList(value) {
66
+ if (!value)
67
+ return [];
68
+ return value.split(",").map(v => v.trim()).filter(v => v.length > 0);
69
+ }
70
+ /**
71
+ * Build the guard for a server bound to `host`.
72
+ *
73
+ * `Host` validation is enforced whenever the bind address names a concrete
74
+ * interface, since the legitimate `Host` header is then known (loopback, or the
75
+ * bind address itself). For a wildcard bind — `--host 0.0.0.0`, e.g. Docker —
76
+ * any of the container's names may legitimately appear, so the check is only
77
+ * enforced when the operator supplies an explicit allowlist. `Origin`
78
+ * validation always applies; browsers are the threat, and they always send it.
79
+ */
80
+ export function resolveOriginGuard(options) {
81
+ const env = options.env ?? process.env;
82
+ const rawOrigins = options.allowedOrigins ?? splitList(env.QMD_ALLOWED_ORIGINS);
83
+ const rawHosts = options.allowedHosts ?? splitList(env.QMD_ALLOWED_HOSTS);
84
+ if (rawOrigins.includes("*")) {
85
+ return { disabled: true, allowedOrigins: [], allowedHosts: [], enforceHost: false };
86
+ }
87
+ const allowedOrigins = rawOrigins
88
+ .map(o => normalizeOrigin(o))
89
+ .filter((o) => o !== undefined);
90
+ const allowedHosts = rawHosts.map(h => h.toLowerCase());
91
+ const bindHost = options.host.trim().toLowerCase();
92
+ const isWildcardBind = WILDCARD_BIND_HOSTS.has(bindHost);
93
+ if (!isWildcardBind && !isLoopbackHostname(bindHost)) {
94
+ // Explicit non-loopback interface: its own address is a legitimate Host.
95
+ allowedHosts.push(bindHost);
96
+ }
97
+ return {
98
+ disabled: false,
99
+ allowedOrigins,
100
+ allowedHosts,
101
+ enforceHost: !isWildcardBind || allowedHosts.length > 0,
102
+ };
103
+ }
104
+ /**
105
+ * Validate a request's `Origin` and `Host` headers against the guard.
106
+ *
107
+ * A missing `Origin` is allowed: non-browser clients (curl, the MCP SDK's HTTP
108
+ * client, editors) omit it, and browsers cannot. The header is the signal that
109
+ * a request came from page JavaScript, so its *absence* is not suspicious while
110
+ * a foreign *value* is conclusive.
111
+ */
112
+ export function checkRequestOrigin(headers, guard) {
113
+ if (guard.disabled)
114
+ return { ok: true };
115
+ const origin = headers.origin?.trim();
116
+ if (origin) {
117
+ const normalized = normalizeOrigin(origin);
118
+ const hostname = originHostname(origin);
119
+ const allowed = (hostname !== undefined && isLoopbackHostname(hostname)) ||
120
+ (normalized !== undefined && guard.allowedOrigins.includes(normalized));
121
+ if (!allowed) {
122
+ return { ok: false, reason: `Origin not allowed: ${origin}` };
123
+ }
124
+ }
125
+ const host = headers.host?.trim();
126
+ if (guard.enforceHost && host) {
127
+ const lowered = host.toLowerCase();
128
+ const hostname = hostHeaderHostname(host);
129
+ const allowed = (hostname !== undefined && isLoopbackHostname(hostname)) ||
130
+ guard.allowedHosts.includes(lowered) ||
131
+ (hostname !== undefined && guard.allowedHosts.includes(hostname.toLowerCase()));
132
+ if (!allowed) {
133
+ return { ok: false, reason: `Host not allowed: ${host}` };
134
+ }
135
+ }
136
+ return { ok: true };
137
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * QMD MCP Server - Model Context Protocol server for QMD
3
+ *
4
+ * Exposes QMD search and document retrieval as MCP tools and resources.
5
+ * Documents are accessible via qmd:// URIs.
6
+ *
7
+ * Speaks MCP spec 2026-07-28 (stateless, no initialize handshake) and dual-speaks
8
+ * 2025-era clients via the official SDK entries (`serveStdio` / `createMcpHandler`).
9
+ */
10
+ export type McpStartupOptions = {
11
+ dbPath?: string;
12
+ };
13
+ /**
14
+ * Counts running request handlers so shutdown can wait for them to settle
15
+ * before tearing down their llm/store dependencies. The SDK aborts in-flight
16
+ * request controllers on close, but qmd's handlers finish their current
17
+ * store/llm work rather than observing the signal mid-operation.
18
+ */
19
+ export type InflightGate = {
20
+ /** Wraps a handler so the gate counts it while it runs. */
21
+ track<T extends (...args: never[]) => unknown>(fn: T): T;
22
+ /** Resolves once no tracked handler runs, or after timeoutMs. Returns whether idle was reached. */
23
+ waitForIdle(timeoutMs: number): Promise<boolean>;
24
+ };
25
+ export declare function createInflightGate(): InflightGate;
26
+ /** Minimal stdin surface consumed by registerStdioEofShutdown, injectable for tests. */
27
+ export type StdioShutdownStdin = {
28
+ once(event: "end" | "close", listener: () => void): unknown;
29
+ off(event: "end" | "close", listener: () => void): unknown;
30
+ readableEnded?: boolean;
31
+ destroyed?: boolean;
32
+ };
33
+ export type StdioShutdownOptions = {
34
+ /** Closes the MCP server and its transport. */
35
+ closeServer: () => Promise<void>;
36
+ /** Closes the SQLite store (owns disposing the per-store llama.cpp instance). */
37
+ closeStore: () => void | Promise<void>;
38
+ /**
39
+ * Optional extra llama.cpp teardown, run before closeStore. The MCP store
40
+ * disposes its own per-store LlamaCpp inside closeStore, so this is left
41
+ * unset there; it exists for callers that own a separate instance. If
42
+ * omitted, the step is skipped (do NOT default it to the global
43
+ * disposeDefaultLlamaCpp — that would tear down an unrelated instance in an
44
+ * embedded process).
45
+ */
46
+ disposeLlm?: () => Promise<void>;
47
+ /** Waits for in-flight handlers to settle (see InflightGate.waitForIdle). */
48
+ waitForIdle?: (timeoutMs: number) => Promise<boolean>;
49
+ /** Deadline for the in-flight wait. Defaults to 5000 ms. */
50
+ idleTimeoutMs?: number;
51
+ /** Defaults to process.stdin. */
52
+ stdin?: StdioShutdownStdin;
53
+ /** Defaults to assigning process.exitCode. */
54
+ setExitCode?: (code: number) => void;
55
+ /** Defaults to reading process.exitCode. */
56
+ getExitCode?: () => number | undefined;
57
+ /** Defaults to process.stderr. */
58
+ stderr?: {
59
+ write(chunk: string): unknown;
60
+ on?(event: "error", listener: (err: unknown) => void): unknown;
61
+ };
62
+ };
63
+ /**
64
+ * Shut the stdio MCP server down when stdin reaches EOF (#751).
65
+ *
66
+ * The SDK's StdioServerTransport subscribes to stdin "data"/"error" only and
67
+ * never notices "end"/"close". When the parent MCP client dies, nothing tears
68
+ * the process down: the warm llama.cpp model's native handles keep the event
69
+ * loop alive, so the server reparents to PID 1, leaks RAM, and keeps the
70
+ * SQLite index open. stdin EOF means the client is gone, so this treats it as
71
+ * a disconnect: no new requests are accepted and nobody is left to read a
72
+ * response — but handlers that are already running get a bounded window to
73
+ * settle (waitForIdle) before their llm/store dependencies are torn down.
74
+ *
75
+ * Teardown order matters. Close the transport first so no further requests
76
+ * are dispatched, wait for in-flight handlers, then close the store last —
77
+ * which disposes the store's own llama.cpp instance and then the database, so
78
+ * the dispose path cannot hit an already-closed DB. (disposeLlm is an optional
79
+ * extra step for callers that own a separate instance; the MCP store does
80
+ * not.) Failures are logged best-effort (the parent's death may have closed
81
+ * stderr too) and do not stop the remaining steps. The function sets process.exitCode
82
+ * instead of calling process.exit() so `beforeExit` still fires and
83
+ * node-llama-cpp's auto-dispose runs before libc's static destructors —
84
+ * process.exit() during native-addon unload has caused exit-time crashes
85
+ * before (#59, #129; same rationale as finishSuccessfulCliCommand in the CLI).
86
+ *
87
+ * Returns the idempotent shutdown function: every invocation (manual, "end",
88
+ * "close", or already-ended stdin) shares one promise, and the promise never
89
+ * rejects.
90
+ */
91
+ export declare function registerStdioEofShutdown(options: StdioShutdownOptions): () => Promise<void>;
92
+ export declare function startMcpServer(options?: McpStartupOptions): Promise<void>;
93
+ export type HttpServerHandle = {
94
+ httpServer: import("http").Server;
95
+ port: number;
96
+ stop: () => Promise<void>;
97
+ };
98
+ /**
99
+ * Start MCP server over Streamable HTTP (JSON responses by default).
100
+ * Binds to `options.host` (default "localhost", overridable via the QMD_HOST
101
+ * env var) — set "0.0.0.0" to accept connections from other hosts, e.g. a
102
+ * container liveness probe. Returns a handle for shutdown and port discovery.
103
+ *
104
+ * HTTP is sessionless (MCP 2026-07-28): there is no `Mcp-Session-Id`, no
105
+ * initialize handshake, and no idle-session TTL. 2025-era clients are still
106
+ * served per-request via the SDK's stateless legacy fallback (initialize
107
+ * works as a standalone call; subsequent 2025 methods need a modern envelope
108
+ * or a stdio connection). The previous session reaper (#816) is gone because
109
+ * there are no sessions to reap.
110
+ */
111
+ export declare function startMcpHttpServer(port: number, options?: ({
112
+ quiet?: boolean;
113
+ host?: string;
114
+ allowedOrigins?: string[];
115
+ allowedHosts?: string[];
116
+ } & McpStartupOptions)): Promise<HttpServerHandle>;