mcp-apps-builder

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

IMPORTANT: How to Use This Skill

重要提示:如何使用本技能

This file provides a NAVIGATION GUIDE ONLY. Before implementing any MCP server features, you MUST:
  1. Read this overview to understand which reference files are relevant
  2. ALWAYS read the specific reference file(s) for the features you're implementing
  3. Apply the detailed patterns from those files to your implementation
Do NOT rely solely on the quick reference examples in this file - they are minimal examples only. The reference files contain critical best practices, security considerations, and advanced patterns.

本文仅提供导航指引。在实现任何MCP服务器功能前,你必须:
  1. 阅读本概述以了解哪些参考文件与你的需求相关
  2. 务必阅读与你要实现的功能对应的具体参考文件
  3. 将这些文件中的详细模式应用到你的实现中
请勿仅依赖本文中的快速参考示例 - 这些只是最简示例。参考文件中包含关键的最佳实践、安全考量和高级模式。

MCP Server Best Practices

MCP服务器最佳实践

Comprehensive guide for building production-ready MCP servers with tools, resources, prompts, and widgets using mcp-use.
使用mcp-use构建生产级MCP服务器(包含工具、资源、提示词和Widgets)的综合指南。

Quick Navigation

快速导航

Choose your path based on what you're building:
根据你要构建的内容选择对应路径:

🚀 Foundations

🚀 基础部分

When: ALWAYS read these first when starting MCP work in a new conversation. Reference later for architecture/concept clarification.
  1. concepts.md - MCP primitives (Tool, Resource, Prompt, Widget) and when to use each
  2. architecture.md - Server structure (Hono-based), middleware system, server.use() vs server.app
  3. quickstart.md - Basic server setup patterns and first tool example
Load these before diving into tools/resources/widgets sections.

适用场景: 当你在新对话中开始MCP相关工作时,请务必先阅读这些内容。后续可作为架构/概念澄清的参考。
  1. concepts.md - MCP基础组件(Tool、Resource、Prompt、Widget)及各自的适用场景
  2. architecture.md - 服务器结构(基于Hono)、中间件系统、server.use()与server.app的区别
  3. quickstart.md - 基础服务器设置模式与首个Tool示例
在深入工具/资源/Widgets章节前,请先阅读这些内容。

🔧 Building Server Backend (No UI)?

🔧 构建服务器后端(无UI)?

When: Implementing MCP features (actions, data, templates). Read the specific file for the primitive you're building.
  • tools.md
    • When: Creating backend actions the AI can call (send-email, fetch-data, create-user)
    • Covers: Tool definition, schemas, annotations, context, error handling
  • resources.md
    • When: Exposing read-only data clients can fetch (config, user profiles, documentation)
    • Covers: Static resources, dynamic resources, parameterized resource templates, URI completion
  • prompts.md
    • When: Creating reusable message templates for AI interactions (code-review, summarize)
    • Covers: Prompt definition, parameterization, argument completion, prompt best practices
  • response-helpers.md
    • When: Formatting responses from tools/resources (text, JSON, markdown, images, errors)
    • Covers:
      text()
      ,
      object()
      ,
      markdown()
      ,
      image()
      ,
      error()
      ,
      mix()

适用场景: 实现MCP功能(操作、数据、模板)时。请阅读与你要构建的基础组件对应的具体文件。
  • tools.md
    • 适用场景:创建AI可调用的后端操作(发送邮件、获取数据、创建用户)
    • 涵盖内容:Tool定义、模式、注解、上下文、错误处理
  • resources.md
    • 适用场景:暴露客户端可获取的只读数据(配置、用户资料、文档)
    • 涵盖内容:静态资源、动态资源、参数化资源模板、URI补全
  • prompts.md
    • 适用场景:创建AI交互的可复用消息模板(代码审查、摘要生成)
    • 涵盖内容:Prompt定义、参数化、参数补全、Prompt最佳实践
  • response-helpers.md
    • 适用场景:格式化工具/资源的响应(文本、JSON、Markdown、图片、错误)
    • 涵盖内容:
      text()
      object()
      markdown()
      image()
      error()
      mix()

🎨 Building Visual Widgets (Interactive UI)?

