Skip to main content
Glama
Xxx00xxX33

FinanceMCP

by Xxx00xxX33

fund_data

Retrieve comprehensive public fund data including listings, managers, net values, dividends, and holdings to support investment analysis and portfolio management decisions.

Instructions

获取公募基金全面数据,包括基金列表、基金经理、基金净值、基金分红、基金持仓等数据。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
ts_codeYes基金代码,如'150018.SZ'表示银华深证100分级,'001753.OF'表示场外基金。注意:查询基金列表(basic)时必须提供此参数
data_typeYes数据类型,可选值:basic(基金列表)、manager(基金经理)、nav(基金净值)、dividend(基金分红)、portfolio(基金持仓)、all(全部数据)
start_dateNo起始日期,格式为YYYYMMDD,如'20230101'。重要:对于基金持仓(portfolio)数据和基金净值(nav)数据,如果不指定时间参数,将返回所有历史数据,可能数据量很大。建议指定时间范围或使用period参数
end_dateNo结束日期,格式为YYYYMMDD,如'20231231'。配合start_date使用可限制数据范围
periodNo特定报告期,格式为YYYYMMDD。例如:'20231231'表示2023年年报,'20240630'表示2024年中报,'20220630'表示2022年三季报,'20240331'表示2024年一季报。指定此参数时将忽略start_date和end_date

