mcp server 还需要自己调用大模型吗

TwoAdmin 2025-9-17 80 9/17

不需要,而且通常不应该由 MCP Server 自己调用大模型。

这是一个非常重要的概念区分。让我来解释一下 MCP 的架构和分工:

MCP 的核心分工

MCP Server 的角色(你写的这个程序)

  • 数据提供者: 提供结构化的数据、资源访问

  • 工具执行者: 执行具体的操作和计算

  • 服务连接器: 连接外部系统和API

  • 内容处理器: 处理和转换信息

MCP Client 的角色(如 Claude AI、Cursor AI 等)

  • 大模型调用者: 负责实际调用和理解大模型

  • 决策制定者: 决定何时使用什么工具/资源

  • 结果解释者: 解释和呈现工具执行的结果

  • 用户交互者: 与最终用户进行对话交互

正确的交互流程

你应该在 MCP Server 中做什么

✅ 应该做的事情

  1. 提供数据访问

go

// 提供数据库查询
server.AddResourceHandler("database", func(ctx context.Context, method string, params map[string]any) (mcp.ResourceResult, error) {
    // 查询数据库并返回结果
    rows := queryDatabase("SELECT * FROM users WHERE id = ?", params["user_id"])
    return mcp.ResourceResult{Contents: convertToResource(rows)}, nil
})
  1. 执行具体工具

go

// 执行系统命令
server.AddToolHandler("run-command", func(ctx context.Context, params map[string]any) (mcp.ToolResult, error) {
    cmd := exec.Command(params["command"].(string))
    output, err := cmd.CombinedOutput()
    return mcp.ToolResult{Content: []mcp.Content{{Type: "text", Text: string(output)}}}, err
})
  1. 连接外部API

go

// 调用天气预报API
server.AddToolHandler("get-weather", func(ctx context.Context, params map[string]any) (mcp.ToolResult, error) {
    data, err := fetchWeatherAPI(params["city"].(string))
    return mcp.ToolResult{Content: []mcp.Content{{Type: "text", Text: formatWeatherData(data)}}}, err
})

❌ 不应该做的事情

go

// 错误:在 MCP Server 中直接调用大模型
server.AddToolHandler("ask-ai", func(ctx context.Context, params map[string]any) (mcp.ToolResult, error) {
    // ❌ 这是错误的方式!
    response, err := openaiClient.ChatCompletion(params["question"].(string))
    return mcp.ToolResult{Content: []mcp.Content{{Type: "text", Text: response}}}, err
})

正确的模式:提供数据,让客户端决策

好的例子:数据分析服务器

go

// 提供销售数据查询
server.AddResourceHandler("sales-data", func(ctx context.Context, method string, params map[string]string) (mcp.ResourceResult, error) {
    // 只返回原始数据,让AI来分析
    data := querySalesData(params["period"], params["region"])
    return mcp.ResourceResult{
        Contents: []mcp.ResourceContent{
            {
                URI: "sales:///latest",
                Content: formatAsJSON(data), // 返回结构化数据
                MimeType: "application/json"
            }
        }
    }, nil
})

// 提供数据统计工具
server.AddToolHandler("calculate-metrics", func(ctx context.Context, params map[string]any) (mcp.ToolResult, error) {
    // 只做数学计算,不做解释
    salesData := getSalesData(params["period"].(string))
    metrics := calculateMetrics(salesData) // 返回数值结果
    
    return mcp.ToolResult{
        Content: []mcp.Content{
            {
                Type: "text",
                Text: fmt.Sprintf("Total: $%.2f, Average: $%.2f", metrics.Total, metrics.Average)
            }
        }
    }, nil
})

为什么这样设计?

  1. 效率: 大模型只需要一个实例(在客户端)

  2. 一致性: 所有AI推理由同一个模型完成

  3. 成本: 避免重复的API调用费用

  4. 专注: 每个组件做自己最擅长的事情

特殊情况:链式调用

在某些高级场景中,你可能需要让一个 MCP Server 调用另一个服务,但仍然不应该直接调用大模型:

go

server.AddToolHandler("analyze-with-external", func(ctx context.Context, params map[string]any) (mcp.ToolResult, error) {
    // 调用专门的数据分析服务(不是大模型!)
    result, err := callDataAnalysisService(params["data"])
    return mcp.ToolResult{Content: []mcp.Content{{Type: "text", Text: result}}}, err
})

总结

你的 MCP Server 应该:

  • 提供原始数据和处理能力

  • 执行具体的、确定性的操作

  • 连接外部系统和服务

  • 返回结构化的结果

让 MCP Client(AI)负责:

  • 理解用户意图

  • 决定使用哪些工具/资源

  • 分析和解释返回的数据

  • 生成最终的自然语言回复

这样就能充分发挥各自组件的优势,构建出高效可靠的 AI 应用生态系统。

- THE END -
Tag:

TwoAdmin

9月17日17:05

最后修改:2025年9月17日
0

非特殊说明,本博所有文章均为博主原创。