screenpipe/screenpipe · warning

404 not found

Error message

404 not found

What it means

The ACP screenpipe-tools MCP server only accepts requests whose URL starts with /mcp (plus /health). Anything else gets a bare HTTP 404 with an empty body. This is a path/router mismatch, not an MCP protocol error — the request never reached the MCP handler.

Source

Thrown at crates/screenpipe-core/assets/acp/screenpipe-tools.mjs:1384

}

// Stateless Streamable-HTTP: each POST /mcp carries one JSON-RPC request (or a
// batch) and gets a single JSON response. None of these tools stream, so no SSE
// channel is opened. Bound to loopback with an Origin check per the MCP spec's
// DNS-rebinding guidance; no session id (stateless), which every ACP harness we
// target tolerates.
const LOOPBACK_ORIGIN = /^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i;

function startHttpServer(port) {
  const server = createServer((req, res) => {
    const url = req.url || "/";
    if (req.method === "GET" && url.startsWith("/health")) {
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(JSON.stringify({ ok: true, server: SERVER_INFO }));
      return;
    }
    if (!url.startsWith("/mcp")) {
      res.writeHead(404).end();
      return;
    }
    const origin = req.headers["origin"];
    if (origin && !LOOPBACK_ORIGIN.test(origin)) {
      res.writeHead(403).end();
      return;
    }
    if (req.method !== "POST") {
      res.writeHead(405, { Allow: "POST" }).end();
      return;
    }
    let body = "";
    req.setEncoding("utf-8");
    req.on("data", (chunk) => {
      body += chunk;
      if (body.length > 4_000_000) req.destroy();
    });
    req.on("end", async () => {

View on GitHub (pinned to 4ebf712990)

Solutions

  1. Point the MCP client at the exact path /mcp on the server port
  2. Verify with GET /health first — it returns 200 {ok:true,server:SERVER_INFO} to confirm you reached the right server
  3. Remove any path prefixes added by reverse proxies or client config
  4. Check SERVER_INFO/health output to confirm the expected endpoint layout

Example fix

// before
const server = new MCPClient({ url: 'http://127.0.0.1:9000/api/mcp' });
// after
const server = new MCPClient({ url: 'http://127.0.0.1:9000/mcp' });
Defensive patterns

Strategy: validation

Validate before calling

function assertMcpUrl(u) {
  const { pathname } = new URL(u);
  if (pathname !== '/mcp') throw new Error(`MCP server expects path /mcp, got ${pathname}`);
  return u;
}
// preflight
await fetch(new URL('/health', base)).then(r => r.json()); // must return {ok:true,...}

Type guard

function isMcpBase(u) {
  try { return new URL(u).pathname === '/mcp'; } catch { return false; }
}

Try / catch

const res = await fetch(mcpUrl, init);
if (res.status === 404) {
  throw new Error(`MCP endpoint 404 — use /mcp (health check: GET /health)`);
}

Prevention

When it happens

Trigger: POSTing to a path like / or /tools or /api/mcp; misconfigured MCP client baseUrl that includes/excludes a path prefix incorrectly; requesting /mcp/ with tools that build URLs differently; hitting the wrong port where another route layout is expected.

Common situations: MCP client configured with server URL http://127.0.0.1:PORT/mcp/ extra-slash variants or a legacy /jsonrpc path; dev proxy stripping or adding prefixes; client pointed at /health by mistake.

Related errors


AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01). Data as JSON: /api/errors/4b1b03a563a3562a. Report an issue: GitHub.