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.
- trading_mcp_server-0.1.0/.gitignore +10 -0
- trading_mcp_server-0.1.0/CLAUDE.md +71 -0
- trading_mcp_server-0.1.0/LICENSE +21 -0
- trading_mcp_server-0.1.0/PKG-INFO +162 -0
- trading_mcp_server-0.1.0/README.md +126 -0
- trading_mcp_server-0.1.0/agent-register.md +32 -0
- trading_mcp_server-0.1.0/pyproject.toml +56 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/__init__.py +3 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/backtest/__init__.py +0 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/backtest/engine.py +111 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/backtest/strategies.py +57 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/broker/__init__.py +0 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/broker/smartapi_adapter.py +176 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/config.py +254 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/prompts/__init__.py +61 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/resources/__init__.py +36 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/server.py +46 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/__init__.py +0 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/broker_service.py +192 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/data_provider_service.py +152 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/indicator_service.py +149 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/notification_service.py +130 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/order_validation_service.py +228 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/paper_trading_service.py +266 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/services/risk_service.py +99 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/__init__.py +33 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/_common.py +33 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/broker.py +105 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/config_tools.py +64 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/indicators.py +78 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/market_data.py +45 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/news.py +34 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/notifications.py +64 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/paper_trading.py +81 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/portfolio.py +45 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/risk.py +65 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/tools/strategy.py +140 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/utils/__init__.py +0 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/utils/instruments.py +69 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/utils/logger.py +37 -0
- trading_mcp_server-0.1.0/src/trading_mcp_server/utils/time_utils.py +73 -0
- trading_mcp_server-0.1.0/tests/conftest.py +53 -0
- trading_mcp_server-0.1.0/tests/test_broker_safety.py +80 -0
- trading_mcp_server-0.1.0/tests/test_config.py +59 -0
- trading_mcp_server-0.1.0/tests/test_indicators.py +70 -0
- trading_mcp_server-0.1.0/tests/test_notifications.py +119 -0
- trading_mcp_server-0.1.0/tests/test_order_validation.py +139 -0
- trading_mcp_server-0.1.0/tests/test_paper_trading.py +71 -0
- trading_mcp_server-0.1.0/tests/test_risk_and_backtest.py +76 -0
|
@@ -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"]
|
|
File without changes
|
|
@@ -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
|
+
}
|
|
File without changes
|