Skip to content

Commit fe37fb4

Browse files
feat: support custom host path (#167)
* support custom host configuration * formatting addressed * update test * format
1 parent e9c91c4 commit fe37fb4

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

src/FastMCP.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,7 @@ test("closing event source does not produce error", async () => {
19991999

20002000
await server.start({
20012001
httpStream: {
2002+
host: "127.0.0.1",
20022003
port,
20032004
},
20042005
transportType: "httpStream",
@@ -3235,3 +3236,28 @@ test("stateless mode health check includes mode indicator", async () => {
32353236
await server.stop();
32363237
}
32373238
});
3239+
3240+
test("host configuration works with 0.0.0.0", async () => {
3241+
const port = await getRandomPort();
3242+
3243+
const server = new FastMCP({
3244+
name: "Test server",
3245+
version: "1.0.0",
3246+
});
3247+
3248+
await server.start({
3249+
httpStream: {
3250+
host: "0.0.0.0",
3251+
port,
3252+
},
3253+
transportType: "httpStream",
3254+
});
3255+
3256+
try {
3257+
const healthResponse = await fetch(`http://0.0.0.0:${port}/health`);
3258+
expect(healthResponse.status).toBe(200);
3259+
expect(await healthResponse.text()).toBe("✓ Ok");
3260+
} finally {
3261+
await server.stop();
3262+
}
3263+
});

src/FastMCP.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,6 +2036,7 @@ export class FastMCP<
20362036
enableJsonResponse?: boolean;
20372037
endpoint?: `/${string}`;
20382038
eventStore?: EventStore;
2039+
host?: string;
20392040
port: number;
20402041
stateless?: boolean;
20412042
};
@@ -2094,7 +2095,7 @@ export class FastMCP<
20942095
if (httpConfig.stateless) {
20952096
// Stateless mode - create new server instance for each request
20962097
this.#logger.info(
2097-
`[FastMCP info] Starting server in stateless mode on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,
2098+
`[FastMCP info] Starting server in stateless mode on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`,
20982099
);
20992100

21002101
this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({
@@ -2111,6 +2112,7 @@ export class FastMCP<
21112112
},
21122113
enableJsonResponse: httpConfig.enableJsonResponse,
21132114
eventStore: httpConfig.eventStore,
2115+
host: httpConfig.host,
21142116
// In stateless mode, we don't track sessions
21152117
onClose: async () => {
21162118
// No session tracking in stateless mode
@@ -2122,7 +2124,7 @@ export class FastMCP<
21222124
);
21232125
},
21242126
onUnhandledRequest: async (req, res) => {
2125-
await this.#handleUnhandledRequest(req, res, true);
2127+
await this.#handleUnhandledRequest(req, res, true, httpConfig.host);
21262128
},
21272129
port: httpConfig.port,
21282130
stateless: true,
@@ -2142,6 +2144,7 @@ export class FastMCP<
21422144
},
21432145
enableJsonResponse: httpConfig.enableJsonResponse,
21442146
eventStore: httpConfig.eventStore,
2147+
host: httpConfig.host,
21452148
onClose: async (session) => {
21462149
this.emit("disconnect", {
21472150
session: session as FastMCPSession<FastMCPSessionAuth>,
@@ -2158,14 +2161,19 @@ export class FastMCP<
21582161
},
21592162

21602163
onUnhandledRequest: async (req, res) => {
2161-
await this.#handleUnhandledRequest(req, res, false);
2164+
await this.#handleUnhandledRequest(
2165+
req,
2166+
res,
2167+
false,
2168+
httpConfig.host,
2169+
);
21622170
},
21632171
port: httpConfig.port,
21642172
streamEndpoint: httpConfig.endpoint,
21652173
});
21662174

21672175
this.#logger.info(
2168-
`[FastMCP info] server is running on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,
2176+
`[FastMCP info] server is running on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`,
21692177
);
21702178
this.#logger.info(
21712179
`[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`,
@@ -2218,6 +2226,7 @@ export class FastMCP<
22182226
req: http.IncomingMessage,
22192227
res: http.ServerResponse,
22202228
isStateless = false,
2229+
host: string,
22212230
) => {
22222231
const healthConfig = this.#options.health ?? {};
22232232

@@ -2226,7 +2235,7 @@ export class FastMCP<
22262235

22272236
if (enabled) {
22282237
const path = healthConfig.path ?? "/health";
2229-
const url = new URL(req.url || "", "http://localhost");
2238+
const url = new URL(req.url || "", `http://${host}`);
22302239

22312240
try {
22322241
if (req.method === "GET" && url.pathname === path) {
@@ -2290,7 +2299,7 @@ export class FastMCP<
22902299
// Handle OAuth well-known endpoints
22912300
const oauthConfig = this.#options.oauth;
22922301
if (oauthConfig?.enabled && req.method === "GET") {
2293-
const url = new URL(req.url || "", "http://localhost");
2302+
const url = new URL(req.url || "", `http://${host}`);
22942303

22952304
if (
22962305
url.pathname === "/.well-known/oauth-authorization-server" &&
@@ -2331,6 +2340,7 @@ export class FastMCP<
23312340
httpStream: {
23322341
enableJsonResponse?: boolean;
23332342
endpoint?: `/${string}`;
2343+
host?: string;
23342344
port: number;
23352345
stateless?: boolean;
23362346
};
@@ -2342,6 +2352,7 @@ export class FastMCP<
23422352
enableJsonResponse?: boolean;
23432353
endpoint: `/${string}`;
23442354
eventStore?: EventStore;
2355+
host: string;
23452356
port: number;
23462357
stateless?: boolean;
23472358
};
@@ -2361,12 +2372,13 @@ export class FastMCP<
23612372
const portArg = getArg("port");
23622373
const endpointArg = getArg("endpoint");
23632374
const statelessArg = getArg("stateless");
2375+
const hostArg = getArg("host");
23642376

23652377
const envTransport = process.env.FASTMCP_TRANSPORT;
23662378
const envPort = process.env.FASTMCP_PORT;
23672379
const envEndpoint = process.env.FASTMCP_ENDPOINT;
23682380
const envStateless = process.env.FASTMCP_STATELESS;
2369-
2381+
const envHost = process.env.FASTMCP_HOST;
23702382
// Overrides > CLI > env > defaults
23712383
const transportType =
23722384
overrides?.transportType ||
@@ -2378,6 +2390,8 @@ export class FastMCP<
23782390
const port = parseInt(
23792391
overrides?.httpStream?.port?.toString() || portArg || envPort || "8080",
23802392
);
2393+
const host =
2394+
overrides?.httpStream?.host || hostArg || envHost || "localhost";
23812395
const endpoint =
23822396
overrides?.httpStream?.endpoint || endpointArg || envEndpoint || "/mcp";
23832397
const enableJsonResponse =
@@ -2392,6 +2406,7 @@ export class FastMCP<
23922406
httpStream: {
23932407
enableJsonResponse,
23942408
endpoint: endpoint as `/${string}`,
2409+
host,
23952410
port,
23962411
stateless,
23972412
},

0 commit comments

Comments
 (0)