Implementation Reference

  • The primary handler function for the 'fund_data' tool. It processes input arguments, fetches fund data (basic, manager, nav, dividend, portfolio) from Tushare API, handles multiple data types including 'all', applies date filtering, merges share data for NAV, formats output as markdown tables/text, and returns MCP-compatible content.
    async run(args) {
        try {
            console.log('基金数据查询参数:', args);
            const TUSHARE_API_KEY = TUSHARE_CONFIG.API_TOKEN;
            const TUSHARE_API_URL = TUSHARE_CONFIG.API_URL;
            if (!TUSHARE_API_KEY) {
                throw new Error('请配置TUSHARE_TOKEN环境变量');
            }
            // 默认日期设置
            const today = new Date();
            const currentYear = today.getFullYear();
            const defaultEndDate = `${currentYear}1231`;
            const defaultStartDate = `${currentYear - 1}0101`;
            const results = [];
            // 根据data_type决定要查询的API
            const dataTypes = args.data_type === 'all'
                ? ['basic', 'manager', 'nav', 'dividend', 'portfolio']
                : [args.data_type];
            for (const dataType of dataTypes) {
                try {
                    // 基金列表(basic)模块必须提供基金代码,否则跳过
                    if (dataType === 'basic' && !args.ts_code) {
                        console.warn('基金列表查询需要提供基金代码,跳过basic模块');
                        results.push({
                            type: dataType,
                            error: '基金列表查询需要提供基金代码(ts_code)参数,否则数据量过大'
                        });
                        continue;
                    }
                    const result = await fetchFundData(dataType, args.ts_code, args.period, args.start_date || defaultStartDate, args.end_date || defaultEndDate, TUSHARE_API_KEY, TUSHARE_API_URL);
                    if (result.data && result.data.length > 0) {
                        results.push({
                            type: dataType,
                            data: result.data,
                            fields: result.fields
                        });
                    }
                }
                catch (error) {
                    console.warn(`获取${dataType}数据失败:`, error);
                    results.push({
                        type: dataType,
                        error: error instanceof Error ? error.message : '未知错误'
                    });
                }
            }
            if (results.length === 0) {
                throw new Error(`未找到相关基金数据`);
            }
            // 格式化输出
            const formattedOutput = formatFundData(results, args.ts_code);
            return {
                content: [{ type: "text", text: formattedOutput }]
            };
        }
        catch (error) {
            console.error('基金数据查询错误:', error);
            return {
                content: [{
                        type: "text",
                        text: `查询基金数据时发生错误: ${error instanceof Error ? error.message : '未知错误'}`
                    }]
            };
        }
    }
  • JSON Schema defining the input parameters for the fund_data tool, including required fields and enums for data_type.
    parameters: {
        type: "object",
        properties: {
            ts_code: {
                type: "string",
                description: "基金代码,如'150018.SZ'表示银华深证100分级,'001753.OF'表示场外基金。注意:查询基金列表(basic)时必须提供此参数"
            },
            data_type: {
                type: "string",
                description: "数据类型,可选值:basic(基金列表)、manager(基金经理)、nav(基金净值)、dividend(基金分红)、portfolio(基金持仓)、all(全部数据)",
                enum: ["basic", "manager", "nav", "dividend", "portfolio", "all"]
            },
            start_date: {
                type: "string",
                description: "起始日期,格式为YYYYMMDD,如'20230101'。重要:对于基金持仓(portfolio)数据和基金净值(nav)数据,如果不指定时间参数,将返回所有历史数据,可能数据量很大。建议指定时间范围或使用period参数"
            },
            end_date: {
                type: "string",
                description: "结束日期,格式为YYYYMMDD,如'20231231'。配合start_date使用可限制数据范围"
            },
            period: {
                type: "string",
                description: "特定报告期,格式为YYYYMMDD。例如:'20231231'表示2023年年报,'20240630'表示2024年中报,'20220630'表示2022年三季报,'20240331'表示2024年一季报。指定此参数时将忽略start_date和end_date"
            }
        },
        required: ["data_type", "ts_code"]
  • build/index.js:290-296 (registration)
    Registration and dispatch of the fund_data tool in the MCP stdio server's CallToolRequest handler switch statement.
    case "fund_data": {
        const ts_code = request.params.arguments?.ts_code ? String(request.params.arguments.ts_code) : undefined;
        const data_type = String(request.params.arguments?.data_type);
        const start_date = request.params.arguments?.start_date ? String(request.params.arguments.start_date) : undefined;
        const end_date = request.params.arguments?.end_date ? String(request.params.arguments.end_date) : undefined;
        const period = request.params.arguments?.period ? String(request.params.arguments.period) : undefined;
        return normalizeResult(await fundData.run({ ts_code, data_type, start_date, end_date, period }));
  • Tool dispatch case for fund_data in the HTTP server's MCP tools/call handler.
    case 'fund_data':
        return await fundData.run({
            ts_code: args?.ts_code ? String(args.ts_code) : undefined,
            data_type: String(args?.data_type),
            start_date: args?.start_date ? String(args.start_date) : undefined,
            end_date: args?.end_date ? String(args.end_date) : undefined,
            period: args?.period ? String(args.period) : undefined,
        });
  • Key helper function that performs the actual API call to Tushare for specific fund data types, handles response parsing, date filtering, and data merging (e.g., NAV with shares). Called from the main run handler.
    async function fetchFundData(dataType, tsCode, period, startDate, endDate, apiKey, apiUrl) {
        const apiConfigs = {
            basic: {
                api_name: "fund_basic",
                default_fields: "ts_code,name,management,custodian,fund_type,found_date,due_date,list_date,issue_date,delist_date,issue_amount,m_fee,c_fee,duration_year,p_value,min_amount,exp_return,benchmark,status,invest_type,type,trustee,purc_startdate,redm_startdate,market"
            },
            manager: {
                api_name: "fund_manager",
                default_fields: "ts_code,ann_date,name,gender,birth_year,edu,nationality,begin_date,end_date,resume"
            },
            nav: {
                api_name: "fund_nav",
                default_fields: "ts_code,ann_date,nav_date,unit_nav,accum_nav,accum_div,net_asset,total_netasset,adj_nav"
            },
            dividend: {
                api_name: "fund_div",
                default_fields: "ts_code,ann_date,imp_anndate,base_date,div_proc,record_date,ex_date,pay_date,earpay_date,net_ex_date,div_cash,base_unit,ear_distr,ear_amount,account_date,base_year"
            },
            portfolio: {
                api_name: "fund_portfolio",
                default_fields: "ts_code,ann_date,end_date,symbol,mkv,amount,stk_mkv_ratio,stk_float_ratio"
            }
        };
        const config = apiConfigs[dataType];
        if (!config) {
            throw new Error(`不支持的数据类型: ${dataType}`);
        }
        // 构建请求参数
        const params = {
            api_name: config.api_name,
            token: apiKey,
            params: {},
            fields: config.default_fields
        };
        // 根据不同的API添加特定参数
        if (dataType === 'basic') {
            if (tsCode)
                params.params.ts_code = tsCode;
        }
        else if (dataType === 'manager') {
            if (tsCode)
                params.params.ts_code = tsCode;
        }
        else if (dataType === 'nav') {
            if (tsCode)
                params.params.ts_code = tsCode;
            if (period) {
                params.params.nav_date = period;
            }
            else {
                if (startDate)
                    params.params.start_date = startDate;
                if (endDate)
                    params.params.end_date = endDate;
            }
        }
        else if (dataType === 'dividend') {
            if (tsCode)
                params.params.ts_code = tsCode;
        }
        else if (dataType === 'portfolio') {
            if (tsCode)
                params.params.ts_code = tsCode;
            if (period) {
                params.params.period = period;
            }
            else {
                if (startDate)
                    params.params.start_date = startDate;
                if (endDate)
                    params.params.end_date = endDate;
            }
        }
        console.log(`调用${config.api_name} API,参数:`, JSON.stringify(params, null, 2));
        // 设置请求超时
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), TUSHARE_CONFIG.TIMEOUT);
        try {
            const response = await fetch(apiUrl || 'https://api.tushare.pro', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(params),
                signal: controller.signal
            });
            clearTimeout(timeoutId);
            if (!response.ok) {
                throw new Error(`API请求失败: ${response.status} ${response.statusText}`);
            }
            const result = await response.json();
            if (result.code !== 0) {
                throw new Error(`API返回错误: ${result.msg || '未知错误'}`);
            }
            if (!result.data || !result.data.items) {
                return { data: [], fields: result.data?.fields || [] };
            }
            // 转换数据格式
            const formattedData = result.data.items.map((item) => {
                const obj = {};
                result.data.fields.forEach((field, index) => {
                    obj[field] = item[index];
                });
                return obj;
            });
            // 对某些数据类型进行日期范围过滤
            let filteredData = formattedData;
            if (['dividend'].includes(dataType) && startDate && endDate && !period) {
                filteredData = formattedData.filter((item) => {
                    const annDate = item.ann_date;
                    if (!annDate)
                        return true;
                    return annDate >= startDate && annDate <= endDate;
                });
                console.log(`日期范围过滤后剩余${filteredData.length}条${dataType}记录`);
            }
            console.log(`成功获取到${filteredData.length}条${dataType}数据记录`);
            // 如果是净值数据且有基金代码,尝试获取基金份额数据并合并
            if (dataType === 'nav' && tsCode && filteredData.length > 0) {
                try {
                    const shareResult = await fetchFundShareData(tsCode, startDate, endDate, period, apiKey, apiUrl);
                    if (shareResult.data && shareResult.data.length > 0) {
                        // 创建份额数据的映射表,以交易日期为键
                        const shareMap = new Map();
                        shareResult.data.forEach((shareItem) => {
                            shareMap.set(shareItem.trade_date, shareItem.fd_share);
                        });
                        // 将份额数据合并到净值数据中
                        filteredData.forEach((navItem) => {
                            const tradeDate = navItem.nav_date || navItem.ann_date;
                            navItem.fd_share = shareMap.get(tradeDate) || null;
                        });
                        console.log(`成功合并${shareResult.data.length}条基金份额数据`);
                    }
                }
                catch (error) {
                    console.warn('获取基金份额数据失败,将继续返回净值数据:', error);
                }
            }
            return {
                data: filteredData,
                fields: result.data.fields
            };
        }
        catch (error) {
            clearTimeout(timeoutId);
            throw error;
        }
    }
