Skip to content

Commit 7ccb9b9

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 92199df commit 7ccb9b9

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
@@ -42,6 +42,8 @@
4242
Config,
4343
GlobalContext,
4444
HookType,
45+
HttpHeaderPayload,
46+
HttpHeaderPayloadResult,
4547
PluginCondition,
4648
PluginContext,
4749
PluginContextTable,
@@ -431,6 +433,54 @@ async def post_resource_fetch(plugin: PluginRef, payload: ResourcePostFetchPaylo
431433
return await plugin.plugin.resource_post_fetch(payload, context)
432434

433435

436+
async def pre_http_forwarding_call(plugin: PluginRef, payload: HttpHeaderPayload, context: PluginContext) -> HttpHeaderPayloadResult:
437+
"""Call plugin's HTTP pre-forwarding call hook.
438+
439+
Args:
440+
plugin: The plugin to execute.
441+
payload: The set of HTTP headers to be analyzed.
442+
context: The plugin context.
443+
444+
Returns:
445+
Modified HTTP headers with processing status.
446+
447+
Examples:
448+
>>> from mcpgateway.plugins.framework.base import PluginRef
449+
>>> from mcpgateway.plugins.framework import Plugin, HttpHeaderPayload, PluginContext, GlobalContext
450+
>>> # Assuming you have a plugin instance:
451+
>>> # plugin_ref = PluginRef(my_plugin)
452+
>>> payload = HttpHeaderPayload({"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="})
453+
>>> context = PluginContext(request_id="123")
454+
>>> # In async context:
455+
>>> # result = await pre_http_forwarding_call(plugin_ref, payload, context)
456+
"""
457+
return await plugin.plugin.http_pre_forwarding_call(payload, context)
458+
459+
460+
async def post_http_forwarding_call(plugin: PluginRef, payload: HttpHeaderPayload, context: PluginContext) -> HttpHeaderPayloadResult:
461+
"""Call plugin's HTTP post-forwarding call hook.
462+
463+
Args:
464+
plugin: The plugin to execute.
465+
payload: The set of HTTP headers to be analyzed.
466+
context: The plugin context.
467+
468+
Returns:
469+
Modified HTTP headers with processing status.
470+
471+
Examples:
472+
>>> from mcpgateway.plugins.framework.base import PluginRef
473+
>>> from mcpgateway.plugins.framework import Plugin, HttpHeaderPayload, PluginContext, GlobalContext
474+
>>> # Assuming you have a plugin instance:
475+
>>> # plugin_ref = PluginRef(my_plugin)
476+
>>> payload = HttpHeaderPayload({"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="})
477+
>>> context = PluginContext(request_id="123")
478+
>>> # In async context:
479+
>>> # result = await post_http_forwarding_call(plugin_ref, payload, context)
480+
"""
481+
return await plugin.plugin.http_post_forwarding_call(payload, context)
482+
483+
434484
class PluginManager:
435485
"""Plugin manager for managing the plugin lifecycle.
436486
@@ -475,6 +525,7 @@ class PluginManager:
475525
_post_tool_executor: PluginExecutor[ToolPostInvokePayload] = PluginExecutor[ToolPostInvokePayload]()
476526
_resource_pre_executor: PluginExecutor[ResourcePreFetchPayload] = PluginExecutor[ResourcePreFetchPayload]()
477527
_resource_post_executor: PluginExecutor[ResourcePostFetchPayload] = PluginExecutor[ResourcePostFetchPayload]()
528+
_http_executor: PluginExecutor[HttpHeaderPayload] = PluginExecutor[HttpHeaderPayload]()
478529

479530
# Context cleanup tracking
480531
_context_store: Dict[str, Tuple[PluginContextTable, float]] = {}
@@ -962,3 +1013,69 @@ async def resource_post_fetch(
9621013
del self._context_store[global_context.request_id]
9631014

9641015
return result
1016+
1017+
async def http_pre_forwarding_call(
1018+
self, payload: HttpHeaderPayload, global_context: GlobalContext, local_contexts: Optional[PluginContextTable] = None
1019+
) -> tuple[HttpHeaderPayloadResult, PluginContextTable | None]:
1020+
"""Execute pre-fetch hooks before an operation is called.
1021+
1022+
Args:
1023+
payload: The http payload containing http headers passed from requests to responses.
1024+
global_context: Shared context for all plugins with request metadata.
1025+
local_contexts: Optional existing contexts from previous hook executions.
1026+
1027+
Returns:
1028+
A tuple containing:
1029+
- HttpHeaderPayloadResult with processing status and modified headers
1030+
- PluginContextTable with plugin contexts for state management
1031+
"""
1032+
# Get plugins configured for this hook
1033+
plugins = self._registry.get_plugins_for_hook(HookType.HTTP_PRE_FORWARDING_CALL)
1034+
1035+
def compare(payload: HttpHeaderPayload, conditions: list[PluginCondition], context: GlobalContext):
1036+
return True
1037+
1038+
# Execute plugins
1039+
result = await self._http_executor.execute(plugins, payload, global_context, pre_http_forwarding_call, compare, local_contexts)
1040+
1041+
# Store context for potential post-fetch
1042+
if result[1]:
1043+
self._context_store[global_context.request_id] = (result[1], time.time())
1044+
1045+
# Periodic cleanup
1046+
await self._cleanup_old_contexts()
1047+
1048+
return result
1049+
1050+
async def http_post_forwarding_call(
1051+
self, payload: HttpHeaderPayload, global_context: GlobalContext, local_contexts: Optional[PluginContextTable] = None
1052+
) -> tuple[HttpHeaderPayloadResult, PluginContextTable | None]:
1053+
"""Execute post-fetch hooks after an operation is complete.
1054+
1055+
Args:
1056+
payload: The http payload containing http headers passed from requests to responses.
1057+
global_context: Shared context for all plugins with request metadata.
1058+
local_contexts: Optional existing contexts from previous hook executions.
1059+
1060+
Returns:
1061+
A tuple containing:
1062+
- HttpHeaderPayloadResult with processing status and modified headers
1063+
- PluginContextTable with plugin contexts for state management
1064+
"""
1065+
# Get plugins configured for this hook
1066+
plugins = self._registry.get_plugins_for_hook(HookType.HTTP_POST_FORWARDING_CALL)
1067+
1068+
def compare(payload: HttpHeaderPayload, conditions: list[PluginCondition], context: GlobalContext):
1069+
return True
1070+
1071+
# Execute plugins
1072+
result = await self._http_executor.execute(plugins, payload, global_context, post_http_forwarding_call, compare, local_contexts)
1073+
1074+
# Store context for potential post-fetch
1075+
if result[1]:
1076+
self._context_store[global_context.request_id] = (result[1], time.time())
1077+
1078+
# Periodic cleanup
1079+
await self._cleanup_old_contexts()
1080+
1081+
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)