eodhd-guard-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 (105) hide show
  1. eodhd_guard_mcp-0.1.0/.gitignore +17 -0
  2. eodhd_guard_mcp-0.1.0/CHANGELOG.md +32 -0
  3. eodhd_guard_mcp-0.1.0/CONTRIBUTING.md +127 -0
  4. eodhd_guard_mcp-0.1.0/LICENSE +21 -0
  5. eodhd_guard_mcp-0.1.0/PKG-INFO +650 -0
  6. eodhd_guard_mcp-0.1.0/README.md +615 -0
  7. eodhd_guard_mcp-0.1.0/SECURITY.md +60 -0
  8. eodhd_guard_mcp-0.1.0/docs/DESIGN.md +755 -0
  9. eodhd_guard_mcp-0.1.0/docs/caveats.md +223 -0
  10. eodhd_guard_mcp-0.1.0/pyproject.toml +130 -0
  11. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/__init__.py +3 -0
  12. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/__main__.py +6 -0
  13. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/cache.py +179 -0
  14. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/cli.py +139 -0
  15. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/client.py +497 -0
  16. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/config.py +244 -0
  17. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/costs.py +54 -0
  18. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/coverage.py +127 -0
  19. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/envelope.py +105 -0
  20. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/errors.py +69 -0
  21. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/freshness.py +70 -0
  22. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/ledger.py +241 -0
  23. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/markets.py +184 -0
  24. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/py.typed +0 -0
  25. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/redact.py +112 -0
  26. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/semantics.py +234 -0
  27. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/server.py +127 -0
  28. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/tools/__init__.py +82 -0
  29. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/tools/calendar.py +1128 -0
  30. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/tools/fundamentals.py +822 -0
  31. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/tools/prices.py +793 -0
  32. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/tools/quotes.py +327 -0
  33. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/tools/reference.py +1151 -0
  34. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/tools/usage.py +135 -0
  35. eodhd_guard_mcp-0.1.0/src/eodhd_guard_mcp/validation.py +312 -0
  36. eodhd_guard_mcp-0.1.0/tests/__init__.py +0 -0
  37. eodhd_guard_mcp-0.1.0/tests/conftest.py +95 -0
  38. eodhd_guard_mcp-0.1.0/tests/contract/__init__.py +0 -0
  39. eodhd_guard_mcp-0.1.0/tests/contract/test_eval_cache.py +355 -0
  40. eodhd_guard_mcp-0.1.0/tests/fixtures/core_account.json +13 -0
  41. eodhd_guard_mcp-0.1.0/tests/fixtures/core_eod_acme.json +6 -0
  42. eodhd_guard_mcp-0.1.0/tests/fixtures/guards_eod_acme_us.json +11 -0
  43. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_cal_dividend_calendar.json +26 -0
  44. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_cal_dividends_acme.json +122 -0
  45. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_cal_dividends_globex.json +32 -0
  46. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_cal_earnings.json +20 -0
  47. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_cal_split_calendar.json +10 -0
  48. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_cal_splits_acme.json +38 -0
  49. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_fund_acme_stock.json +1653 -0
  50. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_fund_etf.json +571 -0
  51. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_fund_fund.json +168 -0
  52. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_fund_globex_lse.json +1127 -0
  53. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_fund_initech_mixed.json +1127 -0
  54. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_eod_acme.json +25 -0
  55. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_eod_filler_acme.json +7 -0
  56. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_eod_frozen_rog.json +20 -0
  57. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_eod_globex_lse.json +8 -0
  58. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_intraday_acme.json +160 -0
  59. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_quote_acme.json +13 -0
  60. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_quote_multi.json +41 -0
  61. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_prices_quote_na_rog.json +13 -0
  62. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_eod_acme_fresh.json +12 -0
  63. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_eod_rog_frozen.json +5 -0
  64. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_exchanges.json +8 -0
  65. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_quote_acme.json +13 -0
  66. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_quote_na.json +13 -0
  67. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_search_acme.json +8 -0
  68. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_search_roche_name.json +7 -0
  69. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_search_roche_name_two.json +6 -0
  70. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_search_rog.json +4 -0
  71. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_search_rog_other.json +4 -0
  72. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_symbols_delisted_sw.json +5 -0
  73. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_symbols_delisted_us.json +5 -0
  74. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_symbols_us.json +32 -0
  75. eodhd_guard_mcp-0.1.0/tests/fixtures/tools_ref_user.json +13 -0
  76. eodhd_guard_mcp-0.1.0/tests/helpers.py +149 -0
  77. eodhd_guard_mcp-0.1.0/tests/integration/__init__.py +0 -0
  78. eodhd_guard_mcp-0.1.0/tests/live/__init__.py +0 -0
  79. eodhd_guard_mcp-0.1.0/tests/live/test_live.py +88 -0
  80. eodhd_guard_mcp-0.1.0/tests/tools/__init__.py +0 -0
  81. eodhd_guard_mcp-0.1.0/tests/tools/test_calendar.py +1438 -0
  82. eodhd_guard_mcp-0.1.0/tests/tools/test_check_symbol.py +1077 -0
  83. eodhd_guard_mcp-0.1.0/tests/tools/test_fundamentals.py +1107 -0
  84. eodhd_guard_mcp-0.1.0/tests/tools/test_prices.py +1376 -0
  85. eodhd_guard_mcp-0.1.0/tests/tools/test_quotes.py +608 -0
  86. eodhd_guard_mcp-0.1.0/tests/tools/test_reference.py +618 -0
  87. eodhd_guard_mcp-0.1.0/tests/tools/test_usage.py +318 -0
  88. eodhd_guard_mcp-0.1.0/tests/unit/__init__.py +0 -0
  89. eodhd_guard_mcp-0.1.0/tests/unit/test_cache.py +318 -0
  90. eodhd_guard_mcp-0.1.0/tests/unit/test_cli.py +175 -0
  91. eodhd_guard_mcp-0.1.0/tests/unit/test_client.py +1100 -0
  92. eodhd_guard_mcp-0.1.0/tests/unit/test_config.py +351 -0
  93. eodhd_guard_mcp-0.1.0/tests/unit/test_costs.py +67 -0
  94. eodhd_guard_mcp-0.1.0/tests/unit/test_coverage.py +266 -0
  95. eodhd_guard_mcp-0.1.0/tests/unit/test_envelope.py +105 -0
  96. eodhd_guard_mcp-0.1.0/tests/unit/test_errors.py +66 -0
  97. eodhd_guard_mcp-0.1.0/tests/unit/test_freshness.py +208 -0
  98. eodhd_guard_mcp-0.1.0/tests/unit/test_ledger.py +402 -0
  99. eodhd_guard_mcp-0.1.0/tests/unit/test_markets.py +708 -0
  100. eodhd_guard_mcp-0.1.0/tests/unit/test_packaging.py +66 -0
  101. eodhd_guard_mcp-0.1.0/tests/unit/test_redact.py +240 -0
  102. eodhd_guard_mcp-0.1.0/tests/unit/test_semantics.py +549 -0
  103. eodhd_guard_mcp-0.1.0/tests/unit/test_server.py +70 -0
  104. eodhd_guard_mcp-0.1.0/tests/unit/test_tools_init.py +71 -0
  105. eodhd_guard_mcp-0.1.0/tests/unit/test_validation.py +553 -0
