@@ -134,6 +134,7 @@ class ServeConfig:
134134 advertise_all : bool = False
135135 max_request_size : int | None = None
136136 validation : ValidationHookConfig | None = None
137+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None
137138
138139 # --- Discovery manifest ---
139140 base_url : str | None = None
@@ -525,6 +526,7 @@ def serve(
525526 max_request_size : int | None = None ,
526527 streaming_responses : bool = False ,
527528 validation : ValidationHookConfig | None = DEFAULT_VALIDATION ,
529+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None ,
528530 enable_debug_endpoints : bool = False ,
529531 debug_traffic_source : Callable [[], dict [str , int ]] | None = None ,
530532 base_url : str | None = None ,
@@ -772,6 +774,7 @@ async def force_account_status(self, account_id, status):
772774 max_request_size = config .max_request_size
773775 streaming_responses = config .streaming_responses
774776 validation = config .validation
777+ pre_validation_hooks = config .pre_validation_hooks
775778 enable_debug_endpoints = config .enable_debug_endpoints
776779 debug_traffic_source = config .debug_traffic_source
777780 base_url = config .base_url
@@ -815,6 +818,7 @@ async def force_account_status(self, account_id, status):
815818 advertise_all = advertise_all ,
816819 max_request_size = max_request_size ,
817820 validation = validation ,
821+ pre_validation_hooks = pre_validation_hooks ,
818822 base_url = base_url ,
819823 specialisms = specialisms ,
820824 description = description ,
@@ -838,6 +842,7 @@ async def force_account_status(self, account_id, status):
838842 max_request_size = max_request_size ,
839843 streaming_responses = streaming_responses ,
840844 validation = validation ,
845+ pre_validation_hooks = pre_validation_hooks ,
841846 base_url = base_url ,
842847 specialisms = specialisms ,
843848 description = description ,
@@ -865,6 +870,7 @@ async def force_account_status(self, account_id, status):
865870 max_request_size = max_request_size ,
866871 streaming_responses = streaming_responses ,
867872 validation = validation ,
873+ pre_validation_hooks = pre_validation_hooks ,
868874 base_url = base_url ,
869875 specialisms = specialisms ,
870876 description = description ,
@@ -1239,6 +1245,7 @@ def _serve_mcp(
12391245 max_request_size : int | None = None ,
12401246 streaming_responses : bool = False ,
12411247 validation : ValidationHookConfig | None = DEFAULT_VALIDATION ,
1248+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None ,
12421249 base_url : str | None = None ,
12431250 specialisms : list [str ] | None = None ,
12441251 description : str | None = None ,
@@ -1260,6 +1267,7 @@ def _serve_mcp(
12601267 advertise_all = advertise_all ,
12611268 streaming_responses = streaming_responses ,
12621269 validation = validation ,
1270+ pre_validation_hooks = pre_validation_hooks ,
12631271 allowed_hosts = allowed_hosts ,
12641272 allowed_origins = allowed_origins ,
12651273 enable_dns_rebinding_protection = enable_dns_rebinding_protection ,
@@ -1399,6 +1407,7 @@ def _serve_a2a(
13991407 advertise_all : bool = False ,
14001408 max_request_size : int | None = None ,
14011409 validation : ValidationHookConfig | None = DEFAULT_VALIDATION ,
1410+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None ,
14021411 base_url : str | None = None ,
14031412 specialisms : list [str ] | None = None ,
14041413 description : str | None = None ,
@@ -1427,6 +1436,7 @@ def _serve_a2a(
14271436 message_parser = message_parser ,
14281437 advertise_all = advertise_all ,
14291438 validation = validation ,
1439+ pre_validation_hooks = pre_validation_hooks ,
14301440 auth = auth ,
14311441 public_url = public_url ,
14321442 )
@@ -1481,6 +1491,7 @@ def _build_mcp_and_a2a_app(
14811491 max_request_size : int | None = None ,
14821492 streaming_responses : bool = False ,
14831493 validation : ValidationHookConfig | None = DEFAULT_VALIDATION ,
1494+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None ,
14841495 base_url : str | None = None ,
14851496 specialisms : list [str ] | None = None ,
14861497 description : str | None = None ,
@@ -1523,6 +1534,7 @@ def _build_mcp_and_a2a_app(
15231534 advertise_all = advertise_all ,
15241535 streaming_responses = streaming_responses ,
15251536 validation = validation ,
1537+ pre_validation_hooks = pre_validation_hooks ,
15261538 allowed_hosts = allowed_hosts ,
15271539 allowed_origins = allowed_origins ,
15281540 enable_dns_rebinding_protection = enable_dns_rebinding_protection ,
@@ -1576,6 +1588,7 @@ def _build_mcp_and_a2a_app(
15761588 message_parser = message_parser ,
15771589 advertise_all = advertise_all ,
15781590 validation = validation ,
1591+ pre_validation_hooks = pre_validation_hooks ,
15791592 auth = auth ,
15801593 public_url = public_url ,
15811594 )
@@ -1659,6 +1672,7 @@ def _serve_mcp_and_a2a(
16591672 max_request_size : int | None = None ,
16601673 streaming_responses : bool = False ,
16611674 validation : ValidationHookConfig | None = DEFAULT_VALIDATION ,
1675+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None ,
16621676 base_url : str | None = None ,
16631677 specialisms : list [str ] | None = None ,
16641678 description : str | None = None ,
@@ -1706,6 +1720,7 @@ def _serve_mcp_and_a2a(
17061720 max_request_size = max_request_size ,
17071721 streaming_responses = streaming_responses ,
17081722 validation = validation ,
1723+ pre_validation_hooks = pre_validation_hooks ,
17091724 base_url = base_url ,
17101725 specialisms = specialisms ,
17111726 description = description ,
@@ -1787,6 +1802,7 @@ def create_mcp_server(
17871802 advertise_all : bool = False ,
17881803 streaming_responses : bool = False ,
17891804 validation : ValidationHookConfig | None = DEFAULT_VALIDATION ,
1805+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None ,
17901806 allowed_hosts : Sequence [str ] | None = None ,
17911807 allowed_origins : Sequence [str ] | None = None ,
17921808 enable_dns_rebinding_protection : bool | None = None ,
@@ -1948,6 +1964,7 @@ def create_mcp_server(
19481964 middleware = middleware ,
19491965 advertise_all = advertise_all ,
19501966 validation = validation ,
1967+ pre_validation_hooks = pre_validation_hooks ,
19511968 )
19521969 return mcp
19531970
@@ -1961,6 +1978,7 @@ def _register_handler_tools(
19611978 middleware : Sequence [SkillMiddleware ] | None = None ,
19621979 advertise_all : bool = False ,
19631980 validation : ValidationHookConfig | None = DEFAULT_VALIDATION ,
1981+ pre_validation_hooks : dict [str , Callable [..., Any ]] | None = None ,
19641982) -> None :
19651983 """Register all ADCP tools from a handler onto a FastMCP server."""
19661984 # Freeze middleware ordering at registration time. Tuple both guards
@@ -1980,7 +1998,10 @@ def _register_handler_tools(
19801998 description = tool_def .get ("description" , "" )
19811999 input_schema = tool_def .get ("inputSchema" , {"type" : "object" , "properties" : {}})
19822000 output_schema = tool_def .get ("outputSchema" )
1983- caller = create_tool_caller (handler , tool_name , validation = validation )
2001+ hook = (pre_validation_hooks or {}).get (tool_name )
2002+ caller = create_tool_caller (
2003+ handler , tool_name , validation = validation , pre_validation_hook = hook
2004+ )
19842005 _register_tool (
19852006 mcp ,
19862007 tool_name ,
0 commit comments