SEC EDGAR Filings MCP Server
Enables AI assistants to download, convert (HTML to PDF), and parse SEC EDGAR filings into Markdown, supporting filing types like 8-K, 10-Q, 10-K, and DEF 14A with Docker deployment and rate limiting.
README
SEC EDGAR Filings MCP Server
A Model Context Protocol (MCP) server that enables AI assistants like Claude to interact with SEC EDGAR filings. Download, convert, and parse SEC financial documents seamlessly.
🎯 Features
- 📄 PDF to Markdown: Parse PDF filings into Markdown using LlamaCloud or Docling
- 🔄 HTML to PDF: Convert SEC EDGAR HTML/iXBRL files to PDF
- 📥 Download SEC Filings: Automatically download filings from SEC EDGAR
- ⚡ Rate Limiting: Respects SEC's 10 requests/second limit
- 🐳 Docker Support: Easy deployment with Docker
📋 Supported Filing Types
- 8-K: Current Report
- 10-Q: Quarterly Report
- 10-K: Annual Report
- DEF 14A: Proxy Statement (bonus)
🔧 Prerequisites
- Python 3.8+
- LlamaCloud API key (for PDF parsing) - Get from https://cloud.llamaindex.ai/
- Claude Desktop (for testing)
🚀 Quick Start (Docker - Recommended)
⚡ Fastest way to get started (< 2 minutes):
1. Prerequisites
- Docker Desktop installed and running
- Windows/macOS: Download Docker Desktop
- Linux: Install Docker Engine
- LlamaCloud API key
⚠️ Important: Start Docker Desktop first!
Verify Docker is running:
docker --version
docker ps
If you see "Cannot connect to the Docker daemon", start Docker Desktop and wait until it's fully running.
2. Clone & Configure
git clone https://github.com/momotime7584/sec-edgar-filings-mcp.git
cd sec-edgar-filings-mcp
# Create .env file
cp .env.example .env
# Edit .env with your LLAMA_CLOUD_API_KEY
Required Configuration:
# LlamaCloud API Key (get from https://cloud.llamaindex.ai/)
LLAMA_CLOUD_API_KEY=your_actual_api_key_here
# SEC API User-Agent (CRITICAL - use browser format!)
# ⚠️ IMPORTANT: Must use browser User-Agent to avoid 403 Forbidden errors
SEC_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
# Your email (optional but recommended)
SEC_FROM_EMAIL=your.email@example.com
🚨 Critical: SEC_USER_AGENT Format
The SEC API requires a browser-like User-Agent string. Using a simple format like "YourName your.email@example.com" will result in 403 Forbidden errors.
Why? While SEC's documentation suggests simple identification, their servers actually filter requests and prefer browser User-Agents to prevent automated scraping abuse.
✅ Use the browser User-Agent shown above (already in .env.example)
3. Start Server
# Download pre-built image (~1-2 seconds) and start
docker-compose pull
docker-compose up -d
✅ Done! The MCP server is now running in a container with all dependencies.
4. Configure Claude Desktop
See Claude Desktop Configuration section below (use Docker option).
🔧 Alternative Installation (Python)
If you prefer not to use Docker, you can install directly with Python:
1. Clone Repository
git clone <your-repository-url>
cd "SEC EDGAR filings MCP"
2. Create Virtual Environment
# Windows
python -m venv venv
venv\Scripts\activate
# macOS/Linux
python3 -m venv venv
source venv/bin/activate
3. Install Dependencies
pip install -r requirements.txt
4. Install Playwright Browsers
playwright install chromium
5. Configure Environment
Create .env file from template:
# Copy example file
cp .env.example .env
# Edit with your credentials
📖 Usage
Claude Desktop Configuration
Configuration File Location:
- Windows:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Option 1: Using Docker (Recommended)
Start the Docker container first:
docker-compose up -d
Then add this configuration:
{
"mcpServers": {
"sec-edgar": {
"command": "docker",
"args": [
"exec", "-i",
"sec-edgar-mcp-server",
"python", "/app/server.py"
],
"toolTimeout": 500000
}
}
}
✅ Benefits:
- No Python installation needed
- All dependencies included
- Reproducible environment
⚠️ Important:
- Container must be running before starting Claude Desktop
- Run
docker-compose up -dfirst - Use
docker psto verify container is running
Option 2: Local Python Installation
{
"mcpServers": {
"sec-edgar": {
"command": "C:\\Users\\YourName\\path\\to\\venv\\Scripts\\python.exe",
"args": [
"C:\\Users\\YourName\\path\\to\\server.py"
],
"env": {
"LLAMA_CLOUD_API_KEY": "your_actual_api_key",
"SEC_USER_AGENT": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
},
"toolTimeout": 500000
}
}
}
Windows Path Examples:
- Using venv:
C:\\Users\\YourName\\projects\\sec-edgar\\venv\\Scripts\\python.exe - System Python:
C:\\Python311\\python.exe - ✅ Use double backslashes (
\\) or forward slashes (/)
macOS/Linux:
{
"mcpServers": {
"sec-edgar": {
"command": "/Users/yourname/projects/sec-edgar/venv/bin/python",
"args": ["/Users/yourname/projects/sec-edgar/server.py"],
"env": {
"LLAMA_CLOUD_API_KEY": "your_actual_api_key",
"SEC_USER_AGENT": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
},
"toolTimeout": 500000
}
}
}
💬 Example Prompts for Claude Desktop
Multiple Tools
Single Prompt Challenge #1: Apple 2021 8-K Analysis
2021 애플 8-k 공시 다 숙지해줘
Expected Workflow:
- Downloads Apple's (CIK: 0000320193) 8-K filing for 2021
- Converts HTML to PDF
- Parses PDF to markdown
- Reads and summarizes the entire filing
Result:
✅ Successfully completed all steps automatically
Downloaded: html/apple_2021_8k/apple_20211109.htm
Converted: pdf/apple_2021_8k.pdf
Parsed: markdown/apple_2021_8k.md
Summary:
2021년 11월 9일자 애플 8-K 공시 - 주요 기업 변동사항 보고
주요 내용:
1. 새 이사 임명 (Item 5.02)
- Alex Gorsky (Johnson & Johnson 전 CEO) 임명
- 지명 및 기업지배구조 위원회 소속
- 연간 현금 보수: $100,000 (분기별 지급)
- 초기 주식 부여: 486 RSU
2. 정관 개정 (Item 5.03)
- 이사회 정원 8명 → 9명 확대
3. 헬스케어 전문성 강화
- Gorsky의 J&J CEO 경험을 통한 헬스케어 분야 전문성 확보
Single Prompt Challenge #2: Apple 2021 DEF 14A Analysis
2021 애플 14def 다 숙지해줘
Expected Workflow:
- Downloads Apple's (CIK: 0000320193) DEF 14A filing for 2021
- Converts HTML to PDF
- Parses PDF to markdown (creates multiple chunks due to large size)
- Auto-recovery: Uses
list_markdown_filesto locate chunks - Reads all chunks sequentially with
read_markdown_chunk - Comprehends the entire proxy statement
Result:
✅ Successfully completed with automatic recovery workflow
Downloaded: html/apple_2021_def14a/apple_20210223.htm
Converted: pdf/apple_2021_def14a.pdf
Parsed: 5 markdown chunks (total ~213KB)
- apple_2021_def14a_chunk_1_of_5.md (50KB)
- apple_2021_def14a_chunk_2_of_5.md (50KB)
- apple_2021_def14a_chunk_3_of_5.md (50KB)
- apple_2021_def14a_chunk_4_of_5.md (50KB)
- apple_2021_def14a_chunk_5_of_5.md (12KB)
⚠️ Known Issue (UNFIXED):
Problem: read_as_markdown returned "No result received from client-side tool execution"
Server Status: ✅ NORMAL
- Server successfully creates chunk files
- Server logs confirm normal operation
- Server returns chunk file list
Claude Status: ❌ ERROR
- Tool execution appears successful in Claude UI
- But no response content received
- Error: "No result received from client-side tool execution"
Root Cause: MCP protocol communication issue
- Server → Claude transmission fails
- NOT a server logic problem
- Possibly related to response format or MCP protocol limitation
Status: UNFIXED (architectural/protocol-level issue)
✅ Workaround Applied:
Used alternative tool chain to bypass the issue:
Step 1: read_as_markdown (Expected to fail, but creates chunk files)
└─ Server creates 5 chunk files
└─ Claude shows "No result" error
Step 2: list_markdown_files (Discovery)
└─ Lists all markdown files in markdown/ directory
└─ Confirms 5 chunk files were created
Step 3: read_markdown_chunk × 5 (Individual retrieval)
└─ Reads apple_2021_def14a_chunk_1_of_5.md
└─ Reads apple_2021_def14a_chunk_2_of_5.md
└─ Reads apple_2021_def14a_chunk_3_of_5.md
└─ Reads apple_2021_def14a_chunk_4_of_5.md
└─ Reads apple_2021_def14a_chunk_5_of_5.md
Result: ✅ All content successfully retrieved
Summary:
2021년 2월 23일 애플 연례 주주총회 공시 (81페이지)
주요 내용:
1. 연례 주주총회
- 일시: 2021년 2월 23일 오전 9시 (PST)
- 가상 회의 (COVID-19 대응)
- 8명 이사 선출 안건
2. 이사회 구성 (다양성 강화)
- 이사 8명 후보: Bell, Cook, Gore, Jung, Levinson, Lozano, Sugar, Wagner
- 50% 여성 리더십, 50% 소수집단 출신
- Monica Lozano 신규 이사 (2021.1월 임명)
3. 임원 보상 프로그램
- CEO Tim Cook: 2020년 총 보상 $14.8M
* 기본급: $3M
* 현금 인센티브: $10.7M (목표 대비 179% 달성)
* 기타: $1M (보안, 항공기 사용)
- NEO 평균 보상: ~$26M
* 기본급: $1M
* 현금 인센티브: $3.6M
* 주식 보상: $21.7M (시간/성과 기반 RSU)
4. 2020년 재무 성과
- 매출: $274.5B (전년 대비 +6%)
- 주당순이익: $3.28 (+10%)
- 영업이익: $66.3B (+4%)
- 주주환원: $90B (배당+자사주)
- 총주주수익률(TSR): 1년 107%, 3년 203%, 5년 324%
5. 2021년 변경사항
- ESG 수정 요소 추가: Apple Values 기반 평가를 연간 인센티브에 반영
- CEO 장기 주식 보상: Tim Cook에게 2011년 이후 첫 신규 RSU 부여
(10년간 시총 $1.5T 증가, TSR 867% 성과 인정)
6. 기업 가치 실천 (2020년)
- COVID-19 대응: 마스크 3천만개, 안면보호구 1천만개 기부
- 탄소중립 목표: 2030년까지 공급망 포함 100% 달성
- 인종평등: $100M 투자 (교육, 경제평등, 형사사법 개혁)
- 주택위기 해결: 캘리포니아 주택 프로젝트 $400M 투자
7. 주주 제안 (안건 4, 5)
- 안건 4: 대리접근권 개정 (이사 최소 2명 또는 20%) - 이사회 반대
- 안건 5: 임원 보상에 급여 비율 고려 - 이사회 반대
- 이사회 권고: 안건 1,2,3 찬성 / 안건 4,5 반대
8. 감사 정보
- 독립 감사인: Ernst & Young LLP (2009년부터)
- 2020년 감사 비용: $22.2M
* 감사: $17.6M, 세무: $3.4M, 기타: $1.2M
**Key Insights:**
- 81페이지 분량의 상세한 기업지배구조 및 보상 정책 공시
- 강력한 재무 성과와 주주가치 창출 (매출/이익 성장, 높은 TSR)
- 다양성과 ESG를 강화하는 이사회 및 경영진 구성
- 투명한 임원 보상 체계 (성과연동, 장기 인센티브 중심)
- 2021년부터 ESG 요소를 보상에 직접 반영하는 선진적 접근
🔀 Markdown Chunking System
Why Chunking?
MCP client-side (Claude) has response size limitations. Large SEC filings (10-K reports often exceed 200,000+ characters) cannot be transmitted from the server to Claude in a single tool response, even though the server successfully processes and returns them.
How it works:
- When
read_as_markdownparses a large PDF (>50,000 chars) - Content is automatically split into 50,000-character chunks
- Each chunk saved as:
{filename}_chunk_{N}_of_{total}.md - Tool returns chunk file list instead of full text
- Claude can then call
read_markdown_chunkto read specific chunks - Use
list_markdown_filesto see all available chunks
Benefits:
- Handles documents of any size
- Complies with MCP response limits
- Allows selective reading of document sections
- Preserves full content without truncation
🛠️ MCP Tools
1. read_as_markdown
Parse PDF files to Markdown format.
Parameters:
input_file_path(string): PDF file path relative topdf/directory
Example:
Input: "Amazon.com Inc. - Form 10-K. For the Fiscal Year Ended 2024-12-31.pdf"
Output: Markdown text content (or chunk file list for large documents)
Supported Parsers:
- LlamaCloud LlamaExtract (primary): High-quality parsing with API
📦 Automatic Chunking:
- Documents >50,000 characters are automatically split into chunks
- Each chunk saved as separate
.mdfile inmarkdown/directory - Returns list of chunk files instead of full text
- Use
read_markdown_chunktool to read individual chunks
🔧 How it works (Code Logic):
- Path Resolution: Converts relative path to absolute path in
pdf/directory - File Validation: Checks if PDF file exists
- API Key Validation: Verifies LLAMA_CLOUD_API_KEY is configured
- LlamaCloud Parsing:
- Initializes
LlamaParseclient with API key - Calls
load_data()to parse PDF to markdown - Runs synchronously in thread pool to avoid blocking
- Initializes
- Chunking Logic:
- Checks if markdown length > 50,000 characters
- Splits into 50KB chunks:
chunks = [text[i:i+50000] for i in range(0, len(text), 50000)] - Saves each chunk:
{filename}_chunk_{N}_of_{total}.md
- Return Strategy:
- Small files (≤50K): Returns markdown text directly
- Large files (>50K): Returns formatted message with chunk file list
- ⚠️ Claude may show "No result" for large files (MCP client limitation)
Code Reference:
# Main workflow
markdown_text = await _parse_pdf_with_llamacloud(file_path)
chunk_files = await _save_markdown_chunks(markdown_text, base_filename)
# Chunking implementation
chunk_size = 50000
total_chunks = (total_length + chunk_size - 1) // chunk_size
for i in range(total_chunks):
start_idx = i * chunk_size
end_idx = min(start_idx + chunk_size, total_length)
chunk_text = markdown_text[start_idx:end_idx]
2. html_to_pdf
Convert HTML/iXBRL files to PDF format.
Parameters:
input_file_path(string): HTML file path relative tohtml/directoryoutput_file_path(string): PDF output path relative topdf/directory
Example:
Input: "html/Form 10-K/amzn-20241231.htm"
Output: "pdf/amazon_10k_2024.pdf"
🔧 How it works (Code Logic):
- Path Resolution: Converts HTML input path and PDF output path to absolute paths
- File Validation: Checks HTML file exists, creates output directory if needed
- Playwright Browser Launch: Launches Chromium browser in headless mode
- HTML Loading: Loads local HTML file using
file://protocolwait_until="networkidle": Waits for all network requests to complete (CSS/images)- 60-second timeout for large SEC documents
- PDF Generation: Calls
page.pdf()with optimized settings- Format: Letter (US standard paper size)
- Background: Enabled (preserves SEC document styling)
- Margins: 0.5 inches on all sides (improved readability)
- File Stabilization: Waits for file write completion
- Checks file size stabilization (10 checks over 2 seconds)
- Prevents empty file errors
Code Reference:
await page.goto(file_url, wait_until="networkidle", timeout=60000)
await page.pdf(
path=str(output_path),
format="Letter",
print_background=True,
margin={"top": "0.5in", "right": "0.5in",
"bottom": "0.5in", "left": "0.5in"}
)
3. download_sec_filing
Download SEC filings from EDGAR.
Parameters:
cik(string): Company CIK number (e.g., "0001018724")year(integer): Filing year (2021-2025)filing_type(string): "8-K" | "10-Q" | "10-K" | "DEF 14A"output_dir_path(string): Output directory relative tohtml/
Example:
CIK: "0001018724"
Year: 2024
Filing Type: "10-K"
Output: "amzn_2024_10k"
Result: "html/amzn_2024_10k/amzn-20241231.htm"
🔧 How it works (Code Logic):
- Input Validation:
- Validates year range (2021-2025)
- Normalizes CIK: Removes leading zeros, pads to 10 digits
- SEC API Request:
- URL:
https://data.sec.gov/submissions/CIK{cik_padded}.json - Uses curl_cffi with Chrome impersonation (prevents 403 errors)
- Applies rate limiting: 100ms delay between requests (SEC 10req/s limit)
- URL:
- Filing Search:
- Matches filings by
reportDate(falls back tofilingDateif unavailable) - Filters by
form_typesfor specified filing_type - Selects most recent filing (sorts by reportDate descending)
- Matches filings by
- Primary Document Naming:
- Extracts ticker from
output_dir_path(e.g.,amzn_2024_8k→amzn) - Formats date:
YYYY-MM-DD→YYYYMMDD - Final filename:
{ticker}_{date}.{ext}(e.g.,amzn_20241231.htm)
- Extracts ticker from
- Full Archive Download:
- Fetches
index.jsonfor complete file list - Downloads all files with rate limiting
- Renames primary document automatically
- Fetches
- Return: Returns relative path of downloaded primary document
Code Reference:
# Rate limiting
await sec_rate_limiter.wait()
# CIK normalization
cik_normalized = str(cik).lstrip("0")
cik_padded = cik_normalized.zfill(10)
# Filing search
matching_filings.sort(key=lambda x: x["reportDate"] or x["filingDate"], reverse=True)
target_filing = matching_filings[0]
4. list_markdown_files
List all available markdown files in the markdown/ directory.
Parameters:
- None
Example:
Output: List of markdown files with size and modification date
🔧 How it works (Code Logic):
- Directory Scan: Scans all
.mdfiles inmarkdown/directory - File Metadata Collection:
- Collects filename, file size (bytes), modification time
- Uses
Path.glob("*.md")for pattern matching
- Sorting: Sorts by modification time descending (newest first)
- Format Output:
- Bold filename
- Size: KB + bytes display
- Modification time:
YYYY-MM-DD HH:MM:SSformat
- Usage Hint: Adds instruction to use
read_markdown_chunktool
Code Reference:
for file_path in MARKDOWN_DIR.glob("*.md"):
stat = file_path.stat()
files.append({
'name': file_path.name,
'size': stat.st_size,
'modified': stat.st_mtime
})
files.sort(key=lambda x: x['modified'], reverse=True)
5. read_markdown_chunk
Read a specific markdown chunk file (for large documents).
Parameters:
file_path(string): Markdown file path relative to base directory (e.g., "markdown/amazon_10k_2024_chunk_1_of_5.md")
Example:
Input: "markdown/amazon_10k_2024_chunk_1_of_5.md"
Output: Markdown content of that specific chunk
🔧 How it works (Code Logic):
- Path Resolution:
- Handles
markdown/prefix - Converts to absolute path
- Handles
- File Validation: Checks if markdown file exists
- Async File Read: Uses
aiofilesfor non-blocking read (UTF-8 encoding) - Response Formatting:
- Adds file path and size header
- Adds separator line (
---) - Appends markdown content
- Return: Returns formatted markdown text with metadata
Code Reference:
async with aiofiles.open(full_path, "r", encoding="utf-8") as f:
content = await f.read()
result = f"📄 **File:** `{file_path}`\n"
result += f"📊 **Size:** {file_size:,} characters\n\n"
result += "---\n\n"
result += content
📁 Project Structure
SEC EDGAR filings MCP/
├── server.py # Main MCP server
├── requirements.txt # Python dependencies
├── .env.example # Environment template
├── .env # Your config (not in git)
├── .gitignore # Git ignore rules
├── README.md # This file
├── Dockerfile # Docker config
├── docker-compose.yml # Docker Compose config
├── pdf/ # PDF files directory
│ └── (downloaded/test PDFs)
└── html/ # HTML/iXBRL files
└── (downloaded filings)
🏢 Common Company CIKs
| Company | CIK |
|---|---|
| Amazon | 0001018724 |
| Apple | 0000320193 |
| Microsoft | 0000789019 |
| Alphabet (Google) | 0001652044 |
| Meta (Facebook) | 0001326801 |
| Tesla | 0001318605 |
| NVIDIA | 0001045810 |
Find more: https://www.sec.gov/edgar/searchedgar/companysearch.html
🔍 Testing
With MCP Inspector
npm install -g @modelcontextprotocol/inspector
npx @modelcontextprotocol/inspector python server.py
Manual Testing
# Test imports
python -c "import fastmcp; print('FastMCP OK')"
python -c "from playwright.async_api import async_playwright; print('Playwright OK')"
# Test server startup
python server.py
🐳 Docker Setup Details
Quick Start (Pre-built Image - Recommended)
⚡ Fastest deployment (~2 seconds):
# 1. Pull pre-built image from Docker Hub
docker-compose pull
# 2. Start container
docker-compose up -d
# 3. Verify
docker ps
Image: momotime7584/sec-edgar-mcp:latest
- Size: ~856 MB
- Pull time: 1-2 seconds
- Includes: Python 3.11, LlamaCloud, Playwright, all dependencies
Useful Commands
# View logs (for debugging)
docker-compose logs -f
# Stop container (after testing)
docker-compose down
# Check environment variables
docker exec sec-edgar-mcp-server env | grep -E "(LLAMA|SEC)"
⚠️ Troubleshooting
"PDF file not found"
- Verify file is in
pdf/directory - Check file name (case-sensitive on Linux/macOS)
- Use exact file name from assignment
"HTML file not found"
- Extract HTML files to
html/directory - Maintain subdirectory structure if needed
- Check path separators (
/vs\)
"LlamaCloud API Error"
- Verify API key in
.env - Check API credits/quota
- Server falls back to Docling automatically
"Rate limit exceeded"
- Server handles SEC rate limiting automatically
- Wait 1-2 seconds if error persists
- Check User-Agent is properly configured
"Playwright browser not installed"
playwright install chromium
Claude Desktop not showing tools
- Restart Claude Desktop completely
- Verify JSON configuration syntax
- Check server path is correct
- Look for errors in Claude Desktop logs
Important: This project is for educational purposes. Respect SEC's usage policies and rate limits when accessing EDGAR data.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。