MCP应用开发工具包

一个用于构建和嵌入符合SEP-1865标准的MCP应用程序的SDK,支持框架无关和React,提供状态管理和工具调用功能。

  • by botdojo-ai
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 botdojo-ai/mcp-app-view

使用说明

mcp应用程序视图

构建和嵌入MCP应用程序(SEP-1865)-MCP的交互式用户界面。

建造于 BotDojo •框架无关•可选React支持•零依赖

这是什么?

MCP Apps(SEP-1865)是模型上下文协议的扩展,使AI代理能够提供交互式用户界面。此SDK使构建与任何MCP兼容主机兼容的MCP应用程序变得容易。

此包是由创建的 BotDojo 作为对MCP生态系统的开源贡献。虽然它与任何MCP主机独立工作,但它与BotDojo无缝集成,具有持久状态、工具流等功能。

安装

npm install mcp-app-view
# or
pnpm add mcp-app-view
# or
yarn add mcp-app-view

特性

  • ✅ 符合SEP-1865标准 -实施 MCP应用程序规范
  • ✅ 框架不可知 -适用于任何框架或vanilla JS
  • ✅ 可选的React支持 -一流的React钩子和组件
  • ✅ 零依赖 -无外部运行时依赖关系
  • ✅ TypeScript优先 -全型安全
  • ✅ 状态管理 -内置状态提供者系统(可扩展)
  • ✅ 主机组件 - McpProxyHost 用于嵌入MCP应用程序

快速开始

React(最简单)

import { useMcpApp } from 'mcp-app-view/react';

function MyMcpApp() {
  const { isInitialized, state, tool, updateState, sendMessage } = useMcpApp({
    initialState: { counter: 0 },
  });

  if (!isInitialized) return <div>Connecting...</div>;
  if (tool.isStreaming) return <div>Processing: {tool.name}...</div>;

  return (
    <div>
      <h1>Counter: {state.counter}</h1>
      <button onClick={() => updateState({ counter: state.counter + 1 })}>
        Increment
      </button>
      <button onClick={() => sendMessage([{ type: 'text', text: 'Hello!' }])}>
        Send Message
      </button>
    </div>
  );
}

框架不可知

import { McpAppClient } from 'mcp-app-view';

const client = new McpAppClient({ debug: true });

// Subscribe to events
client.on('initialize', (params) => {
  console.log('Host:', params.appInfo);
  console.log('Context:', params.hostContext);
});

client.on('toolInput', (params) => {
  console.log('Tool:', params.tool.name);
  console.log('Args:', params.arguments);
});

client.on('toolResult', (params) => {
  console.log('Result:', params.result);
});

// Start the client
client.start();

// Send messages to host
await client.sendMessage([{ type: 'text', text: 'Hello from MCP App!' }]);

// Call tools on the host
const result = await client.callTool('get_weather', { location: 'NYC' });

// Report size changes
client.reportSize(400, 300);

与BotDojo一起使用

BotDojo 是一个用于构建具有丰富工具功能的AI代理的平台。使用时 mcp-app-view 使用BotDojo,您可以获得其他功能:

持久状态

BotDojo会自动在会话之间持久化您的MCP应用程序状态。使用 botdojo/messageType: 'persist-state' 扩展名:

import { useMcpApp } from 'mcp-app-view/react';

function MyApp() {
  const { state, sendMessage } = useMcpApp({
    initialState: { counter: 0 },
  });

  const persistCounter = async (newValue: number) => {
    // BotDojo will persist this state and hydrate it on next load
    await sendMessage([{
      type: 'text',
      text: JSON.stringify({ counter: newValue }),
      'botdojo/messageType': 'persist-state',
    }]);
  };

  return (
    <button onClick={() => persistCounter(state.counter + 1)}>
      Count: {state.counter}
    </button>
  );
}

工具流

BotDojo通过以下方式提供实时工具参数流 ui/notifications/tool-input-partial:

