Skip to main content
Glama
qqzhangyanhua

MCP Stock Assistant

get-stock-history

Retrieve historical stock price data including daily, weekly, and monthly candlestick charts to analyze past performance trends.

Instructions

获取单个股票的历史数据、过去价格、K线数据,支持日K、周K、月K线,用于分析股票过去的表现

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
stock_codeYes股票代码或名称 (例如: 600519 或 贵州茅台)
periodNo时间周期: 1d=日K线, 1w=周K线, 1m=月K线1d
daysNo获取天数 (1-500天)

Implementation Reference

  • src/index.ts:50-110 (registration)
    Registration of the 'get-stock-history' tool via server.tool(), including input schema (Zod) and inline async handler function that orchestrates data fetching and formatting.
    server.tool(
      "get-stock-history",
      "获取单个股票的历史数据、过去价格、K线数据,支持日K、周K、月K线,用于分析股票过去的表现",
      {
        stock_code: z
          .string()
          .describe("股票代码或名称 (例如: 600519 或 贵州茅台)"),
        period: z
          .enum(["1d", "1w", "1m"])
          .default("1d")
          .describe("时间周期: 1d=日K线, 1w=周K线, 1m=月K线"),
        days: z
          .number()
          .min(1)
          .max(500)
          .default(30)
          .describe("获取天数 (1-500天)"),
      },
      async ({ stock_code, period, days }) => {
        // Convert period to API format
        const periodMap = { "1d": "101", "1w": "102", "1m": "103" };
        const apiPeriod = periodMap[period];
    
        const historyData = await fetchStockHistory(stock_code, apiPeriod, days);
    
        if (!historyData || historyData.length === 0) {
          return {
            content: [
              {
                type: "text",
                text: `无法获取股票 ${stock_code} 的历史数据。请检查输入是否正确。`,
              },
            ],
          };
        }
    
        // Get stock name for display
        let stockName = stock_code;
        if (!stock_code.match(/^\d{6}$/)) {
          const searchResult = await searchStock(stock_code);
          if (searchResult) {
            stockName = `${searchResult[1]}(${searchResult[0]})`;
          }
        } else {
          // Try to get name from current data
          const currentData = await fetchStockData(stock_code);
          if (currentData) {
            stockName = `${currentData.name}(${currentData.code})`;
          }
        }
    
        return {
          content: [
            {
              type: "text",
              text: formatHistoryData(historyData, stockName),
            },
          ],
        };
      }
    );
  • Inline handler function for 'get-stock-history' tool: validates inputs, maps period, calls fetchStockHistory, handles stock name resolution, and returns formatted content.
    async ({ stock_code, period, days }) => {
      // Convert period to API format
      const periodMap = { "1d": "101", "1w": "102", "1m": "103" };
      const apiPeriod = periodMap[period];
    
      const historyData = await fetchStockHistory(stock_code, apiPeriod, days);
    
      if (!historyData || historyData.length === 0) {
        return {
          content: [
            {
              type: "text",
              text: `无法获取股票 ${stock_code} 的历史数据。请检查输入是否正确。`,
            },
          ],
        };
      }
    
      // Get stock name for display
      let stockName = stock_code;
      if (!stock_code.match(/^\d{6}$/)) {
        const searchResult = await searchStock(stock_code);
        if (searchResult) {
          stockName = `${searchResult[1]}(${searchResult[0]})`;
        }
      } else {
        // Try to get name from current data
        const currentData = await fetchStockData(stock_code);
        if (currentData) {
          stockName = `${currentData.name}(${currentData.code})`;
        }
      }
    
      return {
        content: [
          {
            type: "text",
            text: formatHistoryData(historyData, stockName),
          },
        ],
      };
    }
  • Zod input schema for 'get-stock-history': stock_code (string), period (enum 1d/1w/1m), days (number 1-500).
    {
      stock_code: z
        .string()
        .describe("股票代码或名称 (例如: 600519 或 贵州茅台)"),
      period: z
        .enum(["1d", "1w", "1m"])
        .default("1d")
        .describe("时间周期: 1d=日K线, 1w=周K线, 1m=月K线"),
      days: z
        .number()
        .min(1)
        .max(500)
        .default(30)
        .describe("获取天数 (1-500天)"),
    },
  • fetchStockHistory helper: resolves stock code, constructs API params, fetches K-line data from HISTORY_API, parses response into HistoryDataPoint array.
    export async function fetchStockHistory(
      stockInput: string,
      period: string = "101",
      days: number = 30
    ): Promise<HistoryDataPoint[] | null> {
      try {
        let stockCode = stockInput;
    
        if (!stockInput.match(/^\d{6}$/)) {
          const searchResult = await searchStock(stockInput);
          if (!searchResult) {
            console.error(`未找到股票:${stockInput}`);
            return null;
          }
          [stockCode] = searchResult;
        }
    
        const [market, fullCode] = getStockMarket(stockCode);
    
        const params = {
          secid: fullCode,
          klt: period,
          fqt: "1",
          lmt: days.toString(),
          end: "20500101",
          iscca: "1",
          fields1: "f1,f2,f3,f4,f5,f6",
          fields2: "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
        };
    
        const response = await makeRequest(HISTORY_API, params);
        const data = (await response.json()) as HistoryResponse;
    
        if (data.rc !== 0 || !data.data || !data.data.klines) {
          throw new Error(data.msg || "获取历史数据失败");
        }
    
        const historyData: HistoryDataPoint[] = data.data.klines.map((kline) => {
          const parts = kline.split(",");
          return {
            date: parts[0],
            open: parseFloat(parts[1]),
            close: parseFloat(parts[2]),
            high: parseFloat(parts[3]),
            low: parseFloat(parts[4]),
            volume: parseInt(parts[5]) / 100,
            amount: parseFloat(parts[6]) / 10000,
            changePercent: parseFloat(parts[8]),
          };
        });
    
        return historyData.reverse();
      } catch (error) {
        console.error("Error fetching stock history:", error);
        return null;
      }
    }
  • formatHistoryData helper: converts history data array and stock name into formatted markdown text with table, stats (high/low/avg/total vol).
    export function formatHistoryData(data: HistoryDataPoint[], stockName: string): string {
      let result = `
    📈 ${stockName} 历史数据 (最近${data.length}个交易日)
    
    `;
    
      const recentData = data.slice(0, Math.min(10, data.length));
      
      result += "日期        开盘    收盘    最高    最低    成交量(手)  涨跌幅\n";
      result += "─".repeat(65) + "\n";
      
      for (const point of recentData) {
        const changeColor = point.changePercent >= 0 ? "📈" : "📉";
        result += `${point.date} ${formatPrice(point.open).padStart(6)} ${formatPrice(point.close).padStart(6)} ${formatPrice(point.high).padStart(6)} ${formatPrice(point.low).padStart(6)} ${formatVolume(point.volume).padStart(8)} ${changeColor}${point.changePercent.toFixed(2)}%\n`;
      }
    
      const prices = data.map(d => d.close);
      const maxPrice = Math.max(...prices);
      const minPrice = Math.min(...prices);
      const avgPrice = prices.reduce((a, b) => a + b, 0) / prices.length;
      const totalVolume = data.reduce((sum, d) => sum + d.volume, 0);
    
      result += `\n📊 统计信息:
    最高价: ${formatPrice(maxPrice)}
    最低价: ${formatPrice(minPrice)}
    平均价: ${formatPrice(avgPrice)}
    总成交量: ${formatVolume(totalVolume)}手
    `;
    
      return result;
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions data retrieval ('获取') and supports different K-line periods, but fails to disclose critical traits such as rate limits, authentication requirements, data freshness, error handling, or response format. For a data-fetching tool with zero annotation coverage, this leaves significant gaps in understanding its operational behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded, stating the core purpose in the first clause. It uses two sentences efficiently: one for the main action and another for usage context. There's no wasted text, and it avoids redundancy, though it could be slightly more structured for clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (3 parameters, no output schema, no annotations), the description is incomplete. It covers the basic purpose and implied usage but lacks details on behavioral aspects (e.g., rate limits, auth), response format, and explicit sibling differentiation. Without annotations or output schema, more context is needed for effective agent use, making it inadequate for a data retrieval tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with all parameters well-documented in the schema itself (e.g., 'stock_code' as stock code/name, 'period' as time cycle with enum values, 'days' as number of days). The description adds minimal value beyond the schema, only reiterating support for daily, weekly, and monthly K-lines without providing additional syntax or usage details. Baseline score of 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: '获取单个股票的历史数据、过去价格、K线数据' (get historical data, past prices, K-line data for a single stock). It specifies the resource (stock) and actions (retrieve historical data), distinguishing it from siblings like 'get-market-index' and 'get-stock-info' by focusing on historical price data rather than market indices or general stock information. However, it doesn't explicitly contrast with siblings in the text, keeping it from a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context with '用于分析股票过去的表现' (used for analyzing past stock performance), suggesting when to use this tool. However, it lacks explicit guidance on when to choose this over alternatives like 'get-stock-info' (which might provide current data) or 'get-market-index', and doesn't mention any prerequisites or exclusions. The guidance is present but not comprehensive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/qqzhangyanhua/mcp-stock'

If you have feedback or need assistance with the MCP directory API, please join our Discord server