Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/cli/qmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2519,6 +2519,7 @@ function parseCLI() {
http: { type: "boolean" },
daemon: { type: "boolean" },
port: { type: "string" },
host: { type: "string" },
},
allowPositionals: true,
strict: false, // Allow unknown options to pass through
Expand Down Expand Up @@ -3216,6 +3217,7 @@ if (isMain) {

if (cli.values.http) {
const port = Number(cli.values.port) || 8181;
const host = (cli.values.host as string) || undefined;

if (cli.values.daemon) {
// Guard: check if already running
Expand All @@ -3234,9 +3236,10 @@ if (isMain) {
const logPath = resolve(cacheDir, "mcp.log");
const logFd = openSync(logPath, "w"); // truncate — fresh log per daemon run
const selfPath = fileURLToPath(import.meta.url);
const hostArgs = host ? ["--host", host] : [];
const spawnArgs = selfPath.endsWith(".ts")
? ["--import", pathJoin(dirname(selfPath), "..", "..", "node_modules", "tsx", "dist", "esm", "index.mjs"), selfPath, "mcp", "--http", "--port", String(port)]
: [selfPath, "mcp", "--http", "--port", String(port)];
? ["--import", pathJoin(dirname(selfPath), "..", "..", "node_modules", "tsx", "dist", "esm", "index.mjs"), selfPath, "mcp", "--http", "--port", String(port), ...hostArgs]
: [selfPath, "mcp", "--http", "--port", String(port), ...hostArgs];
const child = nodeSpawn(process.execPath, spawnArgs, {
stdio: ["ignore", logFd, logFd],
detached: true,
Expand All @@ -3256,7 +3259,7 @@ if (isMain) {
process.removeAllListeners("SIGINT");
const { startMcpHttpServer } = await import("../mcp/server.js");
try {
await startMcpHttpServer(port);
await startMcpHttpServer(port, { host });
} catch (e: any) {
if (e?.code === "EADDRINUSE") {
console.error(`Port ${port} already in use. Try a different port with --port.`);
Expand Down
1 change: 1 addition & 0 deletions src/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export function openDatabase(path: string): Database {
export interface Database {
exec(sql: string): void;
prepare(sql: string): Statement;
transaction<T extends (...args: any[]) => any>(fn: T): T;
loadExtension(path: string): void;
close(): void;
}
Expand Down
12 changes: 8 additions & 4 deletions src/mcp/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,9 +563,12 @@ export type HttpServerHandle = {

/**
* Start MCP server over Streamable HTTP (JSON responses, no SSE).
* Binds to localhost only. Returns a handle for shutdown and port discovery.
* Binds to the address specified by `host` (default: localhost).
* Set `host` to `"0.0.0.0"` to accept connections from other hosts
* (required for Kubernetes / container deployments).
* The `QMD_HOST` environment variable overrides the default.
*/
export async function startMcpHttpServer(port: number, options?: { quiet?: boolean }): Promise<HttpServerHandle> {
export async function startMcpHttpServer(port: number, options?: { quiet?: boolean; host?: string }): Promise<HttpServerHandle> {
const configPath = getConfigPath();
const store = await createStore({
dbPath: getDefaultDbPath(),
Expand Down Expand Up @@ -796,9 +799,10 @@ export async function startMcpHttpServer(port: number, options?: { quiet?: boole
}
});

const bindHost = options?.host ?? process.env.QMD_HOST ?? "localhost";
await new Promise<void>((resolve, reject) => {
httpServer.on("error", reject);
httpServer.listen(port, "localhost", () => resolve());
httpServer.listen(port, bindHost, () => resolve());
});

const actualPort = (httpServer.address() as import("net").AddressInfo).port;
Expand Down Expand Up @@ -826,7 +830,7 @@ export async function startMcpHttpServer(port: number, options?: { quiet?: boole
process.exit(0);
});

log(`QMD MCP server listening on http://localhost:${actualPort}/mcp`);
log(`QMD MCP server listening on http://${bindHost}:${actualPort}/mcp`);
return { httpServer, port: actualPort, stop };
}

Expand Down