Chapter 09

MCP + Observability:互通与可观测

MCP 让 Mastra Agent 能消费任意 MCP Server 的工具,也能把自己暴露成 MCP 让 Claude Desktop / Cursor 用。OTel 标准让 trace/log/metric 流入 Langfuse / Braintrust 等平台。

MCP 两边:Client 与 Server

MCPClient(消费方)
Agent 作为 MCP Client 连上远程 MCP Server,把 Server 暴露的 tool / resource / prompt 动态注入自己。
MCPServer(提供方)
把 Mastra Agent、Workflow、Tool 暴露成 MCP Server,给 Claude Desktop、Cursor、n8n 等 MCP 客户端调用。

作为 Client:接外部 MCP 工具

import { MCPClient } from '@mastra/mcp';

const mcp = new MCPClient({
  servers: {
    filesystem: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp/sandbox'],
    },
    github: {
      url: new URL('https://mcp.github.com/sse'),
      requestInit: { headers: { Authorization: `Bearer ${GH_TOKEN}` } },
    },
  },
});

// 取出所有 server 的工具注入 Agent
const tools = await mcp.getTools();

export const devAgent = new Agent({
  name: 'dev',
  instructions: '...',
  model: anthropic('claude-sonnet-4-6'),
  tools,  // 现在有 filesystem + github 全部工具
});

两种 transport 都支持:stdio(本地进程)和 HTTP/SSE(远程)。每轮对话会自动刷新 tool 列表,MCP Server 新增工具无需重启 Agent。

作为 Server:暴露给 Claude Desktop

// src/mastra/server.ts
import { MCPServer } from '@mastra/mcp';
import { chefAgent } from './agents/chef';
import { kbSearchTool } from './tools/kb';
import { researchFlow } from './workflows/research';

export const server = new MCPServer({
  name: 'gufa-mcp',
  version: '1.0.0',
  agents: { chefAgent },       // Agent 被暴露为 ask_chefAgent tool
  tools: { kbSearchTool },     // 原生 tool
  workflows: { researchFlow }, // Workflow 被暴露为 run_researchFlow tool
});

// stdio 方式(给 Claude Desktop)
await server.startStdio();
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "gufa-mcp": {
      "command": "node",
      "args": ["/abs/path/dist/server.js"]
    }
  }
}

重启 Claude Desktop,它会看到你的 Agent、Tool、Workflow 全部变成可调用工具。

HTTP/SSE 模式(远程)

import express from 'express';

const app = express();
app.get('/sse', server.sseHandler());
app.post('/message', server.messageHandler());
app.listen(3000);

OpenTelemetry:三条腿都跑标准

import { Mastra } from '@mastra/core';

export const mastra = new Mastra({
  agents: { ... },
  telemetry: {
    enabled: true,
    serviceName: 'gufa-agent',
    sampling: { type: 'ratio', probability: 1 },
    export: {
      type: 'otlp',
      endpoint: 'https://otel.langfuse.com/v1/traces',
      headers: { Authorization: `Bearer ${LANGFUSE_KEY}` },
    },
  },
});

Mastra 自动为 Agent.generate、Tool.execute、Workflow.step 创建 span,带以下属性:

接 Langfuse

import { LangfuseExporter } from 'langfuse-vercel';

telemetry: {
  enabled: true,
  serviceName: 'gufa-agent',
  export: {
    type: 'custom',
    exporter: new LangfuseExporter({
      publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
      secretKey: process.env.LANGFUSE_SECRET_KEY!,
      baseUrl: 'https://cloud.langfuse.com',
    }),
  },
},

Langfuse dashboard 显示:每条会话的完整 trace、每步模型调用的 prompt/completion、token 花费、延迟、自定义 tag。对做 A/B 测试、逐次排查 bad case 极有用。

接 Braintrust

import { BraintrustExporter } from 'braintrust-otel';

export: {
  type: 'custom',
  exporter: new BraintrustExporter({
    apiKey: process.env.BRAINTRUST_KEY!,
    projectName: 'gufa',
  }),
},

接 Arize / Phoenix(自托管)

export: {
  type: 'otlp',
  endpoint: 'http://localhost:6006/v1/traces',  // Phoenix 默认端口
},

日志与 Logger

import { PinoLogger } from '@mastra/loggers';

export const mastra = new Mastra({
  ...,
  logger: new PinoLogger({
    name: 'Mastra',
    level: 'info',
  }),
});

Mastra 内置 Pino,所有 info/debug/error 走同一 logger;自定义 Tool 也可以通过 mastra.getLogger() 写日志,自动带 traceId 关联。

评估与告警联动

本章小结