关于 parsec-edgar: SEC EDGAR filings
parsec-edgar 是以 Rust 编写的 SEC EDGAR 客户端,提供 Python 绑定、命令行工具和 MCP 服务,供用户查询与处理公司申报文件。它支持按章节读取、全文搜索和批量抓取,并遵守 SEC 请求频率限制。
主要功能
- 01按股票代码和 CIK 查询公司
- 02按表格类型和日期筛选申报文件
- 03清理文本并解析 Item 章节
- 04EDGAR 全文搜索
- 05可续跑的批量申报抓取
适用场景
- 01阅读 10-K、10-Q 或 8-K 的指定章节
- 02搜索申报文本并读取匹配的附件
- 03按表格类型和日期构建本地申报数据集
MCP 相关
MCP 服务提供公司查询、申报列表与提纲、章节和文档读取以及全文搜索工具,支持 stdio 和 Streamable HTTP 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
parsec-edgar
使用 Rust 编写的高速 SEC EDGAR 客户端和文件解析器,提供 Python 绑定和命令行工具。
- 按股票代码或 CIK 查找公司
- 按表单和日期筛选,列出公司的申报文件,包括可追溯至 1994 年的完整历史记录
- 将申报文件 HTML(或旧版纯文本提交内容)转换为简洁文本,保留表格行在同一行,并将
$符号与数字合并 - 将 10-K、10-Q 和 8-K 申报文件拆分为 Item 章节(Item 1A 风险因素、Item 7 MD&A、8-K Item 2.02 等)
- 遵守 SEC 公平访问限制(默认每秒 8 个请求,最多 10 个),并在磁盘上缓存存档文档
状态:早期开发阶段(0.1.1)。
安装
pip install parsec-edgar # Python library, plus the parsec-edgar command and MCP server
cargo install parsec-edgar-cli # the parsec-edgar command, built from source (Rust 1.88 or newer)
cargo add parsec-edgar # the Rust library
Python wheel 适用于 Linux(x86-64 和 ARM64)、macOS(Intel 和 Apple 芯片)以及 Windows(x86-64),支持 Python 3.10 及更高版本。每个 GitHub 发行版也提供适用于相同平台的独立 parsec-edgar 二进制文件。
SEC User-Agent 要求
SEC 要求每个请求都通过名称和联系邮箱标识调用方。请显式传入,或设置 PARSEC_EDGAR_USER_AGENT(edgartools 使用的 EDGAR_IDENTITY 变量也适用):
export PARSEC_EDGAR_USER_AGENT="Example Corp [email protected]"
命令行
parsec-edgar company AAPL
parsec-edgar filings AAPL --form 10-K --limit 5
parsec-edgar filings MSFT --form 10-K --since 1994 --until 2002 # reaches into older history pages
parsec-edgar text AAPL --form 10-K # clean text of the latest 10-K
parsec-edgar sections AAPL --form 10-K --item 1A --item 7 # JSON
parsec-edgar sections MSFT --form 10-Q --no-text # ids, titles and offsets only
parsec-edgar sections AAPL --accession 0000320193-26-000026
存档文档(申报文件、申报文件索引页以及完整索引中已结束季度的内容)会缓存在 ~/.cache/parsec-edgar 中(使用 --cache-dir 或 PARSEC_EDGAR_CACHE 更改缓存目录,使用 --no-cache 禁用缓存)。申报文件列表、股票代码文件和全文搜索结果不会缓存在磁盘上,因此每次执行命令都会重新获取。MCP 服务运行期间会将其中一部分保存在内存中(见下文)。
MCP 服务
parsec-edgar mcp 会运行一个 Model Context Protocol 服务,让 Claude 和其他大模型客户端能够查询公司、列出申报文件、搜索 EDGAR 全文,并逐个章节阅读申报文件。它是命令行工具的一部分,使用相同的 User-Agent、缓存目录和速率设置。使用 uv 时,uvx parsec-edgar mcp 无需预先安装任何内容即可运行;否则,请按上述说明安装该命令。该服务在 MCP registry 中列为 io.github.ciscoriordan/parsec-edgar。
| 工具 | 返回内容 |
|---|---|
find_company | 最多 10 家与股票代码、CIK 或部分公司名称匹配的申报方 |
list_filings | 精简条目(accession、表格类型、申报日期、报告期、8-K 项目),可按表格类型和申报日期筛选 |
get_filing_outline | 申报文件元数据、总长度,以及各 Item 章节的 ID、标题和字符数,不含正文 |
read_section | 单个 Item 章节的纯文本,每次最多 max_chars 个字符(默认 20,000);还有更多内容时会返回 next_offset |
read_filing_text | 以相同方式读取整个主要文档,适用于没有 Item 章节的表格(S-1、DEF 14A、20-F 等),或读取由 document 指定的某个附件 |
search_full_text | 2001 年以来 SEC 全文搜索的匹配结果:公司、CIK、表格类型、申报日期、accession 和文档 URL;如果匹配内容位于附件中,还会返回附件类型和文件名(document) |
工具描述会引导模型先调用 get_filing_outline,然后只读取所需章节。对于 Apple 的 2026 年 10-K,概要约有 2,200 个字符,而全文有 230,000 个字符,仅“风险因素”就有 86,000 个字符。偏移量以字符计数;如果接近长度限制的位置存在段落、行或单词边界,页面就会在该边界处结束。出错时(股票代码或 CIK 未知、章节缺失、日期无效),工具会返回错误并指出下一步操作,例如列出现有的章节 ID。
许多搜索结果位于附件而非主要文档中,例如附在 8-K 后的 EX-99.1 新闻稿。对于这类结果,search_full_text 会将附件的文件名作为 document 返回;给定匹配结果的 accession 和 document 后,read_filing_text(或 get_filing_outline)会读取该附件。只接受以 .htm、.html、.txt 或 .xml 结尾的纯文件名。
运行期间,服务会在内存中保留最近读取的六份文档(因此翻页时只需解析一次)、按 accession 编号查询过的每份申报文件,以及每种表格类型最新的申报文件,保留时间为 10 分钟。同时进行的、需要读取同一文档的调用会共享一次下载。服务只会加载一次 SEC 股票代码文件,因此,服务启动后新增或变更的股票代码只能通过 CIK 找到,直到服务重启。
Claude Code
claude mcp add parsec-edgar -s user -e PARSEC_EDGAR_USER_AGENT="Example Corp [email protected]" -- uvx parsec-edgar mcp
安装该命令后,请改为在命令行末尾添加 -- parsec-edgar mcp。
Claude Desktop
将该服务添加到 claude_desktop_config.json(macOS 上位于 ~/Library/Application Support/Claude/,Windows 上位于 %APPDATA%\Claude\),然后重启 Claude Desktop:
{
"mcpServers": {
"parsec-edgar": {
"command": "uvx",
"args": ["parsec-edgar", "mcp"],
"env": { "PARSEC_EDGAR_USER_AGENT": "Example Corp [email protected]" }
}
}
}
Claude Desktop 不会读取 shell 的 PATH。如果无法启动该服务,请将 which uvx 输出的完整路径指定为 command;或者使用已安装的命令:将 which parsec-edgar 输出的完整路径指定为 command,并设置 "args": ["mcp"]。
其他 MCP 客户端
使用 stdio 时,命令为 parsec-edgar mcp,并在其环境中设置 PARSEC_EDGAR_USER_AGENT(或 EDGAR_IDENTITY)。全局选项照常适用,例如 parsec-edgar --rps 5 --cache-dir /data/edgar mcp。如果未设置 User-Agent,服务会退出并显示清晰的提示信息。
对于通过 HTTP 连接的客户端,请运行 Streamable HTTP 传输:
parsec-edgar mcp --http 127.0.0.1:8080 # endpoint http://127.0.0.1:8080/mcp
claude mcp add --transport http parsec-edgar http://127.0.0.1:8080/mcp
HTTP 服务只接受发往 localhost、127.0.0.1、::1 或其监听地址的请求,以阻止网页发起 DNS 重绑定攻击。使用 --http 0.0.0.0:8080 时,服务会监听所有网络接口,但仍只接受使用环回地址名称的请求,因此请用 --allow-host 指定其他机器使用的名称;如果服务位于反向代理后方,也请用同样的方式添加公共名称(--allow-host mcp.example.com)。来自网页的请求还必须携带本地 Origin(任意端口上的 http://localhost 或 http://127.0.0.1),或通过 --allow-origin https://app.example.com 指定的 Origin。原生客户端不会发送 Origin,因此不受影响。服务本身没有身份验证功能,因此请勿将其直接暴露到互联网。
测试
cargo test -p parsec-edgar-cli # paging and lookup unit tests, plus stdio and HTTP protocol tests that make no SEC requests
PARSEC_EDGAR_USER_AGENT="Example Corp [email protected]" \
cargo test -p parsec-edgar-cli --test mcp -- --ignored --nocapture # every tool against live SEC data, 3 requests per second
全文搜索
SEC 的 EDGAR 全文搜索(涵盖自 2001 年以来提交的文档)也可通过该库使用。一次调用会返回一页最多包含 100 条结果,并按最佳匹配优先排序;可使用 offset 翻到后续页面。
use parsec_edgar::{Client, FullTextQuery};
let client = Client::builder("Example Corp [email protected]").build()?;
let q = FullTextQuery::new("\"supply chain disruption\" OR tariffs").forms(&["10-K"]).since("2025").cik(320193);
let results = client.full_text_search(&q)?;
println!("{} matching documents", results.total);
for hit in &results.hits {
println!("{} {} {} {}", hit.company, hit.form, hit.filing_date, hit.document_url);
}
所有词语都必须出现;"double quotes" 用于匹配短语;OR 用于匹配任一词语;-word 用于排除某个词语。表单类型筛选也会匹配该表单的修订版。SEC 最多统计 10,000 条结果(超过此数量时 total_is_exact 为 false),且不提供第 10,000 条之后的结果,因此 offset 必须小于 10,000。如果某条搜索记录未列出提交者或文件,该结果会从 hits 中省略,其位置会列在 skipped 中,因此下一页应从 offset + hits.len() + skipped.len() 开始。
搜索结果不提供文本片段。要阅读某条结果,请获取 hit.document_url 并使用 document_to_text 转换,或使用上文的 MCP 工具。hit.document 是匹配的文件,通常是附件(例如 hit.document_type 为 EX-99.1),而不是该申报文件的主要文档。
Python
import parsec_edgar as pe
client = pe.Client("Example Corp [email protected]", cache_dir="~/.cache/parsec-edgar")
client.company("BRK.B") # {'cik': 1067983, 'ticker': 'BRK-B', ...}
filings = client.filings("MSFT", form=["10-K", "10-Q"], since="2024")
latest = client.latest("AAPL", "10-K") # a filing dict
text = client.text(latest) # clean text
for s in client.sections(latest):
print(s["id"], s["title"], len(s["text"]))
pe.html_to_text(html) # parse documents you already have
pe.extract_sections(text, "10-K")
查询失败会引发 LookupError,参数错误会引发 ValueError,网络或 HTTP 故障会引发 parsec_edgar.EdgarError。网络调用会释放 GIL,因此可由多个线程共享同一个客户端;客户端会遵守其速率限制。
Rust
use parsec_edgar::{Client, FilingQuery};
let client = Client::builder("Example Corp [email protected]")
.cache_dir(Some("cache".into()))
.build()?;
let filing = client.latest("AAPL", "10-K")?;
for s in client.filing_sections(&filing)? {
println!("{} {} ({} bytes)", s.id, s.title, s.text.len());
}
let recent = client.filings("NVDA", &FilingQuery::forms(&["8-K"]).since("2026-01").limit(10))?;
批量抓取
parsec-edgar crawl 按表格类型和日期查找文件,下载文件,并将每份文件连同其元数据和条款章节写入一个 JSON 文件。它一步完成了 edgar-crawler 的 download_filings.py 和 extract_items.py 分两步完成的工作。
# Every 8-K filed on two days, across all companies
parsec-edgar crawl --form 8-K --since 2026-11-05 --until 2026-11-06 --out 8k
# Whole years, or some quarters of them
parsec-edgar crawl --form 10-K --form 10-K/A --year 2020-2024 --out 10k
parsec-edgar crawl --form 10-Q --year 2024 --quarter 2,3 --out 10q --jsonl
# A list of companies (tickers or CIKs), through the submissions API
parsec-edgar crawl --form 10-K --company AAPL --company 789019 --year 2015-2025 --out big-tech --raw
parsec-edgar crawl --form 10-K --companies-file sp500.txt --out sp500 # no dates: whole history
parsec-edgar crawl --form 10-K --year 2025 --out 10k --dry-run # count only, download nothing
表格类型必须完全匹配,因此 --form 10-K 不会包含 10-K/A 和 10-K405;每种所需类型都要重复使用 --form。--item 1A --item 7 仅保留这些章节,--limit N 在处理完前 N 份文件后停止,--threads N(默认值为 8)设置工作线程数。工作线程共用一个客户端,因此它们合计不会超过 --rps,同时并行解析文档。
--out 目录中的输出:
- 每份文件对应一个
{cik}_{form}_{filing date}_{accession}.json;使用--jsonl时,则在filings.jsonl中为每份文件写入一行 - 使用
--raw时,输出raw/{same name}.htm(或.txt),即按原样提供的主要文档 failures.jsonl:每行记录最近一次运行中一份失败文件的 URL 和错误(如果运行在下载任何内容前就失败,则保留之前的列表)
再次运行相同命令即可继续抓取:已有输出的文件会被跳过,失败的文件会重试。进程被终止、磁盘已满或断电,都不会留下被误认为已完成的不完整记录:不完整的 JSON 文件会重新抓取,filings.jsonl 会截断到最后一行完整记录。进度和最终摘要(成功、失败、跳过、每分钟文件数、每份文件的请求数)会输出到 stderr;只要有任何失败,退出状态码就是 1。解析某份文件时发生 panic,会被记录为该文件的失败,抓取会继续进行。
如果客户端超出 SEC 的速率限制,SEC 会返回 403。首次收到 403 时,所有工作线程都会暂停一分钟,然后重试该文件;其他工作线程在同一时刻收到的 403 会被视为同一事件。如果在两次此类暂停后、且中间没有成功下载的情况下再次收到 403,抓取就会停止,以便稍后恢复。
每条记录包含以下字段:
| 字段 | edgar-crawler 字段 | 内容 |
|---|---|---|
cik、company、filing_date | 相同 | |
form | filing_type | |
report_date | period_of_report | |
acceptance_datetime | UTC,与 submissions API 中相同 | |
accession_number、items | items 列出 8-K 条款编号 | |
sic、sic_description | sic | |
state_of_incorporation | state_of_inc | |
state_location | state_location | 营业地址所在州或国家/地区代码 |
fiscal_year_end | fiscal_year_end | MMDD |
index_url | filing_html_index | 文件的 -index.htm 页面 |
primary_document、primary_document_url | htm_filing_link | 与 submissions API 中相同;对于 SEC 从 XML 渲染的表格(Form 3、4 和 5、D、13F 等),这是 HTML 渲染文件,例如 xslF345X05/wk-form4_1759530830.xml |
full_submission_url | complete_text_filing_link | |
raw_file | filename | 使用 --raw 时 |
sections | item_1、item_1A、... | 按文件中的顺序排列,以章节 ID为键的章节文本 |
section_list | 每个章节的 id、part、item、title、heading、start、end 和 chars | |
text | 对于没有条款章节的表格,以及未找到任何条款章节的 10-K、10-Q 和 8-K 文件,包含全文(例如只修订封面页的 10-K/A) |
如何查找申报文件
不使用 --company 时,爬取会读取 EDGAR 完整索引,其中按季度各列出一份文件,记录所有公司的每一份申报文件。它会读取 master.gz:该文件以竖线分隔,而 form.idx 和 company.idx 使用定宽列,较长的公司名称可能导致解析错误;此外,master.gz 大约只有 3 MB,是最小的下载文件(master.idx 为 24 MB,form.idx 为 42 MB)。有多名申报人的申报文件会为每名申报人各占一行,但只会爬取一次。已结束季度的索引会被缓存;当前季度的索引则会在每次运行时重新下载,因为 SEC 每晚都会添加前一个工作日提交的申报文件。新季度的索引要等到该季度的第一个工作日后才会出现;在此之前,爬取会报告该索引尚未发布,因此在其中找不到任何文件。
索引只提供每份申报文件完整提交文件的路径(所有文档都在一个 SGML 文件中,10-K 文件通常有 10 MB 或更大)。因此,爬取会读取每份申报文件的 -index.htm 页面(10 到 40 KB),该页面提供主要文档(其链接所对应的类型与表格类型相同的行)、报告期间、受理时间、8-K 条目,以及截至申报日申报人的 SIC 代码、注册州、营业地址和财政年度结束日期。每份申报文件需要两次请求。另一种做法是每家公司调用一次 submissions API;当大多数申报文件来自不同公司时(例如某一天的 8-K 或某一年的 10-K),这种做法并不能减少请求,而且每家公司还要下载一个 100 KB 到 1 MB 的文件,较早的申报文件还需要额外页面,因为最新的一千份申报文件之外的内容需要另行获取。
使用 --company 或 --companies-file 时,申报文件来自 submissions API:每家公司请求一次,同时还会返回公司资料(SIC 代码、注册州等当前信息)。如果日期范围早于最新的一千份申报文件,就会读取较早的页面;如果没有起始日期(未指定 --since 或 --year),则会读取所有页面。之后,每份申报文件都需要一次请求来获取其文档。
以下数据于 2026 年 11 月测得,使用 --rps 3 和 8 个线程;每次爬取都从空缓存目录开始:
| 爬取内容 | 申报文件数 | 用时 | 每分钟申报文件数 | 每份申报文件的请求数 | 失败数 |
|---|---|---|---|---|---|
| 2026-11-05 和 2026-11-06 提交的所有 8-K(完整索引) | 1,009 | 11.2 分钟 | 90.0 | 2.00,另加索引的 1 次请求 | 0 |
| 按索引顺序排列的 2025 年前 200 份 10-K(完整索引) | 200 | 2.3 分钟 | 89.8 | 2.00,另加索引的 4 次请求 | 0 |
7 家公司的 2016 至 2025 年 10-K(--company) | 60 | 44 秒 | 173 | 1.00,另加查找它们的 70 次请求 | 0 |
两次完整索引爬取都达到了请求速率上限(每秒 3 次请求、每份申报文件 2 次请求,即每分钟 90 份)。解析速度远未达到上限:所有文档都已缓存时,解析并写入同样的 200 份 10-K(788 MB HTML)不到 2 秒。再次运行 10-K 爬取时,200 份文件全部跳过,且没有发出请求;公司爬取再次运行时也跳过了全部 60 份,但重复发出了查找这些文件所需的 70 次请求,因为 submissions 文件不会被缓存。在公司爬取中,70 次查找请求里有 58 次是 JPMorgan 较早的 submissions 页面:它每年提交约 26,000 份文档,因此其近期数据块只涵盖一年。对于跨多年提交大量文件的公司,完整索引更省请求。
按默认的每秒 8 次请求爬取一整年的 10-K:2025 年有 6,431 份 10-K 申报文件(连同 10-K/A 共 7,139 份),因此约需 12,900 次请求和 27 分钟。200 份样本的主要文档平均为 3.9 MB,因此全年约为 25 GB,需要约 16 MB/s(125 Mbit/s)的带宽才能跟上;连接速度较慢时,下载时间会决定整体速度。
在 8-K 爬取中,每条记录都获得了主要文档、报告日期和受理时间;97.5% 的记录获得了 SIC 代码,91% 的记录获得了注册州。SEC 提供的数据中这些缺失值同样为空,包括 submissions API。
来自 Rust
use parsec_edgar::{Client, CrawlQuery};
let client = Client::builder("Example Corp [email protected]").build()?;
let query = CrawlQuery::new(&["8-K"]).since("2026-11-05").until("2026-11-06");
for entry in client.crawl_index(&query)? {
let (filing, index) = client.resolve_index_entry(&entry)?; // reads the -index.htm page
let profile = index.filer(filing.cik).map(|f| &f.profile); // SIC code, state, fiscal year end
let sections = client.filing_sections(&filing)?;
}
let tenks = CrawlQuery::new(&["10-K"]).years(2015, 2025);
let (filings, profile) = client.crawl_company_with_profile("AAPL", &tenks)?; // one submissions request
Client::crawl_company 仅返回申报文件,Client::company_profile(cik) 仅返回公司简介。Client::full_index(quarter) 返回一个季度的索引行(如果新季度的索引尚未发布,则不返回任何内容),parse_master_index 和 parse_filing_index 用于解析你已有的文件,而 Client::requests_sent() 用于统计客户端已发送的 HTTP 请求数。
爬取限制
- SEC 每晚更新当前季度的索引,因此某份申报文件会在下一个工作日出现在完整索引爬取结果中。
- 已结束季度的索引会永久缓存(从季度结束几天后开始),因此 SEC 后续对其所做的更正不会被获取。如需重新读取,请从缓存目录中删除
Archives/edgar/full-index/YYYY/QTRn/master.gz,或使用--no-cache进行爬取。 - 爬取下载的每份文档也会保留在缓存中(除非
--cache-dir或PARSEC_EDGAR_CACHE另有指定,否则路径为~/.cache/parsec-edgar)。仅一整年的 10-K 文件就会占用约 25 GB,此外还需要输出文件的空间。请将--cache-dir指向空间充足的磁盘,或者在不会重复爬取时使用--no-cache。 - 使用
--company时,简介字段显示的是公司当前值;完整索引爬取则会显示每份申报文件上列出的值。 - 股票代码指的是当前持有该代码的公司。重组为新的控股公司后,旧申报文件仍归属旧 CIK:2026 年,
XOM转至 ExxonMobil Holdings Corp(CIK 2115436),因此要获取 Exxon Mobil 早期的 10-K 文件,需要使用--company 34088。 - 约 2001 年之前的申报文件没有单独的主文档,因此爬取会读取完整的提交文件及其中的第一份文档。
- 目前还没有与 edgar-crawler 的
remove_tables和include_signature选项等效的功能,也没有用于爬取的 Python 绑定。
章节 ID
| 格式 | ID |
|---|---|
| 10-K(以及 10-K405、10-KSB、10-K/A) | item_1、item_1a、item_1b、item_1c、item_2 … item_16 |
| 10-Q(以及 10-QSB、10-Q/A) | part_1_item_1 … part_1_item_4、part_2_item_1、part_2_item_1a … part_2_item_6 |
| 8-K(以及 8-K/A) | item_1.01 … item_9.01 |
每个章节都有 id、part(仅适用于 10-Q)、item、title(标准标题)、heading(文件中印出的标题)、start 和 end(文件文本中的字节偏移量),以及 text。
工作原理:每一行看起来像 Item 标题的内容都是候选项,包括目录条目和页眉。对于目录条目,如果其标题在正文中以更长的文本段再次出现、位于某个 Item 带标题的标题之前的纯页眉,以及签名后再次印出的 Item 列表,都会先被剔除。然后,提取器为每个 Item 选出一个候选项,使所选标题符合该表格的 Item 顺序,并且对应的文本段最长。在 10-Q 中,Item 上方紧邻的 PART 行决定它属于 Part I 还是 Part II。若没有 PART 行,标题仅是某一部分标准标题的 Item 会归入该部分(“Item 4. Controls and Procedures” 属于 Part I)。若 PART 行标明某些顺序错乱的 Item 属于相应部分,且这些 Item 出现在签名之前,则会予以保留(Part II 出现在 Part I 之前)。最后一个 Item 会在签名处结束;如果没有签名标题,则在签名块的首句处结束;如果附有自带分页目录的文件(例如完整年度报告),则在该文件处结束。
准确性以 1997 至 2026 年的 129 份人工标注文件(bench/)为基准。在其中 25 份文件上,这些文件是在所有调优完成后标注并仅评分一次,提取器找到了标注的 349 个 Item 起始位置中的 345 个,且没有误报(F1 为 0.994),跨度准确率为 0.935。两个较早的测试集在首次评分时、且误报尚未修正前,F1 分别为 0.989(跨度准确率 0.997,共 19 份文件)和 0.955(跨度准确率 0.875,共 20 份文件)。在用于调优的 104 份文件上,F1 为 1.000,跨度准确率为 0.993;这些是样本内数据。跨度准确率按每份文件计算:正确归属到对应 Item 的字符数,除以任何标注或预测 Item 范围内的字符数,再对所有文件取平均。在这 25 份未参与调优的文件上,edgar-crawler 的 F1 为 0.961,跨度准确率为 0.843;edgartools 的 F1 为 0.900,跨度准确率为 0.705。bench/README.md 列出了详情、每一处遗漏,以及每条规则依据的基准文件数量。
已知限制
- 没有 Item 标题的文本会保留在前一个 Item 中。例如:最后一个 Item 之后印出的财务报表页面(没有单独的目录,如 Netflix)、没有 Item 8 标题而出现在 Item 7A 之后的内容(Kroger 2019)、Item 9 与 Part III 之间的内容(Allen Organ 1998),以及最后一个 Item 与签名之间印出的附件索引(Patriot National Bancorp 2025)。
- 只有在 10-Q 中,且仅当 PART 行紧邻 Item 上方时,才会识别顺序错乱的 Item。Capital One 的 2020 年 10-Q 在同一条 PART I 行下先印出 Item 2、再印出 Item 1,因此 Item 1 会被遗漏,而 Item 2 的范围会延伸到 Item 1。
- 没有独立 Item 编号的高管人员章节,或编号为“Item 4(a)”的章节(Lockheed Martin 2006),会保留在 Item 4 中。
- 表格未定义的 Item 编号不会映射到任何 Item:如果 Item 5 仅以“Item 5A”和“Item 5B”的形式印出(McDonald's 2003),则输出中会缺少 Item 5。
- 带有两个分隔符的标题,例如“Item 3. - Quantitative and Qualitative Disclosures”(Samsara Luggage 2023 10-Q),无法识别,其文本会归入前一个 Item。
- 页码页眉和页脚在带有页码且重复出现在五页或更多页面时会被移除;较短的内容(例如“2021 Form 10-K 100”)会保留。
- 表格会渲染为以制表符分隔的行,目前尚未作为结构化数据处理。
目录结构
| 路径 | 内容 |
|---|---|
crates/parsec-edgar | 核心库 |
crates/parsec-edgar-cli | parsec-edgar 命令行工具 |
python | Python 绑定(PyO3,使用 maturin 构建) |
bench | 章节拆分准确度和速度基准测试,附带人工标注 |
server.json | MCP 注册表条目 |
.github/workflows | 持续集成和发布工作流 |
开发
cargo test # unit tests, no network
cargo fmt && cargo clippy --workspace --all-targets # style (rustfmt.toml) and lints
cd python && maturin develop # build the Python extension into the active virtualenv
python -m pytest python/tests # Python package and command, no network
cargo run --release -p parsec-edgar-bench -- score # section accuracy on the labeled filings (downloads them once)
GitHub Actions 会在 Linux、macOS 和 Windows 上运行测试,检查最低 Rust 版本(1.88),并构建和测试 Python 软件包。
发布
在 Cargo.toml(workspace.package.version)和 server.json 中的两处设置新版本,提交后推送一个类似 v0.2.0 的标签。发布工作流会构建 wheel 和二进制文件,然后发布到 PyPI、crates.io、GitHub 发布页和 MCP 注册表。在 Actions 标签页中手动运行该工作流会构建并测试所有内容,但不会发布。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。