以「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 服务器请求资产价格数据,并以文本形式返回结果。

相关推荐
Study9961 小时前
大语言模型的详解与训练
人工智能·ai·语言模型·自然语言处理·大模型·llm·agent
谷哥的小弟2 小时前
SQLite MCP服务器安装以及客户端连接配置
服务器·数据库·人工智能·sqlite·大模型·源码·mcp
tyw153 小时前
解决 Trae MySQL MCP 连接失败(Fail to start)
mcp·trae·fail to start·mysql mcp·mcp兼容
淡淡的说非3 小时前
LangChain4j 深度解析与Java工程化落地实践
ai·llm·springboot·langchain4j
夏日白云3 小时前
《PDF解析工程实录》第 14 章|内容流文本布局计算:pdfminer 在做什么,以及它为什么不够
pdf·llm·大语言模型·rag·文档解析
谷哥的小弟3 小时前
File System MCP服务器安装以及客户端连接配置
服务器·人工智能·大模型·file system·mcp·ai项目
lkbhua莱克瓦243 小时前
参数如何影响着大语言模型
人工智能·llm·大语言模型
智泊AI19 小时前
一文讲清:RAG中语义理解和语义检索的区别到底是什么?有何应用?
llm
啊湘1 天前
vscode 使用 github (适用CURSOR等使用)
ide·vscode·github·cursor·mcp
小小呱呱蛙1 天前
Claude Code 自下而上分析(Slash/Sub Agents/Skills/MCP)带来的启发
agent·claude·mcp