Skip to content

normalizeFilename uses platform-dependent path.resolve, so Edge Function file names are wrong on Windows (5 tests fail on main) #392

Description

@Rjabov
  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

normalizeFilename in packages/mcp-server-supabase/src/edge-function.ts imports resolve from node:path, which is platform-dispatched, but strips a hardcoded POSIX prefix. On Windows resolve returns a backslash-separated path, so neither prefix strip can ever match and the full absolute path is returned instead of the file name.

For a developer running the MCP server locally on Windows, get_edge_function and list_edge_functions report entrypoint_path and files[].name as C:\tmp\user_fn_<deployment>\index.ts rather than index.ts.

This is confined to locally-run servers - the hosted server runs on Linux, where resolve is already POSIX, so hosted users are unaffected. It is also invisible to CI, which is Linux-only.

To Reproduce

Clone main on Windows and run the unit suite. No changes needed:

git clone https://github.com/supabase/mcp.git
cd mcp
pnpm install
pnpm run build
cd packages/mcp-server-supabase
set CI=true && pnpm vitest run --project unit

5 tests across 2 files fail on untouched main (30baa1f):

FAIL  src/edge-function.test.ts > normalizeFilename > handles deno 1 paths
  Expected: "index.ts"
  Received: "C:\tmp\user_fn_xnzcmvwhvqonuunmwgdz_2b72daae-...-46f2df0463d1_2\source\index.ts"

FAIL  src/edge-function.test.ts > normalizeFilename > handles deno 2 paths
FAIL  src/edge-function.test.ts > normalizeFilename > doesn't interfere with nested directories
  Expected: "/my/local/source/index.ts"
  Received: "C:\my\local\source\index.ts"

FAIL  src/server.test.ts > tools > list edge functions
FAIL  src/server.test.ts > tools > get edge function
-   "entrypoint_path": "index.ts",
+   "entrypoint_path": "C:\\tmp\\user_fn_wnibtrpkkvmuyxpollho_74bb898d-...-4f777d13e75a_1\\index.ts",
-       "name": "index.ts",
+       "name": "C:\\tmp\\user_fn_fdkdaergfyvyekhgnrct_3a12780f-...-a6e57ae4a7f1_1\\index.ts",

Test Files  2 failed | 12 passed (14)
     Tests  5 failed | 210 passed (215)

The last two are the tool output itself, so this is not only a test-harness artifact - it is what an MCP client on Windows actually receives.

Root cause

packages/mcp-server-supabase/src/edge-function.ts:

import { resolve } from 'node:path';   // platform-dispatched

export function getPathPrefix(deploymentId: string) {
  return `/tmp/user_fn_${deploymentId}/`;   // always POSIX
}

const filenameAbsolute = resolve(pathPrefix, filename);
let filenameWithoutPrefix = filenameAbsolute;
filenameWithoutPrefix = withoutPrefix(filenameWithoutPrefix, pathPrefix);
filenameWithoutPrefix = withoutPrefix(filenameWithoutPrefix, 'source/');

pathPrefix is always POSIX - it describes a path inside the Deno sandbox on the server, not on the developer's machine - but resolve follows the host OS. On Windows it returns C:\tmp\user_fn_...\source\index.ts, so startsWith(pathPrefix) is false for both /tmp/user_fn_.../ and source/, both strips are no-ops, and the whole absolute path falls through.

The intent is unambiguous elsewhere in the codebase: every caller in platform/api-platform.ts already forces POSIX semantics with fileURLToPath(..., { windows: false }) before calling in. That one platform-dependent import undoes it.

Expected behavior

normalizeFilename should return index.ts, and leave genuinely nested paths alone, regardless of host OS.

Suggested fix

One line - import the POSIX variant, since every path this function touches is POSIX by construction:

-import { resolve } from 'node:path';
+import { resolve } from 'node:path/posix';

Verified on Windows against main at 30baa1f:

result
untouched main 5 failed | 210 passed (215)
same tree, one-line change 215 passed (215)

All five failures clear, including the two in server.test.ts, and nothing else changes.

System information

  • OS: Windows 11 (10.0.26200)
  • Node.js 22 LTS, pnpm 10.34.5
  • supabase/mcp at main, commit 30baa1f

Additional context

This looks like a regression of a bug that was already fixed once. 8e9a447 ("fix: edge function path parsing on windows", May 2025) added { windows: false } to the fileURLToPath calls in api-platform.ts - those are still there, and are what I'm referring to above when I say the callers already force POSIX. normalizeFilename was added later in #138 ("consistent edge function filenames for deno 1 & 2", Sept 2025) and reintroduced the same class of bug at a new call site downstream of them.

That's really an argument for a regression test rather than just the one-line change: the current tests only pass POSIX strings, so they succeed on Linux whichever import is used, and nothing in a Linux-only CI can catch this class of bug before it lands a third time.

Happy to open a PR with the one-line change plus a platform-independent test if that's useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions