From 3f4af6c0abdb5dc3a5921b64d71002bb5bee5bfd Mon Sep 17 00:00:00 2001 From: Kristian Wind Date: Mon, 17 Aug 2026 15:19:35 +0200 Subject: [PATCH] fix: stop the app shell answering for /.well-known/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding the connector to Claude failed with "Couldn't register with Verdande's sign-in service", on a server that has no sign-in service and needs none. Claude probes /.well-known/oauth-authorization-server before connecting to an MCP server. The SPA fallback answered 200 with a page of HTML — which reads as "yes, there is an authorization server here" — so it went on to dynamic client registration and failed there instead of concluding the obvious thing, which is that this server does not use OAuth and the key in the URL is the whole credential. /.well-known/ is reserved by RFC 8615 and is never a route in this app. A 404 is the true answer, and it is also the useful one: the client stops asking and uses the URL as given. This is the third time the catch-all has caused a confusing failure by saying 200 to something that does not exist — /mcp itself was the second. The fallback should hand back the shell for routes the app might have, not for every path on the server. Co-Authored-By: Claude Opus 5 --- internal/httpapi/integrations_test.go | 54 +++++++++++++++++++++++++++ internal/httpapi/server.go | 15 ++++++++ 2 files changed, 69 insertions(+) diff --git a/internal/httpapi/integrations_test.go b/internal/httpapi/integrations_test.go index 939b0eb..6547790 100644 --- a/internal/httpapi/integrations_test.go +++ b/internal/httpapi/integrations_test.go @@ -929,3 +929,57 @@ func TestMailAddressPrefersTheConfiguredSender(t *testing.T) { t.Error("an SMTP host is set, so configured should be true") } } + +// A 200 with the app shell is an answer that says "yes, that exists" to anything +// that asks. For /.well-known/ that is actively harmful: it is a reserved +// namespace, and a client probing it is asking a yes-or-no question. +// +// Claude asks /.well-known/oauth-authorization-server before connecting to an +// MCP server. It read the shell as "there is an authorization server here" and +// then failed trying to register with it, reporting a broken sign-in service on +// a server that has none and needs none. +func TestWellKnownDoesNotAnswerWithTheAppShell(t *testing.T) { + ts := newTestServer(t) + ts.bootstrap(t) + + for _, path := range []string{ + "/.well-known/oauth-authorization-server", + "/.well-known/oauth-protected-resource", + "/.well-known/openid-configuration", + "/.well-known/anything-at-all", + } { + resp, err := ts.client.Get(ts.URL + path) + if err != nil { + t.Fatal(err) + } + body, _ := io.ReadAll(resp.Body) + resp.Body.Close() + + if resp.StatusCode != http.StatusNotFound { + t.Errorf("%s: status %d, want 404", path, resp.StatusCode) + } + if strings.Contains(string(body), "