trading-mcp-server 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 (49) hide show
  1. trading_mcp_server-0.1.0/.gitignore +10 -0
  2. trading_mcp_server-0.1.0/CLAUDE.md +71 -0
  3. trading_mcp_server-0.1.0/LICENSE +21 -0
  4. trading_mcp_server-0.1.0/PKG-INFO +162 -0
  5. trading_mcp_server-0.1.0/README.md +126 -0
  6. trading_mcp_server-0.1.0/agent-register.md +32 -0
  7. trading_mcp_server-0.1.0/pyproject.toml +56 -0
  8. trading_mcp_server-0.1.0/src/trading_mcp_server/__init__.py +3 -0
  9. trading_mcp_server-0.1.0/src/trading_mcp_server/backtest/__init__.py +0 -0
  10. trading_mcp_server-0.1.0/src/trading_mcp_server/backtest/engine.py +111 -0
  11. trading_mcp_server-0.1.0/src/trading_mcp_server/backtest/strategies.py +57 -0
  12. trading_mcp_server-0.1.0/src/trading_mcp_server/broker/__init__.py +0 -0
  13. trading_mcp_server-0.1.0/src/trading_mcp_server/broker/smartapi_adapter.py +176 -0
  14. trading_mcp_server-0.1.0/src/trading_mcp_server/config.py +254 -0
  15. trading_mcp_server-0.1.0/src/trading_mcp_server/prompts/__init__.py +61 -0
  16. trading_mcp_server-0.1.0/src/trading_mcp_server/resources/__init__.py +36 -0
  17. trading_mcp_server-0.1.0/src/trading_mcp_server/server.py +46 -0
  18. trading_mcp_server-0.1.0/src/trading_mcp_server/services/__init__.py +0 -0
  19. trading_mcp_server-0.1.0/src/trading_mcp_server/services/broker_service.py +192 -0
  20. trading_mcp_server-0.1.0/src/trading_mcp_server/services/data_provider_service.py +152 -0
  21. trading_mcp_server-0.1.0/src/trading_mcp_server/services/indicator_service.py +149 -0
  22. trading_mcp_server-0.1.0/src/trading_mcp_server/services/notification_service.py +130 -0
  23. trading_mcp_server-0.1.0/src/trading_mcp_server/services/order_validation_service.py +228 -0
  24. trading_mcp_server-0.1.0/src/trading_mcp_server/services/paper_trading_service.py +266 -0
  25. trading_mcp_server-0.1.0/src/trading_mcp_server/services/risk_service.py +99 -0
  26. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/__init__.py +33 -0
  27. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/_common.py +33 -0
  28. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/broker.py +105 -0
  29. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/config_tools.py +64 -0
  30. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/indicators.py +78 -0
  31. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/market_data.py +45 -0
  32. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/news.py +34 -0
  33. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/notifications.py +64 -0
  34. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/paper_trading.py +81 -0
  35. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/portfolio.py +45 -0
  36. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/risk.py +65 -0
  37. trading_mcp_server-0.1.0/src/trading_mcp_server/tools/strategy.py +140 -0
  38. trading_mcp_server-0.1.0/src/trading_mcp_server/utils/__init__.py +0 -0
  39. trading_mcp_server-0.1.0/src/trading_mcp_server/utils/instruments.py +69 -0
  40. trading_mcp_server-0.1.0/src/trading_mcp_server/utils/logger.py +37 -0
  41. trading_mcp_server-0.1.0/src/trading_mcp_server/utils/time_utils.py +73 -0
  42. trading_mcp_server-0.1.0/tests/conftest.py +53 -0
  43. trading_mcp_server-0.1.0/tests/test_broker_safety.py +80 -0
  44. trading_mcp_server-0.1.0/tests/test_config.py +59 -0
  45. trading_mcp_server-0.1.0/tests/test_indicators.py +70 -0
  46. trading_mcp_server-0.1.0/tests/test_notifications.py +119 -0
  47. trading_mcp_server-0.1.0/tests/test_order_validation.py +139 -0
  48. trading_mcp_server-0.1.0/tests/test_paper_trading.py +71 -0
  49. trading_mcp_server-0.1.0/tests/test_risk_and_backtest.py +76 -0
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ venv/
8
+ .env
9
+ storage/
10
+ .pytest_cache/
@@ -0,0 +1,71 @@
1
+ # CLAUDE.md — trading-mcp-server
2
+
3
+ ## Project context
4
+
5
+ This repo is a **standalone, pip-installable Python package** that implements
6
+ a local MCP server with safe trading tools (NSE / Angel One). It is consumed
7
+ by trading workspaces (e.g. the sibling `TradingAgent` repo) but must never
8
+ depend on them. The agent using the tools lives elsewhere — this package only
9
+ provides data, validation, simulation, and a guarded broker layer.
10
+
11
+ ## Package structure rules
12
+
13
+ - `src/` layout, import package `trading_mcp_server`, distribution name
14
+ `trading-mcp-server`. Do not break this naming or move out of `src/`.
15
+ - `server.py` only wires things together (`create_server()`); logic lives in
16
+ `services/`, tool registration in `tools/` (one module per category, each
17
+ exposing `register(mcp)`), MCP resources/prompts in their packages.
18
+ - `broker/smartapi_adapter.py` is the ONLY module that talks to the real
19
+ broker, and `services/broker_service.py` is the ONLY caller of its order
20
+ methods. Keep it that way — that's what makes the safety layer auditable.
21
+ - All filesystem state goes under `get_storage_dir()`; all config through
22
+ `config.get_config()`. Both resolve from `TRADING_MCP_HOME` (or cwd).
23
+ **Never hardcode a repo path, user path, or absolute path.**
24
+ - Heavy/optional imports (SmartApi, bs4) stay lazy so paper-mode users and
25
+ tests run without the `[broker,scanners]` extras.
26
+
27
+ ## MCP tool design rules
28
+
29
+ - Tools return plain JSON-serializable dicts; errors as `{"error": ...}` via
30
+ `tools/_common.make_tool` — never let raw tracebacks reach the agent.
31
+ - Docstrings are the agent-facing contract: state what the tool does, its
32
+ enums (e.g. timeframes), and any safety behavior.
33
+ - Every order path — paper or live — must pass
34
+ `order_validation_service.validate_order`. Never add a tool that bypasses it.
35
+ - Tools must never return secrets; config goes out via `to_safe_dict()` only.
36
+ - Logs go to stderr (`utils/logger.py`); stdout belongs to the MCP transport.
37
+
38
+ ## Safety invariants (do not weaken)
39
+
40
+ 1. Paper mode is the default; live requires `TRADING_MODE=live` AND
41
+ `ALLOW_LIVE_TRADING=true`, and the latter is not runtime-updatable.
42
+ 2. Delivery sell is hard-blocked at prepare time, at execute time, and in the
43
+ permission checks. Three layers — keep all three.
44
+ 3. Live execution requires the prepare → approval-token → execute flow.
45
+ 4. Every order decision is audited via `log_trade_event`.
46
+ 5. No main-trading-app business logic in this package — keep it a generic,
47
+ reusable toolbox.
48
+ 6. No hardcoded broker secrets, API keys, tokens, or account numbers — ever,
49
+ including in tests and docs.
50
+
51
+ ## Testing
52
+
53
+ ```bash
54
+ pip install -e ".[dev]"
55
+ python -m pytest tests -q
56
+ ```
57
+
58
+ - Tests are network-free and broker-free; keep them that way (the safety tests
59
+ prove the broker is never reached — that's the point).
60
+ - Safety behaviors are covered in `test_broker_safety.py`,
61
+ `test_order_validation.py`, `test_config.py`. Never delete or weaken these
62
+ to make a change pass. New tools need tests where logic is non-trivial.
63
+
64
+ ## Packaging expectations
65
+
66
+ - `pyproject.toml` (hatchling) is the build source of truth; console script
67
+ `trading-mcp-server` must keep working.
68
+ - Keep the package importable on a clean `pip install trading-mcp-server`
69
+ (core deps only). Broker/scanner deps stay in extras.
70
+ - Version lives in `pyproject.toml` + `trading_mcp_server.__version__` — bump
71
+ both together. Future publish: `python -m build` + `twine upload`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mukul Kumar
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,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: trading-mcp-server
3
+ Version: 0.1.0
4
+ Summary: Local MCP server exposing safe trading tools (market data, indicators, risk, paper trading, broker) for AI agents like Claude Code
5
+ Project-URL: Repository, https://github.com/mukul8896/trading-mcp-server
6
+ Author: Mukul Kumar
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Keywords: claude,mcp,nse,paper-trading,trading
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Office/Business :: Financial :: Investment
14
+ Requires-Python: >=3.10
15
+ Requires-Dist: mcp>=1.2.0
16
+ Requires-Dist: numpy
17
+ Requires-Dist: pandas>=2.0
18
+ Requires-Dist: requests
19
+ Provides-Extra: broker
20
+ Requires-Dist: logzero; extra == 'broker'
21
+ Requires-Dist: pyotp; extra == 'broker'
22
+ Requires-Dist: smartapi-python; extra == 'broker'
23
+ Requires-Dist: websocket-client; extra == 'broker'
24
+ Provides-Extra: dev
25
+ Requires-Dist: bs4; extra == 'dev'
26
+ Requires-Dist: logzero; extra == 'dev'
27
+ Requires-Dist: lxml; extra == 'dev'
28
+ Requires-Dist: pyotp; extra == 'dev'
29
+ Requires-Dist: pytest; extra == 'dev'
30
+ Requires-Dist: smartapi-python; extra == 'dev'
31
+ Requires-Dist: websocket-client; extra == 'dev'
32
+ Provides-Extra: scanners
33
+ Requires-Dist: bs4; extra == 'scanners'
34
+ Requires-Dist: lxml; extra == 'scanners'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # trading-mcp-server
38
+
39
+ A local **MCP (Model Context Protocol) server** that exposes safe trading tools for AI agents such as **Claude Code** and **Copilot CLI**. The agent does the reasoning; this server provides market data, technical indicators, news, risk management, a paper-trading engine, backtesting, and a heavily guarded broker layer (Angel One SmartAPI, NSE).
40
+
41
+ **Safety model (non-negotiable):**
42
+
43
+ - Paper trading is the default. Real orders require `TRADING_MODE=live` **and** `ALLOW_LIVE_TRADING=true` (the latter can only be set by a human editing `.env` — no tool can change it).
44
+ - Every order passes a full validation checklist (stop-loss required, risk:reward minimum, position-size / daily-loss / open-position limits, market-hours check).
45
+ - Live orders use a **prepare → human approval → execute** token flow.
46
+ - **Delivery (CNC) sell orders are always blocked** — the server only records a recommendation.
47
+ - Every decision is appended to an audit log (`storage/trade_logs.jsonl`).
48
+
49
+ > Nothing produced by this server is financial advice.
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ # local development (editable, from a sibling checkout)
55
+ pip install -e ../trading-mcp-server
56
+
57
+ # with broker + scanner extras (needed for live data / Chartink watchlist)
58
+ pip install -e "../trading-mcp-server[broker,scanners]"
59
+
60
+ # future, once published to PyPI
61
+ pip install trading-mcp-server
62
+ ```
63
+
64
+ Requires Python 3.10+.
65
+
66
+ ## Running the server
67
+
68
+ The server speaks MCP over stdio:
69
+
70
+ ```bash
71
+ trading-mcp-server
72
+ # or
73
+ python -m trading_mcp_server.server
74
+ ```
75
+
76
+ It resolves its configuration and state from a **home directory**:
77
+
78
+ 1. `TRADING_MCP_HOME` environment variable, if set
79
+ 2. otherwise the current working directory
80
+
81
+ There it reads `<home>/.env` (trading mode, permissions, risk limits, broker credentials) and writes `<home>/storage/` (paper-trading state, pending orders, audit log). This keeps the package independent of any repo path — point `TRADING_MCP_HOME` at your trading project.
82
+
83
+ Register in a client (e.g. `.mcp.json` for Claude Code):
84
+
85
+ ```json
86
+ {
87
+ "mcpServers": {
88
+ "trading-agent": {
89
+ "command": "trading-mcp-server",
90
+ "env": { "TRADING_MCP_HOME": "C:\\path\\to\\your\\trading-repo" }
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ ## What it exposes
97
+
98
+ ### Tools (by category)
99
+
100
+ | Category | Tools |
101
+ |---|---|
102
+ | Config | `get_trading_config`, `get_current_trading_mode`, `update_trading_config`, `switch_to_paper_mode`, `switch_to_live_mode`, `validate_trading_permissions` |
103
+ | Market data | `fetch_live_price`, `fetch_historical_data`, `fetch_market_status`, `fetch_symbol_metadata`, `fetch_watchlist` |
104
+ | Indicators | `calculate_sma/ema/rsi/macd/bollinger_bands/atr/volume_analysis`, `detect_support_resistance`, `detect_trend`, `get_indicator_snapshot` |
105
+ | News | `fetch_latest_news`, `fetch_market_news`, `analyze_news_sentiment` |
106
+ | Portfolio | `fetch_portfolio`, `fetch_order_history`, `calculate_portfolio_exposure`, `calculate_unrealized_pnl` |
107
+ | Risk | `calculate_position_size`, `calculate_stop_loss`, `calculate_target_price`, `check_max_daily_loss`, `check_portfolio_concentration`, `validate_trade_against_risk_rules` |
108
+ | Strategy | `evaluate_intraday_trade_setup`, `evaluate_swing_trade_setup`, `compare_multiple_symbols`, `scan_watchlist_for_intraday_opportunities`, `scan_watchlist_for_swing_opportunities`, `run_strategy_backtest` |
109
+ | Paper trading | `place_paper_order`, `close_paper_position`, `fetch_paper_trades`, `fetch_paper_portfolio`, `calculate_paper_trading_performance`, `generate_paper_trading_report`, `reset_paper_account` |
110
+ | Broker (guarded) | `prepare_order`, `validate_order_before_execution`, `execute_intraday_order_after_validation`, `execute_delivery_buy_after_validation`, `block_delivery_sell_order`, `list_pending_live_orders`, `cancel_pending_live_order`, `fetch_broker_funds/positions/holdings/order_status` |
111
+
112
+ ### Resources
113
+
114
+ - `trading://config` — current configuration (secrets redacted)
115
+ - `trading://safety-rules` — the safety rules the server enforces
116
+
117
+ ### Prompts
118
+
119
+ - `intraday_trade_analysis(symbol)` — disciplined intraday workflow
120
+ - `swing_trade_analysis(symbol)` — swing/delivery workflow
121
+ - `paper_trading_review()` — profitability review workflow
122
+
123
+ Backtest strategies built in: `ma_crossover`, `rsi_reversal`, `macd_trend`, `breakout_volume`.
124
+
125
+ ## Package structure
126
+
127
+ ```
128
+ src/trading_mcp_server/
129
+ ├── server.py # FastMCP entry point (create_server, main)
130
+ ├── config.py # .env-backed TradingConfig — single source of truth
131
+ ├── tools/ # MCP tool modules (one per category, register(mcp))
132
+ ├── resources/ # MCP resources
133
+ ├── prompts/ # MCP prompts
134
+ ├── services/ # data provider, indicators, risk, validation, paper engine, broker safety layer
135
+ ├── broker/ # SmartAPI adapter — the ONLY module talking to the real broker
136
+ ├── backtest/ # engine + built-in strategies
137
+ └── utils/ # logging/audit, market hours, instrument lookup
138
+ tests/ # pytest suite (config, safety, paper engine, indicators, backtest)
139
+ ```
140
+
141
+ ## Development
142
+
143
+ ```bash
144
+ pip install -e ".[dev]"
145
+ python -m pytest tests -q # run tests (no network, no broker needed)
146
+ python -m trading_mcp_server.server # run server from source
147
+ ```
148
+
149
+ ## Configuration reference
150
+
151
+ See `.env.example` in the consuming repo. Key flags: `TRADING_MODE` (paper|live), `ALLOW_LIVE_TRADING`, `REQUIRE_MANUAL_APPROVAL_FOR_LIVE_ORDERS`, `ALLOW_INTRADAY_BUY/SELL`, `ALLOW_DELIVERY_BUY`, `ALLOW_DELIVERY_SELL` (keep `false`), `MAX_RISK_PER_TRADE_PERCENT`, `MAX_DAILY_LOSS_PERCENT`, `MAX_OPEN_POSITIONS`, `MAX_POSITION_SIZE_PERCENT`, `MIN_RISK_REWARD_RATIO`, `PAPER_STARTING_CAPITAL`, `BROKER_*` credentials.
152
+
153
+ ## Publishing to PyPI (future)
154
+
155
+ 1. Bump `version` in `pyproject.toml` and `src/trading_mcp_server/__init__.py`.
156
+ 2. `python -m build` (requires `pip install build`).
157
+ 3. `python -m twine upload dist/*` (requires a PyPI account + API token).
158
+ 4. Consumers then switch from `pip install -e ../trading-mcp-server` to `pip install trading-mcp-server` — no other change needed.
159
+
160
+ ## License
161
+
162
+ MIT
@@ -0,0 +1,126 @@
1
+ # trading-mcp-server
2
+
3
+ A local **MCP (Model Context Protocol) server** that exposes safe trading tools for AI agents such as **Claude Code** and **Copilot CLI**. The agent does the reasoning; this server provides market data, technical indicators, news, risk management, a paper-trading engine, backtesting, and a heavily guarded broker layer (Angel One SmartAPI, NSE).
4
+
5
+ **Safety model (non-negotiable):**
6
+
7
+ - Paper trading is the default. Real orders require `TRADING_MODE=live` **and** `ALLOW_LIVE_TRADING=true` (the latter can only be set by a human editing `.env` — no tool can change it).
8
+ - Every order passes a full validation checklist (stop-loss required, risk:reward minimum, position-size / daily-loss / open-position limits, market-hours check).
9
+ - Live orders use a **prepare → human approval → execute** token flow.
10
+ - **Delivery (CNC) sell orders are always blocked** — the server only records a recommendation.
11
+ - Every decision is appended to an audit log (`storage/trade_logs.jsonl`).
12
+
13
+ > Nothing produced by this server is financial advice.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ # local development (editable, from a sibling checkout)
19
+ pip install -e ../trading-mcp-server
20
+
21
+ # with broker + scanner extras (needed for live data / Chartink watchlist)
22
+ pip install -e "../trading-mcp-server[broker,scanners]"
23
+
24
+ # future, once published to PyPI
25
+ pip install trading-mcp-server
26
+ ```
27
+
28
+ Requires Python 3.10+.
29
+
30
+ ## Running the server
31
+
32
+ The server speaks MCP over stdio:
33
+
34
+ ```bash
35
+ trading-mcp-server
36
+ # or
37
+ python -m trading_mcp_server.server
38
+ ```
39
+
40
+ It resolves its configuration and state from a **home directory**:
41
+
42
+ 1. `TRADING_MCP_HOME` environment variable, if set
43
+ 2. otherwise the current working directory
44
+
45
+ There it reads `<home>/.env` (trading mode, permissions, risk limits, broker credentials) and writes `<home>/storage/` (paper-trading state, pending orders, audit log). This keeps the package independent of any repo path — point `TRADING_MCP_HOME` at your trading project.
46
+
47
+ Register in a client (e.g. `.mcp.json` for Claude Code):
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "trading-agent": {
53
+ "command": "trading-mcp-server",
54
+ "env": { "TRADING_MCP_HOME": "C:\\path\\to\\your\\trading-repo" }
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## What it exposes
61
+
62
+ ### Tools (by category)
63
+
64
+ | Category | Tools |
65
+ |---|---|
66
+ | Config | `get_trading_config`, `get_current_trading_mode`, `update_trading_config`, `switch_to_paper_mode`, `switch_to_live_mode`, `validate_trading_permissions` |
67
+ | Market data | `fetch_live_price`, `fetch_historical_data`, `fetch_market_status`, `fetch_symbol_metadata`, `fetch_watchlist` |
68
+ | Indicators | `calculate_sma/ema/rsi/macd/bollinger_bands/atr/volume_analysis`, `detect_support_resistance`, `detect_trend`, `get_indicator_snapshot` |
69
+ | News | `fetch_latest_news`, `fetch_market_news`, `analyze_news_sentiment` |
70
+ | Portfolio | `fetch_portfolio`, `fetch_order_history`, `calculate_portfolio_exposure`, `calculate_unrealized_pnl` |
71
+ | Risk | `calculate_position_size`, `calculate_stop_loss`, `calculate_target_price`, `check_max_daily_loss`, `check_portfolio_concentration`, `validate_trade_against_risk_rules` |
72
+ | Strategy | `evaluate_intraday_trade_setup`, `evaluate_swing_trade_setup`, `compare_multiple_symbols`, `scan_watchlist_for_intraday_opportunities`, `scan_watchlist_for_swing_opportunities`, `run_strategy_backtest` |
73
+ | Paper trading | `place_paper_order`, `close_paper_position`, `fetch_paper_trades`, `fetch_paper_portfolio`, `calculate_paper_trading_performance`, `generate_paper_trading_report`, `reset_paper_account` |
74
+ | Broker (guarded) | `prepare_order`, `validate_order_before_execution`, `execute_intraday_order_after_validation`, `execute_delivery_buy_after_validation`, `block_delivery_sell_order`, `list_pending_live_orders`, `cancel_pending_live_order`, `fetch_broker_funds/positions/holdings/order_status` |
75
+
76
+ ### Resources
77
+
78
+ - `trading://config` — current configuration (secrets redacted)
79
+ - `trading://safety-rules` — the safety rules the server enforces
80
+
81
+ ### Prompts
82
+
83
+ - `intraday_trade_analysis(symbol)` — disciplined intraday workflow
84
+ - `swing_trade_analysis(symbol)` — swing/delivery workflow
85
+ - `paper_trading_review()` — profitability review workflow
86
+
87
+ Backtest strategies built in: `ma_crossover`, `rsi_reversal`, `macd_trend`, `breakout_volume`.
88
+
89
+ ## Package structure
90
+
91
+ ```
92
+ src/trading_mcp_server/
93
+ ├── server.py # FastMCP entry point (create_server, main)
94
+ ├── config.py # .env-backed TradingConfig — single source of truth
95
+ ├── tools/ # MCP tool modules (one per category, register(mcp))
96
+ ├── resources/ # MCP resources
97
+ ├── prompts/ # MCP prompts
98
+ ├── services/ # data provider, indicators, risk, validation, paper engine, broker safety layer
99
+ ├── broker/ # SmartAPI adapter — the ONLY module talking to the real broker
100
+ ├── backtest/ # engine + built-in strategies
101
+ └── utils/ # logging/audit, market hours, instrument lookup
102
+ tests/ # pytest suite (config, safety, paper engine, indicators, backtest)
103
+ ```
104
+
105
+ ## Development
106
+
107
+ ```bash
108
+ pip install -e ".[dev]"
109
+ python -m pytest tests -q # run tests (no network, no broker needed)
110
+ python -m trading_mcp_server.server # run server from source
111
+ ```
112
+
113
+ ## Configuration reference
114
+
115
+ See `.env.example` in the consuming repo. Key flags: `TRADING_MODE` (paper|live), `ALLOW_LIVE_TRADING`, `REQUIRE_MANUAL_APPROVAL_FOR_LIVE_ORDERS`, `ALLOW_INTRADAY_BUY/SELL`, `ALLOW_DELIVERY_BUY`, `ALLOW_DELIVERY_SELL` (keep `false`), `MAX_RISK_PER_TRADE_PERCENT`, `MAX_DAILY_LOSS_PERCENT`, `MAX_OPEN_POSITIONS`, `MAX_POSITION_SIZE_PERCENT`, `MIN_RISK_REWARD_RATIO`, `PAPER_STARTING_CAPITAL`, `BROKER_*` credentials.
116
+
117
+ ## Publishing to PyPI (future)
118
+
119
+ 1. Bump `version` in `pyproject.toml` and `src/trading_mcp_server/__init__.py`.
120
+ 2. `python -m build` (requires `pip install build`).
121
+ 3. `python -m twine upload dist/*` (requires a PyPI account + API token).
122
+ 4. Consumers then switch from `pip install -e ../trading-mcp-server` to `pip install trading-mcp-server` — no other change needed.
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,32 @@
1
+ # Agent register — trading-mcp-server
2
+
3
+ ## A. MCP Server Agent
4
+
5
+ **Role:** Maintains the MCP server package.
6
+
7
+ **Responsibilities:**
8
+ - Create and maintain MCP tools, resources, and prompts under
9
+ `src/trading_mcp_server/` (tools in `tools/`, one module per category).
10
+ - Keep the MCP server independent from any consuming trading repo — paths
11
+ resolve via `TRADING_MCP_HOME`/cwd, never a hardcoded repo location.
12
+ - Ensure the package always installs with `pip install -e .` and the console
13
+ script `trading-mcp-server` keeps working.
14
+ - Keep the code ready for future PyPI publishing (pyproject metadata, src/
15
+ layout, version sync between `pyproject.toml` and `__init__.py`).
16
+ - Maintain clean package structure under `src/trading_mcp_server/`.
17
+ - Add tests for MCP tools and services (`tests/`, pytest, network-free);
18
+ preserve the safety test suite (paper default, delivery-sell block,
19
+ approval flow, risk limits).
20
+
21
+ **Restrictions:**
22
+ - Do not add main trading app business logic into the MCP server — it is a
23
+ generic, reusable toolbox.
24
+ - Do not hardcode broker secrets, API keys, tokens, or account numbers.
25
+ - Do not make the MCP server dependent on one specific repo path.
26
+ - Do not break future pip packaging compatibility (src/ layout, extras,
27
+ lazy optional imports).
28
+ - Do not weaken the safety invariants listed in CLAUDE.md.
29
+
30
+ **When to use:** modifying MCP tools/resources/prompts, server startup,
31
+ package metadata, `pyproject.toml`, services, the broker safety layer, or
32
+ reusable trading utilities.
@@ -0,0 +1,56 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "trading-mcp-server"
7
+ version = "0.1.0"
8
+ description = "Local MCP server exposing safe trading tools (market data, indicators, risk, paper trading, broker) for AI agents like Claude Code"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Mukul Kumar" }]
13
+ keywords = ["mcp", "trading", "paper-trading", "nse", "claude"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3",
18
+ "Topic :: Office/Business :: Financial :: Investment",
19
+ ]
20
+
21
+ dependencies = [
22
+ "mcp>=1.2.0",
23
+ "pandas>=2.0",
24
+ "numpy",
25
+ "requests",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ # Live broker connectivity (Angel One SmartAPI) — not needed for paper-only use
30
+ broker = [
31
+ "smartapi-python",
32
+ "pyotp",
33
+ "logzero",
34
+ "websocket-client",
35
+ ]
36
+ # Chartink watchlist scanning
37
+ scanners = [
38
+ "bs4",
39
+ "lxml",
40
+ ]
41
+ dev = [
42
+ "pytest",
43
+ "trading-mcp-server[broker,scanners]",
44
+ ]
45
+
46
+ [project.scripts]
47
+ trading-mcp-server = "trading_mcp_server.server:main"
48
+
49
+ [project.urls]
50
+ Repository = "https://github.com/mukul8896/trading-mcp-server"
51
+
52
+ [tool.hatch.build.targets.wheel]
53
+ packages = ["src/trading_mcp_server"]
54
+
55
+ [tool.pytest.ini_options]
56
+ testpaths = ["tests"]
@@ -0,0 +1,3 @@
1
+ """trading-mcp-server: safe trading tools for AI agents over MCP."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,111 @@
1
+ """Minimal long-only backtest engine over signal series (1=long, 0=flat).
2
+
3
+ Entries/exits execute at the NEXT bar's open to avoid look-ahead bias.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import pandas as pd
8
+
9
+ from trading_mcp_server.backtest.strategies import STRATEGIES
10
+
11
+
12
+ def run_backtest(
13
+ df: pd.DataFrame,
14
+ strategy_name: str,
15
+ initial_capital: float = 100_000.0,
16
+ strategy_params: dict | None = None,
17
+ ) -> dict:
18
+ if strategy_name not in STRATEGIES:
19
+ return {"error": f"Unknown strategy '{strategy_name}'. Available: {sorted(STRATEGIES)}"}
20
+ if len(df) < 60:
21
+ return {"error": f"Not enough candles ({len(df)}) — need at least 60."}
22
+
23
+ signal = STRATEGIES[strategy_name](df, **(strategy_params or {}))
24
+
25
+ trades: list[dict] = []
26
+ in_position = False
27
+ entry_price = 0.0
28
+ entry_date = None
29
+ quantity = 0
30
+ cash = initial_capital
31
+
32
+ for i in range(len(df) - 1):
33
+ next_open = float(df["open"].iloc[i + 1])
34
+ next_date = df.index[i + 1]
35
+ want_long = bool(signal.iloc[i])
36
+
37
+ if want_long and not in_position:
38
+ quantity = int(cash // next_open)
39
+ if quantity > 0:
40
+ in_position = True
41
+ entry_price = next_open
42
+ entry_date = next_date
43
+ cash -= quantity * next_open
44
+ elif not want_long and in_position:
45
+ cash += quantity * next_open
46
+ trades.append(
47
+ {
48
+ "entry_date": str(entry_date),
49
+ "exit_date": str(next_date),
50
+ "entry_price": round(entry_price, 2),
51
+ "exit_price": round(next_open, 2),
52
+ "quantity": quantity,
53
+ "pnl": round((next_open - entry_price) * quantity, 2),
54
+ "return_pct": round((next_open / entry_price - 1) * 100, 2),
55
+ }
56
+ )
57
+ in_position = False
58
+
59
+ # Close any open position at the final close
60
+ if in_position:
61
+ last_close = float(df["close"].iloc[-1])
62
+ cash += quantity * last_close
63
+ trades.append(
64
+ {
65
+ "entry_date": str(entry_date),
66
+ "exit_date": str(df.index[-1]),
67
+ "entry_price": round(entry_price, 2),
68
+ "exit_price": round(last_close, 2),
69
+ "quantity": quantity,
70
+ "pnl": round((last_close - entry_price) * quantity, 2),
71
+ "return_pct": round((last_close / entry_price - 1) * 100, 2),
72
+ "closed_at_end": True,
73
+ }
74
+ )
75
+
76
+ return _metrics(trades, initial_capital, cash, strategy_name, df)
77
+
78
+
79
+ def _metrics(trades: list[dict], initial: float, final: float, strategy: str, df: pd.DataFrame) -> dict:
80
+ pnls = [t["pnl"] for t in trades]
81
+ wins = [p for p in pnls if p > 0]
82
+ losses = [p for p in pnls if p <= 0]
83
+
84
+ equity, peak, max_dd = initial, initial, 0.0
85
+ for p in pnls:
86
+ equity += p
87
+ peak = max(peak, equity)
88
+ max_dd = max(max_dd, (peak - equity) / peak * 100 if peak else 0)
89
+
90
+ total_return_pct = (final / initial - 1) * 100
91
+ buy_hold_pct = (float(df["close"].iloc[-1]) / float(df["close"].iloc[0]) - 1) * 100
92
+
93
+ return {
94
+ "strategy": strategy,
95
+ "period": {"start": str(df.index[0]), "end": str(df.index[-1]), "bars": len(df)},
96
+ "initial_capital": initial,
97
+ "final_capital": round(final, 2),
98
+ "total_return_pct": round(total_return_pct, 2),
99
+ "buy_and_hold_return_pct": round(buy_hold_pct, 2),
100
+ "num_trades": len(trades),
101
+ "win_rate_pct": round(len(wins) / len(trades) * 100, 1) if trades else None,
102
+ "total_pnl": round(sum(pnls), 2),
103
+ "avg_pnl_per_trade": round(sum(pnls) / len(trades), 2) if trades else None,
104
+ "avg_win": round(sum(wins) / len(wins), 2) if wins else 0,
105
+ "avg_loss": round(sum(losses) / len(losses), 2) if losses else 0,
106
+ "profit_factor": round(sum(wins) / abs(sum(losses)), 2) if losses and sum(losses) else None,
107
+ "max_drawdown_pct": round(max_dd, 2),
108
+ "profitable": total_return_pct > 0,
109
+ "beats_buy_and_hold": total_return_pct > buy_hold_pct,
110
+ "trades": trades[-20:], # last 20 trades for inspection
111
+ }
@@ -0,0 +1,57 @@
1
+ """Built-in backtest strategies. Each returns a Series of signals per bar:
2
+ 1 = enter/hold long, 0 = flat. The engine trades the transitions."""
3
+ from __future__ import annotations
4
+
5
+ import pandas as pd
6
+
7
+ from trading_mcp_server.services import indicator_service as ind
8
+
9
+
10
+ def ma_crossover(df: pd.DataFrame, fast: int = 20, slow: int = 50) -> pd.Series:
11
+ fast_ma = ind.sma(df["close"], fast)
12
+ slow_ma = ind.sma(df["close"], slow)
13
+ return (fast_ma > slow_ma).astype(int)
14
+
15
+
16
+ def rsi_reversal(df: pd.DataFrame, period: int = 14, oversold: int = 30, exit_level: int = 60) -> pd.Series:
17
+ rsi = ind.rsi(df, period)
18
+ signal = pd.Series(0, index=df.index)
19
+ holding = False
20
+ for i in range(len(df)):
21
+ value = rsi.iloc[i]
22
+ if not holding and value < oversold:
23
+ holding = True
24
+ elif holding and value > exit_level:
25
+ holding = False
26
+ signal.iloc[i] = int(holding)
27
+ return signal
28
+
29
+
30
+ def macd_trend(df: pd.DataFrame) -> pd.Series:
31
+ m = ind.macd(df)
32
+ above_ema200 = df["close"] > ind.ema(df["close"], 200)
33
+ return ((m["macd"] > m["signal"]) & above_ema200).astype(int)
34
+
35
+
36
+ def breakout_volume(df: pd.DataFrame, lookback: int = 20, volume_mult: float = 2.0) -> pd.Series:
37
+ rolling_high = df["high"].rolling(lookback).max().shift(1)
38
+ vol_ema = df["volume"].ewm(span=20, adjust=False).mean()
39
+ entry = (df["close"] > rolling_high) & (df["volume"] > vol_ema * volume_mult)
40
+ exit_ = df["close"] < ind.ema(df["close"], 20)
41
+ signal = pd.Series(0, index=df.index)
42
+ holding = False
43
+ for i in range(len(df)):
44
+ if not holding and bool(entry.iloc[i]):
45
+ holding = True
46
+ elif holding and bool(exit_.iloc[i]):
47
+ holding = False
48
+ signal.iloc[i] = int(holding)
49
+ return signal
50
+
51
+
52
+ STRATEGIES = {
53
+ "ma_crossover": ma_crossover,
54
+ "rsi_reversal": rsi_reversal,
55
+ "macd_trend": macd_trend,
56
+ "breakout_volume": breakout_volume,
57
+ }