codal-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. codal_mcp-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +43 -0
  2. codal_mcp-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. codal_mcp-0.1.0/.github/banner.png +0 -0
  4. codal_mcp-0.1.0/.github/dependabot.yml +10 -0
  5. codal_mcp-0.1.0/.github/workflows/ci.yml +22 -0
  6. codal_mcp-0.1.0/.github/workflows/publish.yml +51 -0
  7. codal_mcp-0.1.0/.gitignore +6 -0
  8. codal_mcp-0.1.0/LICENSE +21 -0
  9. codal_mcp-0.1.0/PKG-INFO +405 -0
  10. codal_mcp-0.1.0/README.md +376 -0
  11. codal_mcp-0.1.0/pyproject.toml +57 -0
  12. codal_mcp-0.1.0/server.json +32 -0
  13. codal_mcp-0.1.0/src/codal_mcp/__init__.py +5 -0
  14. codal_mcp-0.1.0/src/codal_mcp/codal.py +538 -0
  15. codal_mcp-0.1.0/src/codal_mcp/http.py +256 -0
  16. codal_mcp-0.1.0/src/codal_mcp/registry.py +16 -0
  17. codal_mcp-0.1.0/src/codal_mcp/server.py +88 -0
  18. codal_mcp-0.1.0/tests/conftest.py +80 -0
  19. codal_mcp-0.1.0/tests/fixtures/attachment_1618277.html +89 -0
  20. codal_mcp-0.1.0/tests/fixtures/attachment_1618277_curl.html +84 -0
  21. codal_mcp-0.1.0/tests/fixtures/categories.json +1 -0
  22. codal_mcp-0.1.0/tests/fixtures/companies_trim.json +1 -0
  23. codal_mcp-0.1.0/tests/fixtures/decision_1612323.html +590 -0
  24. codal_mcp-0.1.0/tests/fixtures/decision_1612323_sheet0.html +590 -0
  25. codal_mcp-0.1.0/tests/fixtures/decision_1618277.html +985 -0
  26. codal_mcp-0.1.0/tests/fixtures/decision_captcha_wall.html +87 -0
  27. codal_mcp-0.1.0/tests/fixtures/financial_years_foolad.json +1 -0
  28. codal_mcp-0.1.0/tests/fixtures/industry_groups.json +1 -0
  29. codal_mcp-0.1.0/tests/fixtures/search_foolad.json +1 -0
  30. codal_mcp-0.1.0/tests/fixtures/search_tracing_1612323.json +1 -0
  31. codal_mcp-0.1.0/tests/fixtures/search_tracing_1618277.json +1 -0
  32. codal_mcp-0.1.0/tests/test_codal.py +235 -0
  33. codal_mcp-0.1.0/tests/test_live_codal.py +23 -0
  34. codal_mcp-0.1.0/uv.lock +1344 -0