🎨 构建可视化Widgets(交互式UI)?

When: Creating React-based visual interfaces for browsing, comparing, or selecting data
  • basics.md
    • When: Creating your first widget or adding UI to an existing tool
    • Covers: Widget setup,
      useWidget()
      hook,
      isPending
      checks, props handling
  • state.md
    • When: Managing UI state (selections, filters, tabs) within widgets
    • Covers:
      useState
      ,
      setState
      , state persistence, when to use tool vs widget state
  • interactivity.md
    • When: Adding buttons, forms, or calling tools from within widgets
    • Covers:
      callTool()
      , form handling, action buttons, optimistic updates
  • ui-guidelines.md
    • When: Styling widgets to support themes, responsive layouts, or accessibility
    • Covers:
      useWidgetTheme()
      , light/dark mode,
      autoSize
      , layout patterns, CSS best practices
  • advanced.md
    • When: Building complex widgets with async data, error boundaries, or performance optimizations
    • Covers: Loading states, error handling, memoization, code splitting

适用场景: 创建基于React的可视化界面,用于浏览、比较或选择数据
  • basics.md
    • 适用场景:创建你的首个Widget或为现有工具添加UI
    • 涵盖内容:Widget设置、
      useWidget()
      钩子、
      isPending
      检查、属性处理
  • state.md
    • 适用场景:在Widget内管理UI状态(选择项、过滤器、标签页)
    • 涵盖内容:
      useState
      setState
      、状态持久化、何时使用工具状态vs Widget状态
  • interactivity.md
    • 适用场景:在Widget内添加按钮、表单或调用工具
    • 涵盖内容:
      callTool()
      、表单处理、操作按钮、乐观更新
  • ui-guidelines.md
    • 适用场景:对Widget进行样式设置以支持主题、响应式布局或无障碍访问
    • 涵盖内容:
      useWidgetTheme()
      、明暗模式、
      autoSize
      、布局模式、CSS最佳实践
  • advanced.md
    • 适用场景:构建包含异步数据、错误边界或性能优化的复杂Widget
    • 涵盖内容:加载状态、错误处理、记忆化、代码分割

📚 Need Complete Examples?

📚 需要完整示例?

When: You want to see full implementations of common use cases
  • common-patterns.md
    • End-to-end examples: weather app, todo list, recipe browser
    • Shows: Server code + widget code + best practices in context

适用场景: 你想查看常见用例的完整实现
  • common-patterns.md
    • 端到端示例:天气应用、待办事项列表、食谱浏览器
    • 展示内容:服务器代码 + Widget代码 + 上下文内的最佳实践

Decision Tree

决策树

What do you need to build?

├─ Simple backend action (no UI)
│  └─> Use Tool: server/tools.md
├─ Read-only data for clients
│  └─> Use Resource: server/resources.md
├─ Reusable prompt template
│  └─> Use Prompt: server/prompts.md
└─ Visual/interactive UI
   └─> Use Widget: widgets/basics.md

What do you need to build?

├─ Simple backend action (no UI)
│  └─> Use Tool: server/tools.md
├─ Read-only data for clients
│  └─> Use Resource: server/resources.md
├─ Reusable prompt template
│  └─> Use Prompt: server/prompts.md
└─ Visual/interactive UI
   └─> Use Widget: widgets/basics.md

Core Principles

核心原则

  1. Tools for actions - Backend operations with input/output
  2. Resources for data - Read-only data clients can fetch
  3. Prompts for templates - Reusable message templates
  4. Widgets for UI - Visual interfaces when helpful
  5. Mock data first - Prototype quickly, connect APIs later

  1. 工具用于操作 - 带有输入/输出的后端操作
  2. 资源用于数据 - 客户端可获取的只读数据
  3. 提示词用于模板 - 可复用的消息模板
  4. Widgets用于UI - 必要时使用可视化界面
  5. 优先使用模拟数据 - 快速原型开发,后续再连接API

❌ Common Mistakes

❌ 常见错误

Avoid these anti-patterns found in production MCP servers:
避免在生产环境MCP服务器中出现这些反模式:

Tool Definition

