]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/commitdiff
server: use status code 403 for disabled features (#24970)
authorXuan-Son Nguyen <redacted>
Thu, 25 Jun 2026 14:36:40 +0000 (16:36 +0200)
committerGitHub <redacted>
Thu, 25 Jun 2026 14:36:40 +0000 (16:36 +0200)
* server: use status code 403 for disabled features

* cont

* fix test case

tools/server/server.cpp
tools/server/tests/unit/test_proxy.py
tools/ui/src/lib/stores/tools.svelte.ts

index 680590871f6b2137536447d3f0483ab6eea8a240..0a1947faf5b77ffd23bde4de91befc5f6a0e3f16 100644 (file)
@@ -242,6 +242,19 @@ int llama_server(int argc, char ** argv) {
     // Google Cloud Platform (Vertex AI) compat
     ctx_http.register_gcp_compat();
 
+    // return 403 for disabled features
+    server_http_context::handler_t res_403 = [](const server_http_req &) {
+        auto res = std::make_unique<server_http_res>();
+        res->status = 403;
+        res->data = safe_json_to_str({
+            {"error", {
+                {"message", "this feature is disabled"},
+                {"type", "feature_disabled"},
+            }}
+        });
+        return res;
+    };
+
     // CORS proxy (EXPERIMENTAL, only used by the Web UI for MCP)
     if (params.ui_mcp_proxy) {
         SRV_WRN("%s", "-----------------\n");
@@ -250,7 +263,11 @@ int llama_server(int argc, char ** argv) {
         SRV_WRN("%s", "-----------------\n");
         ctx_http.get ("/cors-proxy",      ex_wrapper(proxy_handler_get));
         ctx_http.post("/cors-proxy",      ex_wrapper(proxy_handler_post));
+    } else {
+        ctx_http.get ("/cors-proxy",      ex_wrapper(res_403));
+        ctx_http.post("/cors-proxy",      ex_wrapper(res_403));
     }
+
     // EXPERIMENTAL built-in tools
     if (!params.server_tools.empty()) {
         try {
@@ -265,6 +282,9 @@ int llama_server(int argc, char ** argv) {
         SRV_WRN("%s", "-----------------\n");
         ctx_http.get ("/tools",           ex_wrapper(tools.handle_get));
         ctx_http.post("/tools",           ex_wrapper(tools.handle_post));
+    } else {
+        ctx_http.get ("/tools",           ex_wrapper(res_403));
+        ctx_http.post("/tools",           ex_wrapper(res_403));
     }
 
     //
index 3b86d80473edbe71665550bbf26c1fbb96074ebb..0fed536e59af51d6bd00f493a47bc74e7c49c716 100644 (file)
@@ -16,7 +16,7 @@ def test_mcp_no_proxy():
     server.start()
 
     res = server.make_request("GET", "/cors-proxy")
-    assert res.status_code == 404
+    assert res.status_code == 403
 
 
 def test_mcp_proxy():
index 9f0101a82e41b31b11e500fe2dd154a6908575e5..a637819885064caf179dff859240185792805159 100644 (file)
@@ -392,11 +392,14 @@ class ToolsStore {
                } catch (err) {
                        const errorMessage = err instanceof Error ? err.message : String(err);
                        this._error = errorMessage;
-                       // 404 from /tools means the server was started without --tools
-                       if (errorMessage.includes('404') || errorMessage.toLowerCase().includes('not found')) {
+                       // 403 from /tools means the server was started without --tools
+                       // TODO: check status code instead of relying on message
+                       if (errorMessage.includes('this feature is disabled')) {
                                this._toolsEndpointUnreachable = true;
+                               console.info('[ToolsStore] Built-in tools are disabled on the server');
+                       } else {
+                               console.error('[ToolsStore] Failed to fetch built-in tools:', err);
                        }
-                       console.error('[ToolsStore] Failed to fetch built-in tools:', err);
                } finally {
                        this._loading = false;
                }