@@ -0,0 +1,17 @@
1
+ # Local-only material (EODHD eval cache holds licensed data; never commit)
2
+ _local/
3
+ .env
4
+ .env.*
5
+ !.env.example
6
+ .venv/
7
+ __pycache__/
8
+ *.py[cod]
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ coverage.xml
14
+ htmlcov/
15
+ dist/
16
+ build/
17
+ *.egg-info/
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). While the version is below 1.0, a minor release can change tool names, parameters and output fields.
4
+
5
+ ## [Unreleased]
6
+
7
+ The first release, planned as 0.1.0.
8
+
9
+ ### Added
10
+
11
+ - Fourteen read-only tools: `get_eod_prices`, `get_intraday_prices`, `get_quote`, `get_fundamentals`, `get_earnings_calendar`, `get_dividends`, `get_dividend_calendar`, `get_splits`, `get_split_calendar`, `list_exchanges`, `list_exchange_symbols`, `search_symbols`, `check_symbol` and `get_usage`.
12
+ - A common response envelope: `data`, `warnings` with stable codes, and `meta` with the cost, the cache state, when EODHD produced the data, and notes. Failures are errors with stable codes and hints.
13
+ - Argument validation before any call, because EODHD ignores bad parameters: strict `YYYY-MM-DD` dates, `CODE.EXCHANGE` symbols, range and size limits, and clamping of future end dates.
14
+ - Guards for empty and placeholder answers: HTTP 200 with `[]`, `"NA"` quote fields or the wrong shape becomes an error or an explicit warning.
15
+ - Detection of frozen, delisted and renamed codes (`STALE_DATA`, `NO_QUOTE`, `POSSIBLY_INACTIVE`), and `check_symbol`, which also looks for likely successor codes.
16
+ - A coverage registry for Tokyo and the UAE. Requests for those markets are refused with `NOT_COVERED` before they cost anything. `EODHD_GUARD_ALLOW_UNCOVERED` switches the pre-check off.
17
+ - Price semantics: a `price_basis` choice of raw, adjusted or both, removal of holiday filler bars, warnings for known spin-off back-adjustments (Novartis, Unilever and Reliance), pence-quoting notes for London lines, and a check for split ratios that look like spin-offs.
18
+ - Timing guards: quotes are always marked as delayed, same-day intraday bars are flagged as not yet available, and a per-market model of publication lag decides when a bar should exist.
19
+ - Trimmed fundamentals, capped at about 150 KB, with warnings for currency mismatches, unreliable filing dates, an inconsistent dividend yield and the analyst basis of EPS.
20
+ - Calendars served from one whole-market request that is filtered locally, with warnings for unreliable timing flags and missing rows.
21
+ - Cost control: a per-endpoint cost table, the cost on every response, a local SQLite usage ledger that keeps 90 days, a daily budget per GMT day (default 1000) with `BUDGET_EXCEEDED` and `BUDGET_LOW`, and the `get_usage` tool.
22
+ - A local SQLite response cache with a lifetime for each endpoint. `EODHD_GUARD_CACHE=off` turns it off.
23
+ - Key handling: the key is read from `EODHD_API_KEY` or `EODHD_API_KEY_FILE`, and is never a tool argument, never logged, never cached and never returned. Logs and errors are redacted, and the account tool returns counters only.
24
+ - Retries with backoff for 429, 5xx and network errors.
25
+ - Command line and transports: stdio by default and streamable HTTP on `127.0.0.1`, with `--check`, `--check --online` and `--version`, and `python -m eodhd_guard_mcp`.
26
+ - Short instructions that the server sends to the model when it connects.
27
+ - Support for Python 3.10 to 3.13 on Linux, macOS and Windows.
28
+ - Documentation: README, `docs/DESIGN.md` and `docs/caveats.md`, with configuration examples for Claude Code and Claude Desktop.
29
+ - Project files: contributing guide with a synthetic-fixtures-only policy, security policy, code of conduct, issue and pull request templates.
30
+ - Tooling: CI (lint, type check, tests on three operating systems, package build, secret scan), Dependabot, pre-commit hooks and a gitleaks configuration.
31
+
32
+ [Unreleased]: https://github.com/techfreakworm/eodhd-guard-mcp/commits/main
@@ -0,0 +1,127 @@
1
+ # Contributing
2
+
3
+ Thanks for helping. This is a small, deliberately narrow project, so please read this page and [docs/DESIGN.md](docs/DESIGN.md) before you change code. Everyone taking part is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
4
+
5
+ For a new tool or a large change, open an issue first so we can agree that it fits. A tool belongs here when it guards against a failure an AI assistant cannot see, or against a cost it cannot see.
6
+
7
+ ## Fixture policy: read this first
8
+
9
+ **Tests use synthetic data only. Never commit a real EODHD response, or values copied from one.**
10
+
11
+ EODHD's licence is for personal use and forbids redistributing its data. A real response in a fixture, an issue, a pull request, a log or a doc counts as redistribution.
12
+
13
+ - Fixtures live in `tests/fixtures/` as JSON. They use fictional companies (`ACME.US`, `GLOBEX.LSE`, `INITECH.SW`, `UMBRELLA.NSE`) and invented numbers.
14
+ - Copy only the **shape** of real answers: field names, types and quirks such as `"NA"` strings, `[]` bodies, plain-text 404 bodies, filler bars and odd split ratios. Do not copy values.
15
+ - A real number that has been nudged is still a real number. Invent new ones.
16
+ - Real responses may be used only from a local, git-ignored folder, through the contract tests described below. That folder never leaves your machine.
17
+ - The same rule covers issues, pull requests, commit messages and docs: describe the shape of a result and do not paste it. Percentages and dates of public corporate events are fine.
18
+ - The secret scanners catch keys, not licensed data. You are the check.
19
+
20
+ ## Set up
21
+
22
+ ```bash
23
+ git clone https://github.com/techfreakworm/eodhd-guard-mcp.git
24
+ cd eodhd-guard-mcp
25
+ python -m venv .venv
26
+ source .venv/bin/activate # on Windows: .venv\Scripts\activate
27
+ pip install -e ".[dev]"
28
+ pip install pre-commit && pre-commit install # optional, but it catches problems early
29
+ ```
30
+
31
+ Python 3.10 is the floor, and the code must run on 3.10 to 3.13. Do not use `StrEnum`, `datetime.UTC`, `typing.Self` or `tomllib`. Use `datetime.timezone.utc` and `class X(str, Enum)`.
32
+
33
+ ## Run the checks
34
+
35
+ ```bash
36
+ pytest # the test suite; it makes no network calls
37
+ pytest --cov=eodhd_guard_mcp --cov-report=term-missing # with coverage; CI fails below 85%
38
+ ruff check . # lint
39
+ ruff format . # format (add --check to only report)
40
+ mypy # strict type check
41
+ ```
42
+
43
+ CI runs the same checks. It runs the tests on Linux with Python 3.10 to 3.13, and on macOS and Windows with Python 3.12. It also builds the package and scans the history for secrets.
44
+
45
+ ## Contract tests and live tests
46
+
47
+ **Contract tests** (`tests/contract`, marker `contract`) run against a local folder of real responses. They are skipped unless `EODHD_GUARD_EVAL_CACHE` points at that folder.
48
+
49
+ ```bash
50
+ EODHD_GUARD_EVAL_CACHE=/path/to/your/local/folder pytest tests/contract
51
+ ```
52
+
53
+ The folder holds licensed data. Keep it outside the repository, or in `_local/`, which is git-ignored. Never commit it, share it or attach it to an issue.
54
+
55
+ **Live tests** (`tests/live`, marker `live`) call the real API. They run only with `EODHD_GUARD_LIVE=1` and a key, and must stay under 10 calls per run. CI never runs them.
56
+
57
+ ```bash
58
+ EODHD_GUARD_LIVE=1 EODHD_API_KEY_FILE="$HOME/.config/eodhd-guard-mcp/api_key" pytest tests/live
59
+ ```
60
+
61
+ On Windows PowerShell, set the variables with `$env:EODHD_GUARD_LIVE = "1"`. Prefer a mock test whenever one can prove the same thing, because every live call spends your allowance.
62
+
63
+ ## Add a tool
64
+
65
+ Follow [docs/DESIGN.md](docs/DESIGN.md). It is the contract between the modules, so change it in the same pull request as the code.
66
+
67
+ 1. **Design first.** Add the tool to DESIGN.md: signature with defaults, cost, cache lifetime, guards in order, and output shape.
68
+ 2. **Price it.** Add the endpoint to the cost table in `costs.py`. If you took the price from EODHD's documentation and did not measure it, say so with `measured=False`.
69
+ 3. **Validate before calling.** Use `validation.py` (`parse_symbol`, `parse_date`, `resolve_range`, `check_int` and the rest). EODHD ignores bad parameters, so the tool must not. Every `INVALID_PARAMS` message names the field, the value received and what is accepted.
70
+ 4. **Write the tool** in the matching module under `src/eodhd_guard_mcp/tools/` and register it in `register_all`. Declare parameters as `Annotated[T, Field(description=...)]`, because the SDK does not read docstrings for parameter descriptions. The tool description states the cost in API calls and the main caveat, in two to four sentences. Tools are read-only and go through the `guarded` decorator.
71
+ 5. **Treat empty and placeholder answers as non-data.** HTTP 200 with `[]`, `"NA"` fields or the wrong shape becomes an error or an explicit warning, never a silent success. Return `build_response`, add any new warning code to `WarningCode` and to the table in DESIGN.md, and keep default outputs small.
72
+ 6. **Test every guard.** For each guard, write a test that fails when the guard is removed. Use the `MockEODHD` helper and synthetic fixtures. An unmocked path fails the test with an error that names it, so a test cannot reach the network by accident. Add an integration test through the in-process MCP client for registration and error mapping.
73
+ 7. **Document it.** Update the README tool table and tool section, `docs/caveats.md` if the tool guards a new quirk of the data, and `CHANGELOG.md`.
74
+
75
+ ## Update the coverage registry
76
+
77
+ `coverage.py` holds `GAPS`, the markets where EODHD has no usable data. A request for a symbol on one of them is refused with `NOT_COVERED` before it costs anything.
78
+
79
+ To add a gap:
80
+
81
+ 1. Check it on your own account. Record the date, the endpoints you tried and the HTTP statuses. Put that evidence in the pull request as statuses and shapes, not data.
82
+ 2. Add a `CoverageGap` with its `key`, `market`, every exchange code and suffix that means the market (`suffixes`), whether the earnings calendar still has rows (`calendar_dates`), a `message` that says what is missing and when it was checked ("in checks in October 2026"), and `alternatives`.
83
+ 3. Be careful with look-alike suffixes. `T` is Tokyo, but `TO` is Toronto and `TA` is Tel Aviv.
84
+ 4. Add tests for `find_gap` and `ensure_covered`, and update the registry list in DESIGN.md and the section in `docs/caveats.md`.
85
+
86
+ To remove a gap, repeat the check when EODHD announces coverage, delete the entry, and say so in the changelog. Users can switch the pre-check off in the meantime with `EODHD_GUARD_ALLOW_UNCOVERED=1`.
87
+
88
+ Two other registries work the same way:
89
+
90
+ - `KNOWN_SPINOFF_ADJUSTMENTS` in `semantics.py` lists spin-offs and demergers that EODHD folds into `close`. Add one only after confirming the back-adjustment against a second source, and give the event date and a plain description. Both are public facts.
91
+ - `MARKETS` in `markets.py` holds trading hours, time zones and publication lags. Set `lag_measured` to true only for a lag you measured.
92
+
93
+ ## Commit messages
94
+
95
+ Write the subject in the imperative mood, in about 72 characters or fewer, and explain why in the body. The diff already shows what changed.
96
+
97
+ ```text
98
+ Drop holiday filler bars from EOD results
99
+
100
+ EODHD returns flat, zero-volume bars on exchange holidays. A model reads
101
+ them as trading days on which nothing moved, so remove them unless the
102
+ caller asks to keep them.
103
+ ```
104
+
105
+ Keep one logical change in each commit, and keep pull requests small.
106
+
107
+ ## Pull request checklist
108
+
109
+ The pull request template has the same list.
110
+
111
+ - [ ] `pytest` passes and the 85% coverage gate holds.
112
+ - [ ] `ruff check .`, `ruff format --check .` and `mypy` are clean.
113
+ - [ ] Every new or changed guard has a test that fails without it.
114
+ - [ ] Test data is synthetic: fictional tickers and invented numbers, no real EODHD responses.
115
+ - [ ] A new or changed tool states its cost in API calls and its main caveat in its description, and DESIGN.md and the README match.
116
+ - [ ] `CHANGELOG.md` has a line under "Unreleased".
117
+ - [ ] No API keys, account details or private paths appear in the diff, in logs, or in the description.
118
+
119
+ ## Never paste API keys
120
+
121
+ Do not put an API key in an issue, a pull request, a commit message, a test, a log, a screenshot or a chat. The same goes for account details such as your name, email address or payment method.
122
+
123
+ - Give the server your key through `EODHD_API_KEY_FILE`, so it stays out of your shell history.
124
+ - `eodhd-guard-mcp --check` shows whether a key is set and never shows the key.
125
+ - If a key leaks, rotate it in your EODHD account straight away. Deleting a comment is not enough, because git history, caches and mirrors keep copies.
126
+ - The tests use the fake key `test-key-0123456789`, and `.gitleaks.toml` excuses that string inside `tests/` only. Use it for nothing else, and do not add other exceptions without a reason.
127
+ - To report a security problem, follow [SECURITY.md](SECURITY.md) instead of opening an issue.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mayank Gupta
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.