89 lines
3.1 KiB
Python
89 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
import mcp.types as mcp_types
|
|
|
|
from wf_mcp.events import EventBus, make_event
|
|
from wf_mcp.notifications import (
|
|
FastMcpContextNotificationSink,
|
|
RecordingNotificationSink,
|
|
map_event_to_notifications,
|
|
)
|
|
|
|
|
|
class FakeFastMcpContext:
|
|
def __init__(self) -> None:
|
|
self.sent: list[mcp_types.ServerNotificationType] = []
|
|
|
|
async def send_notification(
|
|
self,
|
|
notification: mcp_types.ServerNotificationType,
|
|
) -> None:
|
|
self.sent.append(notification)
|
|
|
|
|
|
def test_maps_capability_change_events_to_mcp_list_changed_notifications() -> None:
|
|
tool_event = make_event("tools_changed", connection_id="demo.personal")
|
|
resource_event = make_event("resources_changed", connection_id="demo.personal")
|
|
prompt_event = make_event("prompts_changed", connection_id="demo.personal")
|
|
|
|
tool_notifications = map_event_to_notifications(tool_event)
|
|
resource_notifications = map_event_to_notifications(resource_event)
|
|
prompt_notifications = map_event_to_notifications(prompt_event)
|
|
|
|
assert isinstance(tool_notifications[0].root, mcp_types.ToolListChangedNotification)
|
|
assert tool_notifications[0].root.method == "notifications/tools/list_changed"
|
|
assert isinstance(
|
|
resource_notifications[0].root,
|
|
mcp_types.ResourceListChangedNotification,
|
|
)
|
|
assert (
|
|
resource_notifications[0].root.method == "notifications/resources/list_changed"
|
|
)
|
|
assert isinstance(
|
|
prompt_notifications[0].root,
|
|
mcp_types.PromptListChangedNotification,
|
|
)
|
|
assert prompt_notifications[0].root.method == "notifications/prompts/list_changed"
|
|
|
|
|
|
def test_ignores_events_that_do_not_have_an_mcp_notification_projection() -> None:
|
|
event = make_event("workflow_artifact_saved", workflow_name="demo")
|
|
|
|
assert map_event_to_notifications(event) == []
|
|
|
|
|
|
def test_recording_notification_sink_projects_events_from_event_bus() -> None:
|
|
bus = EventBus()
|
|
sink = RecordingNotificationSink()
|
|
bus.subscribe(sink)
|
|
|
|
bus.publish(make_event("tools_changed", connection_id="demo.personal"))
|
|
bus.publish(make_event("workflow_deployment_saved", workflow_name="demo"))
|
|
bus.publish(make_event("prompts_changed", connection_id="demo.personal"))
|
|
|
|
notifications = sink.list_notifications()
|
|
assert len(notifications) == 2
|
|
assert notifications[0].root.method == "notifications/tools/list_changed"
|
|
assert notifications[1].root.method == "notifications/prompts/list_changed"
|
|
|
|
|
|
def test_fastmcp_context_notification_sink_sends_projected_notifications() -> None:
|
|
context = FakeFastMcpContext()
|
|
sink = FastMcpContextNotificationSink(context)
|
|
|
|
async def run() -> None:
|
|
await sink.send_event(
|
|
make_event("resources_changed", connection_id="demo.personal")
|
|
)
|
|
await sink.send_event(
|
|
make_event("workflow_artifact_saved", workflow_name="demo")
|
|
)
|
|
|
|
asyncio.run(run())
|
|
|
|
assert len(context.sent) == 1
|
|
assert isinstance(context.sent[0], mcp_types.ResourceListChangedNotification)
|
|
assert context.sent[0].method == "notifications/resources/list_changed"
|