mcp-proxy 6.5.1 → 6.5.2

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.
package/jsr.json CHANGED
@@ -3,5 +3,5 @@
3
3
  "include": ["src/index.ts", "src/bin/mcp-proxy.ts"],
4
4
  "license": "MIT",
5
5
  "name": "@punkpeye/mcp-proxy",
6
- "version": "6.5.1"
6
+ "version": "6.5.2"
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-proxy",
3
- "version": "6.5.1",
3
+ "version": "6.5.2",
4
4
  "main": "dist/index.mjs",
5
5
  "scripts": {
6
6
  "build": "tsdown",
@@ -667,6 +667,36 @@ it("does not require auth for /ping endpoint", async () => {
667
667
  await httpServer.close();
668
668
  });
669
669
 
670
+ it("responds with 400 to a malformed request target instead of crashing", async () => {
671
+ const port = await getRandomPort();
672
+
673
+ const httpServer = await startHTTPServer({
674
+ createServer: async () => {
675
+ return new Server({ name: "test", version: "1.0.0" }, { capabilities: {} });
676
+ },
677
+ port,
678
+ });
679
+
680
+ // `//` is not a valid URL target; sent via http.request so it isn't
681
+ // normalized away. Before the fix this threw inside the request listener
682
+ // and crashed the process.
683
+ const statusCode = await new Promise<number>((resolve, reject) => {
684
+ const request = http.request(
685
+ { host: "localhost", path: "//", port },
686
+ (res) => {
687
+ res.resume();
688
+ resolve(res.statusCode ?? 0);
689
+ },
690
+ );
691
+ request.on("error", reject);
692
+ request.end();
693
+ });
694
+
695
+ expect(statusCode).toBe(400);
696
+
697
+ await httpServer.close();
698
+ });
699
+
670
700
  it("does not require auth for OPTIONS requests", async () => {
671
701
  const port = await getRandomPort();
672
702
  const apiKey = "test-api-key-999";
@@ -951,7 +951,15 @@ export const startHTTPServer = async <T extends ServerLike>({
951
951
  // and would otherwise short-circuit the MCP protocol handlers.
952
952
  // Use a fixed base because `host` may be "::" (IPv6 any), which is not a
953
953
  // valid URL authority. We only need pathname here.
954
- const requestUrl = new URL(req.url || "", "http://localhost");
954
+ // A malformed request target (e.g. "//") makes `new URL` throw, which
955
+ // would crash the process from this listener, so reject it with 400.
956
+ let requestUrl: URL;
957
+ try {
958
+ requestUrl = new URL(req.url || "", "http://localhost");
959
+ } catch {
960
+ res.writeHead(400).end("Bad Request");
961
+ return;
962
+ }
955
963
  const isMcpEndpoint =
956
964
  (sseEndpoint && requestUrl.pathname === sseEndpoint) ||
957
965
  (streamEndpoint && requestUrl.pathname === streamEndpoint);