Tool定义

  • ❌ Returning raw objects instead of using response helpers
    • ✅ Use
      text()
      ,
      object()
      ,
      widget()
      ,
      error()
      helpers
  • ❌ Skipping Zod schema
    .describe()
    on every field
    • ✅ Add descriptions to all schema fields for better AI understanding
  • ❌ No input validation or sanitization
    • ✅ Validate inputs with Zod, sanitize user-provided data
  • ❌ Throwing errors instead of returning
    error()
    helper
    • ✅ Use
      error("message")
      for graceful error responses
  • ❌ 返回原始对象而非使用响应助手
    • ✅ 使用
      text()
      object()
      widget()
      error()
      助手
  • ❌ 跳过Zod模式中每个字段的
    .describe()
    • ✅ 为所有模式字段添加描述,以便AI更好理解
  • ❌ 未进行输入验证或清理
    • ✅ 使用Zod验证输入,清理用户提供的数据
  • ❌ 抛出错误而非返回
    error()
    助手
    • ✅ 使用
      error("message")
      实现优雅的错误响应

Widget Development

Widget开发

  • ❌ Accessing
    props
    without checking
    isPending
    • ✅ Always check
      if (isPending) return <Loading/>
  • ❌ Widget handles server state (filters, selections)
    • ✅ Widgets manage their own UI state with
      useState
  • ❌ Missing
    McpUseProvider
    wrapper or
    autoSize
    • ✅ Wrap root component:
      <McpUseProvider autoSize>
  • ❌ Inline styles without theme awareness
    • ✅ Use
      useWidgetTheme()
      for light/dark mode support
  • ❌ 未检查
    isPending
    就访问
    props
    • ✅ 始终先检查
      if (isPending) return <Loading/>
  • ❌ Widget处理服务器状态(过滤器、选择项)
    • ✅ Widget使用
      useState
      管理自身UI状态
  • ❌ 缺少
    McpUseProvider
    包裹或
    autoSize
    • ✅ 包裹根组件:
      <McpUseProvider autoSize>
  • ❌ 使用内联样式但未考虑主题
    • ✅ 使用
      useWidgetTheme()
      支持明暗模式

Security & Production

安全与生产环境

  • ❌ Hardcoded API keys or secrets in code
    • ✅ Use
      process.env.API_KEY
      , document in
      .env.example
  • ❌ No error handling in tool handlers
    • ✅ Wrap in try/catch, return
      error()
      on failure
  • ❌ Expensive operations without caching
    • ✅ Cache API calls, computations with TTL
  • ❌ Missing CORS configuration
    • ✅ Configure CORS for production deployments

  • ❌ 在代码中硬编码API密钥或机密信息
    • ✅ 使用
      process.env.API_KEY
      ,在
      .env.example
      中记录
  • ❌ 工具处理函数中未添加错误处理
    • ✅ 包裹在try/catch中,失败时返回
      error()
  • ❌ 未对耗时操作进行缓存
    • ✅ 对API调用、计算结果添加TTL缓存
  • ❌ 缺少CORS配置
    • ✅ 为生产部署配置CORS

🔒 Golden Rules

🔒 黄金法则

Opinionated architectural guidelines:
带有倾向性的架构指南:

1. One Tool = One Capability

1. 一个工具对应一项能力

Split broad actions into focused tools:
  • manage-users
    (too vague)
  • create-user
    ,
    delete-user
    ,
    list-users
将宽泛的操作拆分为专注的工具:
  • manage-users
    (过于模糊)
  • create-user
    delete-user
    list-users

2. Return Complete Data Upfront

2. 提前返回完整数据

Tool calls are expensive. Avoid lazy-loading:
  • list-products
    +
    get-product-details
    (2 calls)
  • list-products
    returns full data including details
工具调用成本较高,避免懒加载:
  • list-products
    +
    get-product-details
    (两次调用)
  • list-products
    返回包含详情的完整数据

3. Widgets Own Their State

3. Widget管理自身状态

UI state lives in the widget, not in separate tools:
  • select-item
    tool,
    set-filter
    tool
  • ✅ Widget manages with
    useState
    or
    setState
UI状态存放在Widget中,而非单独的工具:
  • select-item
    工具、
    set-filter
    工具
  • ✅ Widget使用
    useState
    setState
    管理

4. Use
exposeAsTool: false
for Custom Widget Tools