@@ -0,0 +1,43 @@
1
+ name: Bug report
2
+ description: A tool failed or returned wrong data
3
+ labels: [bug]
4
+ body:
5
+ - type: input
6
+ id: tool
7
+ attributes:
8
+ label: Tool
9
+ description: Which tool, e.g. cd_letter
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: input
14
+ attributes:
15
+ label: Arguments and result
16
+ description: The arguments the agent sent and the error or wrong output. Remove anything personal.
17
+ render: json
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: expected
22
+ attributes:
23
+ label: What you expected
24
+ description: e.g. what the letter page on codal.ir shows (include the tracing number)
25
+ - type: input
26
+ id: client
27
+ attributes:
28
+ label: MCP client and OS
29
+ placeholder: Claude Desktop 1.x on Windows 11
30
+ - type: dropdown
31
+ id: network
32
+ attributes:
33
+ label: Network
34
+ options:
35
+ - Direct connection from Iran
36
+ - Direct connection outside Iran
37
+ - VPN or proxy
38
+ - CODAL_MCP_PROXY set
39
+ - type: input
40
+ id: version
41
+ attributes:
42
+ label: codal-mcp version
43
+ placeholder: "0.1.0"
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Question or idea
4
+ url: https://github.com/sepehr071/codal-mcp/discussions
5
+ about: Ask how to use it or suggest a new tool
Binary file
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: monthly
7
+ - package-ecosystem: uv
8
+ directory: /
9
+ schedule:
10
+ interval: monthly
@@ -0,0 +1,22 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python: ["3.10", "3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ - uses: astral-sh/setup-uv@v10.2.0
17
+ with:
18
+ python-version: ${{ matrix.python }}
19
+ - run: uv sync --locked
20
+ - run: uv run ruff check .
21
+ - run: uv run ruff format --check .
22
+ - run: uv run pytest -q
@@ -0,0 +1,51 @@
1
+ name: Publish
2
+
3
+ # Tag a release (git tag v0.1.0 && git push --tags) after bumping the version in
4
+ # pyproject.toml and server.json.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+
9
+ jobs:
10
+ pypi:
11
+ runs-on: ubuntu-latest
12
+ environment: pypi
13
+ permissions:
14
+ id-token: write # PyPI trusted publishing
15
+ contents: write # GitHub Release
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+ - uses: astral-sh/setup-uv@v10.2.0
19
+ - name: Check versions match the tag
20
+ run: |
21
+ TAG=${GITHUB_REF_NAME#v}
22
+ grep -q "^version = \"$TAG\"" pyproject.toml
23
+ test "$(jq -r .version server.json)" = "$TAG"
24
+ test "$(jq -r '.packages[0].version' server.json)" = "$TAG"
25
+ - run: uv sync --locked && uv run pytest -q
26
+ - run: uv build
27
+ - uses: pypa/gh-action-pypi-publish@release/v1
28
+ - run: gh release create "$GITHUB_REF_NAME" dist/* --generate-notes --title "$GITHUB_REF_NAME"
29
+ env:
30
+ GH_TOKEN: ${{ github.token }}
31
+
32
+ mcp-registry:
33
+ needs: pypi
34
+ runs-on: ubuntu-latest
35
+ permissions:
36
+ id-token: write # MCP Registry login via GitHub OIDC
37
+ contents: read
38
+ steps:
39
+ - uses: actions/checkout@v7
40
+ - name: Wait for PyPI to serve the new version
41
+ run: |
42
+ for i in $(seq 1 30); do
43
+ curl -sf "https://pypi.org/pypi/codal-mcp/${GITHUB_REF_NAME#v}/json" >/dev/null && exit 0
44
+ sleep 10
45
+ done
46
+ exit 1
47
+ - name: Install mcp-publisher
48
+ run: |
49
+ curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.8.1/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
50
+ - run: ./mcp-publisher login github-oidc
51
+ - run: ./mcp-publisher publish
@@ -0,0 +1,6 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ dist/
5
+ .pytest_cache/
6
+ .ruff_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sepehr Radmard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,405 @@
1
+ Metadata-Version: 2.5
2
+ Name: codal-mcp
3
+ Version: 0.1.0
4
+ Summary: Unofficial read-only MCP server for codal.ir (کدال): disclosures, letters and financial statements of Iranian listed companies.
5
+ Project-URL: Homepage, https://github.com/sepehr071/codal-mcp
6
+ Project-URL: Issues, https://github.com/sepehr071/codal-mcp/issues
7
+ Project-URL: Website, https://mcpfarsi.ir/
8
+ Author-email: Sepehr Radmard <sepehrr80@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: annual-report,bourse,codal,codal-ir,disclosures,eps,financial-statements,iran,listed-companies,mcp,model-context-protocol,persian,tehran-stock-exchange,tse
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Office/Business :: Financial :: Investment
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: curl-cffi>=0.16.3
25
+ Requires-Dist: httpx-curl-cffi>=0.1.5
26
+ Requires-Dist: httpx>=0.27
27
+ Requires-Dist: mcp<3,>=2.2
28
+ Description-Content-Type: text/markdown
29
+
30
+ <!-- mcp-name: io.github.sepehr071/codal-mcp -->
31
+
32
+ <div align="center">
33
+
34
+ <img src="https://raw.githubusercontent.com/sepehr071/codal-mcp/main/.github/banner.png" alt="codal-mcp: unofficial Codal (کدال) MCP server that reads Iranian listed companies' disclosures and financial statements for Claude, Cursor and Copilot" width="100%">
35
+
36
+ # codal-mcp: Codal (کدال) disclosure and financial statement MCP server for AI agents
37
+
38
+ **codal-mcp lets an AI agent search and read Codal, the official disclosure system of Iranian listed companies.**<br>
39
+ Codal (codal.ir, سامانه جامع اطلاع‌رسانی ناشران) is where companies and funds on the Tehran Stock Exchange, Iran Fara Bourse<br>
40
+ and the other Iranian exchanges publish financial statements, monthly activity reports, meeting decisions and material news.<br>
41
+ codal-mcp is an unofficial, read-only MCP server with 5 tools that turns those letters into text and tables for Claude, Cursor or Copilot.
42
+
43
+ [![PyPI](https://img.shields.io/pypi/v/codal-mcp?color=2563eb)](https://pypi.org/project/codal-mcp/)
44
+ [![Python](https://img.shields.io/pypi/pyversions/codal-mcp)](https://pypi.org/project/codal-mcp/)
45
+ [![CI](https://github.com/sepehr071/codal-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/sepehr071/codal-mcp/actions/workflows/ci.yml)
46
+ [![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.sepehr071%2Fcodal--mcp-7c3aed)](https://registry.modelcontextprotocol.io/?q=codal-mcp)
47
+ [![License: MIT](https://img.shields.io/badge/license-MIT-16a34a)](https://github.com/sepehr071/codal-mcp/blob/main/LICENSE)
48
+
49
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_codal--mcp-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=codal&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22codal-mcp%22%5D%7D)
50
+
51
+ [For AI agents](#for-ai-agents) · [Quick start](#quick-start) · [What it can do](#what-it-can-do) · [Tools](#tools) · [FAQ](#faq) · [فارسی](#فارسی)
52
+
53
+ </div>
54
+
55
+ ---
56
+
57
+ ## For AI agents
58
+
59
+ - **What:** unofficial MCP server (model context protocol) for codal.ir, the disclosure system of companies and funds listed on Iranian exchanges (Tehran Stock Exchange, Iran Fara Bourse, commodity and energy exchanges, and registered unlisted companies).
60
+ - **Install:** `uvx codal-mcp` or `claude mcp add codal -- uvx codal-mcp`. Transport: stdio. Needs [uv](https://docs.astral.sh/uv/getting-started/installation/) (Python 3.10+).
61
+ - **Auth:** none, no API key or account. Optional `CODAL_MCP_PROXY` (HTTP proxy URL, or a comma-separated list); system proxy settings are ignored.
62
+ - **Access:** read-only. It cannot log in or file anything, so no confirmation is needed before calling any tool.
63
+ - **Tools:** 5, all prefixed `cd_`. Typical sequence: `cd_company` -> `cd_search_letters` -> `cd_letter`.
64
+ `cd_letter_types` gives letter type ids for filtering; `cd_financial_years` gives a company's fiscal year ends.
65
+ - **Use when:** the user asks what a listed company disclosed: its latest interim or annual financial statements, EPS, monthly sales and production, shareholder meeting decisions, dividend schedule, capital increase, or the text of one Codal letter.
66
+ - **Do not use when:** the user wants share prices, order books or market indices (use [tsetmc-mcp](https://github.com/sepehr071/tsetmc-mcp)), or wants to trade.
67
+ - **Output:** compact JSON with ASCII digits. Dates are Jalali (`YYYY/MM/DD`), Tehran time. Report amounts are as published, usually **million Rial** (see `unit_note`).
68
+ - **Rate limit:** codal.ir blocks an IP for up to an hour after a burst of requests. Make few, targeted calls and reuse results. If a tool says codal.ir is rate limiting, stop and wait.
69
+ - **Network:** codal.ir often answers only Iranian connections. If requests time out, set `CODAL_MCP_PROXY` to an Iranian HTTP proxy.
70
+ - **Machine-readable:** [`server.json`](https://github.com/sepehr071/codal-mcp/blob/main/server.json) and the
71
+ [iran-mcp catalog](https://github.com/sepehr071/iran-mcp).
72
+
73
+ ## Why
74
+
75
+ Everything an Iranian listed company publishes is on Codal, but behind a search form, Persian digits and report
76
+ pages rendered by JavaScript, with one statement sheet per page. Answering "how did Foolad do in the first half of
77
+ the year?" means finding the right letter among 1,475 and reading a table on screen. `codal-mcp` searches with the
78
+ site's own filters and returns the statement as rows an agent can read:
79
+
80
+ > **You:** What did Foolad (فولاد) report for its first six months of 1405?
81
+ >
82
+ > **Agent:** *calls* `cd_search_letters(symbol="فولاد", letter_type=6, period_months=6)` -> `cd_letter(tracing_no=1612323)`
83
+ >
84
+ > Mobarakeh Steel's unaudited six-month statements to 1405/06/31 (published 1405/07/30) show operating revenue of
85
+ > 2,509,422,184 million Rial, 56% more than the same period a year earlier, and a net profit of 591,629,286 million
86
+ > Rial, up 133%. Basic earnings per share were 308 Rial.
87
+
88
+ <sub>Real figures from tracing number 1612323, read with codal-mcp on 2026-10-31 and checked against the letter page on codal.ir.</sub>
89
+
90
+ ## What it can do
91
+
92
+ - **Search disclosures** of any publisher on Codal, newest first: by symbol, letter group, letter type, words in the title, Jalali date range, report period (1-12 months) or tracing number
93
+ - **List the newest letters** of the whole market when no filter is given
94
+ - **Read financial statements** as tables, one sheet at a time: income statement, comprehensive income, balance sheet, changes in equity, cash flows and the interpretive report pages, with the unit note and listed capital
95
+ - **Read monthly activity reports**: raw material purchases, production and sales by product, energy use and foreign currency sources and uses
96
+ - **Read text letters** such as explanations, clarifications and notices, without the page's hidden form templates
97
+ - **Get the links** to each letter's page, PDF, Excel file and attachments (with their descriptions and dates)
98
+ - **Look up companies and funds** by symbol or name: ISIC code, market, kind, industry and reporting type
99
+ - **List letter groups and letter types** with the ids the search takes, and a company's fiscal year ends
100
+ - **Read-only by design**: no login, no captcha solving
101
+
102
+ Example prompts:
103
+
104
+ - "What did Foolad report in its latest interim financial statements?"
105
+ - "Show the balance sheet from that letter."
106
+ - "List Iran Khodro's monthly activity reports for 1405."
107
+ - "Which companies published monthly activity reports this week?"
108
+ - "When does Foolad's fiscal year end, and when were its last annual statements published?"
109
+ - <span dir="rtl">آخرین صورت‌های مالی میان‌دوره‌ای فولاد در کدال چه بود؟</span>
110
+ - <span dir="rtl">گزارش فعالیت ماهانه مهر ۱۴۰۵ ایران خودرو را بیاور.</span>
111
+ - <span dir="rtl">تصمیمات آخرین مجمع عمومی سالیانه فولاد را از کدال بخوان.</span>
112
+
113
+ ## Quick start
114
+
115
+ You need [uv](https://docs.astral.sh/uv/getting-started/installation/). No API key or account.
116
+
117
+ <details open>
118
+ <summary><b>Claude Code</b></summary>
119
+
120
+ ```bash
121
+ claude mcp add codal -- uvx codal-mcp
122
+ ```
123
+ </details>
124
+
125
+ <details>
126
+ <summary><b>Claude Desktop</b></summary>
127
+
128
+ Settings → Developer → Edit Config, then add:
129
+
130
+ ```json
131
+ {
132
+ "mcpServers": {
133
+ "codal": { "command": "uvx", "args": ["codal-mcp"] }
134
+ }
135
+ }
136
+ ```
137
+ </details>
138
+
139
+ <details>
140
+ <summary><b>Cursor</b></summary>
141
+
142
+ Add the Claude Desktop block above to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project).
143
+ </details>
144
+
145
+ <details>
146
+ <summary><b>VS Code (Copilot agent mode)</b></summary>
147
+
148
+ Click **Install in VS Code** above, or add to `.vscode/mcp.json`:
149
+
150
+ ```json
151
+ {
152
+ "servers": {
153
+ "codal": { "type": "stdio", "command": "uvx", "args": ["codal-mcp"] }
154
+ }
155
+ }
156
+ ```
157
+ </details>
158
+
159
+ <details>
160
+ <summary><b>Codex CLI</b></summary>
161
+
162
+ ```bash
163
+ codex mcp add codal -- uvx codal-mcp
164
+ ```
165
+
166
+ Or in `~/.codex/config.toml`:
167
+
168
+ ```toml
169
+ [mcp_servers.codal]
170
+ command = "uvx"
171
+ args = ["codal-mcp"]
172
+ ```
173
+ </details>
174
+
175
+ <details>
176
+ <summary><b>Gemini CLI</b></summary>
177
+
178
+ Add to `~/.gemini/settings.json`:
179
+
180
+ ```json
181
+ {
182
+ "mcpServers": {
183
+ "codal": { "command": "uvx", "args": ["codal-mcp"] }
184
+ }
185
+ }
186
+ ```
187
+ </details>
188
+
189
+ <details>
190
+ <summary><b>Windsurf</b></summary>
191
+
192
+ Add the Claude Desktop block to `~/.codeium/windsurf/mcp_config.json`.
193
+ </details>
194
+
195
+ <details>
196
+ <summary><b>Anything else</b></summary>
197
+
198
+ It is a standard stdio MCP server: run `uvx codal-mcp`, or `pip install codal-mcp` and run `codal-mcp`.
199
+ </details>
200
+
201
+ ## Tools
202
+
203
+ Pass the trading symbol in Persian (`فولاد`, `خودرو`). Dates are Jalali `YYYY/MM/DD`; Persian digits are accepted.
204
+
205
+ | Tool | What it does |
206
+ |---|---|
207
+ | `cd_search_letters` | Search codal.ir disclosures (letters) of Iranian listed companies, newest first, 20 per page |
208
+ | `cd_letter` | Read one codal.ir letter: its text or tables, plus links to its page, PDF, Excel and attachments |
209
+ | `cd_company` | Find companies and funds on codal.ir by symbol or name, with their market, industry and type |
210
+ | `cd_letter_types` | List codal.ir letter groups, or the letter types of one group with the ids `cd_search_letters` takes |
211
+ | `cd_financial_years` | List the fiscal year-end dates codal.ir knows for one company, newest first (Jalali) |
212
+
213
+ All 5 tools are annotated `readOnlyHint: true`.
214
+
215
+ ## How it works
216
+
217
+ ```text
218
+ AI agent (Claude, Cursor, Copilot, ...)
219
+ │
220
+ │ MCP over stdio
221
+ ▼
222
+ codal-mcp (runs on your machine)
223
+ │
224
+ │ HTTPS, one request at a time, at least 2 s apart
225
+ ├──────▶ search.codal.ir search API, company list, letter types, fiscal years
226
+ └──────▶ www.codal.ir letter pages, sheets, attachment lists
227
+ ```
228
+
229
+ `codal-mcp` runs locally and calls the same search API and letter pages the codal.ir website uses. It has no hosted
230
+ server in between and no API key. Structured reports carry their tables as data inside the letter page; the server
231
+ reads that data and returns each row as one line, in the site's column order. Other letters come back as their
232
+ visible text. Requests go out through a Chrome-impersonating client, only to `search.codal.ir` and `www.codal.ir`.
233
+ It only reads.
234
+
235
+ ## Good to know
236
+
237
+ - **Rate limit.** codal.ir answers HTTP 429 and shows a captcha after a burst of requests, then blocks the IP for up to an hour. The server sends one request at a time, at least 2 seconds apart, keeps the company list and letter types for 12 hours, letters for an hour and searches for 2 minutes, and never retries a 429. After a 429 it stops calling codal.ir for 10 minutes and tells the agent to wait. It never solves captchas.
238
+ - **Iranian connection.** codal.ir often does not answer connections from outside Iran (from a foreign VPN exit, requests timed out in our tests). Set `CODAL_MCP_PROXY` to an HTTP proxy with an Iranian exit. System proxy variables are ignored on purpose.
239
+ - **Units.** Statement and report amounts are as published, usually million Rial; `unit_note` quotes the page. EPS is in Rial. Divide Rial by 10 for Toman.
240
+ - **Tables are text.** Each table row is one line with cells separated by ` | `. Numbers have no thousands separators, and negatives are `-N` where the site shows `(N)`. Income statements have two «درصد تغيير» columns: change against the same period last year and against the last full year.
241
+ - **One sheet at a time.** Financial statements are split into sheets; `cd_letter` returns the list of `sheets` and takes `sheet` to read another one (for example `0` for the balance sheet).
242
+ - **Attachments are listed, not read.** Explanation letters often carry their content in an attached image or PDF. `cd_letter` returns the links.
243
+ - **Long letters** are cut at 16,000 characters (`truncated`); the PDF link has the whole letter.
244
+ - **Search tips.** `period_months=12` finds annual reports, `6` half-year and `3` quarterly; `title` matches words in the letter title. `cd_letter_types` lists letter type ids (6 financial statements, 58 monthly activity report, 20 annual general meeting decisions).
245
+ - **Persian text.** Letter text is returned as the company wrote it, including Arabic ي/ك. Digits are converted to ASCII.
246
+ - **What it does not do:** no share prices (see tsetmc-mcp), no XBRL parsing, no reading of attached files, no login and no captcha solving.
247
+
248
+ ## FAQ
249
+
250
+ <details>
251
+ <summary><b>What is Codal (کدال)?</b></summary>
252
+
253
+ Codal (codal.ir, سامانه جامع اطلاع‌رسانی ناشران) is the official disclosure system run under Iran's Securities and
254
+ Exchange Organization (SEO). Companies and funds listed on the Tehran Stock Exchange, Iran Fara Bourse and the other
255
+ Iranian exchanges publish their financial statements, monthly activity reports, meeting notices and decisions,
256
+ capital increases and material news there. About 5,400 publishers are on it.
257
+ </details>
258
+
259
+ <details>
260
+ <summary><b>How can an AI read a company's financial statements from Codal?</b></summary>
261
+
262
+ Add `codal-mcp` to your agent, then ask in plain language. The agent finds the letter with `cd_search_letters`
263
+ (for example `symbol="فولاد", letter_type=6, period_months=6`) and reads it with `cd_letter(tracing_no=...)`, which
264
+ returns the income statement as rows; `sheet=0` gives the balance sheet.
265
+ </details>
266
+
267
+ <details>
268
+ <summary><b>Is there an official Codal API?</b></summary>
269
+
270
+ There is no documented public API. `codal-mcp` uses the same search API and letter pages that the codal.ir website
271
+ uses, without login, and returns compact JSON.
272
+ </details>
273
+
274
+ <details>
275
+ <summary><b>Does it work outside Iran?</b></summary>
276
+
277
+ Often not directly: codal.ir did not answer requests from a foreign VPN exit in our tests. Run it on an Iranian
278
+ connection, or set `CODAL_MCP_PROXY` to an HTTP proxy with an Iranian exit.
279
+ </details>
280
+
281
+ <details>
282
+ <summary><b>Why does it say codal.ir is rate limiting?</b></summary>
283
+
284
+ codal.ir blocks an IP for up to an hour after many requests in a short time. The server spaces and caches requests
285
+ to avoid it; if it still happens, wait and ask again with fewer calls. Results you already have stay valid.
286
+ </details>
287
+
288
+ <details>
289
+ <summary><b>How is it different from tsetmc-mcp?</b></summary>
290
+
291
+ [tsetmc-mcp](https://github.com/sepehr071/tsetmc-mcp) gives market data from the Tehran Stock Exchange: prices,
292
+ order book, trades and indices. `codal-mcp` gives what the companies themselves publish: statements, reports and
293
+ notices. Use both for a full picture of a stock.
294
+ </details>
295
+
296
+ <details>
297
+ <summary><b>Does it parse XBRL or give financial ratios?</b></summary>
298
+
299
+ No. It returns the tables as the site shows them; the agent can compute ratios from the rows. For a spreadsheet,
300
+ use the `excel` link that `cd_letter` returns.
301
+ </details>
302
+
303
+ <details>
304
+ <summary><b>Can it give investment advice?</b></summary>
305
+
306
+ No. It only reads what companies published. Nothing it returns is financial advice.
307
+ </details>
308
+
309
+ <details>
310
+ <summary><b>How do I debug what the agent sees?</b></summary>
311
+
312
+ ```bash
313
+ npx @modelcontextprotocol/inspector uvx codal-mcp
314
+ ```
315
+ </details>
316
+
317
+ ## Configuration
318
+
319
+ | Variable | Default | Meaning |
320
+ |---|---|---|
321
+ | `CODAL_MCP_PROXY` | unset | Optional HTTP proxy URL for codal.ir requests; system proxy settings are ignored. A comma-separated list is used one at a time: the next proxy takes over when one is blocked or cannot connect |
322
+
323
+ <a id="فارسی"></a>
324
+
325
+ ## فارسی: سرور MCP کدال برای دستیار هوش مصنوعی
326
+
327
+ <div dir="rtl">
328
+
329
+ پروژه **codal-mcp** یک سرور MCP غیررسمی و فقط‌خواندنی برای کدال (codal.ir) است، سامانه‌ای که شرکت‌ها و صندوق‌های بورس تهران، فرابورس و بقیه بورس‌های ایران اطلاعیه‌ها و صورت‌های مالی خود را در آن منتشر می‌کنند. با این سرور، دستیار هوش مصنوعی شما (Claude، Cursor، Copilot و ...) اطلاعیه‌های کدال را جستجو می‌کند و متن و جدول‌های آن‌ها را می‌خواند.
330
+
331
+ **چه کارهایی می‌کند**
332
+
333
+ - **جستجوی اطلاعیه‌ها** با نماد، گروه و نوع اطلاعیه، کلمه‌های عنوان، بازه تاریخ شمسی، طول دوره گزارش یا شماره پیگیری؛ جدیدترین‌ها اول.
334
+ - **خواندن صورت‌های مالی** به شکل جدول، هر بار یک برگه: سود و زیان، وضعیت مالی، جریان‌های نقدی و بقیه برگه‌ها.
335
+ - **خواندن گزارش فعالیت ماهانه**: خرید مواد اولیه، تولید و فروش هر محصول، مصرف انرژی و منابع و مصارف ارزی.
336
+ - **متن اطلاعیه‌های توضیحی** و شفاف‌سازی، همراه با لینک PDF، فایل اکسل و پیوست‌ها.
337
+ - **جستجوی شرکت‌ها و صندوق‌ها** با نماد یا نام، با کد آیسیک، بازار، صنعت و سال‌های مالی.
338
+
339
+ **نکته‌ها**
340
+
341
+ - فقط اطلاعات منتشرشده را می‌خواند؛ وارد حسابی نمی‌شود و توصیه سرمایه‌گذاری نیست.
342
+ - مبلغ‌ها همان‌طور است که در کدال آمده، معمولاً میلیون ریال. تاریخ‌ها شمسی است.
343
+ - کدال بعد از تعداد زیادی درخواست، دسترسی را تا یک ساعت می‌بندد. این سرور درخواست‌ها را یکی‌یکی و با فاصله دست‌کم ۲ ثانیه می‌فرستد و نتیجه را نگه می‌دارد.
344
+ - کدال معمولاً فقط به اینترنت ایران جواب می‌دهد. اگر درخواست‌ها بی‌جواب ماند، متغیر `CODAL_MCP_PROXY` را روی یک پراکسی HTTP با خروجی ایران بگذارید.
345
+ - کلید API لازم نیست و سرور روی سیستم خود شما اجرا می‌شود.
346
+
347
+ **نصب** (اول [uv](https://docs.astral.sh/uv/getting-started/installation/) را نصب کنید). در Claude Code:
348
+
349
+ </div>
350
+
351
+ ```bash
352
+ claude mcp add codal -- uvx codal-mcp
353
+ ```
354
+
355
+ <div dir="rtl">
356
+
357
+ در Claude Desktop، Cursor و بقیه برنامه‌ها همان تنظیم بخش [Quick start](#quick-start) را بگذارید.
358
+
359
+ **نمونه پرسش‌ها**
360
+
361
+ - «آخرین صورت‌های مالی شش‌ماهه فولاد را بیاور و سود خالص را با پارسال مقایسه کن.»
362
+ - «ترازنامه همان اطلاعیه را هم نشان بده.»
363
+ - «گزارش‌های فعالیت ماهانه ایران خودرو در سال ۱۴۰۵ را فهرست کن.»
364
+ - «این هفته کدام شرکت‌ها گزارش فعالیت ماهانه منتشر کرده‌اند؟»
365
+ - «سال مالی فولاد کی تمام می‌شود؟»
366
+
367
+ </div>
368
+
369
+ ## Development
370
+
371
+ ```bash
372
+ git clone https://github.com/sepehr071/codal-mcp && cd codal-mcp
373
+ uv sync
374
+ uv run ruff check . && uv run ruff format --check .
375
+ uv run python -m pytest -q # offline unit tests on recorded codal.ir pages
376
+ uv run python -m pytest -m live -q # one pass over every tool against codal.ir (about 8 requests)
377
+ uv build
378
+ ```
379
+
380
+ All tools live in `src/codal_mcp/codal.py`; all HTTP, pacing and caching in `src/codal_mcp/http.py`. Keep the live
381
+ suite small: codal.ir rate-limits hard. Issues and PRs are welcome.
382
+
383
+ Releases: bump the version in `pyproject.toml` and `server.json`, then push a `v*` tag. GitHub Actions publishes to PyPI.
384
+
385
+ ## Related servers
386
+
387
+ - [tsetmc-mcp](https://github.com/sepehr071/tsetmc-mcp) for Tehran Stock Exchange prices, order book, real vs legal trading and indices
388
+ - [iran-tax-mcp](https://github.com/sepehr071/iran-tax-mcp) for Iranian tax data: goods IDs and VAT, activity codes, property values and tax laws
389
+ - [iran-mcp](https://github.com/sepehr071/iran-mcp): catalog of all Iranian-service MCP servers
390
+
391
+ ## Disclaimer
392
+
393
+ Unofficial and not affiliated with or endorsed by Codal or the Securities and Exchange Organization of Iran (SEO).
394
+ It is read-only and uses the search API and pages of the codal.ir website, which can change without
395
+ notice. Data is informational. Nothing here is financial advice.
396
+
397
+ ## Author
398
+
399
+ <a href="https://www.linkedin.com/in/sepehr-radmard"><img src="https://raw.githubusercontent.com/sepehr071/iran-mcp/main/assets/author-banner.png" alt="Sepehr Radmard: open-source MCP servers for the Iranian web. LinkedIn: linkedin.com/in/sepehr-radmard" width="100%"></a>
400
+
401
+ Built and maintained by **Sepehr Radmard** (سپهر رادمرد). Connect on [LinkedIn](https://www.linkedin.com/in/sepehr-radmard) or follow [@sepehr071 on GitHub](https://github.com/sepehr071) for more MCP servers for Iranian websites, all listed in [iran-mcp](https://github.com/sepehr071/iran-mcp). If this saves you time, a star on the repo helps other people find it.
402
+
403
+ ## License
404
+
405
+ [MIT](https://github.com/sepehr071/codal-mcp/blob/main/LICENSE)