以「asset-price-mcp」为例,从 0 开发 MCP Server

简介

关于 MCP 的介绍之前已经写过,可以参考 《Model Context Protocol (MCP) 快速开始》。

今天从 0 开始开发一个 MCP Server,实现一个资产价格查询的 MCP Server。


实现步骤

1. 设置 MCP 服务器

首先,使用 @modelcontextprotocol/sdk 提供的 McpServer 类创建一个 MCP 服务器实例:

javascript 复制代码
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'

const server = new McpServer({
  name: 'asset-price',
  version: '1.0.0',
})

这里,我们将服务器命名为 "asset-price",版本号为 "1.0.0"。

2. 定义数据结构

使用 zod 库定义资产符号和资产价格的数据结构,以确保从 API 获取的数据符合预期格式:

javascript 复制代码
import { z } from 'zod'

const AssetSymbolSchema = z.object({
  name: z.string(),
  symbol: z.string(),
})

const AssetPriceSchema = z.object({
  name: z.string(),
  price: z.number(),
  symbol: z.string(),
  updatedAt: z.string(),
  updatedAtReadable: z.string(),
})

这些模式用于验证从外部 API 获取的数据的结构和类型。

3. 实现缓存机制

为了提高性能并减少对外部 API 的请求次数,实现了一个简单的内存缓存:

javascript 复制代码
class SimpleCache {
  private cache: Map<string, CacheEntry<any>> = new Map();

  get<T>(key: string): T | null {
    const entry = this.cache.get(key);
    if (!entry) return null;

    if (Date.now() - entry.timestamp > CACHE_TTL) {
      this.cache.delete(key);
      return null;
    }

    return entry.data as T;
  }

  set<T>(key: string, data: T): void {
    this.cache.set(key, {
      data,
      timestamp: Date.now()
    });
  }

  clear(): void {
    this.cache.clear();
  }
}

const apiCache = new SimpleCache();

该缓存会在设定的时间间隔后自动清除过期的数据。

4. 获取资产符号和价格数据

定义一个通用的函数 fetchApiData,用于从外部 API 获取数据并进行验证:

javascript 复制代码
async function fetchApiData<T>(url: string, schema: z.ZodSchema<T>, useCache = true): Promise<T | null> {
  if (useCache) {
    const cachedData = apiCache.get<T>(url);
    if (cachedData) {
      return cachedData;
    }
  }

  const headers = {
    "User-Agent": USER_AGENT,
    "Accept": "application/json",
  };

  try {
    const response = await fetchWithTimeout(url, { headers });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}, url: ${url}`);
    }

    const data = await response.json();
    const parsedData = schema.parse(data);

    if (useCache && parsedData) {
      apiCache.set(url, parsedData);
    }

    return parsedData;
  } catch (error: any) {
    if (error instanceof z.ZodError) {
      console.error(`Schema validation failed for ${url}:`, error.errors);
    } else if (error.name === 'AbortError') {
      console.error(`Request timeout for ${url}`);
    } else {
      console.error(`API request failed for ${url}:`, error);
    }
    return null;
  }
}

该函数首先检查缓存,如果缓存中没有数据,则从 API 获取数据,并使用 zod 模式进行验证。

5. 定义 MCP 工具

在 MCP 服务器上注册一个工具 get_asset_price,用于检索当前的资产价格信息:

javascript 复制代码
server.tool(
  "get_asset_price",
  "Retrieves current pricing information for various assets including precious metals and cryptocurrencies",
  {
    random_string: z.string().optional().describe("Dummy parameter for no-parameter tools")
  },
  async () => {
    try {
      const symbols = await fetchApiData(
        `${GOLD_API_BASE}/symbols`,
        z.array(AssetSymbolSchema)
      );

      if (!symbols?.length) {
        return {
          content: [{
            type: "text",
            text: "No available asset symbols found. Service might be temporarily unavailable.",
          }]
        };
      }

      const prices: AssetPrice[] = [];
      for (const { symbol } of symbols) {
        const priceData = await fetchApiData(`${GOLD_API_BASE}/price/${symbol}`, AssetPriceSchema);
        if (priceData) {
          prices.push(priceData);
        }
      }

      return {
        content: [{
          type: "text",
          text: prices.map(price => `${price.name}: ${price.price}`).join("\n"),
        }]
      };
    } catch (error) {
      console.error("Tool execution failed:", error);
      return {
        content: [{
          type: "text",
          text: "An error occurred while processing your request. Please try again later.",
        }]
      };
    }
  }
);

此工具允许 LLM 通过 MCP 服务器请求资产价格数据,并以文本形式返回结果。

相关推荐
米小虾2 小时前
LLM评测的失效与依赖感知聚合
人工智能·llm
xrlfreedom6 小时前
大厂 MCP 面试实录:Tool 调用身份认证、授权与最小权限落地实践
mcp·rag 知识库·java mcp sdk
Crazy_MT6 小时前
Flutter 本地大模型实战:做一个自然语言记账工具
flutter·llm·ai编程
XLYcmy6 小时前
DeepMMSearch-R1: Empowering Multimodal LLMs in Multimodal Web Search论文分享
llm·sft·强化学习·多模态·苹果·rag·检索
Sophnet云平台6 小时前
2026:AI Agent应用元年,企业从试点到核心业务的跨越逻辑
网络·人工智能·llm·openai·agent
凌奕7 小时前
OpenCodeReview 架构拆解:AI Code Review 为什么不能只是 Git Diff + LLM?
llm·github·agent
GreatVicent7 小时前
腾讯AI产业大会解读:Agent进场,企业基础设施怎么搭
大数据·数据库·人工智能·llm·agent·企业信息化
xrlfreedom8 小时前
大厂 MCP 面试实录:调用异常排查与提示注入防护的工程实践
mcp·提示注入防护·typescript mcp sdk
掰头战士8 小时前
你说你折这玩意干什么-agent工作的核心,还真得好好考虑怎么折叠上下文
typescript·llm·agent
千桐科技9 小时前
qKnow 开源版 v2.4.3 更新解析:从知识数据接入到自定义解析与结果复用
开源·llm·agent·ai智能体·qknow·智能体构建