import { useMcpApp } from 'mcp-app-view/react';

function StreamingApp() {
  const { tool } = useMcpApp();

  // BotDojo streams tool arguments in real-time
  if (tool.isStreaming) {
    return (
      <div>
        <h2>Running: {tool.name}</h2>
        <p>Step: {tool.arguments?.stepId}</p>
        <p>Progress: {tool.arguments?.progress}%</p>
      </div>
    );
  }

  return <div>Result: {JSON.stringify(tool.result)}</div>;
}

BotDojo状态提供者

为了实现完全集成,请使用BotDojo状态提供程序(可在 @botdojo/sdk):

import { useMcpApp } from 'mcp-app-view/react';
import { BotDojoStateProvider } from '@botdojo/sdk';

function MyApp() {
  const { state, updateState } = useMcpApp({
    initialState: { counter: 0 },
    // BotDojo provider handles persistence automatically
    stateProvider: new BotDojoStateProvider({ canvasId: 'my-app' }),
  });

  return <div>{state.counter}</div>;
}

在BotDojo中托管MCP应用程序

使用 McpProxyHost 将MCP应用程序嵌入到基于BotDojo的应用程序中:

import { McpProxyHost } from 'mcp-app-view/host';

function MyHost() {
  return (
    <McpProxyHost
      proxyUrl="https://your-proxy.botdojo.com"
      appUrl="https://your-mcp-app.com"
      hostContext={{
        theme: 'dark',
        // BotDojo passes persisted state here
        state: persistedState,
      }}
      onMessage={async (params) => {
        // Handle messages, including persist-state
        const content = params.content[0];
        if (content['botdojo/messageType'] === 'persist-state') {
          await persistState(JSON.parse(content.text));
        }
      }}
      onToolCall={async (name, args) => {
        // Execute tools via BotDojo
        return await botdojo.callTool(name, args);
      }}
    />
  );
}

api参考

框架不可知论(核心)

McpAppClient

MCP Apps通信的主要客户端。

import { McpAppClient } from 'mcp-app-view';

const client = new McpAppClient({
  debug: false,           // Enable debug logging
  autoAcknowledge: true,  // Auto-send ui/notifications/initialized
});

// Lifecycle
client.start();
client.stop();

// State
client.isInitialized;
client.state.appInfo;
client.state.hostCapabilities;
client.state.hostContext;
client.state.tool;

// Events
client.on('initialize', (params) => {});
client.on('toolInputPartial', (params) => {});
client.on('toolInput', (params) => {});
client.on('toolResult', (params) => {});
client.on('hostContextChanged', (context) => {});
client.on('resourceTeardown', () => {});

// Actions
await client.sendMessage(content);
await client.openLink(url);
await client.callTool(name, args);
client.reportSize(width, height);

状态提供

可插拔状态管理系统。

import { createMemoryStateProvider, MemoryStateProvider } from 'mcp-app-view';

// Functional
const provider = createMemoryStateProvider({ counter: 0 });

// Class-based
const provider = new MemoryStateProvider({ counter: 0 });

// API
provider.getState();
provider.setState(newState);
provider.updateState(patch);
provider.subscribe((state, prevState) => {});
provider.reset();
provider.dispose();

反应

useMcpApp

高级方便挂钩。

import { useMcpApp } from 'mcp-app-view/react';

function MyApp() {
  const {
    // Connection
    isInitialized,
    appInfo,
    hostCapabilities,
    hostContext,
    
    // Tool state
    tool, // { name, arguments, result, status, isStreaming }
    
    // State management
    state,
    updateState,
    setState,
    
    // Actions
    sendMessage,
    openLink,
    callTool,
    reportSize,
    
    // Utilities
    getArgumentValue,
    client,
  } = useMcpApp({
    initialState: { counter: 0 },
    debug: false,
    containerRef, // For auto size reporting
    autoReportSize: true,
  });
}

useMcpProtocol