4. 为自定义Widget工具设置
exposeAsTool: false

Prevent duplicate tool registration:
typescript
// ✅ ALL 4 STEPS REQUIRED for proper type inference:

// Step 1: Define schema separately
const propsSchema = z.object({
  title: z.string(),
  items: z.array(z.string())
});

// Step 2: Reference schema variable in metadata
export const widgetMetadata: WidgetMetadata = {
  description: "...",
  props: propsSchema,  // ← NOT inline z.object()
  exposeAsTool: false
};

// Step 3: Infer Props type from schema variable
type Props = z.infer<typeof propsSchema>;

// Step 4: Use typed Props with useWidget
export default function MyWidget() {
  const { props, isPending } = useWidget<Props>();  // ← Add <Props>
  // ...
}
⚠️ Common mistake: Only doing steps 1-2 but skipping 3-4 (loses type safety)
避免重复注册工具:
typescript
// ✅ 正确类型推断所需的4个步骤:

// 步骤1:单独定义模式
const propsSchema = z.object({
  title: z.string(),
  items: z.array(z.string())
});

// 步骤2:在元数据中引用模式变量
export const widgetMetadata: WidgetMetadata = {
  description: "...",
  props: propsSchema,  // ← 不要内联z.object()
  exposeAsTool: false
};

// 步骤3:从模式变量推断Props类型
type Props = z.infer<typeof propsSchema>;

// 步骤4:将带类型的Props与useWidget一起使用
export default function MyWidget() {
  const { props, isPending } = useWidget<Props>();  // ← 添加<Props>
  // ...
}
⚠️ 常见错误: 只完成步骤1-2但跳过步骤3-4(失去类型安全性)

5. Validate at Boundaries Only

5. 仅在边界处验证

  • Trust internal code and framework guarantees
  • Validate user input, external API responses
  • Don't add error handling for scenarios that can't happen
  • 信任内部代码和框架保证
  • 验证用户输入、外部API响应
  • 不要为不可能发生的场景添加错误处理

6. Prefer Widgets for Browsing/Comparing

6. 优先使用Widget进行浏览/比较

When in doubt, add a widget. Visual UI improves:
  • Browsing multiple items
  • Comparing data side-by-side
  • Interactive selection workflows

如有疑问,添加Widget。可视化UI可提升:
  • 多项目浏览体验
  • 数据并排比较
  • 交互式选择流程

Quick Reference

快速参考

Minimal Server

最简服务器

typescript
import { MCPServer, text } from "mcp-use/server";
import { z } from "zod";

const server = new MCPServer({
  name: "my-server",
  title: "My Server",
  version: "1.0.0"
});

server.tool(
  {
    name: "greet",
    description: "Greet a user",
    schema: z.object({ name: z.string().describe("User's name") })
  },
  async ({ name }) => text("Hello " + name + "!"),
);

server.listen();

typescript
import { MCPServer, text } from "mcp-use/server";
import { z } from "zod";

const server = new MCPServer({
  name: "my-server",
  title: "My Server",
  version: "1.0.0"
});

server.tool(
  {
    name: "greet",
    description: "Greet a user",
    schema: z.object({ name: z.string().describe("User's name") })
  },
  async ({ name }) => text("Hello " + name + "!"),
);

server.listen();

Response Helpers

响应助手

HelperUse WhenExample
text()
Simple string response
text("Success!")
object()
Structured data
object({ status: "ok" })
markdown()
Formatted text
markdown("# Title\nContent")
widget()
Visual UI
widget({ props: {...}, output: text(...) })
mix()
Multiple contents
mix(text("Hi"), image(url))
error()
Error responses
error("Failed to fetch data")
resource()
Embed resource refs
resource("docs://guide", "text/markdown")
助手函数适用场景示例
text()
简单字符串响应
text("Success!")
object()
结构化数据
object({ status: "ok" })
markdown()
格式化文本
markdown("# Title\nContent")
widget()
可视化UI
widget({ props: {...}, output: text(...) })
mix()
多内容组合
mix(text("Hi"), image(url))
error()
错误响应
error("Failed to fetch data")
resource()
嵌入资源引用
resource("docs://guide", "text/markdown")