From 196b8d2cb84a341e5bc6991a2fc7174207326562 Mon Sep 17 00:00:00 2001 From: Abhiraaj R C Date: Thu, 16 Apr 2026 13:23:00 +0530 Subject: [PATCH] fix: preserve wrapped function metadata in register() decorator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The register() decorator replaces the user's endpoint function with an inner wrapper, but doesn't copy over __module__, __name__, etc. On Frappe v17, frappe.whitelist() unconditionally wraps every function with validate_argument_types, which resolves the app name at decoration time via func.__module__.split(".")[0]. Without @functools.wraps, this resolves to "frappe_mcp" instead of the user's app, causing Frappe to load frappe_mcp.hooks — which doesn't exist since frappe_mcp is a pip package, not a Frappe app. --- frappe_mcp/server/server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe_mcp/server/server.py b/frappe_mcp/server/server.py index b9fb292..b819ab6 100644 --- a/frappe_mcp/server/server.py +++ b/frappe_mcp/server/server.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import functools from collections import OrderedDict from collections.abc import Callable @@ -102,6 +103,7 @@ def decorator(fn): self._mcp_entry_fn = fn + @functools.wraps(fn) def wrapper() -> Response: # Runs wrapped dummy mcp handler before handling the request. # This should import all the files with the registered mcp