{
  "markdown": "# Nordic Financial MCP\n\n<!-- mcp-name: io.github.AIDataNordic/nordic-financial-mcp -->\n\n[![smithery badge](https://smithery.ai/badge/kontakt-qy0g/nordic-financial-mcp)](https://smithery.ai/servers/kontakt-qy0g/nordic-financial-mcp) [![nordic_financial_mcp MCP server](https://glama.ai/mcp/servers/AIDataNordic/nordic_financial_mcp/badges/score.svg)](https://glama.ai/mcp/servers/AIDataNordic/nordic_financial_mcp)\n\nA production-grade semantic search server for Nordic financial markets — built for autonomous AI agents. 1,000,000+ vectors across exchange filings, company reports, commodity prices, freight rates, energy data and press releases.\n\n**Search:** Natural language queries over annual reports, quarterly reports, exchange announcements and macroeconomic summaries — filtered by company, ticker, country, sector or year. Two-stage hybrid retrieval (dense + sparse BM25, fused via RRF) with cross-encoder reranking for high-precision results.\n\n**Live endpoint:** `https://mcp.aidatanorge.no/mcp`  \n**Transport:** `streamable-http`  \n**Registry:** [Smithery](https://smithery.ai/servers/kontakt-qy0g/nordic-financial-mcp) · [MCP Registry](https://registry.modelcontextprotocol.io/v0/servers/io.github.AIDataNordic%2Fnordic-financial-mcp/versions) · [Glama](https://glama.ai/mcp/servers/AIDataNordic/nordic_financial_mcp) · [mcp.so](https://mcp.so)\n\n---\n\n## Connect\n\nAdd to your MCP client config:\n\n```json\n{\n  \"mcpServers\": {\n    \"nordic-financial\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.aidatanorge.no/mcp\"\n    }\n  }\n}\n```\n\nOr with Claude Code:\n```bash\nclaude mcp add --transport http nordic-financial https://mcp.aidatanorge.no/mcp\n```\n\n---\n\n## Quick Test\n\n**Try the live demo in your browser:**  \n👉 [https://mcp.aidatanorge.no/demo](https://mcp.aidatanorge.no/demo)\n\nNo installation, no configuration. Just search for \"Equinor dividend\", \"Swedish policy rate\", or \"salmon price Q3\".\n\n---\n\n## For MCP Client Developers\n\nThis server follows the **StreamableHTTP** MCP transport. A complete handshake is required before calling tools.\n\n### Full Handshake Example (Copy-Paste Ready)\n\n```bash\n# 1. Create session and capture session ID\nSESSION_ID=$(curl -X GET https://mcp.aidatanorge.no/mcp \\\n  -H \"Accept: application/json, text/event-stream\" \\\n  -s -i | grep -i \"mcp-session-id\" | awk '{print $2}' | tr -d '\\r')\n\necho \"Session ID: $SESSION_ID\"\n\n# 2. Initialize session\ncurl -X POST https://mcp.aidatanorge.no/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json, text/event-stream\" \\\n  -H \"mcp-session-id: $SESSION_ID\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"id\": 1,\n    \"method\": \"initialize\",\n    \"params\": {\n      \"protocolVersion\": \"2024-11-05\",\n      \"capabilities\": {},\n      \"clientInfo\": {\"name\": \"example-client\", \"version\": \"1.0\"}\n    }\n  }'\n\n# 3. Send initialized notification\ncurl -X POST https://mcp.aidatanorge.no/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json, text/event-stream\" \\\n  -H \"mcp-session-id: $SESSION_ID\" \\\n  -d '{\"jsonrpc\": \"2.0\", \"method\": \"notifications/initialized\"}'\n\n# 4. List available tools\ncurl -X POST https://mcp.aidatanorge.no/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json, text/event-stream\" \\\n  -H \"mcp-session-id: $SESSION_ID\" \\\n  -d '{\"jsonrpc\": \"2.0\", \"id\": 2, \"method\": \"tools/list\", \"params\": {}}'\n\n# 5. Perform a search\ncurl -X POST https://mcp.aidatanorge.no/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json, text/event-stream\" \\\n  -H \"mcp-session-id: $SESSION_ID\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"id\": 3,\n    \"method\": \"tools/call\",\n    \"params\": {\n      \"name\": \"search_filings\",\n      \"arguments\": {\"query\": \"Equinor dividend\", \"limit\": 3}\n    }\n  }'\n```\n\n### Common Issues & Solutions\n\n| Error | Cause | Solution |\n|-------|-------|----------|\n| `406 Not Acceptable` | Missing `text/event-stream` in Accept header | Send: `Accept: application/json, text/event-stream` |\n| `400 Bad Request: Missing session ID` | No session established | First `GET /mcp`, use returned `mcp-session-id` header |\n| `-32602 Invalid request parameters` | Missing `initialize` before `tools/list` | Complete steps 1-3 in order |\n\n### Python Example with MCP SDK\n\n```python\nfrom mcp import ClientSession\nfrom mcp.client.streamable_http import streamablehttp_client\n\nasync with streamablehttp_client(\"https://mcp.aidatanorge.no/mcp\") as transport:\n    async with ClientSession(*transport) as session:\n        await session.initialize()\n        tools = await session.list_tools()\n        result = await session.call_tool(\n            \"search_filings\",\n            {\"query\": \"Norwegian housing market Q3 2024\", \"country\": \"NO\"}\n        )\n        print(result.content[0].text)\n```\n\n### Why This Matters\n\nThis handshake is **automatic** in MCP-compliant clients like Claude Desktop, LangChain, and the MCP Python SDK. If you're building a custom client, following the sequence above ensures compatibility.\n\nThe `/demo` endpoint shows how a browser can perform the same handshake using JavaScript `fetch()` — view source for a working implementation.\n\n---\n\n## What This Is\n\nAIDataNorge is a full-stack data pipeline and semantic search system that ingests, processes, and indexes financial data from Nordic markets into a vector database optimized for AI agent queries. It exposes data through a Model Context Protocol (MCP) server, making it natively compatible with Claude, LangChain, and other LLM-based agents.\n\nThe system is designed with autonomous machine-to-machine consumption in mind, including support for emerging agent payment protocols. The database is updated nightly.\n\n---\n\n## MCP Tools\n\n### `search_filings`\n\nSemantic search over Nordic company filings, press releases and macroeconomic summaries.\n\n```python\nsearch_filings(\n    query=\"Nordea net interest margin outlook 2025\",\n    report_type=\"quarterly_report\",  # annual_report | quarterly_report | press_release | macro_summary\n    country=\"SE\",                    # NO | SE | DK | FI\n    ticker=\"NDA\",                    # optional — filter by company ticker\n    fiscal_year=2025,                # optional — filter by year\n    sector=\"energy\",                 # optional — seafood | energy | shipping\n    limit=10                         # default 5, max 20\n)\n# Returns semantically ranked text chunks with rerank_score, hybrid_score, vector_score,\n# company, ticker, country, fiscal_year, report_type, filing_date and full text.\n```\n\n**Search pipeline:** Dense embedding (`intfloat/e5-large-v2`, 1024d) + sparse BM25, fused via Reciprocal Rank Fusion (RRF), reranked by `mmarco-mMiniLMv2-L12-H384-v1`. Natural language queries in any language are supported.\n\n### `get_company_info`\n\nLook up a company in the official business registry.\n\n```python\nget_company_info(\n    identifier=\"923609016\",  # org/CVR/business ID\n    country=\"NO\"             # NO (Brønnøysund) | DK (CVR) | FI (PRH)\n)\n# Returns company name, status and registered address.\n```\n\n### `parse_pdf_to_text`\n\nDownload a PDF from a URL and extract all text, page by page.\n\n```python\nparse_pdf_to_text(\n    pdf_url=\"https://example.com/annual_report_2024.pdf\"\n)\n# Returns extracted text with page separators.\n# Useful for reading report attachments not indexed in the main database.\n```\n\n### `get_current_power_price`\n\nReal-time day-ahead electricity spot prices for all Nordic bidding zones.\n\n```python\nget_current_power_price(\n    zone=\"NO1\",              # NO1–NO5, SE1–SE4, DK1, DK2, FI\n    include_tomorrow=False   # fetch tomorrow's prices if available (published ~13:00 CET)\n)\n# Returns EUR/kWh — current hour price + full hourly breakdown + daily min/max/avg.\n# Norwegian zones sourced from hvakosterstrommen.no, others directly from ENTSO-E.\n# Handles both PT60M (hourly) and PT15M (15-min) resolutions.\n```\n\n### `company_research`\n\nRun multiple targeted searches in a single call and get raw results grouped by section. The caller defines all sections and queries and is responsible for synthesizing the output.\n\n```python\ncompany_research(\n    company=\"Equinor\",\n    sections=[\n        {\"name\": \"financials\", \"query\": \"Equinor revenue EBITDA operating profit 2024\", \"ticker\": \"EQNR\"},\n        {\"name\": \"risk\",       \"query\": \"Equinor climate regulatory risk stranded assets\", \"ticker\": \"EQNR\"},\n        {\"name\": \"macro\",      \"query\": \"Brent crude oil price energy sector Norway 2024\", \"limit\": 3},\n        {\"name\": \"news\",       \"query\": \"Equinor press release dividend acquisition 2024\", \"ticker\": \"EQNR\"}\n    ]\n)\n# Returns: {company, generated_at, sections} — one entry per section with ranked text chunks.\n# All sections are searched in parallel. Up to 8 sections, max 10 results each.\n# Use ticker on company-specific sections to avoid false positives from documents\n# that merely mention the company as a customer or competitor.\n```\n\nFor a fully orchestrated due diligence report where AI plans the sections and synthesizes the narrative, use [Alfred MCP](https://alfred.aidatanorge.no/mcp) instead.\n\n### `ping`\n\n```python\nping(name=\"world\")\n# Returns: \"Hello world! Nordic MCP server is running.\"\n```\n\n---\n\n## Data Coverage\n\n| Source | Geography | Content | Volume |\n|--------|-----------|---------|--------|\n| XBRL ESEF (filings.xbrl.org) | NO/SE/DK/FI/IS | Annual reports, regulated markets, 2020–present | ~89k vectors |\n| MFN Nordics | SE/NO/DK/FI | Annual & quarterly reports, First North companies | ~116k vectors |\n| Oslo Børs Newsweb | NO | Exchange announcements, 2020–present | ~52k vectors |\n| Nasdaq Copenhagen | DK | Exchange announcements, 2020–present | ~8k vectors |\n| Nasdaq Helsinki | FI | Exchange announcements, 2020–present | ~5k vectors |\n| Nasdaq Stockholm | SE | Exchange announcements, 2020–present | in progress |\n| Cision | SE/NO/DK/FI | Press releases | ~20k vectors |\n| GlobeNewswire | NO/SE/DK/FI | Press releases, updated hourly Mon–Fri | ~500 vectors |\n| ENTSO-E | NO/SE/DK/FI | Day-ahead electricity prices, all bidding zones | ~24k vectors |\n| Commodity & freight | Global | Oil, gas, metals, shipping rates (BDRY/FRO/ZIM proxies) | 25 quarters |\n| Macro Norway | Norway | GDP, CPI, rates, housing, salmon, power | 24 quarters |\n| Macro Nordics | SE/DK/FI | Rates, housing, credit, power | 72 quarters |\n\n**Total: 1,000,000+ vectors** · Updated nightly\n\n---\n\n## Architecture\n\n```\nData Sources                 Pipeline                  Serving\n─────────────────            ─────────────────         ─────────────────\nXBRL ESEF               →    Python ingest scripts  →  Qdrant\nMFN Nordics             →    + Playwright scraping  →  Vector Database\nOslo Børs Newsweb       →    + PDF extraction        →  (1,000,000+ vectors)\nNasdaq Copenhagen       →    + Chunking              →        ↓\nCision / GlobeNewswire  →\nSSB / Norges Bank       →    + Chunking              →        ↓\nSSB / Norges Bank       →    + Dense embeddings      →  MCP Server\nSCB / DST / stat.fi     →\n                        →      (e5-large-v2, 1024d)  →  (FastMCP 3.2)\n                        →    + Sparse BM25            →        ↓\n                        →    + RRF fusion             →  AI Agents / LLMs\n```\n\n---\n\n## Technical Stack\n\n**Data ingestion**\n- Python with Playwright for JavaScript-rendered IR pages and MFN feed\n- PyMuPDF (fitz) for PDF text extraction\n- Paragraph-aware chunking (512-token chunks, 100-token overlap)\n- Dense embeddings: `intfloat/e5-large-v2` (1024d)\n- Sparse embeddings: `Qdrant/bm25` via fastembed\n\n**Storage & search**\n- Qdrant vector database (self-hosted)\n- Hybrid dense+sparse retrieval with Reciprocal Rank Fusion (RRF)\n- Cross-encoder reranking (`mmarco-mMiniLMv2-L12-H384-v1`)\n\n**Serving**\n- FastMCP 3.2 over HTTP (`/mcp` endpoint)\n- Cloudflare Tunnel — rate limited to 60 req/min per IP\n- Compatible with Claude, LangChain, and any MCP-capable agent\n\n**Infrastructure**\n- Ubuntu Server 24 LTS, self-hosted\n- 16 GB RAM\n- Automated cron jobs for continuous ingestion\n- Bitcoin full node (LND) for Lightning Network payments\n- DigiByte full node with DigiRail and DigiDollar Oracle node\n\n---\n\n## Agent Payment Infrastructure\n\nThe system is built with autonomous agent monetization in mind, supporting three complementary payment protocols:\n\n**x402 Micropayments**  \nA pay-per-call variant of the server (`mcp_server_x402.py`) is implemented using the [x402 protocol](https://x402.org) — the HTTP 402 payment standard for autonomous agents. Agents receive a payment requirement response, pay in USDC on Base, and retry automatically. Currently **paused** — x402 functionality will be integrated directly into the main server (`mcp_server.py`) in a future release.\n\n**Lightning Network (L402)**  \nRunning a full Bitcoin node with LND enables L402 — the HTTP payment protocol for autonomous agents. Agents can discover the API, receive a Lightning invoice, pay in millisatoshis, and get access — all without human intervention. Infrastructure in place, monetization layer in development.\n\n**DigiRail / DigiDollar**  \nAlso running a DigiByte full node with DigiRail (an agent payment protocol similar to L402) and a DigiDollar Oracle node. DigiDollar is the world's first UTXO-native decentralized stablecoin, implemented directly in DigiByte Core v9.26. The oracle node contributes to the decentralized price feed that maintains DigiDollar's USD peg — 15 of 30 randomly selected oracle nodes must reach consensus every ~25 minutes using Schnorr signatures.\n\nThis multi-protocol payment infrastructure (x402/Base + Bitcoin/Lightning + DigiByte/DigiRail) positions AIDataNorge to serve agents operating across different payment ecosystems.\n\n---\n\n## Ingest Pipeline Design\n\nEach data source has a dedicated ingest script with:\n- Idempotent processing via MD5-based point IDs (upsert-safe)\n- `processed.txt` log to avoid redundant re-fetching\n- `nohup` + cron scheduling for unattended overnight runs\n- Structured payload per chunk: `source`, `country`, `ticker`, `company_name`, `report_type`, `published_date`, `chunk_index`, `total_chunks`\n\nChunking strategy: paragraphs are accumulated until reaching the 512-token model window. Chunks never split mid-sentence. 100-token overlap ensures context continuity across chunk boundaries.\n\n---\n\n## Cron Schedule\n\n| Time | Job |\n|------|-----|\n| 03:17 Sundays | XBRL annual reports |\n| 06:00 Mon–Fri | yfinance — stock prices and FX rates |\n| 06:15 daily | MFN Nordics — quarterly reports and press releases |\n| 06:30 Mon–Fri | ENTSO-E — energy data |\n| 07:00 daily | Oslo Børs Newsweb — exchange announcements |\n| 08:00–18:00 hourly Mon–Fri | GlobeNewswire — press releases (NO/SE/DK/FI) |\n| 09:00 daily | Query analysis report (email) |\n\n---\n\n## Monitoring & Activity\n\n### Check server health\n\n```bash\n# Qdrant responding?\ncurl http://localhost:6333\n\n# Vector count\ncurl http://localhost:6333/collections/nordic_company_data | python3 -m json.tool\n```\n\n### Check MCP server process\n\n```bash\nps aux | grep mcp_server.py\n```\n\n### Check MCP query activity\n\n```bash\n# Tail live log\ntail -f ~/logs/mcp_server.log\n\n# Run full query analysis\ncd ~/norsk-mcp-server && venv/bin/python3 analyze_queries.py\n```\n\n### Check Cloudflare tunnel\n\n```bash\njournalctl -u cloudflared --since \"1 hour ago\" | tail -50\n```\n\n---\n\n## Skills Demonstrated\n\n- **RAG system design** — end-to-end pipeline from raw data to semantic search\n- **Hybrid retrieval** — dense+sparse embeddings with RRF fusion and cross-encoder reranking\n- **Web scraping at scale** — Playwright, RSS feeds, REST APIs, PDF extraction\n- **Vector database operations** — Qdrant, embedding models, reranking\n- **MCP server development** — FastMCP, tool design for LLM agents\n- **Agent payment protocols** — x402, L402, DigiRail\n- **Linux server administration** — process management, cron, systemd\n- **Blockchain infrastructure** — Bitcoin full node + LND, DigiByte full node + oracle\n- **Python engineering** — async pipelines, error handling, idempotent design\n- **Financial data domain knowledge** — Nordic exchanges, regulatory filings, macro data\n\n---\n\n## Status (May 2026)\n\n- `nordic_company_data`: 1,000,000+ vectors — XBRL, MFN, Newsweb, Cision, GlobeNewswire, ENTSO-E, commodity/freight, macro\n- MCP server: live at `https://mcp.aidatanorge.no/mcp`\n- Published: Smithery · MCP Registry · Glama · mcp.so\n- x402 pay-per-call: implemented, currently paused — will be integrated into main server\n- L402 / DigiRail: infrastructure in place, monetization layer in development\n- Live demo: `https://mcp.aidatanorge.no/demo`\n",
  "bytes": 16484,
  "sha": "b52bc3783c65080d80da7663e6e70cdfa3d06b167d542ec7467acdd8f1cd7d41",
  "repo_slug": "aidatanordic/nordic_financial_mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_aidatanordic_nordic_financial__a186d760/readme"
}