systemprompt-mcp 0.8.0

Native Model Context Protocol (MCP) implementation for systemprompt.io. Orchestration, per-server OAuth2, RBAC middleware, and tool-call governance — the core of the AI governance pipeline.
Documentation
use crate::error::McpDomainResult;
use std::sync::Arc;
use tokio::sync::broadcast;

use super::events::McpEvent;
use super::handlers::EventHandler;

pub struct EventBus {
    handlers: Vec<Arc<dyn EventHandler>>,
    sender: broadcast::Sender<McpEvent>,
}

impl EventBus {
    pub fn new(capacity: usize) -> Self {
        let (sender, _) = broadcast::channel(capacity);

        Self {
            handlers: Vec::new(),
            sender,
        }
    }

    pub fn register_handler(&mut self, handler: Arc<dyn EventHandler>) {
        self.handlers.push(handler);
    }

    pub async fn publish(&self, event: McpEvent) -> McpDomainResult<()> {
        if let Err(e) = self.sender.send(event.clone()) {
            tracing::debug!(error = %e, "No broadcast subscribers for event");
        }

        for handler in &self.handlers {
            if handler.handles(&event) {
                handler.handle(&event).await?;
            }
        }

        Ok(())
    }

    pub fn subscribe(&self) -> broadcast::Receiver<McpEvent> {
        self.sender.subscribe()
    }

    pub fn sender(&self) -> broadcast::Sender<McpEvent> {
        self.sender.clone()
    }
}

impl std::fmt::Debug for EventBus {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("EventBus")
            .field("handlers_count", &self.handlers.len())
            .field("sender", &"<broadcast channel>")
            .finish()
    }
}