关于 Flexreport Finance
Flexreport Finance 是面向投资者和研究团队的 MCP 服务,提供实时市场事件、公司数据和研究报告。其工具结合事件流、精选金融数据集与报告生成。
主要功能
- 01实时市场事件流
- 02公司概况与事件图谱
- 03覆盖 2,900 多家公司的金融数据
- 04最新及定制研究报告
- 05股票筛选与财报分析
适用场景
- 01跟踪新发布的财报和 SEC 文件
- 02查看公司的最新报告及季度变化
- 03按基本面和技术指标筛选股票
- 04利用电话会记录和引文研究市场主题
MCP 相关
它将 Flexreport Finance 的市场事件、研究报告资料和金融数据作为工具提供给 MCP 客户端,支持事件订阅与流式读取,以及公司研究和报告生成。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://mcp.flexreportfinapi.com/mcpclaude mcp add --transport http com-flexreportfinapi-flexreport-finance https://mcp.flexreportfinapi.com/mcp{"mcpServers":{"com-flexreportfinapi-flexreport-finance":{"type":"http","url":"https://mcp.flexreportfinapi.com/mcp"}}}在 Cursor 中打开{"servers":{"com-flexreportfinapi-flexreport-finance":{"type":"http","url":"https://mcp.flexreportfinapi.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"com-flexreportfinapi-flexreport-finance":{"type":"http","url":"https://mcp.flexreportfinapi.com/mcp"}}}{"mcpServers":{"com-flexreportfinapi-flexreport-finance":{"serverUrl":"https://mcp.flexreportfinapi.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
flexreport-mcp
一个独立的 MCP 微服务,可按需为 Claude(以及任何 MCP 客户端)提供对 Flexreport Finance 的实时事件、 研究报告资料和包含超过 7.5 亿个数据点的数据库的访问。
它为 AI Agent 提供实时市场事件和经过整理的黄金来源数据,涵盖基本面、电话会议文字记录、申报文件、内部人士交易(Form 3、4 和 5)、 比率、宏观数据、直接从各公司投资者关系网站获取的 IR 演示文稿等。
快速安装
将连接器添加到 Claude Code
claude mcp add --transport http flexreport https://mcp.flexreportfinapi.com/mcp
或添加到 Codex
codex mcp add flexreport --url https://mcp.flexreportfinapi.com/mcp
然后启动 Claude 并直接提问(例如 “从 flexreport 获取涨幅最大的股票”)。
首次调用数据时,MCP 客户端会在浏览器中启动 OAuth 登录流程 —
按提示登录或注册;无需粘贴令牌。添加 --scope user,即可在所有目录中使用。详情请参阅身份验证。
演示
**在终端中流式接收实时事件。**让 Claude 监控市场,事件发生时即可接收: 涨跌幅较大的股票、财报发布、8-K、IR 演示文稿和最新报告计划。每当报告计划保存后,Claude 都会呈现更新后的报告。
“关注涨跌幅最大的股票、财报发布、文字记录更新、投资者演示文稿和收盘后的 8-K 发布,并通过 Flexreport 实时接收这些事件”
“每有新事件发生时,能否检查是否有最新的报告计划,并获取更新后的报告以提供更深入的背景信息?”

