local source change events to mcp notifs

This commit is contained in:
lda
2026-05-13 18:10:31 +07:00 Verified
parent f3bb63389f
commit 7723d8558e
8 changed files with 267 additions and 32 deletions
+13
View File
@@ -0,0 +1,13 @@
from .mapping import map_event_to_notifications
from .sink import (
FastMcpContextNotificationSink,
NotificationSink,
RecordingNotificationSink,
)
__all__ = [
"FastMcpContextNotificationSink",
"NotificationSink",
"RecordingNotificationSink",
"map_event_to_notifications",
]
+35
View File
@@ -0,0 +1,35 @@
from __future__ import annotations
import mcp.types as mcp_types
from wf_mcp.events import McpEvent
def map_event_to_notifications(event: McpEvent) -> list[mcp_types.ServerNotification]:
"""Project broker-local events into MCP server notifications.
The event bus is intentionally protocol-neutral. This function is the
boundary where local capability changes become official MCP notification
payloads that a FastMCP transport can later send to connected clients.
"""
notification = _list_changed_notification(event)
if notification is None:
return []
return [mcp_types.ServerNotification(notification)]
def _list_changed_notification(
event: McpEvent,
) -> (
mcp_types.ToolListChangedNotification
| mcp_types.ResourceListChangedNotification
| mcp_types.PromptListChangedNotification
| None
):
if event.kind == "tools_changed":
return mcp_types.ToolListChangedNotification()
if event.kind == "resources_changed":
return mcp_types.ResourceListChangedNotification()
if event.kind == "prompts_changed":
return mcp_types.PromptListChangedNotification()
return None
+49
View File
@@ -0,0 +1,49 @@
from __future__ import annotations
from typing import Protocol
import mcp.types as mcp_types
from wf_mcp.events import McpEvent
from .mapping import map_event_to_notifications
class NotificationSink(Protocol):
"""Consumes local events and emits or records MCP notifications."""
def __call__(self, event: McpEvent) -> None: ...
class RecordingNotificationSink:
"""Test sink that records MCP notifications projected from local events."""
def __init__(self) -> None:
self._notifications: list[mcp_types.ServerNotification] = []
def __call__(self, event: McpEvent) -> None:
self._notifications.extend(map_event_to_notifications(event))
def list_notifications(self) -> list[mcp_types.ServerNotification]:
"""Return a defensive copy of projected notifications."""
return list(self._notifications)
class FastMcpNotificationContext(Protocol):
"""Small protocol for the FastMCP context method we need."""
async def send_notification(
self,
notification: mcp_types.ServerNotificationType,
) -> None: ...
class FastMcpContextNotificationSink:
"""Send projected local events through a request-scoped FastMCP context."""
def __init__(self, context: FastMcpNotificationContext) -> None:
self._context = context
async def send_event(self, event: McpEvent) -> None:
for notification in map_event_to_notifications(event):
await self._context.send_notification(notification.root)