Skip to content

Commit e9d1b76

Browse files
authored
server: use status code 403 for disabled features (ggml-org#24970)
* server: use status code 403 for disabled features * cont * fix test case
1 parent 099bf06 commit e9d1b76

3 files changed

Lines changed: 27 additions & 4 deletions

File tree

tools/server/server.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,19 @@ int llama_server(int argc, char ** argv) {
242242
// Google Cloud Platform (Vertex AI) compat
243243
ctx_http.register_gcp_compat();
244244

245+
// return 403 for disabled features
246+
server_http_context::handler_t res_403 = [](const server_http_req &) {
247+
auto res = std::make_unique<server_http_res>();
248+
res->status = 403;
249+
res->data = safe_json_to_str({
250+
{"error", {
251+
{"message", "this feature is disabled"},
252+
{"type", "feature_disabled"},
253+
}}
254+
});
255+
return res;
256+
};
257+
245258
// CORS proxy (EXPERIMENTAL, only used by the Web UI for MCP)
246259
if (params.ui_mcp_proxy) {
247260
SRV_WRN("%s", "-----------------\n");
@@ -250,7 +263,11 @@ int llama_server(int argc, char ** argv) {
250263
SRV_WRN("%s", "-----------------\n");
251264
ctx_http.get ("/cors-proxy", ex_wrapper(proxy_handler_get));
252265
ctx_http.post("/cors-proxy", ex_wrapper(proxy_handler_post));
266+
} else {
267+
ctx_http.get ("/cors-proxy", ex_wrapper(res_403));
268+
ctx_http.post("/cors-proxy", ex_wrapper(res_403));
253269
}
270+
254271
// EXPERIMENTAL built-in tools
255272
if (!params.server_tools.empty()) {
256273
try {
@@ -265,6 +282,9 @@ int llama_server(int argc, char ** argv) {
265282
SRV_WRN("%s", "-----------------\n");
266283
ctx_http.get ("/tools", ex_wrapper(tools.handle_get));
267284
ctx_http.post("/tools", ex_wrapper(tools.handle_post));
285+
} else {
286+
ctx_http.get ("/tools", ex_wrapper(res_403));
287+
ctx_http.post("/tools", ex_wrapper(res_403));
268288
}
269289

270290
//

tools/server/tests/unit/test_proxy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def test_mcp_no_proxy():
1616
server.start()
1717

1818
res = server.make_request("GET", "/cors-proxy")
19-
assert res.status_code == 404
19+
assert res.status_code == 403
2020

2121

2222
def test_mcp_proxy():

tools/ui/src/lib/stores/tools.svelte.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,14 @@ class ToolsStore {
392392
} catch (err) {
393393
const errorMessage = err instanceof Error ? err.message : String(err);
394394
this._error = errorMessage;
395-
// 404 from /tools means the server was started without --tools
396-
if (errorMessage.includes('404') || errorMessage.toLowerCase().includes('not found')) {
395+
// 403 from /tools means the server was started without --tools
396+
// TODO: check status code instead of relying on message
397+
if (errorMessage.includes('this feature is disabled')) {
397398
this._toolsEndpointUnreachable = true;
399+
console.info('[ToolsStore] Built-in tools are disabled on the server');
400+
} else {
401+
console.error('[ToolsStore] Failed to fetch built-in tools:', err);
398402
}
399-
console.error('[ToolsStore] Failed to fetch built-in tools:', err);
400403
} finally {
401404
this._loading = false;
402405
}

0 commit comments

Comments
 (0)