nordnet-mcp
# nordnet-mcp
A [Model Context Protocol](https://modelcontextprotocol.io) server exposing
Nordnet's **public** market data — quotes, charts, news, trade tape, fund/ETF/
stock profiles and FX rates — via the [`nordnet-sdk`](https://pypi.org/project/nordnet-sdk).
**No account. No API key. No login.** This talks to the same API Nordnet's
website uses for anonymous visitors, so it runs anywhere, needs zero
configuration, and holds no secrets.
## Install
```bash
pip install nordnet-mcp
# or with pipx for an isolated runtime:
pipx install nordnet-mcp
```
Requires Python 3.10+.
## Run
```bash
nordnet-mcp # console script
python -m nordnet_mcp # or module form
```
The server speaks MCP over **stdio** — wire it into any MCP client.
## Configuration
Configuration is read from environment variables; defaults target Nordnet's
Finnish site and the public market-data host:
| Variable | Default | Purpose |
| --- | --- | --- |
| `NORDNET_BASE_URL` | `https://www.nordnet.fi` | main site host (`.se`/`.dk`/`.no` also work) |
| `NORDNET_MARKET_DATA_BASE_URL` | `https://api.prod.nntech.io` | charts, indices, screening host |
| `NORDNET_LOCALE` | `fi-FI` | sent as `x-locale` on the market-data host |
## Client wiring
Claude Desktop (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"nordnet": {
"command": "nordnet-mcp"
}
}
}
```
Hermes Agent (`~/.hermes/config.yaml`):
```yaml
mcp_servers:
nordnet:
command: /path/to/nordnet-mcp
```
Generic stdio MCP client:
```json
{ "mcpServers": { "nordnet": { "command": "uvx", "args": ["nordnet-mcp"] } } }
```
## Tools
| Tool | Returns |
| --- | --- |
| `search(query, limit)` | free-text search grouped by asset class |
| `instrument(instrument_id)` | full snapshot: identity, quote, returns, key ratios |
| `quote(instrument_id)` | latest price block with identity context |
| `trades(instrument_id, count)` | recent executed trades (the tape) |
| `stocklist(limit, sort_attribute, sort_order, risers_only)` | market overview (risers/fallers) |
| `fund(instrument_id)` | fund snapshot: NAV, fees, risk class, SFDR article |
| `fund_profile(instrument_id)` / `fund_profile_by_slug(slug)` | full fund screening profile |
| `etf_profile(instrument_id)` / `etf_profile_by_slug(slug)` | full ETF screening profile |
| `stock_profile(instrument_id)` / `stock_profile_by_slug(slug)` | full stock screening profile |
| `chart(instrument_id, period)` / `chart_by_identifier(identifier, period)` | price time series (8 periods) |
| `news(instrument_id, limit, offset)` | paginated news feed |
| `indicators(list_id)` | index/FX quotes for a market list |
| `indicator(slug)` | single indicator / FX quote (e.g. `eurusd`) |
| `market_hours(instrument_id)` / `market_hours_for_order_book(order_book_id)` | trading sessions; `null` when none |
Chart periods: `DAY_1`, `WEEK_1`, `MONTH_1`, `MONTH_3`, `MONTH_6`, `YTD`,
`YEAR_1`, `ALL`.
Instrument IDs are Nordnet's internal numeric IDs (e.g. `16100884` = Wärtsilä
B, `17794251` = Nordnet One Rohkea EUR). Find them with `search`, or read them
from instrument pages on nordnet.fi.
## Public data boundary
Everything served here is data Nordnet shows to anonymous visitors. The one
notable exception: full order book depth (the multi-level bid/ask ladder) is
login-only — anonymously you only get top-of-book (best bid/ask with resting
volumes). This server respects that boundary by design.
## Development
```bash
pip install -e ".[dev]"
pytest # offline — runs against a local fixture server
uv build # wheel + sdist
```
## Legal
Unofficial, not affiliated with or endorsed by Nordnet. Only reads public
data; please be polite to the API (the SDK retries transient failures with
backoff). Use at your own risk; market data may be delayed. MIT licensed.
TDQS
Scored across 19 tools
Several tools have overlapping names or similar purposes: 'indicator' vs 'indicators' differ only in pluralization, and pairs like 'chart'/'chart_by_identifier' and 'market_hours'/'market_hours_for_order_book' are distinguished only by input format. Descriptions clarify the differences, but an agent could easily select the wrong tool without careful reading.
Tool names follow a consistent snake_case noun pattern (e.g., instrument, quote, trades, stock_profile), with suffixes like _by_slug and _by_identifier used systematically. The naming is predictable, though the lack of verb prefixes and the close similarity between 'indicator' and 'indicators' slightly reduce consistency.
With 19 tools, the server covers a broad range of market data needs—quotes, charts, news, profiles, market hours, and search—without becoming unwieldy. The count is on the higher end but well-justified for a comprehensive financial data server.
The tool surface is comprehensive, covering search, quotes, charts, news, trades, market hours, and detailed profiles for stocks, funds, and ETFs. Both slug and raw identifier variants ensure no dead ends for different input formats, and there are no obvious gaps in public market data coverage.