mcp-server-saxo-openapi 0.1.1__py3-none-any.whl
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.
- mcp_server_saxo_openapi-0.1.1.dist-info/METADATA +214 -0
- mcp_server_saxo_openapi-0.1.1.dist-info/RECORD +97 -0
- mcp_server_saxo_openapi-0.1.1.dist-info/WHEEL +4 -0
- mcp_server_saxo_openapi-0.1.1.dist-info/entry_points.txt +3 -0
- mcp_server_saxo_openapi-0.1.1.dist-info/licenses/LICENSE +21 -0
- saxo_doc_helper/__init__.py +32 -0
- saxo_doc_helper/__main__.py +6 -0
- saxo_doc_helper/cli.py +95 -0
- saxo_doc_helper/commands.py +119 -0
- saxo_doc_helper/data/__init__.py +1 -0
- saxo_doc_helper/data/json/atr/cashmanagement-beneficiaryinstructions.json +83 -0
- saxo_doc_helper/data/json/atr/cashmanagement-cashwithdrawal.json +76 -0
- saxo_doc_helper/data/json/atr/cashmanagement-cashwithdrawallimits.json +63 -0
- saxo_doc_helper/data/json/atr/cashmanagement-interaccounttransfers.json +48 -0
- saxo_doc_helper/data/json/atr/cashmanagement-periodicpayment.json +389 -0
- saxo_doc_helper/data/json/atr/partner-cashtransfer.json +227 -0
- saxo_doc_helper/data/json/atr/partner-cashtransferlimits.json +63 -0
- saxo_doc_helper/data/json/atr/partner-prefunding.json +108 -0
- saxo_doc_helper/data/json/atr/securitiestransfers.json +1268 -0
- saxo_doc_helper/data/json/ca/elections.json +156 -0
- saxo_doc_helper/data/json/ca/events.json +1446 -0
- saxo_doc_helper/data/json/ca/eventviews.json +876 -0
- saxo_doc_helper/data/json/ca/holdings.json +281 -0
- saxo_doc_helper/data/json/ca/proxyvoting.json +347 -0
- saxo_doc_helper/data/json/ca/standinginstructions.json +401 -0
- saxo_doc_helper/data/json/chart/charts.json +1707 -0
- saxo_doc_helper/data/json/cm/accounts.json +41 -0
- saxo_doc_helper/data/json/cm/clientrenewals.json +3244 -0
- saxo_doc_helper/data/json/cm/documents.json +108 -0
- saxo_doc_helper/data/json/cm/signups.json +633 -0
- saxo_doc_helper/data/json/cm/users.json +45 -0
- saxo_doc_helper/data/json/cr/historicalreportdata-accountstatement.json +82 -0
- saxo_doc_helper/data/json/cr/historicalreportdata-portfoliomanagement.json +157 -0
- saxo_doc_helper/data/json/cr/historicalreportdata-tradedetails.json +82 -0
- saxo_doc_helper/data/json/cr/historicalreportdata-tradesexecuted.json +57 -0
- saxo_doc_helper/data/json/cs/audit-orderactivities.json +257 -0
- saxo_doc_helper/data/json/cs/cashmanagement-interaccounttransfer.json +68 -0
- saxo_doc_helper/data/json/cs/cashmanagement-wiretransfers.json +66 -0
- saxo_doc_helper/data/json/cs/clientinfo.json +164 -0
- saxo_doc_helper/data/json/cs/historicalreportdata-aggregatedamounts.json +149 -0
- saxo_doc_helper/data/json/cs/historicalreportdata-bookings.json +257 -0
- saxo_doc_helper/data/json/cs/historicalreportdata-closedpositions.json +111 -0
- saxo_doc_helper/data/json/cs/historicalreportdata-trades.json +139 -0
- saxo_doc_helper/data/json/cs/support-cases.json +565 -0
- saxo_doc_helper/data/json/cs/tradingconditions-contractoption.json +122 -0
- saxo_doc_helper/data/json/cs/tradingconditions-cost.json +919 -0
- saxo_doc_helper/data/json/cs/tradingconditions.json +899 -0
- saxo_doc_helper/data/json/dm/disclaimermanagement.json +129 -0
- saxo_doc_helper/data/json/ens/clientactivities.json +1512 -0
- saxo_doc_helper/data/json/hist/accountvalues.json +57 -0
- saxo_doc_helper/data/json/hist/historicalpositions.json +800 -0
- saxo_doc_helper/data/json/hist/performance.json +1082 -0
- saxo_doc_helper/data/json/hist/transactions.json +367 -0
- saxo_doc_helper/data/json/hist/unsettledamounts.json +524 -0
- saxo_doc_helper/data/json/mkt/instrumentdocument.json +1512 -0
- saxo_doc_helper/data/json/partnerintegration/advisoryaccounts.json +490 -0
- saxo_doc_helper/data/json/partnerintegration/externalaccounts.json +785 -0
- saxo_doc_helper/data/json/partnerintegration/fundinginstruction.json +266 -0
- saxo_doc_helper/data/json/partnerintegration/interactiveesigning.json +235 -0
- saxo_doc_helper/data/json/partnerintegration/interactiveidverification.json +185 -0
- saxo_doc_helper/data/json/partnerintegration/partnerbulkbookings.json +80 -0
- saxo_doc_helper/data/json/partnerintegration/updatepricing.json +716 -0
- saxo_doc_helper/data/json/port/accountgroups.json +191 -0
- saxo_doc_helper/data/json/port/accounts.json +1106 -0
- saxo_doc_helper/data/json/port/balances.json +3457 -0
- saxo_doc_helper/data/json/port/clients.json +1418 -0
- saxo_doc_helper/data/json/port/closedpositions.json +612 -0
- saxo_doc_helper/data/json/port/exposure.json +2987 -0
- saxo_doc_helper/data/json/port/netpositions.json +2079 -0
- saxo_doc_helper/data/json/port/orders.json +664 -0
- saxo_doc_helper/data/json/port/positions.json +852 -0
- saxo_doc_helper/data/json/port/users.json +1047 -0
- saxo_doc_helper/data/json/ref/algostrategies.json +102 -0
- saxo_doc_helper/data/json/ref/countries.json +244 -0
- saxo_doc_helper/data/json/ref/cultures.json +74 -0
- saxo_doc_helper/data/json/ref/currencies.json +91 -0
- saxo_doc_helper/data/json/ref/currencypairs.json +86 -0
- saxo_doc_helper/data/json/ref/exchanges.json +76 -0
- saxo_doc_helper/data/json/ref/instruments.json +3475 -0
- saxo_doc_helper/data/json/ref/languages.json +83 -0
- saxo_doc_helper/data/json/ref/standarddates.json +69 -0
- saxo_doc_helper/data/json/ref/timezones.json +129 -0
- saxo_doc_helper/data/json/reg/financialoverview.json +483 -0
- saxo_doc_helper/data/json/reg/investmentprofile.json +843 -0
- saxo_doc_helper/data/json/reg/knowledgeandexperience.json +131 -0
- saxo_doc_helper/data/json/trade/allocationkeys.json +1044 -0
- saxo_doc_helper/data/json/trade/infoprices.json +2811 -0
- saxo_doc_helper/data/json/trade/messages.json +362 -0
- saxo_doc_helper/data/json/trade/optionschain.json +1179 -0
- saxo_doc_helper/data/json/trade/orders.json +10001 -0
- saxo_doc_helper/data/json/trade/positions.json +1395 -0
- saxo_doc_helper/data/json/trade/prices.json +3053 -0
- saxo_doc_helper/data/json/trade/trades.json +936 -0
- saxo_doc_helper/data/json/vas/pricealerts.json +1933 -0
- saxo_doc_helper/index.py +151 -0
- saxo_doc_helper/mcp_server.py +146 -0
- saxo_doc_helper/py.typed +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcp-server-saxo-openapi
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: MCP server and CLI for Saxo Bank OpenAPI spec lookup (offline; no trading)
|
|
5
|
+
Project-URL: Homepage, https://github.com/nohikomiso/mcp-server-saxo-openapi
|
|
6
|
+
Project-URL: Repository, https://github.com/nohikomiso/mcp-server-saxo-openapi
|
|
7
|
+
Project-URL: Issues, https://github.com/nohikomiso/mcp-server-saxo-openapi/issues
|
|
8
|
+
Author: nohikomiso
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: cli,mcp,model-context-protocol,openapi,saxo,saxo-bank,saxobank,trading
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
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: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# mcp-server-saxo-openapi
|
|
28
|
+
|
|
29
|
+
**Saxo Bank OpenAPI spec lookup — CLI tool and MCP server**
|
|
30
|
+
|
|
31
|
+
English | [日本語](https://github.com/nohikomiso/mcp-server-saxo-openapi/blob/main/README.ja.md)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
Look up **Saxo Bank** / **Saxobank** OpenAPI endpoint parameters and JSON samples from your terminal, or attach the same tools to Cursor, Claude Desktop, and other MCP clients — without wrestling the deep official reference tree.
|
|
42
|
+
|
|
43
|
+
Zero third-party dependencies (Python stdlib only). Spec database: ~260 endpoints across 17 service groups, shipped inside the wheel.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Spec snapshot
|
|
48
|
+
|
|
49
|
+
**Spec snapshot: 2026-07-08** (Saxo Release Notes through **2025/05/15**).
|
|
50
|
+
|
|
51
|
+
Structured endpoint specs for agents and developers. Saxo does not publish a single docs semver; we record the crawl date and the newest Release Notes heading present at that time. Details: [SPEC_FRESHNESS.md](SPEC_FRESHNESS.md).
|
|
52
|
+
|
|
53
|
+
Missing endpoint, wrong parameter, or something that looks out of date? Please [open an Issue](https://github.com/nohikomiso/mcp-server-saxo-openapi/issues). Pull requests: [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## What this is / is not
|
|
58
|
+
|
|
59
|
+
| This package | Not this package |
|
|
60
|
+
|--------------|------------------|
|
|
61
|
+
| Offline **spec lookup** (CLI + MCP) | Live trading / portfolio API calls |
|
|
62
|
+
| No Saxo credentials required | OAuth, order placement, balances |
|
|
63
|
+
| Token-efficient progressive disclosure | A substitute for a full OpenAPI client |
|
|
64
|
+
|
|
65
|
+
For **live** Saxo OpenAPI access from an MCP client, see community servers such as [`@borgels/mcp-server-saxo`](https://www.npmjs.com/package/@borgels/mcp-server-saxo) (npm, unofficial, separate project).
|
|
66
|
+
|
|
67
|
+
**Unofficial** — not affiliated with or endorsed by Saxo Bank A/S.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Features
|
|
72
|
+
|
|
73
|
+
- **Structured spec database** — nested parameters and request/response samples
|
|
74
|
+
- **CLI** — `search-endpoints`, `get-endpoint`, `get-schema` with depth control and "Did you mean?" suggestions
|
|
75
|
+
- **MCP server** — stdio JSON-RPC; same three tools
|
|
76
|
+
- **Token-efficient** — progressive disclosure (collapsed nested schemas, drill down on demand)
|
|
77
|
+
|
|
78
|
+
**Requirements:** Python 3.10+
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Getting started — recommended (uvx)
|
|
83
|
+
|
|
84
|
+
### Production PyPI
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uvx mcp-server-saxo-openapi
|
|
88
|
+
uvx --from mcp-server-saxo-openapi saxo-doc-helper search-endpoints orders
|
|
89
|
+
uvx --from mcp-server-saxo-openapi saxo-doc-helper --version
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`uvx` resolves the **package** name; use `--from mcp-server-saxo-openapi` to run the `saxo-doc-helper` console script.
|
|
93
|
+
|
|
94
|
+
MCP client config:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"mcpServers": {
|
|
99
|
+
"saxo-openapi": {
|
|
100
|
+
"command": "uvx",
|
|
101
|
+
"args": ["mcp-server-saxo-openapi"]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### From GitHub
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
uvx --from git+https://github.com/nohikomiso/mcp-server-saxo-openapi.git saxo-doc-helper search-endpoints orders
|
|
111
|
+
uvx --from git+https://github.com/nohikomiso/mcp-server-saxo-openapi.git mcp-server-saxo-openapi
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### TestPyPI (development only)
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
uvx --index-url https://test.pypi.org/simple/ \
|
|
118
|
+
--index https://pypi.org/simple/ \
|
|
119
|
+
--from mcp-server-saxo-openapi \
|
|
120
|
+
saxo-doc-helper search-endpoints orders
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Getting started — local clone
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
git clone https://github.com/nohikomiso/mcp-server-saxo-openapi.git
|
|
129
|
+
cd mcp-server-saxo-openapi
|
|
130
|
+
python tools/saxo_doc_helper.py search-endpoints orders
|
|
131
|
+
python tools/saxo_doc_helper.py get-endpoint POST /trade/v2/orders
|
|
132
|
+
python tools/saxo_doc_helper.py get-schema algorithmicorderdata
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Or install editable:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
uv sync
|
|
139
|
+
uv run saxo-doc-helper --version
|
|
140
|
+
uv run saxo-doc-helper search-endpoints orders
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Input normalization
|
|
144
|
+
|
|
145
|
+
| Input | Normalized |
|
|
146
|
+
|-------|------------|
|
|
147
|
+
| `post` | `POST` |
|
|
148
|
+
| `trade/v2/orders` | `/trade/v2/orders` |
|
|
149
|
+
| `https://gateway.saxobank.com/sim/openapi/trade/v2/orders` | `/trade/v2/orders` |
|
|
150
|
+
|
|
151
|
+
If no exact match is found, **Did you mean?** suggestions are returned.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## MCP tools exposed
|
|
156
|
+
|
|
157
|
+
| Tool | Description |
|
|
158
|
+
|------|-------------|
|
|
159
|
+
| `search_saxo_endpoints(query)` | Keyword search across all endpoints |
|
|
160
|
+
| `get_saxo_endpoint_spec(method, path, depth?)` | Parameters + request/response samples |
|
|
161
|
+
| `get_saxo_schema_spec(schema_name, depth?)` | Nested schema drill-down |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Agent integration
|
|
166
|
+
|
|
167
|
+
> When researching Saxo OpenAPI specs, do **not** read `spec/json/` files directly.
|
|
168
|
+
> Use `saxo-doc-helper` (or `python tools/saxo_doc_helper.py` from a clone).
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Repository layout
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
mcp-server-saxo-openapi/
|
|
176
|
+
├── pyproject.toml
|
|
177
|
+
├── SPEC_FRESHNESS.md
|
|
178
|
+
├── LICENSE
|
|
179
|
+
├── README.md / README.ja.md
|
|
180
|
+
├── CONTRIBUTING.md
|
|
181
|
+
├── docs/
|
|
182
|
+
│ └── MAINTAINER.md
|
|
183
|
+
├── src/saxo_doc_helper/ # installable package (+ data/json)
|
|
184
|
+
├── spec/json/ # maintainer source of truth
|
|
185
|
+
├── tests/
|
|
186
|
+
└── tools/
|
|
187
|
+
└── saxo_doc_helper.py # thin clone-compatible wrapper
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Related projects
|
|
193
|
+
|
|
194
|
+
| Project | Role |
|
|
195
|
+
|---------|------|
|
|
196
|
+
| [saxo-apy](https://github.com/nohikomiso/saxo-apy) | OAuth and session management |
|
|
197
|
+
| [saxo-openapi](https://github.com/nohikomiso/saxo-openapi) | Python REST/WebSocket client (AI-ready) |
|
|
198
|
+
| [@borgels/mcp-server-saxo](https://www.npmjs.com/package/@borgels/mcp-server-saxo) | Live Saxo OpenAPI MCP (npm; unofficial) |
|
|
199
|
+
|
|
200
|
+
This repository provides **spec lookup**. Runtime API access is a separate concern.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Feedback and maintainers
|
|
205
|
+
|
|
206
|
+
- Bugs / stale specs: [GitHub Issues](https://github.com/nohikomiso/mcp-server-saxo-openapi/issues)
|
|
207
|
+
- Maintainers: [docs/MAINTAINER.md](docs/MAINTAINER.md)
|
|
208
|
+
- Source crawl: public Saxo Developer Portal reference docs
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
[MIT License](LICENSE)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
saxo_doc_helper/__init__.py,sha256=jgAACGnHmifW1pM2gySGgI3lqy2TiLlkRus75fFcfXY,698
|
|
2
|
+
saxo_doc_helper/__main__.py,sha256=LtnpzKxHY-8E9Uh-yHKZnEtAZC6PJB7OxH5MD0ZUE4U,120
|
|
3
|
+
saxo_doc_helper/cli.py,sha256=bhF8iNx1EsG0lNKRSAaInmEild5JEAv6GwVYNvQk6fY,2924
|
|
4
|
+
saxo_doc_helper/commands.py,sha256=CK4OifhnsGmxXlI6uOxiyYqBh7XKoOJ-VpzKF1yLIl8,4173
|
|
5
|
+
saxo_doc_helper/index.py,sha256=c1W1zNlRb57fBsrkCYOIQSfUnz8pMQjV7lBQDjUhls0,5218
|
|
6
|
+
saxo_doc_helper/mcp_server.py,sha256=nWD2PVr-GjWesSb24xpKwRmpKhOmYkbcjnPtUNT5JFk,5070
|
|
7
|
+
saxo_doc_helper/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
saxo_doc_helper/data/__init__.py,sha256=akk-TI8vMzEAQ91pbrj5o9ZCQIHAPy4-k6G7vBvORD0,58
|
|
9
|
+
saxo_doc_helper/data/json/atr/cashmanagement-beneficiaryinstructions.json,sha256=NIsKFEEDKQIFumFuUJM6m9WCQnCpDfWfOCrpuTG9PN4,2680
|
|
10
|
+
saxo_doc_helper/data/json/atr/cashmanagement-cashwithdrawal.json,sha256=cUVSyLzFCZpu0hwIQHtgvsVwk04hpb4WCjKpnwGLa3w,2675
|
|
11
|
+
saxo_doc_helper/data/json/atr/cashmanagement-cashwithdrawallimits.json,sha256=2ZOqXFW3x1Y9y-NItacdsSozah5wKZf6sUeJxCX0KzA,1947
|
|
12
|
+
saxo_doc_helper/data/json/atr/cashmanagement-interaccounttransfers.json,sha256=xYypjh-7l7gXTG1o8pOpDu73gXDg0Oiec1SQxN36yt0,1611
|
|
13
|
+
saxo_doc_helper/data/json/atr/cashmanagement-periodicpayment.json,sha256=D5l2q1XWRYpoa96i4pLvmbdVegXoR3BZCv_budO5R8Y,12634
|
|
14
|
+
saxo_doc_helper/data/json/atr/partner-cashtransfer.json,sha256=h4lf0qRgEPhSs45WJdTd_Yz6SzfvqqJvdzqMl7Uut7Q,8843
|
|
15
|
+
saxo_doc_helper/data/json/atr/partner-cashtransferlimits.json,sha256=bLi-ZFnDmmRwx_HWeC0vxtguZXTMxjFgu-LWUXeU3QA,1879
|
|
16
|
+
saxo_doc_helper/data/json/atr/partner-prefunding.json,sha256=NEO3zx9G0nJyqAs20TJT01MG8Z9cJUtWS4bj54nUwd0,3117
|
|
17
|
+
saxo_doc_helper/data/json/atr/securitiestransfers.json,sha256=5lQmKGFwqKcWhYzCy3VxWBtLyAVu6NAIKX-8X0l7SR4,40835
|
|
18
|
+
saxo_doc_helper/data/json/ca/elections.json,sha256=qPR7LWpZF2K8OKJaZZpOfqKFyDCfmMEG_856BstquHc,4540
|
|
19
|
+
saxo_doc_helper/data/json/ca/events.json,sha256=Uc_FB7hEkAna0DslwB27DF7MNjD31lP9vGd1JbeZ2qs,56805
|
|
20
|
+
saxo_doc_helper/data/json/ca/eventviews.json,sha256=hJYXhfgpQaZmbHCSf-L6hHMEs2bGyiEZkV_G3B6DI9Y,34603
|
|
21
|
+
saxo_doc_helper/data/json/ca/holdings.json,sha256=cAjKpTgMLgSSJV-mPqFg27pMQ7lgZ1jTsxSxSuQIQtE,8556
|
|
22
|
+
saxo_doc_helper/data/json/ca/proxyvoting.json,sha256=zeXhuUAcLInxAg4tsaUvJKJnLE5MaaAJ7ySMZc7MSFE,10462
|
|
23
|
+
saxo_doc_helper/data/json/ca/standinginstructions.json,sha256=4qnTUC6HbUw1LpI_95X7Xcj9EtGZ7iSnyso5CuMa7I4,14460
|
|
24
|
+
saxo_doc_helper/data/json/chart/charts.json,sha256=EZVWb0lqk9ujoQVzHbPeX1sy80nIqI52NxbmU7Wm1O4,69680
|
|
25
|
+
saxo_doc_helper/data/json/cm/accounts.json,sha256=mUWHRjYC2OtmHBeZXaupLiv786R2JsBBUftujQdlBL8,1160
|
|
26
|
+
saxo_doc_helper/data/json/cm/clientrenewals.json,sha256=wkLw2dF-9QVyssRaSDyaE_SvkRoVm95x5hUQcVE8bEc,121956
|
|
27
|
+
saxo_doc_helper/data/json/cm/documents.json,sha256=oBfdkX4N3kDMjmcT6HGwPn12Z3jOQBQQpd9_Q1LZTL0,3704
|
|
28
|
+
saxo_doc_helper/data/json/cm/signups.json,sha256=4ARUo3I_hPr7ORYFdtj_ANDjDJmwPtwVJ6R8gn90wBg,21788
|
|
29
|
+
saxo_doc_helper/data/json/cm/users.json,sha256=Fg7XmGmdGbA3LZ3dLGW_k8gZwxum3EYDkQjJVVq59yA,1299
|
|
30
|
+
saxo_doc_helper/data/json/cr/historicalreportdata-accountstatement.json,sha256=fbwNQ-YcB4rlz7HcgV7XB2XRErpSACDk5EaBHEle6Ic,2803
|
|
31
|
+
saxo_doc_helper/data/json/cr/historicalreportdata-portfoliomanagement.json,sha256=NaC9SL1cfxISxt0ObbSQra_5BO9xbTxSpWOvbzTidws,4873
|
|
32
|
+
saxo_doc_helper/data/json/cr/historicalreportdata-tradedetails.json,sha256=to-FjuSXM1Cm2F8-fnkqZ0q3tId7F4yqeTx3yUGiCSw,2567
|
|
33
|
+
saxo_doc_helper/data/json/cr/historicalreportdata-tradesexecuted.json,sha256=H0rs31KnM4PrUL4m-fnv1f70X-SE5EJyvb9z43xqFv4,2133
|
|
34
|
+
saxo_doc_helper/data/json/cs/audit-orderactivities.json,sha256=CScmK654B60lIT_fjkoY5v0TE1cC3dfyq-EwxeLfFEo,9002
|
|
35
|
+
saxo_doc_helper/data/json/cs/cashmanagement-interaccounttransfer.json,sha256=erGyWtA2foECdB3G6CkGxnKKi2lpAFdqmfoIz2cZri4,1942
|
|
36
|
+
saxo_doc_helper/data/json/cs/cashmanagement-wiretransfers.json,sha256=Ac8FSOBBBsvcd350cw0pCqeM_1aLkTaBVjtKA0nZqu0,2127
|
|
37
|
+
saxo_doc_helper/data/json/cs/clientinfo.json,sha256=_tcDCnvAa59EW7mABs00jUNeVDxn_vg_znKZGYzaAxU,5256
|
|
38
|
+
saxo_doc_helper/data/json/cs/historicalreportdata-aggregatedamounts.json,sha256=P86S3VlFTe5tmNW2mYfkeJNoVUVT-4jekXAGhsybCl8,5168
|
|
39
|
+
saxo_doc_helper/data/json/cs/historicalreportdata-bookings.json,sha256=kRPk9jMhLq-nIUYRKAt_kaHepc3qcmiKqoB2QLjj51Y,9387
|
|
40
|
+
saxo_doc_helper/data/json/cs/historicalreportdata-closedpositions.json,sha256=gtgsXRc6sjwYuoEkETCkSRFOS_TmyGEzHHTM7W2zMvA,3977
|
|
41
|
+
saxo_doc_helper/data/json/cs/historicalreportdata-trades.json,sha256=v6jdWuJ_KajVEc9HpTOBtJiJEqytNGjH-vcqcGlACZ8,4653
|
|
42
|
+
saxo_doc_helper/data/json/cs/support-cases.json,sha256=wX46VGtV38lU_jF7agnIJ1TTjiJXz3aLJ-XupoStkG4,17378
|
|
43
|
+
saxo_doc_helper/data/json/cs/tradingconditions-contractoption.json,sha256=HSt_0z3WMMPMXyelLYYCHfd92D2ab7izItyndk8l2rg,3904
|
|
44
|
+
saxo_doc_helper/data/json/cs/tradingconditions-cost.json,sha256=G_ZSHduuCgBwn-hGitIG7Q69ZPx7JVFAh6SAmVTCVow,34163
|
|
45
|
+
saxo_doc_helper/data/json/cs/tradingconditions.json,sha256=0eie6MnB50TK_cu43QpURIcuaBTCWJ-PEXMuURYw71g,33629
|
|
46
|
+
saxo_doc_helper/data/json/dm/disclaimermanagement.json,sha256=Zbz09kxb39DnCcj0K_001t9x5-UzDAaDt55iJgdPdiY,4087
|
|
47
|
+
saxo_doc_helper/data/json/ens/clientactivities.json,sha256=bUA9yYCIiyz3t1VIsU7VubB8dOU3TvhtLeoQBRBiotA,56968
|
|
48
|
+
saxo_doc_helper/data/json/hist/accountvalues.json,sha256=KV-eK4eF6HDtMiO9Ta36gMZjN3YhvZkui8rwcROdpBM,1673
|
|
49
|
+
saxo_doc_helper/data/json/hist/historicalpositions.json,sha256=RX69wVgPkZY6YaqfIsiw3yGJmz5om65tAQy7jDXpCDU,31230
|
|
50
|
+
saxo_doc_helper/data/json/hist/performance.json,sha256=JPDeWjAOc5i7cMNOC01Un2VzjawMGnlj2kMIwLALLUM,32486
|
|
51
|
+
saxo_doc_helper/data/json/hist/transactions.json,sha256=fEue4etjGleRqC1Fb59e6Da1uhIhrMySq_XuhRZfmvM,12508
|
|
52
|
+
saxo_doc_helper/data/json/hist/unsettledamounts.json,sha256=8Sgano8cIhYkzFNWr1XGIXUBLi6zfByLUdZw0aKJBKc,16232
|
|
53
|
+
saxo_doc_helper/data/json/mkt/instrumentdocument.json,sha256=JKARdIGgTrAhHfQK6OUrwp_KpM0VPNNB2wif6WXesF0,58337
|
|
54
|
+
saxo_doc_helper/data/json/partnerintegration/advisoryaccounts.json,sha256=R3LbafiZqgQR_geh7YwjuYU6ndp8rR74AJdkoI1aA8s,14990
|
|
55
|
+
saxo_doc_helper/data/json/partnerintegration/externalaccounts.json,sha256=WSQzmDPoMjmTZUPyahPLAcKxmxjbLduu3e9Mp7TqQ6I,24166
|
|
56
|
+
saxo_doc_helper/data/json/partnerintegration/fundinginstruction.json,sha256=ZcJDIdyuHBp59cyLu7TWvGUWY9cYz4UWkNTJP6KYZ10,9454
|
|
57
|
+
saxo_doc_helper/data/json/partnerintegration/interactiveesigning.json,sha256=YzHJMwmExEHRCP_Um5JOQ61cUGE6AJA3e67KYPJziZ8,8043
|
|
58
|
+
saxo_doc_helper/data/json/partnerintegration/interactiveidverification.json,sha256=wrRnlZmFSUfJKzVM0lGovhQGFs-ieQqgFg5ABix2fQ8,7839
|
|
59
|
+
saxo_doc_helper/data/json/partnerintegration/partnerbulkbookings.json,sha256=MWxSxj20ioYMrEVjRT5p0Sti1z1nOk7F1_Mb0u6xJLw,2638
|
|
60
|
+
saxo_doc_helper/data/json/partnerintegration/updatepricing.json,sha256=GKxg9YlgaJ5kUjK6fXpGr8Z7Q6Cz23quFa0EgQiEHXg,30372
|
|
61
|
+
saxo_doc_helper/data/json/port/accountgroups.json,sha256=q6bdllOVQhbhhzfeAmPx8z-lBwWnqW1DLp6uXWfcJPY,6833
|
|
62
|
+
saxo_doc_helper/data/json/port/accounts.json,sha256=kQz5QzX4jHLPUCXd1aDZwyr1y1ZDQOCq14q6HZh1Dew,44562
|
|
63
|
+
saxo_doc_helper/data/json/port/balances.json,sha256=6pubwQ02nyfGDrAJQH3EVqHv2kysJFxRON7SlZ1MDq4,151500
|
|
64
|
+
saxo_doc_helper/data/json/port/clients.json,sha256=pjd67drLipy9VB_UOBG46oRead6T6HBoq7fP9X0LuOE,53783
|
|
65
|
+
saxo_doc_helper/data/json/port/closedpositions.json,sha256=rt5DnLNnVny07WzdvMNesd7YdYekMRVl9ypAx9RuJW8,23193
|
|
66
|
+
saxo_doc_helper/data/json/port/exposure.json,sha256=JjdhsEtgUpVu1IcmHKPZ_xVJj1LyedK1g2rdO0NCzm8,121480
|
|
67
|
+
saxo_doc_helper/data/json/port/netpositions.json,sha256=3v0Kwl0k5krVqMXCNl6m9p-cjUXgvdWtx-iXqTmuIY4,82634
|
|
68
|
+
saxo_doc_helper/data/json/port/orders.json,sha256=mZ14pqh3w8aDH-kwMY9ftLRROnbNmzPQfhZ0zfpAgK0,24706
|
|
69
|
+
saxo_doc_helper/data/json/port/positions.json,sha256=-7SOXFNQzpz31Yyg9arjUtOg3enoab4Wk0ZDHSnH5AQ,30559
|
|
70
|
+
saxo_doc_helper/data/json/port/users.json,sha256=lcvCfJqIJHuflnnZbk0tHSIjhaOxQOZtIiGGWfgSsik,38556
|
|
71
|
+
saxo_doc_helper/data/json/ref/algostrategies.json,sha256=ZhRH9V8dpj6r7QHFGSwvVFT4CsHIXWZb9pYMppA21n0,2898
|
|
72
|
+
saxo_doc_helper/data/json/ref/countries.json,sha256=-N54qPyW1GBljwPX64r5qX4M_XvAzcl_BDtsGwG6pa0,6382
|
|
73
|
+
saxo_doc_helper/data/json/ref/cultures.json,sha256=AiU1CzKB63CnbFcQf0_bH7SVUfeM5EakatJ6ZYu8CY0,2207
|
|
74
|
+
saxo_doc_helper/data/json/ref/currencies.json,sha256=oLUlQnBiIKPI7FwgPjpSR6zl80FHtxXnS4ZO8_zmrs8,2665
|
|
75
|
+
saxo_doc_helper/data/json/ref/currencypairs.json,sha256=wm4--ZMgfxAlh5L3f1ywvao_PashMoNyjdJbjSd5L1w,2101
|
|
76
|
+
saxo_doc_helper/data/json/ref/exchanges.json,sha256=nf_Une7xoIlvI9mXU6gBeSXhkl08O5wkByOsoAkamZo,2204
|
|
77
|
+
saxo_doc_helper/data/json/ref/instruments.json,sha256=RqhecpyEf4h7Oo4z-V0Efav9CACvYu6z403xEsdMyBw,132970
|
|
78
|
+
saxo_doc_helper/data/json/ref/languages.json,sha256=wEGssgj6JyMgp6VaqFNJOar4r0GRbowXJ6MTRnzNzqw,2619
|
|
79
|
+
saxo_doc_helper/data/json/ref/standarddates.json,sha256=RRtNG7l_iblldgS2HES3FXZHLWaYgks-h9dMlY6VRnw,2011
|
|
80
|
+
saxo_doc_helper/data/json/ref/timezones.json,sha256=8YMukXNSGzFp3WY7ahHhjHtYQGvvhBe3b9vLPgscJNU,3969
|
|
81
|
+
saxo_doc_helper/data/json/reg/financialoverview.json,sha256=IP6YBAdnjOqpyQW8Q23ZDaPSPrNI6c6fDAXeXPx7faI,15645
|
|
82
|
+
saxo_doc_helper/data/json/reg/investmentprofile.json,sha256=TpUnpOAIpuhYdDOma85Op5bAtkzsW9cLtCE7gXpK8hk,32023
|
|
83
|
+
saxo_doc_helper/data/json/reg/knowledgeandexperience.json,sha256=aHqTGu-HHdGDPSH47jrRKn-sb-OBGcIFRGwxPSxIHRM,4390
|
|
84
|
+
saxo_doc_helper/data/json/trade/allocationkeys.json,sha256=Em_eZ-_o5DhtOJwwF1ZGzAAwvzx8SJnvS_qMnH2mApI,40244
|
|
85
|
+
saxo_doc_helper/data/json/trade/infoprices.json,sha256=KaJLwwGoK_JEHv_iL-zx48ftSTmRW5eXso0t29E3huo,109859
|
|
86
|
+
saxo_doc_helper/data/json/trade/messages.json,sha256=njZ0gP0Kg4hIun6Nbq0gAuQwzZ0IgRPtw5-qk6ciDvg,13341
|
|
87
|
+
saxo_doc_helper/data/json/trade/optionschain.json,sha256=T-yrA7q2txgrw7VHoBRkZ3XSqn7GckKBKJFwZU1Ioxw,47487
|
|
88
|
+
saxo_doc_helper/data/json/trade/orders.json,sha256=eiBgEbbt5H9dhEr4mBl9PawOTxqdNtlfDxTjveXKOLU,396941
|
|
89
|
+
saxo_doc_helper/data/json/trade/positions.json,sha256=2JGdfwp6HnMmIa51jyJ25tHlFgKSihfoqml_-PY4nJE,54533
|
|
90
|
+
saxo_doc_helper/data/json/trade/prices.json,sha256=jO3Pk1VTJipJWTeTSBKAQmqe76xPfnQmHugneS1Rs4o,127465
|
|
91
|
+
saxo_doc_helper/data/json/trade/trades.json,sha256=JX2Ie20bE0owWuid75buoyqbit7Sxya--Tz9rdr8cYY,36142
|
|
92
|
+
saxo_doc_helper/data/json/vas/pricealerts.json,sha256=VDuknIGAUJa8A-PWCeIx1VA2uB7vHRTE99oAMyJ__Yg,73789
|
|
93
|
+
mcp_server_saxo_openapi-0.1.1.dist-info/METADATA,sha256=4Fe-f6clAQlD8c6oZ8m8X11dME1V3S6ULVsFpk6ZN9E,7104
|
|
94
|
+
mcp_server_saxo_openapi-0.1.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
95
|
+
mcp_server_saxo_openapi-0.1.1.dist-info/entry_points.txt,sha256=YSgs4xx7gQ1lBTH3cd6rg5OAsrlOIpIB5-ek-mtFM_w,116
|
|
96
|
+
mcp_server_saxo_openapi-0.1.1.dist-info/licenses/LICENSE,sha256=_HRu5kqPvkdh0yNADHdfHiBRiCyUAwHOm8Fk8VJYxy4,1067
|
|
97
|
+
mcp_server_saxo_openapi-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nohikomiso
|
|
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,32 @@
|
|
|
1
|
+
"""Saxo OpenAPI spec lookup — CLI and MCP server."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.1"
|
|
4
|
+
SPEC_SNAPSHOT_DATE = "2026-07-08"
|
|
5
|
+
SAXO_RELEASE_NOTES_THROUGH = "2025/05/15"
|
|
6
|
+
|
|
7
|
+
from saxo_doc_helper.index import (
|
|
8
|
+
SaxoDocIndex,
|
|
9
|
+
normalize_method,
|
|
10
|
+
normalize_path,
|
|
11
|
+
normalize_schema_name,
|
|
12
|
+
resolve_spec_dir,
|
|
13
|
+
)
|
|
14
|
+
from saxo_doc_helper.commands import (
|
|
15
|
+
cmd_get_endpoint,
|
|
16
|
+
cmd_get_schema,
|
|
17
|
+
cmd_search_endpoints,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"SAXO_RELEASE_NOTES_THROUGH",
|
|
22
|
+
"SPEC_SNAPSHOT_DATE",
|
|
23
|
+
"SaxoDocIndex",
|
|
24
|
+
"__version__",
|
|
25
|
+
"cmd_get_endpoint",
|
|
26
|
+
"cmd_get_schema",
|
|
27
|
+
"cmd_search_endpoints",
|
|
28
|
+
"normalize_method",
|
|
29
|
+
"normalize_path",
|
|
30
|
+
"normalize_schema_name",
|
|
31
|
+
"resolve_spec_dir",
|
|
32
|
+
]
|
saxo_doc_helper/cli.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""CLI and MCP entry points."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from saxo_doc_helper import (
|
|
9
|
+
SAXO_RELEASE_NOTES_THROUGH,
|
|
10
|
+
SPEC_SNAPSHOT_DATE,
|
|
11
|
+
__version__,
|
|
12
|
+
)
|
|
13
|
+
from saxo_doc_helper.commands import cmd_get_endpoint, cmd_get_schema, cmd_search_endpoints
|
|
14
|
+
from saxo_doc_helper.index import SaxoDocIndex, resolve_spec_dir
|
|
15
|
+
from saxo_doc_helper.mcp_server import run_mcp_server
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def version_string() -> str:
|
|
19
|
+
return (
|
|
20
|
+
f"mcp-server-saxo-openapi {__version__} "
|
|
21
|
+
f"(spec snapshot {SPEC_SNAPSHOT_DATE}; "
|
|
22
|
+
f"saxo RN through {SAXO_RELEASE_NOTES_THROUGH})"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def mcp_main() -> None:
|
|
27
|
+
"""Entry point for ``mcp-server-saxo-openapi`` (stdio MCP only)."""
|
|
28
|
+
index = SaxoDocIndex(resolve_spec_dir())
|
|
29
|
+
run_mcp_server(index)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main(argv: list[str] | None = None) -> None:
|
|
33
|
+
"""Entry point for ``saxo-doc-helper`` and ``python -m saxo_doc_helper``."""
|
|
34
|
+
parser = argparse.ArgumentParser(
|
|
35
|
+
description="Saxo OpenAPI spec lookup — CLI & MCP helper",
|
|
36
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
37
|
+
epilog="""
|
|
38
|
+
Examples:
|
|
39
|
+
saxo-doc-helper search-endpoints orders
|
|
40
|
+
saxo-doc-helper get-endpoint POST /trade/v2/orders
|
|
41
|
+
saxo-doc-helper get-endpoint post trade/v2/orders --depth 1
|
|
42
|
+
saxo-doc-helper get-schema algorithmicorderdata
|
|
43
|
+
saxo-doc-helper --mcp
|
|
44
|
+
mcp-server-saxo-openapi
|
|
45
|
+
""",
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--version",
|
|
49
|
+
action="version",
|
|
50
|
+
version=version_string(),
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument("--mcp", action="store_true", help="Run as MCP stdio server")
|
|
53
|
+
parser.add_argument(
|
|
54
|
+
"command",
|
|
55
|
+
nargs="?",
|
|
56
|
+
choices=["search-endpoints", "get-endpoint", "get-schema"],
|
|
57
|
+
help="CLI command to run",
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument("args", nargs=argparse.REMAINDER, help="Command arguments")
|
|
60
|
+
|
|
61
|
+
parsed = parser.parse_args(argv)
|
|
62
|
+
index = SaxoDocIndex(resolve_spec_dir())
|
|
63
|
+
|
|
64
|
+
if parsed.mcp:
|
|
65
|
+
run_mcp_server(index)
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
if not parsed.command:
|
|
69
|
+
parser.print_help()
|
|
70
|
+
sys.exit(1)
|
|
71
|
+
|
|
72
|
+
if parsed.command == "search-endpoints":
|
|
73
|
+
if not parsed.args:
|
|
74
|
+
print("Usage: search-endpoints <query>")
|
|
75
|
+
sys.exit(1)
|
|
76
|
+
print(cmd_search_endpoints(index, " ".join(parsed.args)))
|
|
77
|
+
|
|
78
|
+
elif parsed.command == "get-endpoint":
|
|
79
|
+
sub = argparse.ArgumentParser()
|
|
80
|
+
sub.add_argument("method")
|
|
81
|
+
sub.add_argument("path")
|
|
82
|
+
sub.add_argument("--depth", type=int, default=0)
|
|
83
|
+
a = sub.parse_args(parsed.args)
|
|
84
|
+
print(cmd_get_endpoint(index, a.method, a.path, a.depth))
|
|
85
|
+
|
|
86
|
+
elif parsed.command == "get-schema":
|
|
87
|
+
sub = argparse.ArgumentParser()
|
|
88
|
+
sub.add_argument("schema_name")
|
|
89
|
+
sub.add_argument("--depth", type=int, default=0)
|
|
90
|
+
a = sub.parse_args(parsed.args)
|
|
91
|
+
print(cmd_get_schema(index, a.schema_name, a.depth))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
main()
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""CLI command implementations for Saxo OpenAPI spec lookup."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from saxo_doc_helper.index import SaxoDocIndex, normalize_method, normalize_path, normalize_schema_name
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _format_params(params: list, depth: int = 0, max_depth: int = 0) -> list[str]:
|
|
11
|
+
lines = []
|
|
12
|
+
for p in params:
|
|
13
|
+
indent = " " * depth
|
|
14
|
+
origin = f" ({p['origin']})" if p.get("origin") else ""
|
|
15
|
+
line = f"{indent}- **{p['name']}** (`{p['type']}`){origin}: {p.get('description', '')}"
|
|
16
|
+
lines.append(line)
|
|
17
|
+
|
|
18
|
+
children = p.get("children", [])
|
|
19
|
+
if children:
|
|
20
|
+
link = p.get("link") or ""
|
|
21
|
+
schema_key = (
|
|
22
|
+
normalize_schema_name(link.split("/schema-")[-1]) if "/schema-" in link else ""
|
|
23
|
+
)
|
|
24
|
+
if depth < max_depth:
|
|
25
|
+
lines.extend(_format_params(children, depth + 1, max_depth))
|
|
26
|
+
else:
|
|
27
|
+
hint = f" [Refer to Schema: {schema_key}]" if schema_key else ""
|
|
28
|
+
lines.append(f"{indent} * (Nested parameters collapsed.{hint})")
|
|
29
|
+
return lines
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _render_json_sample(sample, label: str) -> str:
|
|
33
|
+
if sample is None:
|
|
34
|
+
return ""
|
|
35
|
+
if isinstance(sample, (dict, list)):
|
|
36
|
+
body = json.dumps(sample, indent=2, ensure_ascii=False)
|
|
37
|
+
else:
|
|
38
|
+
body = str(sample)
|
|
39
|
+
return f"\n{label}:\n{body}"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def cmd_search_endpoints(index: SaxoDocIndex, query: str) -> str:
|
|
43
|
+
q = query.lower()
|
|
44
|
+
results = [
|
|
45
|
+
ep
|
|
46
|
+
for ep in index.endpoints
|
|
47
|
+
if q in ep["path"].lower()
|
|
48
|
+
or q in ep["name"].lower()
|
|
49
|
+
or q in ep["service"].lower()
|
|
50
|
+
or q in ep["category"].lower()
|
|
51
|
+
]
|
|
52
|
+
if not results:
|
|
53
|
+
return f"No endpoints found matching '{query}'."
|
|
54
|
+
lines = [f"Found {len(results)} endpoint(s) matching '{query}':\n"]
|
|
55
|
+
for ep in results:
|
|
56
|
+
lines.append(
|
|
57
|
+
f" [{ep['service']}/{ep['category']}] {ep['method']} {ep['path']} -> {ep['name']}"
|
|
58
|
+
)
|
|
59
|
+
return "\n".join(lines)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def cmd_get_endpoint(index: SaxoDocIndex, method: str, path: str, depth: int = 0) -> str:
|
|
63
|
+
method = normalize_method(method)
|
|
64
|
+
path = normalize_path(path)
|
|
65
|
+
|
|
66
|
+
match = next(
|
|
67
|
+
(ep for ep in index.endpoints if ep["method"] == method and ep["path"] == path),
|
|
68
|
+
None,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if match is None:
|
|
72
|
+
candidates = [
|
|
73
|
+
ep for ep in index.endpoints if (path.rstrip("s") in ep["path"] or path in ep["path"])
|
|
74
|
+
]
|
|
75
|
+
lines = [f'Error: Endpoint "{method} {path}" not found.']
|
|
76
|
+
if candidates:
|
|
77
|
+
lines.append("\nDid you mean one of these?")
|
|
78
|
+
for c in candidates[:5]:
|
|
79
|
+
lines.append(f" - {c['method']} {c['path']} ({c['name']})")
|
|
80
|
+
return "\n".join(lines)
|
|
81
|
+
|
|
82
|
+
param_lines = _format_params(match["parameters"], max_depth=depth)
|
|
83
|
+
out = [
|
|
84
|
+
f"Name: {match['name']}",
|
|
85
|
+
f"Path: {match['method']} {match['path']}",
|
|
86
|
+
f"URL: {match['url']}",
|
|
87
|
+
"",
|
|
88
|
+
"Parameters:",
|
|
89
|
+
]
|
|
90
|
+
out.extend(param_lines if param_lines else [" (no parameters)"])
|
|
91
|
+
out.append(_render_json_sample(match["request_sample"], "Request Sample"))
|
|
92
|
+
out.append(_render_json_sample(match["response_sample"], "Response Sample"))
|
|
93
|
+
return "\n".join(out).strip()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def cmd_get_schema(index: SaxoDocIndex, schema_name: str, depth: int = 0) -> str:
|
|
97
|
+
key = normalize_schema_name(schema_name)
|
|
98
|
+
schema = index.schemas.get(key)
|
|
99
|
+
if schema is None:
|
|
100
|
+
candidates = [k for k in index.schemas if key in k or k in key]
|
|
101
|
+
if candidates:
|
|
102
|
+
schema = index.schemas[candidates[0]]
|
|
103
|
+
key = candidates[0]
|
|
104
|
+
else:
|
|
105
|
+
available = sorted(index.schemas.keys())[:10]
|
|
106
|
+
return (
|
|
107
|
+
f'Error: Schema "{schema_name}" not found.\n'
|
|
108
|
+
f"Available schemas (first 10): {available}"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
param_lines = _format_params(schema["parameters"], max_depth=depth)
|
|
112
|
+
out = [
|
|
113
|
+
f"Schema: {schema['type_name']} (key: {key})",
|
|
114
|
+
f"Description: {schema['description']}",
|
|
115
|
+
"",
|
|
116
|
+
"Parameters:",
|
|
117
|
+
]
|
|
118
|
+
out.extend(param_lines if param_lines else [" (no parameters)"])
|
|
119
|
+
return "\n".join(out)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Package data marker (JSON files live under data/json/).
|