Newer
Older
cortex-hub / frontend / src / shared / components / WebMcpProvider.js
import React, { createContext, useContext, useEffect, useState } from 'react';
import mcpService from '../../services/mcpService';
import { getUserAccessibleNodes } from '../../services/api/nodeService';

const WebMcpContext = createContext(null);

export const WebMcpProvider = ({ children }) => {
    const [isMcpActive, setIsMcpActive] = useState(false);

    useEffect(() => {
        // Register global tools immediately.
        // mcpService queues them internally if navigator.modelContext isn't ready yet,
        // and flushes the queue automatically once the extension injects it.
        mcpService.registerTool({
            name: 'list_nodes',
            description: 'List all agent nodes in the Cortex swarm mesh and their connectivity status.',
            inputSchema: { type: 'object', properties: {} },
            execute: async () => {
                try {
                    const nodes = await getUserAccessibleNodes();
                    return {
                        content: [{
                            type: 'text',
                            text: JSON.stringify({
                                nodes: nodes.map(n => ({
                                    id: n.node_id,
                                    name: n.display_name,
                                    status: n.last_status,
                                    os: n.capabilities?.os
                                }))
                            }, null, 2)
                        }]
                    };
                } catch (err) {
                    return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
                }
            }
        });

        mcpService.registerTool({
            name: 'get_app_info',
            description: 'Get metadata about the Cortex Hub environment.',
            inputSchema: { type: 'object', properties: {} },
            execute: async () => {
                return {
                    content: [{
                        type: 'text',
                        text: JSON.stringify({
                            name: 'Cortex Hub',
                            version: '1.0.0',
                            capabilities: ['swarms', 'webmcp', 'mcp-sse', 'voice-chat', 'rag'],
                            environment: window.location.hostname === 'localhost' ? 'development' : 'production',
                            mcp_server: `${window.location.origin}/api/v1/mcp/sse`,
                        }, null, 2)
                    }]
                };
            }
        });

        // Poll isMcpActive state so UI can show a badge when WebMCP is live
        const statusInterval = setInterval(() => {
            const active = mcpService.isActive();
            setIsMcpActive(prev => {
                if (prev !== active) {
                    if (active) console.log('[MCP] 🟢 WebMCP is now active — tools registered with browser.');
                    return active;
                }
                return prev;
            });
        }, 200);

        return () => clearInterval(statusInterval);
    }, []);

    const [isAiProcessing, setIsAiProcessing] = useState(false);

    const value = {
        isMcpActive,
        isAiProcessing,
        setIsAiProcessing,
        registerTool: (tool) => {
            // Normalize legacy 'handler' property
            const aligned = { ...tool };
            if (tool.handler && !tool.execute) aligned.execute = tool.handler;
            mcpService.registerTool(aligned);
        },
        unregisterTool: (toolName) => mcpService.unregisterTool(toolName),
        listRegistered: () => mcpService.listRegistered(),
    };

    return (
        <WebMcpContext.Provider value={value}>
            {children}
        </WebMcpContext.Provider>
    );
};

export const useWebMcp = () => {
    const ctx = useContext(WebMcpContext);
    if (!ctx) throw new Error('useWebMcp must be used within a WebMcpProvider');
    return ctx;
};