For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/guides/advanced-features/mcp-apps/configuration.md.
  • 简体中文
  • 定义工具与视图

    根目录 mcp_apps.ts 定义工具、业务 handler 和结果卡片。defineMcpServer() 提供类型推导;mcpAppsPlugin() 默认读取该文件并自动注册 /mcp,无需手写 BFF 入口。

    应用内组件模式下的定义

    工具通过 view.module 直接引用当前项目的 React 组件文件。下面以应用内问候卡片为例:

    mcp_apps.ts
    import { defineMcpServer } from '@modern-js/mcp-apps/config';
    import { withViewProps } from '@modern-js/mcp-apps/server';
    import { name, version } from './package.json';
    
    export default defineMcpServer({
      name,
      version,
      tools: [
        {
          name: 'greet',
          description: 'Greet someone.',
          inputSchema: {
            name: { type: 'string', minLength: 1 },
          },
          annotations: { readOnlyHint: true },
          handler: async ({ name }) => {
            const message = `Hello, ${name}!`;
            return withViewProps({
              content: [{ type: 'text', text: message }],
              structuredContent: { message },
            });
          },
          visibility: ['model', 'app'],
          view: { module: './src/components/Greeting.tsx' },
        },
        {
          name: 'add_numbers',
          description: 'Add two numbers.',
          inputSchema: {
            a: { type: 'number' },
            b: { type: 'number' },
          },
          annotations: { readOnlyHint: true },
          handler: ({ a, b }) => {
            const sum = a + b;
            return {
              content: [{ type: 'text', text: `${a} + ${b} = ${sum}` }],
              structuredContent: { a, b, sum },
            };
          },
          visibility: ['model', 'app'],
        },
      ],
    });
    字段含义
    remotes可选的远程 UI 资源列表,默认空数组;应用内组件卡片和纯工具项目可省略
    tools[].name工具唯一名称,宿主和卡片通过它调用工具
    tools[].description工具用途说明,帮助模型选择工具
    tools[].inputSchema工具参数的 JSON Schema,服务端在执行 handler 前校验
    tools[].handler工具业务函数,接收输入参数和请求上下文
    tools[].view可选卡片配置;省略时只返回工具结果,不展示卡片
    tools[].remoteMF 模式下引用的 remotes[].name

    应用内组件卡片的 view.module 相对项目根目录解析。工具可以只有 handler 或只有 view,但不能两者都省略。

    工具与组件的对应关系

    模板中的对应关系如下:

    MCP 工具 name服务端 handlerview.module组件默认导出
    greetgreet handler./src/components/Greeting.tsx问候卡片组件
    add_numbersadd_numbers handler—无卡片,仅返回工具结果

    宿主调用 greet 后,服务端执行 greet handler。Modern.js 为 view.module 指定的组件生成卡片入口,并通过工具关联的 ui://app/greet 资源向宿主提供 HTML。宿主加载卡片后,组件接收工具输入、handler 返回的 viewProps 和 mcpApp。工具业务函数在服务端执行,React 组件在宿主的卡片界面中运行。

    配置时注意:

    • tools[].name 是工具调用名称,与组件文件名、组件函数名无须一致;view.module 是相对项目根目录的文件路径。
    • view.exportName 默认为 default,对应组件的 export default。如果文件通过 export function Greeting() 导出组件,则配置 view: { module: './src/components/Greeting.tsx', exportName: 'Greeting' }。
    • 将组件放入 src/components/ 不会自动注册工具。需要在 tools 中声明工具并配置 view,插件才会为它生成卡片入口。该模式省略工具的 remote,全部使用应用内组件时可省略 remotes。
    • 多个工具可以引用同一组件文件,插件按工具分别生成入口和 UI 资源;共享组件应能处理这些工具传入的属性。每个工具配置一个 view,组件内部可以组合多个子组件。
    • 卡片通过 mcpApp.callServerTool() 再次调用工具时,使用 tools[].name,例如 add_numbers,而不是组件名或文件路径。只提供业务能力的工具可以省略 view。

    新增一张卡片

    1. 在 src/components/ 中创建 React 组件并导出。
    2. 在 mcp_apps.ts 中实现业务 handler,通过 viewProps 返回组件需要的属性。
    3. 在 tools 中添加工具对象,通过 view.module 指向组件文件。
    4. 运行协议验证,并在宿主中触发工具,检查卡片展示和交互,具体步骤见创建项目。

    handler 如何把结果交给卡片

    tools/greet.ts
    import { defineTool } from '@modern-js/mcp-apps/config';
    import { withViewProps } from '@modern-js/mcp-apps/server';
    
    export const greet = defineTool({
      name: 'greet',
      description: 'Greet someone.',
      inputSchema: {
        name: { type: 'string', minLength: 1 },
      },
      annotations: { readOnlyHint: true },
      handler: async ({ name }) => {
        const message = `Hello, ${name}!`;
        return withViewProps({
          content: [{ type: 'text', text: message }],
          structuredContent: { message },
        });
      },
    });

    当业务数据与组件属性相同时,使用 withViewProps(result) 避免重复声明。需要转换组件接口时,传入映射函数,例如 withViewProps(result, data => ({ message: data.message }))。仍可显式返回 viewProps,不会自动将任意业务字段展开到组件。

    content 提供文本等工具内容,structuredContent 提供结构化业务数据,viewProps 明确指定传给卡片的属性。渲染器合并工具输入参数和 viewProps,同名属性以 viewProps 为准,并注入已连接的 mcpApp。例如,上面的卡片可以接收 name、message 和 mcpApp;组件通过 mcpApp.callServerTool() 再次调用工具。

    MF 模式下的定义

    MF 通过 exposes 声明可被加载的 UI 模块,MCP 通过 tools 声明可被调用的工具。两者通过工具的 remote 和 view.module 显式关联。

    1. 暴露卡片组件

    在提供组件的项目中配置:

    module-federation.config.ts
    import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
    
    export default createModuleFederationConfig({
      name: 'mcp_ui',
      manifest: { filePath: 'static' },
      filename: 'static/remoteEntry.js',
      exposes: {
        './Greeting': './src/components/Greeting.tsx',
      },
      shared: {
        react: { singleton: true },
        'react-dom': { singleton: true },
        'react/jsx-runtime': { singleton: true },
        'react/jsx-dev-runtime': { singleton: true },
      },
    });

    exposes 的键是对外暴露的模块名,值是组件源码路径。例如,./Greeting 指向 Greeting.tsx。组件默认通过 export default 导出;命名导出可通过工具的 view.exportName 指定。

    2. 将工具关联到卡片

    无论 MF 组件由本应用还是独立服务托管,都必须在 remotes[].baseUrl 中显式配置完整的 manifest URL,并声明 CSP 域名。插件不会发现 manifest 或推断 remote 地址。

    mcp_apps.ts
    import { defineMcpServer } from '@modern-js/mcp-apps/config';
    import { withViewProps } from '@modern-js/mcp-apps/server';
    
    export default defineMcpServer({
      name: 'my-mcp-server',
      version: '1.0.0',
      remotes: [
        {
          name: 'mcp_ui',
          baseUrl: 'https://cdn.example.com/static/mf-manifest.json',
          csp: {
            resourceDomains: ['https://cdn.example.com'],
            connectDomains: ['https://cdn.example.com'],
          },
        },
      ],
      tools: [
        {
          name: 'greet',
          description: 'Greet someone.',
          inputSchema: {
            name: { type: 'string', minLength: 1 },
          },
          annotations: { readOnlyHint: true },
          handler: async ({ name }) => {
            const message = `Hello, ${name}!`;
            return withViewProps({
              content: [{ type: 'text', text: message }],
              structuredContent: { message },
            });
          },
          remote: 'mcp_ui',
          view: { module: './Greeting' },
        },
      ],
    });

    这里的 view.module: './Greeting' 是 module-federation.config.ts 中的 expose 名称,不是磁盘文件路径。baseUrl 指向标准 MF manifest;csp.resourceDomains 声明脚本、样式等资源来源,csp.connectDomains 声明网络请求来源。使用其他资源或 API 域名时也需要加入对应列表。

    3. 理解对应关系

    上面配置示例中,两个工具与组件的对应关系如下:

    MCP 工具 name服务端 handlerremoteview.moduleexposes 对应源码
    greetgreet handlermcp_ui./Greeting./src/components/Greeting.tsx
    add_numbersadd_numbers handler——无卡片,仅返回工具结果

    以 greet 为例,宿主调用工具后,服务端执行 greet handler 并返回业务结果。卡片渲染器根据 remote: 'mcp_ui' 找到 remotes 中的 manifest,再通过 view.module: './Greeting' 加载暴露的组件,将工具输入、handler 返回的 viewProps 和 mcpApp 传给它。

    配置时需要区分以下名称和职责:

    • tools[].name 是 MCP 工具名,用于工具调用;view.module 是 MF expose 名,两者无须同名。例如,工具 greet 对应组件 ./Greeting。
    • tools[].remote 必须匹配 remotes[].name,baseUrl 必须是完整的 manifest URL。remoteEntry、JS 和 CSS 资产由 MF runtime 负责加载。
    • view.module 必须与 exposes 的键一致,包括大小写和 ./ 前缀。在工具配置中填写 ./Greeting,而不是组件源码路径。
    • 配置 exposes 只会暴露模块,不会自动注册 MCP 工具。只有 tools 中声明的工具才会出现在工具列表中;服务端业务函数通过 handler 配置,无须放入 MF exposes。
    • 多个工具可以复用同一个 expose,只要组件能处理各工具传入的属性。每个工具配置一个 view,该组件内部可以组合多个子组件;纯工具可以省略 view 和 remote。
    • 卡片内调用 mcpApp.callServerTool({ name: 'add_numbers', arguments: { a: 2, b: 3 } }) 时,name 使用 MCP 工具名,不使用 ./Greeting 这样的 expose 名。

    新增卡片时,先在 exposes 中暴露组件,再在 tools 中配置业务 handler、remote 和 view.module。如果工具执行成功但卡片加载失败,优先检查 manifest 地址、expose 名称、组件导出方式和资源 CSP。

    自动挂载时,插件调用现有服务端编译器处理根目录定义及导入的 handler;手动 BFF 路由由 BFF 编译,不会作为 UI 入口导入浏览器。构建阶段也会读取定义来发现 UI 入口,因此应避免在模块顶层启动监听器等副作用。

    完整字段和类型定义见 API 参考。

    卡片如何调用工具、向对话发送消息和同步模型上下文,见卡片交互。

    viewDefaults

    export default defineMcpServer({
      name: 'my-mcp-server',
      version: '1.0.0',
      viewDefaults: {
        assetBase: 'request',
        csp: {
          resourceDomains: [],
          connectDomains: [],
          frameDomains: [],
          baseUriDomains: [],
        },
      },
      tools: [
        { name: 'card', visibility: ['model', 'app'], view: { module: './Card' } },
      ],
    });

    应用级默认值只作用于带 view 的工具。单个 tool 的 view 按字段覆盖默认值;CSP 各域名列表独立覆盖,空数组清空默认列表,不自动合并域名。MF 资源的 CSP 仍由 remote.csp 配置。

    工具类型推导

    defineTool() 将 JSON Schema 与 handler 放在一起,推导必填和可选参数、枚举、数组及嵌套对象。handler 支持同步或异步返回。前端可使用 InferToolInput<typeof tool> 和 InferToolOutput<typeof tool> 获取输入和结构化输出类型。执行前仍会校验输入,不支持推导的 schema 形式保留为 unknown。

    name、version 标识 MCP server。remotes 默认 [],本地视图和无 UI 工具可省略。viewDefaults 仍作为顶层分组。旧入口 defineMcpApps 和 mcpApps 保留兼容。

    视图默认使用 default 导出、component 渲染模式,并在浏览器运行;模板无需显式填写这三项配置。

    内联工具与输入简写

    defineMcpServer({ tools: [...] }) 会为每个内联工具推导 handler 参数,无需再包裹 defineTool()。把工具拆到独立文件时,仍可使用 defineTool() 保留推导。

    const inputSchema = {
      name: { type: 'string', minLength: 1 },
      count: { type: 'integer', optional: true },
    } as const;
    // tools: [{ name: 'greet', inputSchema, handler: ... }]

    属性简写默认所有字段必填,并禁止额外属性;optional: true 表示可选字段,发布给客户端前会移除此标记。完整 JSON Schema 仍受支持;嵌套对象使用标准 JSON Schema。字段名与 type、description 等 Schema 关键字冲突时,使用完整的 type: 'object'、properties、required 写法。

    MF 工具使用 remote 和 expose 名称作为 view.module。插件会为 /static/* 公共资源处理跨域请求,无需额外的 server/modern.server.ts;独立 CDN 的跨域策略仍由 CDN 配置。