低级协议访问。

import { useMcpProtocol } from 'mcp-app-view/react';

function AdvancedApp() {
  const {
    isInitialized,
    parentOrigin,
    appInfo,
    hostCapabilities,
    hostContext,
    
    // Raw messaging
    sendRequest,
    sendNotification,
    sendResponse,
    sendError,
    
    // Event subscriptions
    onInitialize,
    onToolInputPartial,
    onToolInput,
    onToolResult,
    onHostContextChanged,
    onResourceTeardown,
  } = useMcpProtocol({ debug: true });
}

useMcpToolStream

细粒度工具流状态。

import { useMcpToolStream } from 'mcp-app-view/react';

function StreamingApp() {
  const {
    name,
    arguments,
    partialArguments,
    result,
    status, // 'idle' | 'streaming' | 'complete' | 'error' | 'teardown'
    isStreaming,
    getArgumentValue,
    reset,
  } = useMcpToolStream();
}

McpApp & McpAppProvider

组件包装。

import { McpApp, McpAppProvider, useMcpAppContext } from 'mcp-app-view/react';

// Simple wrapper
function App() {
  return (
    <McpApp initialState={{ counter: 0 }}>
      <MyWidget />
    </McpApp>
  );
}

// Provider pattern
function App() {
  return (
    <McpAppProvider
      initialState={{ counter: 0 }}
      onInitialize={(ctx) => console.log('Ready!')}
      onToolResult={(result) => console.log('Done!')}
    >
      <MyWidget />
    </McpAppProvider>
  );
}

function MyWidget() {
  const { state, updateState } = useMcpAppContext();
  return <div>{state.counter}</div>;
}

主机组件

McpProxyHost

在React应用程序中嵌入MCP应用程序。

import { McpProxyHost, McpProxyHostRef } from 'mcp-app-view/host';

function MyHost() {
  const hostRef = useRef<McpProxyHostRef>(null);

  const handleToolCall = async (name: string, args?: Record<string, unknown>) => {
    if (name === 'get_data') {
      return { data: 'Hello from host!' };
    }
    throw new Error(`Unknown tool: ${name}`);
  };

  // Send updates to the app
  useEffect(() => {
    hostRef.current?.sendToolInput({
      tool: { name: 'process_data' },
      arguments: { step: 1 },
    });
  }, []);

  return (
    <McpProxyHost
      ref={hostRef}
      proxyUrl="https://proxy.example.com"
      appUrl="https://my-mcp-app.example.com"
      appInfo={{ name: 'My Host', version: '1.0.0' }}
      hostCapabilities={{ openLinks: {} }}
      hostContext={{ theme: 'dark' }}
      onMessage={async (params) => {
        console.log('Message from app:', params.content);
      }}
      onToolCall={handleToolCall}
      onSizeChange={(size) => {
        console.log('App size:', size);
      }}
    />
  );
}

SEP-1865协议

此SDK实现了 SEP-1865 MCP应用程序规范.

Host → 应用消息

方法 类型 描述
ui/initialize 请求 初始化应用程序
ui/notifications/tool-input-partial 通知 流媒体工具参数
ui/notifications/tool-input 通知 最终工具参数
ui/notifications/tool-result 通知 工具结果
ui/tool-cancelled 通知 工具已取消
ui/notifications/host-context-changed 通知 上下文更新
ui/resource-teardown 通知 清理

App → 主机消息

方法 类型 描述
ui/notifications/initialized 通知 应用程序就绪
ui/notifications/size-change 通知 大小更改
ui/open-link 请求 打开URL
ui/message 请求 发送消息
tools/call 请求 呼叫工具

贡献

我们欢迎捐款!请查看我们的 贡献指南.

关于BotDojo

BotDojo 是一个用于构建、运行和集成AI代理的平台。我们创建了这个SDK,以帮助开发人员与MCP建立丰富的交互体验。

许可证

MIT© BotDojo