**打开研究报告。**每个数据都链接回生成它的查询,每个标题都链接到其来源。以下是 AAPL 的报告:
“获取最新的 AAPL flexreport 报告”
使用场景
1. 实时
1a. 流式传输(事件和实时报告)。 订阅发布的事件,包括每当报告准备就绪时触发的 report_plan 主题,然后获取渲染后的报告:“订阅 NVDA、AVGO、AMD 和 MU 的业绩发布、8-K 文件、投资者关系(IR)出版物和新报告计划。每当有新内容发布,告诉我发生了什么,检查盘中行情是否出现异常波动,并在 Flexreport Finance 报告准备就绪后获取它。”
工具:register_event_subscription → stream_event_subscription,或按需调用 stream_events,然后调用 detect_intraday_outlier_jumps 和 get_latest_report。
默认情况下,对于实时流式传输请求,会生成仪表板(在 Claude 中为 Artifact),而不是聊天记录。页面会自行运行 stream_events 循环,在每次读取时传递游标,因此一个提示词就能让数据流持续打开。如果页面无法连接到服务,Agent 会运行该循环,并将每个事件写入仪表板。如果你更喜欢上方演示中显示的终端视图,请明确要求输出聊天内容。
1b. 过去十二小时内的事件。 分析实时 SEC 8-K 文件,同时获取投资者关系演示文稿和 5 分钟 K 线数据,以便快速识别出现显著波动的股票:“最新发布的 8-K 文件有哪些?重点介绍其中最重要的文件,通过 Flexreport Finance 获取配套的投资者关系发布内容,为出现显著波动的股票绘制 5 分钟 K 线图,并说明这些信息与各公司的当前状况有何关联。我希望以表格形式呈现:8-K 摘要、公司趋势、Flexreport Finance 8-K 分析 S3 链接、IR 演示文稿链接。”
工具:situate → list_realtime_events,然后调用 get_aftermarket_data / detect_intraday_outlier_jumps 和 get_latest_report。
2. 报告
2a. 特定公司的最新报告: “获取 Snowflake 最新的 Flexreport Finance 报告,并总结本季度的变化:业绩指引、利润率,以及管理层在电话会议上提到的事项。”
工具:get_latest_report(["SNOW"])。新计划约需 10–20 秒完成渲染;对于状态为 stale 或 missing 的标的,可以使用 generate_report_for_stock 重新生成。
2b. 特定时间段内的最新报告: “过去三天,能源行业发布了哪些报告?获取最新报告,并根据相关事件的重要程度进行排序。”
工具:list_available_reports(report_date=<3 days ago>),筛选能源行业标的(list_options("sectors")、get_company_snapshot),然后对状态为 fresh 的标的调用 get_latest_report。
2c. 根据你的标准定制报告: “为我生成一份美国大型市值半导体公司的报告,筛选条件为 ROIC 高于 20%、净债务/EBITDA 低于 1 倍、股价高于 200 日 SMA 且 RSI 低于 60。展示每家公司的基本面、技术指标和最新预期修正,并按我保存的模板排版。”
工具:screen_stocks、explore_data_catalogue(比率、基本面、预期)、get_technical_indicator_data 和 get_user_template。Agent 会按照你的模板整理 PDF;使用 draft_user_template → save_user_template 创建模板。
3. 预测分析
预测即将发布财报的波动性,获取简单移动平均线、指数移动平均线和布林带数据,并生成定制投资备忘录:“预测明天即将发布财报的股票可能出现的波动,重点指出预期波动最大的股票;绘制它们的简单移动平均线、指数移动平均线和布林带;并重点说明当前最重要的基本面驱动因素,将这些内容整理成一份供团队使用的投资备忘录。”
工具:list_earnings_announcements → predict_earnings_move、get_technical_indicator_data、get_company_snapshot。
4. 研究与探索
围绕一个市场叙事开展主题研究:“AI 交易近期有所降温,主要是由于对资本支出和投资回报的担忧。我认为这种情况在 2025 年秋季之前也出现过。你能确认吗?当时有哪些因素消除了这些担忧?是管理层评论、AI 服务需求持续增长、盈利能力强劲,还是上调了指引?请使用 Flexreport Finance 编写一份深入报告。”
工具:explore_data_catalogue(电话会议记录、基本面数据、预估数据)、trace_data_sources / get_document_section(获取引用原文),或 generate_research_report(生成完整报告)。
工具
共 50 个工具,按注册工具的模块分组。客户端按 tools/__init__.py 中的导入顺序看到这些工具(situate 优先)。
情境分析与实时事件(tools/realtime_events.py)
| 工具 | 后端端点 | 功能 |
|---|---|---|
situate(symbols, window_days, question) | GET /get-company-event-web + GET /get-event-ontology + GET /is-market-open | **首次调用。**将事件网络(这家公司发生了什么)、本体(这类事件意味着什么、后续会发生什么、12h 缓存过期后其数据存放在哪里、每张表何时会刷新)和市场状态整合为当前情况,并提供按顺序排列的精确工具调用 plan、会返回空结果的调用 skip 列表,以及针对当前情境的 guidance。计划从问题所指的实时事件类型开始(situate.py 中的 EVENT_VOCABULARY 涵盖 list_options("event_types") 中的所有类型);如果问题只提到某个类别,则遍历该类别下的事件;如果没有提到任何类别,则遍历所有事件——不会使用默认类别;对于面向整个市场的“今天”问题,绝不会安排 explore_data_catalogue。逻辑位于 situate.py(纯函数;python tests/test_situate_routing.py);无需新增后端路由。公开、同步 |
list_realtime_events(event_type, tickers, sector, industry, market_cap) | POST /get-realtime-events | 从 12h 缓存中提取实时事件(EPS 更新、电话会议记录、评级等);每个事件的 report_inputs(约 27 KB 的报告配置)都会被丢弃,但会保留 report_inputs_key |
get_company_snapshot(symbol) | GET /get-company-snapshot | 结构化快照:投资论点、基本面、技术指标、目标价、所有权、评级 |
get_company_event_web(symbol, window_days, max_nodes) | GET /get-company-event-web | 揭示快照背后的原因——公司近期事件的图谱:按时间排序的事件/data_update 节点,包含 fetch 提示和带类型的边(same_chain_run / lineage / co_occurrence)。请将其与 get_company_snapshot 配合使用;针对单个标的调用 list_realtime_events / explore_data_catalogue / 报告工具前,也应先调用此工具 |
get_event_ontology(event_type, family, relation, format) | GET /get-event-ontology | 事件网络背后的类级本体,说明某种事件类型包含什么:事件触发时写入的表(按层分类)、通常会接续发生的事件(观察到的发生率/时滞)、12h 实时缓存过期后数据存放的位置(persisted_in)、负责刷新的工作流及各关系的 next_run_at(新鲜度检查),以及读取这些数据的工具。与标的无关、公开、可缓存——对于任何事件驱动的请求,请先调用此工具,再将其与网络节点的 type / relation / family 关联起来 |
事件流(tools/event_subscriptions.py)
对于实时流式传输的请求,默认交付方式是一个仪表板(在 Claude 中是一个 Artifact),其页面会循环调用 stream_events 并传入游标。服务端说明和流工具的文档字符串都对此进行了说明。
| 工具 | 后端端点 | 功能 |
|---|---|---|
stream_events(topics, symbols, cursor, max_events, max_wait_seconds) | GET /events (SSE) | 推送交付,临时调用。 对实时事件流进行有界读取:达到 max_events 条匹配事件或等待 max_wait_seconds(上限为 55 秒)后返回 {events, cursor, closed} — 每个事件都是 list_realtime_events 返回的同一个对象,即事件发布时的内容。可通过 topics(来自 list_options("event_types") 的事件类型或类别,以及仅限流的 report_plan 主题 — 每次保存报告计划时都会生成一个帧)和 symbols 内联筛选。服务端不保存状态:务必将返回的 cursor 传回,否则下一次调用会从“现在”开始(已认证) |
register_event_subscription(topics, symbols) | POST /register-subscription | 在服务端保存筛选条件 → {subscription_id, filter, cursor, created_at}。只会交付注册后发布的事件;请保存 ID(目前还没有列表端点)。每小时 30 次(已认证) |
stream_event_subscription(subscription_id, cursor, max_events, max_wait_seconds) | GET /event-subscription/{id} (SSE) | 可恢复的推送交付。 有界读取的形式与 stream_events 相同,但 API 会在读取结束时保存游标,因此重复调用时,每条匹配事件都会恰好出现一次,无需管理 cursor;cursor 只会为单次连接覆盖已保存的位置。closed: "subscription deleted" 表示应停止重新连接;对于不存在的 ID 和其他用户的 ID,都会返回 404(已认证) |
delete_event_subscription(subscription_id) | DELETE /event-subscription/{id} | 删除已保存的订阅;任何正在运行的订阅流都会在一个读取周期内以 closed 帧结束(已认证) |
报告与 PDF 模板(tools/pdf_reports.py)
| 工具 | 后端端点 | 功能 |
|---|---|---|
get_latest_report(symbols) | POST /get-cached-reports | 快速路径,适用于一个或多个指定股票代码。具有新鲜已保存计划的股票代码会进入 rendering({task_id, status, symbol}):后端会获取计划 JSON,并在约 10-20 s 内将其渲染到用户的模板中——轮询 get_task_status 获取 {"pdf": ...}。其他股票代码则返回缓存的 PDF(预签名 URL + 内联 base64,并附带 generated_at、age_hours、latest_event_at、stale),或列在 missing 中。stale: true 表示计划本身已过期——只有重建 generate_report_for_stock(ticker)(约 10 min)才能刷新。每小时 500 次 |
list_available_reports(event_types, report_date) | POST /list-available-reports | 查询 report_date(YYYY-MM-DD,默认为今天)或之后生成的已保存报告计划清单(计划在 7 天内都可渲染,因此查询当前清单时请传入更早的日期——空列表表示该时间范围内没有计划,而不是没有研究)——列出每个因重大事件(eps_update、eps_release、8k_release、financials_release、ir_publication、transcript_update;company_update 每晚执行)而保存计划的股票代码,按最新时间优先排列,每项包含 event_type、planned_at、queued_at、source,以及应用与 /get-cached-reports 相同规则的 fresh 标志:true → get_latest_report([ticker]) 在约 10-20 s 内渲染,false → 只有重建 generate_report_for_stock(约 10 min)才能刷新。可通过 event_types 筛选;通过 report_date 扩大范围(日期格式错误会返回 422)。可用于检查 list_realtime_events(刚刚发布的内容)与 get_latest_report(获取内容)之间的情况,也是查看当前可用实时研究的直接方式 |
generate_report_for_stock(ticker, user_override, financial_items, as_reported_financial_items, ratios, revenue_segment, technical_analysis_items, estimate_items, institutional_ownership, include_as_report_financials, as_reported_periods) | POST /create-full-report | 仅用于完整重建(约 10 min)——请谨慎使用。 标准模式(仅 ticker):重建并保存该股票代码的报告计划;只有当 get_latest_report 返回该股票代码的 stale 或 missing,且用户愿意等待时才调用——绝不要对处于 rendering 状态的股票代码调用。自定义模式(user_override=true + 定制列表):围绕用户指定的行项目、比率、按报告口径列示的概念、细分项、指标、估算值或管理者 CIK,完整生成一次报告(约 10 min,不保存);只要某个定制字段非空,该工具就会自动设置开关。对于定制需求,通常应先探索 → 构思 → 再叠加到模板中。异步返回 → {ticker: {task_id, status}} |
generate_research_report(query, delivery) | POST /generate-research-report | 深度分析(约 10-12 min,异步)——分析师级别的报告,仅在用户明确要求完整报告时使用 → {task_id, status} |
download_pdf_from_url(url, file_name) | POST /download-pdf-from-url | 在服务端获取预签名的 S3 PDF URL(带 SSRF 防护),并以内联 base64 返回——例如,供无法打开链接的客户端使用 get_latest_report 的 url(需认证) |
draft_user_template(template, template_type, anchor) | POST /draft-user-template | 用户自有 PDF 格式的第 1 步,共 2 步:将 HTML 页面编译为蓝图,提供多种处理样式,并将每种样式渲染为平台示例文档的预签名 PNG 预览——每种内容类型各一份(标题、导语、章节、项目符号、KPI 卡片、表格、图表、插图、来源行、脚注);add_on 按其在报告中的栏宽呈现,bespoke 则呈现为整页——另附 draft_id。用户确认设计如何处理每种内容类型,而不是确认示例文本。不会存储任何内容——草稿有效期为 24h(需认证,每分钟 30 次) |
save_user_template(draft_id, variant_id, template, template_type, anchor) | POST /save-user-template | 第 2 步,共 2 步:传入 draft_id + 选定的 variant_id,即可保存已审核的处理样式;或直接传入 template + template_type(+ anchor)以跳过预览(仅支持 HTML——markdown 会返回 422)。每位用户只能有一个模板——采用 upsert,保存时会替换之前的模板。返回 {status: "SAVED", template_type, anchor, bytes, patterns, tones, warnings}——包括设计所采用样式的内容类型及其语气类别(需认证,每分钟 100 次) |
update_user_template(template, template_type, anchor, draft_id, variant_id) | PUT /update-user-template | 更改已保存的模板——可更改任意字段(省略的字段保留已存储值),也可不传任何字段,以当前编译器按已存储内容重新编译。异步返回:{task_id, status: "PENDING", changed, next_step} → 轮询 get_task_status 获取 {status: "SAVED", patterns, tones, warnings}。404 = 尚未保存任何内容(请先保存);422 = 验证错误(需认证) |
get_user_template() | GET /get-user-template | 调用者已保存的模板(template_type、template_format、anchor、经清理的 template、时间戳)。404 = 未保存;503 表示后端表尚未创建,并非“未保存任何内容”。同时提供用于排版 Agent 组合生成的 PDF 的标记 |
delete_user_template() | DELETE /delete-user-template | 删除已保存的模板——此操作不可撤销,PDF 将恢复为标准版式;在 WHERE 子句中强制执行所有权检查 |
Data exploration, citations & saved queries (tools/data_exploration.py)
| 工具 | 后端端点 | 功能 |
|---|---|---|
explore_data_catalogue(query) | POST /data-catalogue-exploration | 默认路由——针对数据平台开展快速、交互式 EDA → 返回可渲染为图表/表格的结果集(仅限仪表板,每小时 20 次)→ {task_id, status} |
explore_data_coverage(query) | POST /data-coverage-exploration | 覆盖范围计数和细分——有多少标的包含某数据集(IR 演示文稿、文字记录、13F、内部人士、预估数据……),按行业板块/行业/国家/市值/年份细分,以及历史数据覆盖范围。公开访问:无需账号,因此潜在客户可以询问平台涵盖哪些内容 |
get_signed_sql_drilldown(encrypted_query_token, prompt, values, max_rows) | GET /query-data | 根据 get_company_event_web 节点的 signed_query_url(或其裸 t 令牌),获取其背后的数据行——包含标记为 is_new_record: true 的新记录,以及上下文行;令牌仅由服务端生成,绝不自行构造。可选的 values(类型化槽位填充,不使用 LLM)和 prompt(自然语言,填充 values 未提供的内容)可将作为占位符孪生的令牌重新定向到其他实体;max_rows 限制返回数据量,截断的回复会附带 row_count 和 truncated: true(需认证) |
trace_data_sources(relation, keys, column, encrypted_query_token, prompt, values, max_documents, resolve_passages) | GET /trace-sources | 引用溯源——将 explore_data_catalogue / run_saved_query / get_signed_sql_drilldown 返回行中的数字追溯到其出处:文件、章节或经核实的引文。优先使用 relation + keys(所有标识列,包括期间),而非令牌 |
get_document_section(symbol, year, quarter, n, name) | GET /query-section | 打开源文档中的一个编号章节——即 trace_data_sources 引用所指向的准确财报电话会议发言者轮次。从引用 URL 中读取这四个值;year / quarter 是电话会议的财年期间,而非日历季度 |
save_user_query(user_request, query_tokens) | POST /save-user-query | 按用户自己的措辞保存 explore_data_catalogue 结果中不透明的 query_token,以便无需重新规划即可重放请求。返回 {msg, id, placeholder_status}——id 是删除时使用的键;PENDING 表示后端正在为每个查询编写占位符孪生,并为该行生成 metadata 槽位架构(约需 10 秒至 5 分钟),之后便可针对其他实体重新提问;NOT_DISPATCHED 表示只能精确重放(需认证,限定所有者;不执行 upsert——保存两次会创建两行,每分钟最多 100 次) |
list_saved_queries(limit) | GET /get-saved-queries | 调用者保存的请求,按时间从新到旧排列——包括 id(删除时使用)、queries(用于精确重放的令牌)、query_placeholder(与 queries 按索引对齐的孪生令牌)、user_request(用户自己的标签),以及 metadata:该行的 summary(一行说明,槽位用花括号括起)、parameters 槽位架构({name, type, description, example}——即 run_saved_query(values=…) 的键)、entities、datasets、topics、每个查询的 result_schema、stale、run_count、last_run_at。根据 metadata 匹配问题,而不是根据标签,并跳过 stale 行;占位符任务运行前,metadata 和 query_placeholder 均为 null。503 表示后端表尚未创建,而非“没有已保存内容” |
run_saved_query(query_tokens, prompt, values, max_rows) | GET /query-data | 重放已保存的请求:每个令牌都会按给定顺序针对实时数据同步运行(最多 25 个)——仅返回数据行,绝不返回 SQL;耗时为几秒,而非约 1–5 分钟的规划任务,且不占用每小时 20 次的探索额度。使用 query_placeholder 令牌时,values(以 metadata.parameters 为键确定性填充,不使用 LLM——实体集合槽位接受 [{id, name}] 行,若仅提供名称,则由服务端解析)会重新定向已保存的查询;prompt(“KSS 过去 8 个季度的销售额”)仅填充 values 未提供的内容,既未由 values 覆盖也未由 prompt 填充的槽位则保留已保存的示例。回复包含 parameters、defaulted_parameters 和 ignored_values;422 表示无法映射该请求——请改用 explore_data_catalogue。始终传入 max_rows(例如 500):不设上限时,一行的 _constituents 配套数据可能返回 7,000–35,000 行 |
delete_saved_query(query_id) | DELETE /delete-saved-query | 根据 id 删除一条已保存的请求——此操作不可撤销,相关令牌也会一并删除;404 有意同时涵盖“该 id 不存在”和“该 id 不属于你” |
市场数据(tools/market_data.py)
| 工具 | 后端端点 | 功能说明 |
|---|---|---|
get_technical_indicator_data(symbol, indicator, start_date, end_date) | GET /technical-indicator-endpoint | 获取一个技术指标的每日历史数据(来自 list_options("technical_indicators")),日期范围为含首尾的 YYYY-MM-DD(需认证) |
detect_intraday_outlier_jumps(symbol, frequency, zscore_threshold) | GET /detect-intraday-outlier-jumps | 实时查看今日的 1 分钟行情;按 frequency(来自 list_options("intraday_frequency"))筛选;标记波动幅度属于日标准差异常值的 K 线(同步,需认证) |
get_aftermarket_data(symbols, start_datetime, end_datetime) | POST /get-aftermarket-data | 查询指定股票在 ET 日期时间范围内已存储的盘后 15 分钟 K 线(开盘价/最高价/最低价/收盘价/成交量,16:00-20:00 ET);按股票代码、K 线时间降序排列(默认为今日,需认证,每分钟 300 次) |
predict_earnings_move(symbols) | POST /predict-earnings-announcement-move | 预测各股票下一次财报发布后的预期涨跌幅(例如,NFLX 的 expected_move 为 0.10,即约 10%),并与其自身的历史平均值并列显示 |
list_earnings_announcements(start_date, end_date, symbols, industry, sector, market_cap) | POST /list-upcoming-earnings-announcements | 查询指定日期范围内(起止日期默认为今日)已安排的财报发布;仅包含覆盖范围内的股票;sector / industry / market_cap 由服务端校验(无效值返回 422) |
is_market_open(exchange) | GET /is-market-open | 查询交易所当前是否开放——返回单个 is_open 布尔值(交易所代码,默认为 NYSE);根据市场状态路由至 detect_intraday_outlier_jumps(开放时)或 get_aftermarket_data(关闭时)。公开 |
数据源(tools/data_feeds.py)
| 工具 | 后端端点 | 功能 |
|---|---|---|
download_dataset(dataset, start_date, end_date, latest_file_version, bulk_download, event_types, symbols, include_page_text, document_urls, max_rows) | GET /list-data-feed-options + POST /download-dataset | 按日期读取 Flexreport 的带版本的每日数据源文件。数据源并非硬编码:每次调用都会先读取公开目录(list_options("data_feeds")),并在开始下载前拒绝未知的 dataset 或 event_types;目录中的 returns 决定返回行还是预签名链接(有效期 12 小时);如果未请求页面文本,带有 document_url + page_number 的行会合并为每份文档一行。每位用户每周限 3 次调用,因此必须提供 start_date(明确的 ET 日期,绝不使用 API 的 UTC 默认值),工具会在单次响应中自行缩小结果范围:按 symbols / document_urls 过滤、合并页面、设置 max_rows 上限(默认 500),并返回 row_count / truncated,以及说明省略内容的 notes。获取一次并嵌入;绝不要从仪表盘轮询(需认证) |
draft_custom_dataset(request, previous_draft_id, feedback, sample_rows, target_format) | POST /draft-custom-dataset | 用户自定义定时数据集的第 1 步:根据通俗英文描述规划候选表并对每张表进行采样;target_format 为 rss/atom 时,每个数据源项目对应一行。异步执行(task_id = draft_id,通过 get_task_status 查询,约 45 秒至 4 分钟;sample_rows 为 1-5,默认 5)。对于事件/新闻数据源,Agent 会先进行调研(定位 + 本体、与用户确认定义、执行一次限定范围的探索性普查),并发送一个指出每个字段对应表和列的请求;普通数据源则直接生成草稿。默认情况下,每个数据源都会包含调研报告:构建过程会为带有 symbol / ticker 列的行添加 research_url,因此请求中无需填写报告链接;结果中的候选项带有不透明的 query_token,该令牌绝不显示,只会传递给保存步骤。使用相同的 request + previous_draft_id + feedback 进行修改。每位用户每小时限 20 次(需认证) |
save_user_dataset(draft_id, query_token, dataset_name, date_mode, cron, format, build_now) | POST /save-user-dataset | 第 2 步:保存所选候选项及其架构、格式(parquet、csv、tsv、json、jsonl、xlsx、xml、rss、atom)、日期模式(rolling 会将固定日期移至每次构建日期,snapshot 会按保存时的查询重新运行)以及任何有效的 5 字段 ET cron(每小时、每 30 分钟、范围)。发布前会由 LLM 审核新项目,每次构建最多 40 个(大型首次构建的其余项目会按查询结果发布,之后再审核;链接/GUID/股票代码/日期永不更改);rss 项目带有 <company:symbol> 和最多 10 个 <category>,每个 guid 对应一个项目。每个带有 symbol / ticker 的行都会获得 research_url,这是指向该股票代码最新调研报告 PDF 的固定签名链接(/user-dataset-research/<token>/<SYMBOL>,无需登录),在 rss/atom 项目中显示为“Research”链接。按名称执行 upsert;计划会以 ds:{email}:{name} 的形式显示在 list_scheduled_tasks 中。返回 latest_url(指向最新文件的固定免登录链接)以及 rss/atom 的 feed_fields。最多 5 个数据集;与工作流共用 10 个计划(需认证) |
list_user_datasets(dataset_name, start_date, end_date, latest_only) | GET /list-user-datasets | 用户的数据集,包含最近一次构建状态(written / unchanged / empty / too_large / schema_drift / failed)以及指向每次构建文件的 12 小时预签名链接——交给用户,不要获取文件(需认证) |
get_user_dataset_file(dataset_name, version) | GET /list-user-datasets + latest_url 中的文件(或某个日期版本的预签名链接) | 读取用户已发布的一个数据集并返回其行(json、jsonl、csv、tsv、xml,或带有类别、股票代码和 research_url 的 rss/atom 项目)。仪表盘应以此读取数据集,而不是重放其已保存的查询;文件会在响应大小上限内由服务器端获取,不使用 bearer(链接本身就是密钥)(需认证) |
delete_user_data_feed(dataset_name) | DELETE /delete-user-data-feed | 完全移除用户的一个数据集:计划、文件、固定链接和已保存的查询。此操作不可撤销,因此 Agent 会先确认;遇到 503 时可安全重试(需认证) |
筛选、投资组合与策略(tools/strategies.py)
| 工具 | 后端端点 | 功能 |
|---|---|---|
screen_stocks(metrics, sectors, sub_sectors, market_cap, analyst_ratings, institutional_ownership, countries, price_performance) | POST /screen-stocks | 按增长指标、行业/子行业、市值、分析师评级、机构持仓、国家和价格表现筛选股票范围。异步 → {task_id}(每小时 10 次) |
optimize_portfolio_default(symbols, risk_tolerance) | POST /optimize-symbols-non-llm | 默认优化器——为股票代码列表计算经过风险优化的权重;同步执行,不使用 LLM;不支持的股票代码列于 missing,历史数据较短的列于 dropped。公开 |
optimize_portfolio(symbols, risk_tolerance, delivery) | POST /optimize-symbols | 速度较慢的 LLM 筛选版本:多信号评分 + LLM 筛选 + 风险优化。异步 → {task_id}(每小时 10 次) |
get_stock_picks(strategy_name) | GET /get-stock-picks | 获取当前再平衡周期中最新的 LLM 选股结果(可选指定一个策略) |
get_strategy_performance_summary(amount) | GET /get-strategy-performance-summary | 展示自成立以来每个策略组合与 S&P 500 的排行榜(回报、超额回报、夏普比率、回撤、年初至今表现、amount 的增长)——了解“这些选股表现如何?”的首选入口 |
get_strategy_track_record(strategy_name, book, amount) | GET /get-strategy-track-record | 展示单个组合自成立以来的每日表现序列及与 S&P 500 的对比,以及关键统计数据;book = llm(默认)或 mechanical,strategy_name 可以是 pooled |
get_strategy_swaps(strategy_name) | GET /get-strategy-swaps | 按交易记录每周的加入/移除项,并分别与 S&P 500 对比(移除项按错失的回报计算) |
调度(tools/scheduling.py)
| 工具 | 后端端点 | 功能 |
|---|---|---|
schedule_task(name, steps, regular_cron, delivery, description) | POST /save-user-workflow | 保存一个包含 1–8 个步骤的工作流(fetch 允许列表中的端点 + transform 步骤),并附加定期 cron 投递;按小写连字符格式的 name 执行插入或更新 |
list_scheduled_tasks() | GET /get-scheduled-tasks | 调用者的 cron 作业(name、schedule、enabled、last_run_at、total_run_count);工作流作业的名称格式为 wf:{email}:{workflow-name} |
delete_scheduled_task(task_name) | DELETE /delete-scheduled-task | 按 list_scheduled_tasks 返回的完整 name 删除 cron 作业;保留已保存的工作流定义 |
实用工具与计费(tools/utility.py)
| 工具 | 后端端点 | 功能说明 |
|---|---|---|
get_task_status(task_id) | GET /task-status | 轮询异步任务,直至状态变为 SUCCESS,并读取其 result。超过 8 MB(MCP_MAX_TASK_RESULT_BYTES)的结果将被拒绝,并返回“请缩小查询范围”错误;在 _send 中,其他所有后端响应的大小上限均为 16 MB(MCP_MAX_RESPONSE_BYTES) |
list_options(kind, ticker, q, cik) | GET /list-realtime-event-options、/list-financial-items、/list-financial-ratios、/list-as-reported-items?ticker=、/list-revenue-segments?ticker=、/list-institutional-managers?q=&cik=、/get-sectors、/list-institutional-investor-types、/list-countries、/get-fiscal-quarter、/list-marketcap-options、/list-intraday-chart-options、/list-technical-indicators、/list-tickers、/list-symbols-with-names、/list-data-feed-options | 一个目录工具:列出某个参数的有效值(事件类型、明细项目、比率、申报方自己的 as-reported XBRL 概念和营收细分(ticker)、按名称片段 / CIK 查找机构管理人(q / cik)、行业板块、投资者类型、国家、财年季度、市值区间、日内频率、技术指标、带或不带公司名称的股票代码全集,以及 download_dataset 数据源) |
list_sub_industries(sectors) | GET /get-sub-industries | 给定行业板块中的不同细分行业 |
onboard_symbol(symbol) | POST /onboard-symbol | 请求接入尚未覆盖的股票代码(异步、需认证,每小时 5 次) |
upgrade_plan() | GET /payment/upgrade-link | 用于升级或更改用户套餐的结账链接(例如,达到配额上限后);付款在浏览器中完成 |
manage_billing() | GET /payment/portal-link | Stripe 账单门户链接 — 发票、银行卡、取消订阅 |
对于单家指定公司,get_company_snapshot 和 get_company_event_web 是标准组合——它们是同一个问题的两个部分,通常会一起调用。快照说明是什么(公司当前的状况:投资论点、基本面、技术面、持仓、评级);事件关系网说明为什么(背后的事件经过:业绩公布 → 8-K → 电话会议记录更新 → 投资者关系部门发布内容 → 分析师反应,并通过边说明各事件之间的关系)。单独的快照只是没有证据支撑的结论;事件关系网则提供了证据。事件关系网也是成本低廉的依据调用,能让后续工作流更加精准——每个节点都附带确切的后续调用,因此接下来的 list_realtime_events、explore_data_catalogue 或报告请求都能使用真实的事件类型和日期,而不是猜测。
典型 Agent 工作流:对于开放式 / 探索性问题,默认使用 explore_data_catalogue(query)(快速交互式图表 / 表格)。仅在意图非常明确时才升级调用——对于指定股票代码的现有报告,使用 get_latest_report(symbols);要筛选整个股票全集,使用 screen_stocks(...);要进行明确的深度研究,使用 generate_research_report(query)(约需 10–12 分钟,异步——使用 get_task_status 进行轮询)。
重复问了同一个问题——还是问了关于另一家公司的同一个问题?explore_data_catalogue 每次都会重新规划 SQL,因此一次探索完成后,Agent 会提出保存结果:save_user_query 会存储其 query_token,后端则为每个查询创建一个占位符孪生查询——将股票代码、CIK 列表、日期、间隔和数量提取为类型化槽位——并保存该行的 metadata,其中会命名这些槽位并概述该行查询的内容。run_saved_query 随后会原样重放该行的 queries(使用实时数据运行相同查询,几秒内完成,无需规划步骤,也无需轮询),或者使用该行的 query_placeholder 令牌和类型化的 values,将请求重新指向其他实体——昨天保存的“TGT 最近 8 个季度的销售额”,今天便能确定性地回答“KSS 最近 8 个季度的销售额”,填充过程不使用大模型;替换后的 parameters(以及任何 defaulted_parameters / ignored_values)会与结果行一并返回;prompt 仍可用于处理 Agent 无法填入的内容。每次探索前都应先检查 list_saved_queries,它会将问题与每行的 metadata——summary、parameters、datasets——进行匹配,而不是与其 user_request 标签匹配,并跳过标记为 stale 的行;delete_saved_query 可清除其中一行。每次重放都要传入 max_rows,并根据 metadata.result_schema 选择要运行的查询,这样 _constituents 配套查询(7,000–35,000 行)就不会被纳入调用。令牌是后端生成的不透明密文:原样传递,绝不要自行构造或编辑,也绝不要向用户展示。
想要使用自己的格式生成报告?用户提供一个 HTML 页面——包括页眉、颜色、布局和品牌元素——并将其保存为蓝图:作者的样式表和页面框架,加上每种内容类型对应的一种标记模式;后端会自动将其应用于为该用户生成的每份 PDF(get_latest_report 对新计划的渲染、generate_report_for_stock 的重建版本、标准版和自定义版,以及定期报告)。模板是应用于文档自身内容的结构和样式:没有人会填充模板标记,也不会有其他调用来修改它。这是视觉选择,因此需要通过查看来批准:draft_user_template 会使用多种处理方式编译页面,并将每种处理方式渲染为平台样本文档的 PNG 预览(add_on 会按 anchor 指定的名称重新设置标准布局中某个部分的样式;bespoke 则控制整个文档);用户选定一种后,save_user_template(draft_id, variant_id) 会保存该样式——每位用户只有一个模板,采用 upsert 方式保存。update_user_template 可在之后修改任何字段,或者在不带参数调用时重新编译已保存的设计;get_user_template 会显示当前生效的模板;delete_user_template 会让用户恢复使用标准布局。
没有由 Agent 驱动的 PDF 构建器:build_pdf_full_width / build_pdf_sidebar 工具(后端 /create-pdf 和 /create-pdf-sidebar)以及 pdf_options 目录已弃用,改用模板。当用户想要一份由 Flexreport Finance 数据组成、且没有后端报告覆盖的文档时——包括定制的公司报告(例如“以产品收入和 RPO 为核心构建的 SNOW 报告”)——Agent 会探索用户指定的条目,与用户一起构思并完善结果集,再使用自己的文档工具构建 PDF;如果用户已保存模板,则将商定的结果叠加到该模板中(get_user_template);如果没有模板,则提议起草一个(起草 → 预览 → 保存,然后更新)。
报告按需生成:只有有人提出请求时才会重新生成。两个报告端点严格分开:
get_latest_report→/get-cached-reports是快速路径。 已保存的报告计划是 JSON,包含摘要、查询、结果和格式映射;当某个标的发布重大事件时(或通过重建),系统会立即生成该计划,并在其输入持续变化期间每晚刷新。当某个标的的计划新鲜(有格式映射、生成时间不到 7 天、不早于该标的最新报告输入,且读取 EDGAR/FMP 数据分流的正确一侧)时,端点不会返回预先生成的 PDF:它会在约 10-20 秒内将该计划渲染到用户的模板中,并在rendering下列出该标的,同时提供用于轮询的task_id。其他标的则会以缓存的 PDF 返回,并标记为stale(true= 计划本身已过时,即之后出现了财报、文件提交或 13F 刷新),或者归入missing。generate_report_for_stock→/create-full-report是完整重建(约 10 分钟),应谨慎使用。 只有当get_latest_report将该标的返回为stale或missing,且用户愿意等待时,Agent 才会仅使用股票代码调用它;重建后的计划会被保存,因此之后调用get_latest_report时,只需几秒即可渲染。绝不用于处于rendering状态的标的,也绝不对列表中的多个标的批量调用。- 定制请求应通过探索完成,而非重建。 Agent 会探索用户指定的项目(先调用
list_saved_queries,再调用explore_data_catalogue),与用户一起构思如何使用结果集,并通过自有的文档工具将双方确认的结果叠加到用户的模板(get_user_template)中。
list_available_reports(event_types, report_date) 用于盘点已保存的计划,范围限定为在 report_date 当天或之后生成的计划(默认值为今天)——显示哪些标的已准备好实时研究,以及每个计划是新鲜的(get_latest_report 可在几秒内完成渲染)还是需要重建(需几分钟)——这样 Agent 就能从 list_realtime_events(事件已发布)直接获取新鲜报告,而不必猜测;也可以跳过事件步骤,直接列出当前可用的报告。对于“提取今天最相关的报告”,应先用事件筛选,再检查计划是否可用:提取重大事件类型(transcript_update、8k_release、ir_publication、eps_release、financials_release)和市场行情(biggest_mover、biggest_loser),读取内容,通过 detect_intraday_outlier_jumps 根据日内价格走势确认重要性,将符合条件的事件与计划通过 list_available_reports(event_types=[...]) 匹配,然后仅通过 get_latest_report 提取匹配的报告。每当市场范围的计划出现此建议时,situate 都会显示该建议;如果 12 小时实时窗口在更早的 UTC 日期开启,还会附带 report_date。只有当用户明确要求围绕指定项目重建流水线自身的报告时,才会生成自定义报告——设置 user_override=true,并提供塑形列表(financial_items、ratios、as_reported_financial_items、revenue_segment、technical_analysis_items、estimate_items、机构持仓 institutional_ownership CIK,以及 include_as_report_financials / as_reported_periods)——这是一次完整构建(约 10 分钟),且绝不会保存。若未设置开关却提供了塑形列表,后端会拒绝请求(422),因此只要塑形字段非空,工具就会设置该开关。可用词汇表来自 list_options:financial_items、financial_ratios、technical_indicators,以及按股票代码限定的 as_reported_items / revenue_segments 和按 q 限定的 institutional_managers(返回 CIK)。事件上下文由服务端管理——请求中不包含论点、变更摘要、include_* 或价格日期字段。
代码布局
server.py entrypoint: imports the tools package, adds /health, runs the transport
core.py the FastMCP instance, server instructions and `_send` (backend forwarding)
client.py shared httpx client + inbound-bearer forwarding
auth_verifier.py OAuth resource-server token validation (RS256 via the backend JWKS)
situate.py pure composition logic behind the `situate` tool
instructions.json server instructions (non-code copy)
tools/
realtime_events.py situate, list_realtime_events, company snapshot / event web, event ontology
event_subscriptions.py stream_events, register / stream / delete_event_subscription (SSE bounded reads)
pdf_reports.py get_latest_report, list_available_reports, generate_*, download_pdf_from_url, PDF templates
data_exploration.py explore_data_*, signed drilldowns, trace_data_sources, document sections, saved queries
utility.py get_task_status, list_options, list_sub_industries, onboard_symbol, billing
market_data.py technical indicators, intraday outliers, after-hours bars, earnings calendar + move prediction, market status
data_feeds.py download_dataset (versioned daily feed files), user datasets (draft / save / list / delete)
strategies.py screen_stocks, portfolio optimization, stock picks, strategy track records
scheduling.py schedule / list / delete scheduled tasks
每个模块都会执行 from core import mcp, _send,并通过 @mcp.tool(...) 注册;导入 tools 会注册所有工具。tools/__init__.py 固定了导入顺序,这也是向客户端展示工具的顺序(situate 排在最前)。
本地运行
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # set API_BASE_URL, MCP_HOST, MCP_PORT
set -a && source .env && set +a
python server.py # serves streamable-http on http://MCP_HOST:MCP_PORT/mcp
身份验证
该服务器是一个OAuth 2.0 资源服务器,并且是无状态的(适合负载均衡),因此每次调用都会携带身份验证信息。它不保存凭据,也不保存签名密钥——它会验证传入的 Bearer 令牌,并将其转发给后端,由后端执行范围、套餐和配额检查。
工作原理
登录采用标准的浏览器授权码 + PKCE流程,由你的 MCP 客户端(例如 Claude)通过 Flexreport Finance 后端(即授权服务器)执行。你可以使用电子邮件和密码注册或登录,也可以使用 Google Sign-In——无需粘贴或输入令牌:
- 收到不含有效令牌的请求时,服务器会返回
401和WWW-Authenticate挑战,并在/.well-known/oauth-protected-resource提供受保护资源元数据,指引客户端访问后端 AS。 - 客户端会打开浏览器;你登录并同意授权后,客户端会收到由后端签发的 RS256 访问令牌。
- 服务器会在每次调用时验证该令牌——通过后端的 JWKS(RS256 公钥)验证签名,并验证
aud、iss和exp——然后将令牌转发给后端。令牌无效或已过期时,服务器会返回明确的401,客户端会重新执行此流程。
服务器永远不会看到你的密码,也不会持有签名密钥——它始终是一个不持有凭据的代理。只接受有效的 RS256 OAuth 令牌;不支持密码或静态 JWT 回退方式。
配置(环境变量)
| 变量 | 默认值 | 用途 |
|---|---|---|
OAUTH_ISSUER | https://app.flexreportfinapi.com | 预期令牌的 iss,以及公布的授权服务器。必须与后端的 iss 一致——生产环境使用根域名 https://flexreportfinapi.com。 |
OAUTH_AUDIENCE | = OAUTH_ISSUER | 预期令牌的 aud。将两端都设为规范 MCP URL,以实现真正的受众绑定。 |
OAUTH_JWKS_URL | {issuer}/.well-known/jwks.json | 获取公钥的地址(与签发者解耦,以适应容器网络)。 |
MCP_RESOURCE_URL | https://mcp.flexreportfinapi.com/mcp | 此服务器的规范资源标识符(PRM resource)。 |
静态请求头
在 MCP 客户端中配置 Authorization: Bearer <OAuth access token>,服务器会像处理其他调用一样验证并转发令牌——适用于使用其他位置签发的令牌进行测试。令牌不会持久化存储;每次调用时都会转发。
接入 MCP 客户端
.mcp.json(Claude Code):
{
"mcpServers": {
"flexreport": {
"type": "http",
"url": "http://localhost:8000/mcp",
"headers": { "Authorization": "Bearer <YOUR_OAUTH_ACCESS_TOKEN>" }
}
}
}
使用 MCP Inspector 验证
npx @modelcontextprotocol/inspector
# Connect to http://localhost:8000/mcp with header Authorization: Bearer <OAuth access token>
# Confirm the tools list loads (46 tools), then exercise:
# list_realtime_events("eps_update") -> events (or [])
# get_company_event_web("NVDA") -> event graph (or an empty/degraded web)
# get_latest_report(["AAPL"]) -> rendering task_id, cached PDF url, or missing [named-ticker report; max 100 symbols]
# list_available_reports(["eps_release"]) -> plans built today with `fresh` flags (or []); report_date="YYYY-MM-DD" widens
# explore_data_catalogue("MU EPS growth last 8 quarters") -> task_id [default exploratory route]
# get_task_status(task_id) -> eventually SUCCESS
# Negative: connect with no/invalid token -> 401 + WWW-Authenticate challenge
部署
构建镜像并将其作为独立容器运行(例如,使用独立任务定义的单独 ECS 服务),与 API 和 Celery 工作进程分开。将 API_BASE_URL 设置为已部署的后端 URL。
docker build -t flexreport-mcp .
docker run -p 8000:8000 -e API_BASE_URL=https://flexreportfinapi.com flexreport-mcp
隐私
Flexreport Finance 的隐私政策——包括收集的信息、保留期限和涉及的第三方——已发布于 app.flexreportfinapi.com/privacy (来源:PRIVACY.md)。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。