Behavior2/5

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

With no annotations provided, the description carries full burden but offers minimal behavioral information. It states what data can be retrieved but doesn't disclose important behavioral traits like rate limits, authentication requirements, data freshness, potential performance implications (especially for 'all' data type), or what happens when large historical datasets are requested. The description is purely functional without operational context.

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 appropriately concise - a single sentence that efficiently communicates the scope of available data. It's front-loaded with the core purpose and follows with specific examples. While brief, every word serves a purpose in defining the tool's capabilities.

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?

For a tool with 5 parameters, no annotations, and no output schema, the description is insufficiently complete. It doesn't address how results are structured, what format data is returned in, whether pagination is needed for large result sets, or any error conditions. The description covers 'what' data is available but not 'how' to effectively retrieve it or interpret results.

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?

With 100% schema description coverage, the baseline is 3. The description doesn't add meaningful parameter semantics beyond what's already documented in the schema. It mentions the data types available but doesn't provide additional context about parameter interactions, default behaviors, or practical usage patterns that would help an agent understand how to effectively use the parameters together.

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: '获取公募基金全面数据' (get comprehensive public fund data) and lists specific data types including fund lists, fund managers, net values, dividends, and holdings. It distinguishes from siblings by focusing on fund data specifically, though it doesn't explicitly contrast with fund_manager_by_name which appears to be a related but different tool.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention the sibling tool 'fund_manager_by_name' or explain when to choose one over the other. There's no context about appropriate use cases, prerequisites, or limitations beyond what's implied by the parameter descriptions.

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/Xxx00xxX33/FinanceMCP'

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