Skip to content

Commit eee2394

Browse files
author
Teryl Taylor
committed
feat: added hooks to the plugin manager for http pre/post header requests.
Signed-off-by: Teryl Taylor <[email protected]>
1 parent fa872ed commit eee2394

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

mcpgateway/plugins/framework/manager.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
Config,
4141
GlobalContext,
4242
HookType,
43+
HttpHeaderPayload,
44+
HttpHeaderPayloadResult,
4345
PluginCondition,
4446
PluginContext,
4547
PluginContextTable,
@@ -421,6 +423,54 @@ async def post_resource_fetch(plugin: PluginRef, payload: ResourcePostFetchPaylo
421423
return await plugin.plugin.resource_post_fetch(payload, context)
422424

423425

426+
async def pre_http_forwarding_call(plugin: PluginRef, payload: HttpHeaderPayload, context: PluginContext) -> HttpHeaderPayloadResult:
427+
"""Call plugin's HTTP pre-forwarding call hook.
428+
429+
Args:
430+
plugin: The plugin to execute.
431+
payload: The set of HTTP headers to be analyzed.
432+
context: The plugin context.
433+
434+
Returns:
435+
Modified HTTP headers with processing status.
436+
437+
Examples:
438+
>>> from mcpgateway.plugins.framework.base import PluginRef
439+
>>> from mcpgateway.plugins.framework import Plugin, HttpHeaderPayload, PluginContext, GlobalContext
440+
>>> # Assuming you have a plugin instance:
441+
>>> # plugin_ref = PluginRef(my_plugin)
442+
>>> payload = HttpHeaderPayload({"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="})
443+
>>> context = PluginContext(request_id="123")
444+
>>> # In async context:
445+
>>> # result = await pre_http_forwarding_call(plugin_ref, payload, context)
446+
"""
447+
return await plugin.plugin.http_pre_forwarding_call(payload, context)
448+
449+
450+
async def post_http_forwarding_call(plugin: PluginRef, payload: HttpHeaderPayload, context: PluginContext) -> HttpHeaderPayloadResult:
451+
"""Call plugin's HTTP post-forwarding call hook.
452+
453+
Args:
454+
plugin: The plugin to execute.
455+
payload: The set of HTTP headers to be analyzed.
456+
context: The plugin context.
457+
458+
Returns:
459+
Modified HTTP headers with processing status.
460+
461+
Examples:
462+
>>> from mcpgateway.plugins.framework.base import PluginRef
463+
>>> from mcpgateway.plugins.framework import Plugin, HttpHeaderPayload, PluginContext, GlobalContext
464+
>>> # Assuming you have a plugin instance:
465+
>>> # plugin_ref = PluginRef(my_plugin)
466+
>>> payload = HttpHeaderPayload({"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="})
467+
>>> context = PluginContext(request_id="123")
468+
>>> # In async context:
469+
>>> # result = await post_http_forwarding_call(plugin_ref, payload, context)
470+
"""
471+
return await plugin.plugin.http_post_forwarding_call(payload, context)
472+
473+
424474
class PluginManager:
425475
"""Plugin manager for managing the plugin lifecycle.
426476
@@ -465,6 +515,7 @@ class PluginManager:
465515
_post_tool_executor: PluginExecutor[ToolPostInvokePayload] = PluginExecutor[ToolPostInvokePayload]()
466516
_resource_pre_executor: PluginExecutor[ResourcePreFetchPayload] = PluginExecutor[ResourcePreFetchPayload]()
467517
_resource_post_executor: PluginExecutor[ResourcePostFetchPayload] = PluginExecutor[ResourcePostFetchPayload]()
518+
_http_executor: PluginExecutor[HttpHeaderPayload] = PluginExecutor[HttpHeaderPayload]()
468519

469520
# Context cleanup tracking
470521
_context_store: Dict[str, Tuple[PluginContextTable, float]] = {}
@@ -946,3 +997,69 @@ async def resource_post_fetch(
946997
del self._context_store[global_context.request_id]
947998

948999
return result
1000+
1001+
async def http_pre_forwarding_call(
1002+
self, payload: HttpHeaderPayload, global_context: GlobalContext, local_contexts: Optional[PluginContextTable] = None
1003+
) -> tuple[HttpHeaderPayloadResult, PluginContextTable | None]:
1004+
"""Execute pre-fetch hooks before an operation is called.
1005+
1006+
Args:
1007+
payload: The http payload containing http headers passed from requests to responses.
1008+
global_context: Shared context for all plugins with request metadata.
1009+
local_contexts: Optional existing contexts from previous hook executions.
1010+
1011+
Returns:
1012+
A tuple containing:
1013+
- HttpHeaderPayloadResult with processing status and modified headers
1014+
- PluginContextTable with plugin contexts for state management
1015+
"""
1016+
# Get plugins configured for this hook
1017+
plugins = self._registry.get_plugins_for_hook(HookType.HTTP_PRE_FORWARDING_CALL)
1018+
1019+
def compare(payload: HttpHeaderPayload, conditions: list[PluginCondition], context: GlobalContext):
1020+
return True
1021+
1022+
# Execute plugins
1023+
result = await self._http_executor.execute(plugins, payload, global_context, pre_http_forwarding_call, compare, local_contexts)
1024+
1025+
# Store context for potential post-fetch
1026+
if result[1]:
1027+
self._context_store[global_context.request_id] = (result[1], time.time())
1028+
1029+
# Periodic cleanup
1030+
await self._cleanup_old_contexts()
1031+
1032+
return result
1033+
1034+
async def http_post_forwarding_call(
1035+
self, payload: HttpHeaderPayload, global_context: GlobalContext, local_contexts: Optional[PluginContextTable] = None
1036+
) -> tuple[HttpHeaderPayloadResult, PluginContextTable | None]:
1037+
"""Execute post-fetch hooks after an operation is complete.
1038+
1039+
Args:
1040+
payload: The http payload containing http headers passed from requests to responses.
1041+
global_context: Shared context for all plugins with request metadata.
1042+
local_contexts: Optional existing contexts from previous hook executions.
1043+
1044+
Returns:
1045+
A tuple containing:
1046+
- HttpHeaderPayloadResult with processing status and modified headers
1047+
- PluginContextTable with plugin contexts for state management
1048+
"""
1049+
# Get plugins configured for this hook
1050+
plugins = self._registry.get_plugins_for_hook(HookType.HTTP_POST_FORWARDING_CALL)
1051+
1052+
def compare(payload: HttpHeaderPayload, conditions: list[PluginCondition], context: GlobalContext):
1053+
return True
1054+
1055+
# Execute plugins
1056+
result = await self._http_executor.execute(plugins, payload, global_context, post_http_forwarding_call, compare, local_contexts)
1057+
1058+
# Store context for potential post-fetch
1059+
if result[1]:
1060+
self._context_store[global_context.request_id] = (result[1], time.time())
1061+
1062+
# Periodic cleanup
1063+
await self._cleanup_old_contexts()
1064+
1065+
return result

mcpgateway/plugins/framework/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class HookType(str, Enum):
3030
"""MCP Forge Gateway hook points.
3131
3232
Attributes:
33+
http_pre_forwarding_call: The pre hook before an http forwarding request.
34+
http_post_forwarding_call: The post hook after an http forwarding request.
3335
prompt_pre_fetch: The prompt pre hook.
3436
prompt_post_fetch: The prompt post hook.
3537
tool_pre_invoke: The tool pre invoke hook.
@@ -48,6 +50,8 @@ class HookType(str, Enum):
4850
[<HookType.PROMPT_PRE_FETCH: 'prompt_pre_fetch'>, <HookType.PROMPT_POST_FETCH: 'prompt_post_fetch'>, <HookType.TOOL_PRE_INVOKE: 'tool_pre_invoke'>, <HookType.TOOL_POST_INVOKE: 'tool_post_invoke'>, ...]
4951
"""
5052

53+
HTTP_PRE_FORWARDING_CALL = "http_pre_forwarding_call"
54+
HTTP_POST_FORWARDING_CALL = "http_post_forwarding_call"
5155
PROMPT_PRE_FETCH = "prompt_pre_fetch"
5256
PROMPT_POST_FETCH = "prompt_post_fetch"
5357
TOOL_PRE_INVOKE = "tool_pre_invoke"

0 commit comments

Comments
 (0)