portfolio-analytics-mcp 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. portfolio_analytics_mcp-0.2.0/.github/workflows/ci.yml +33 -0
  2. portfolio_analytics_mcp-0.2.0/.github/workflows/release.yml +54 -0
  3. portfolio_analytics_mcp-0.2.0/.gitignore +64 -0
  4. portfolio_analytics_mcp-0.2.0/.python-version +1 -0
  5. portfolio_analytics_mcp-0.2.0/CONTRIBUTING.md +134 -0
  6. portfolio_analytics_mcp-0.2.0/LICENSE +21 -0
  7. portfolio_analytics_mcp-0.2.0/PKG-INFO +133 -0
  8. portfolio_analytics_mcp-0.2.0/README.md +108 -0
  9. portfolio_analytics_mcp-0.2.0/docs/USER_GUIDE.md +225 -0
  10. portfolio_analytics_mcp-0.2.0/finance_mcp/__init__.py +1 -0
  11. portfolio_analytics_mcp-0.2.0/finance_mcp/__main__.py +5 -0
  12. portfolio_analytics_mcp-0.2.0/finance_mcp/auth.py +111 -0
  13. portfolio_analytics_mcp-0.2.0/finance_mcp/concurrency.py +78 -0
  14. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/__init__.py +1 -0
  15. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/analysis.py +330 -0
  16. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/client.py +246 -0
  17. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/data/etfs.json +281 -0
  18. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/parser.py +470 -0
  19. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/registry.py +214 -0
  20. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/search.py +134 -0
  21. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/service.py +76 -0
  22. portfolio_analytics_mcp-0.2.0/finance_mcp/justetf/tools.py +370 -0
  23. portfolio_analytics_mcp-0.2.0/finance_mcp/portfolio/__init__.py +1 -0
  24. portfolio_analytics_mcp-0.2.0/finance_mcp/portfolio/resolve.py +179 -0
  25. portfolio_analytics_mcp-0.2.0/finance_mcp/portfolio/risk.py +400 -0
  26. portfolio_analytics_mcp-0.2.0/finance_mcp/portfolio/tools.py +117 -0
  27. portfolio_analytics_mcp-0.2.0/finance_mcp/server.py +91 -0
  28. portfolio_analytics_mcp-0.2.0/finance_mcp/yahoo/__init__.py +1 -0
  29. portfolio_analytics_mcp-0.2.0/finance_mcp/yahoo/analytics.py +516 -0
  30. portfolio_analytics_mcp-0.2.0/finance_mcp/yahoo/data.py +339 -0
  31. portfolio_analytics_mcp-0.2.0/finance_mcp/yahoo/tools.py +599 -0
  32. portfolio_analytics_mcp-0.2.0/pyproject.toml +116 -0
  33. portfolio_analytics_mcp-0.2.0/render.yaml +16 -0
  34. portfolio_analytics_mcp-0.2.0/skill/portfolio-analytics/SKILL.md +170 -0
  35. portfolio_analytics_mcp-0.2.0/tests/__init__.py +1 -0
  36. portfolio_analytics_mcp-0.2.0/tests/conftest.py +109 -0
  37. portfolio_analytics_mcp-0.2.0/tests/fakes.py +293 -0
  38. portfolio_analytics_mcp-0.2.0/tests/justetf/__init__.py +1 -0
  39. portfolio_analytics_mcp-0.2.0/tests/justetf/test_analysis.py +66 -0
  40. portfolio_analytics_mcp-0.2.0/tests/justetf/test_client.py +209 -0
  41. portfolio_analytics_mcp-0.2.0/tests/justetf/test_parser.py +110 -0
  42. portfolio_analytics_mcp-0.2.0/tests/justetf/test_registry.py +31 -0
  43. portfolio_analytics_mcp-0.2.0/tests/justetf/test_search.py +46 -0
  44. portfolio_analytics_mcp-0.2.0/tests/justetf/test_service.py +90 -0
  45. portfolio_analytics_mcp-0.2.0/tests/justetf/test_tools.py +152 -0
  46. portfolio_analytics_mcp-0.2.0/tests/portfolio/__init__.py +1 -0
  47. portfolio_analytics_mcp-0.2.0/tests/portfolio/test_resolve.py +126 -0
  48. portfolio_analytics_mcp-0.2.0/tests/portfolio/test_risk.py +144 -0
  49. portfolio_analytics_mcp-0.2.0/tests/portfolio/test_tools.py +45 -0
  50. portfolio_analytics_mcp-0.2.0/tests/test_auth.py +60 -0
  51. portfolio_analytics_mcp-0.2.0/tests/test_server.py +176 -0
  52. portfolio_analytics_mcp-0.2.0/tests/yahoo/__init__.py +1 -0
  53. portfolio_analytics_mcp-0.2.0/tests/yahoo/test_analytics.py +203 -0
  54. portfolio_analytics_mcp-0.2.0/tests/yahoo/test_data.py +158 -0
  55. portfolio_analytics_mcp-0.2.0/tests/yahoo/test_tools.py +212 -0
  56. portfolio_analytics_mcp-0.2.0/uv.lock +1082 -0
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ # Cancel superseded runs of the same branch/PR.
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ ci-checks:
19
+ name: CI checks
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
23
+ # Python version comes from .python-version (kept in sync with
24
+ # PYTHON_VERSION in render.yaml).
25
+ - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
26
+ with:
27
+ enable-cache: true
28
+ - run: uv sync --locked
29
+ # Same command as locally: format-check (ruff + prettier), lint,
30
+ # type check and tests with the coverage minimum.
31
+ - run: uv run poe ci-checks
32
+ - name: Build package
33
+ run: uv build
@@ -0,0 +1,54 @@
1
+ name: Release
2
+
3
+ # Pushing a tag like v1.2.3 runs the checks, builds version 1.2.3 (taken from
4
+ # the tag by hatch-vcs) and publishes it to PyPI.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build:
14
+ name: Check and build
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
18
+ with:
19
+ fetch-depth: 0 # full history and tags, so hatch-vcs sees the tag
20
+ persist-credentials: false
21
+ - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
22
+ - run: uv sync --locked
23
+ - run: uv run poe ci-checks
24
+ - run: uv build
25
+ # Guard against a tag on the wrong commit or an unexpected version.
26
+ - name: Check version matches tag
27
+ run: |
28
+ expected="$(uv run --with packaging python -c \
29
+ 'from packaging.version import Version; import sys; print(Version(sys.argv[1]))' \
30
+ "${GITHUB_REF_NAME#v}")"
31
+ ls dist
32
+ test -f "dist/portfolio_analytics_mcp-${expected}-py3-none-any.whl" \
33
+ || { echo "Built version does not match tag ${GITHUB_REF_NAME}"; exit 1; }
34
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
35
+ with:
36
+ name: dist
37
+ path: dist/
38
+
39
+ publish:
40
+ name: Publish to PyPI
41
+ needs: build
42
+ runs-on: ubuntu-latest
43
+ environment:
44
+ name: pypi
45
+ url: https://pypi.org/project/portfolio-analytics-mcp/
46
+ permissions:
47
+ id-token: write # trusted publishing: PyPI accepts this job's identity, no token stored
48
+ steps:
49
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
50
+ with:
51
+ name: dist
52
+ path: dist/
53
+ - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
54
+ - run: uv publish --trusted-publishing always
@@ -0,0 +1,64 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # Unit test / coverage reports
28
+ htmlcov/
29
+ .tox/
30
+ .coverage
31
+ .coverage.*
32
+ .cache
33
+ nosetests.xml
34
+ coverage.xml
35
+ *.cover
36
+ .hypothesis/
37
+ .pytest_cache/
38
+
39
+ # Environments
40
+ .env
41
+ .venv
42
+ env/
43
+ venv/
44
+ ENV/
45
+ env.bak/
46
+ venv.bak/
47
+
48
+ # mypy
49
+ .mypy_cache/
50
+ .dmypy.json
51
+ dmypy.json
52
+
53
+ # IDEs
54
+ .idea/
55
+
56
+ # Jupyter Notebook
57
+ .ipynb_checkpoints
58
+
59
+ # macOS
60
+ .DS_Store
61
+
62
+ # Local tooling
63
+ .vscode/
64
+ .ruff_cache/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,134 @@
1
+ # Contributing
2
+
3
+ Thanks for your interest! Bug reports, fixes and new tools are welcome.
4
+ Please open an issue first for larger changes, so we can agree on the
5
+ approach.
6
+
7
+ ## Setup
8
+
9
+ You need [uv](https://docs.astral.sh/uv/) and Python 3.12. Formatting
10
+ Markdown and YAML also needs [Node.js](https://nodejs.org) (Prettier runs
11
+ through `npx`, nothing to install).
12
+
13
+ ```bash
14
+ git clone https://github.com/RugSec/portfolio-analytics-mcp.git
15
+ cd portfolio-analytics-mcp
16
+ uv sync # creates .venv with runtime + dev dependencies
17
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
18
+ ```
19
+
20
+ ## Tasks
21
+
22
+ Tasks run with [poe](https://poethepoet.natn.io/) (`poe -h` lists them):
23
+
24
+ | Command | What it does |
25
+ | ------------------ | ------------------------------------------------------------------ |
26
+ | `poe ci-checks` | Everything CI runs, read-only: format-check, lint, typecheck, test |
27
+ | `poe test` | Tests with coverage; fails below 80% |
28
+ | `poe format` | Format Python (ruff) and Markdown/YAML (Prettier), sort imports |
29
+ | `poe fix` | Format, then lint |
30
+ | `poe format-check` | Check formatting without writing files |
31
+ | `poe lint` | Lint with ruff (style, docstrings, type hints) |
32
+ | `poe typecheck` | Type check with basedpyright |
33
+ | `poe check` | Quick check: lint + typecheck |
34
+
35
+ **Run `poe ci-checks` before opening a pull request.** GitHub Actions runs
36
+ the same command on Python 3.12.
37
+
38
+ To try the tools interactively, use the MCP inspector:
39
+ `mcp dev finance_mcp/server.py`. To check that Yahoo is reachable from your
40
+ machine:
41
+
42
+ ```bash
43
+ uv run python -c "from finance_mcp.yahoo.tools import get_quote; print(get_quote(['AAPL']))"
44
+ ```
45
+
46
+ ## Project layout
47
+
48
+ ```
49
+ finance_mcp/
50
+ server.py builds the FastMCP server and registers all tools
51
+ auth.py API-key middleware for the HTTP transport
52
+ yahoo/
53
+ analytics.py return/risk maths: pure pandas/numpy, no network
54
+ data.py yfinance downloads, currencies, FX, error classification
55
+ tools.py Yahoo MCP tools
56
+ justetf/
57
+ client.py polite HTTP: rate limit, retries, disk cache, ISIN check
58
+ parser.py profile page HTML -> dict (stable data-testid hooks)
59
+ service.py fetch + parse + cache, the tools' single entry point
60
+ registry.py local name/ticker -> ISIN registry (seed + learned)
61
+ search.py ETF search: ISIN, registry, then Yahoo fallback
62
+ analysis.py ETF portfolio maths: pure functions, no network
63
+ tools.py justETF MCP tools
64
+ data/etfs.json seed registry of popular ETFs
65
+ portfolio/
66
+ resolve.py ISIN -> Yahoo symbols via justETF listings
67
+ risk.py whole-portfolio risk in one base currency
68
+ tools.py portfolio MCP tools
69
+ tests/ mirrors finance_mcp/ (tests/yahoo, tests/justetf, ...)
70
+ conftest.py fixtures that fake Yahoo and justETF
71
+ fakes.py synthetic prices, pages and profiles
72
+ ```
73
+
74
+ The pattern in each package: network code (`data.py`, `client.py`) is
75
+ separate from pure logic (`analytics.py`, `parser.py`, `analysis.py`), and
76
+ `tools.py` only adapts inputs and outputs for the MCP client.
77
+
78
+ ## Conventions
79
+
80
+ - **Tests never touch the network.** Fake Yahoo and justETF with the
81
+ fixtures in `tests/conftest.py` (`fake_yahoo`, `fake_yf`, `registry_env`)
82
+ or with `monkeypatch`. Put a module's tests in the matching file under
83
+ `tests/`, e.g. `finance_mcp/justetf/parser.py` in
84
+ `tests/justetf/test_parser.py`.
85
+ - **Coverage stays at or above 80%** (branch coverage); CI fails below it.
86
+ - **Type hints on every function**, checked by basedpyright.
87
+ - **Docstrings on every function** in Google style: a one-line summary, then
88
+ `Args:`, `Returns:` and `Raises:` sections as they apply. Test functions
89
+ only need the one-line summary. Ruff enforces this.
90
+ - **Tool docstrings are read by the LLM.** They are the tool's description,
91
+ so say when to use the tool, what it needs and what comes back, and keep
92
+ them short.
93
+ - **Tools return errors, they don't raise them.** Return
94
+ `YahooError(...).to_dict()` (with an `error_code` from the
95
+ [user guide](docs/USER_GUIDE.md#errors)) or `{"error": ...}`, so the agent
96
+ can explain the failure or try another tool.
97
+ - **Be polite to data sources.** New justETF requests go through
98
+ `client._get` (rate limit + retries) and the cache; never retry a 403/429.
99
+
100
+ ## Dependencies
101
+
102
+ Dependencies are declared in `pyproject.toml` and locked in `uv.lock`.
103
+
104
+ - `mcp` is pinned below 2 because the code uses the v1 `FastMCP` API.
105
+ - `pandas` is pinned exactly, with a matching `pandas-stubs` in the dev
106
+ group: bump both together.
107
+ - Dependabot opens monthly update PRs for Python packages and GitHub
108
+ Actions.
109
+
110
+ ## Releases
111
+
112
+ The version comes from the git tag ([hatch-vcs](https://github.com/ofek/hatch-vcs)),
113
+ so there is no version number to edit in `pyproject.toml`. To release from an
114
+ up-to-date `main`:
115
+
116
+ ```bash
117
+ git tag -a v0.2.0 -m "v0.2.0"
118
+ git push origin v0.2.0
119
+ ```
120
+
121
+ The [Release workflow](.github/workflows/release.yml) runs `poe ci-checks`,
122
+ builds the package, checks that its version matches the tag and publishes it
123
+ to [PyPI](https://pypi.org/project/portfolio-analytics-mcp/) with trusted
124
+ publishing (no token stored). Users running `uvx portfolio-analytics-mcp@latest`
125
+ get it the next time the server starts.
126
+
127
+ - Use [semantic versioning](https://semver.org): patch for fixes, minor for
128
+ new tools or fields, major for removed or renamed tools.
129
+ - PyPI never accepts the same version twice, even after deleting it. Fix a
130
+ bad release by tagging the next patch version.
131
+ - Builds between tags get a development version such as
132
+ `0.2.1.dev3+g1a2b3c4`; PyPI rejects these, so only tags can be published.
133
+ - `skill/portfolio-analytics/SKILL.md` has its own `version`: bump it only
134
+ when you change the skill and upload it to Agensi again.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ruggiero Seccia
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,133 @@
1
+ Metadata-Version: 2.5
2
+ Name: portfolio-analytics-mcp
3
+ Version: 0.2.0
4
+ Summary: MCP server for portfolio analysis with Yahoo Finance and justETF data
5
+ Project-URL: Homepage, https://github.com/RugSec/portfolio-analytics-mcp
6
+ Project-URL: Documentation, https://github.com/RugSec/portfolio-analytics-mcp/blob/main/docs/USER_GUIDE.md
7
+ Project-URL: Issues, https://github.com/RugSec/portfolio-analytics-mcp/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: etf,finance,investing,justetf,mcp,portfolio,yfinance
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Topic :: Office/Business :: Financial :: Investment
14
+ Requires-Python: ==3.12.*
15
+ Requires-Dist: beautifulsoup4>=4.15.0
16
+ Requires-Dist: httpx>=0.28.1
17
+ Requires-Dist: mcp[cli]<2,>=1.9.0
18
+ Requires-Dist: numpy>=2.0
19
+ Requires-Dist: pandas==3.0.6
20
+ Requires-Dist: pydantic>=2.7
21
+ Requires-Dist: starlette>=0.40
22
+ Requires-Dist: uvicorn>=0.30
23
+ Requires-Dist: yfinance>=0.2.50
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Portfolio Analytics MCP
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/portfolio-analytics-mcp.svg)](https://pypi.org/project/portfolio-analytics-mcp/)
29
+ [![CI](https://github.com/RugSec/portfolio-analytics-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/RugSec/portfolio-analytics-mcp/actions/workflows/ci.yml)
30
+ [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/pyproject.toml)
31
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/LICENSE)
32
+
33
+ **Ask Claude about your investments in plain language.** This is an
34
+ [MCP](https://modelcontextprotocol.io) server that gives Claude (or any MCP
35
+ client) read-only tools for market data and portfolio analysis: prices, FX,
36
+ ETF costs and exposure, and risk for a whole portfolio of stocks and ETFs,
37
+ measured in your own currency.
38
+
39
+ It is built for European investors as much as US ones: it understands ISINs,
40
+ UCITS ETFs listed on several exchanges, and prices quoted in pence.
41
+
42
+ ## What you can ask
43
+
44
+ > "I hold 30k EUR of IE00B4L5Y983, 10 ASML.AS and 25 AAPL. How volatile is
45
+ > this portfolio, and which position contributes most to the risk?"
46
+
47
+ > "Compare the costs of the iShares Core MSCI World and the Vanguard FTSE
48
+ > All-World. Which is cheaper and bigger?"
49
+
50
+ > "How much of my ETF portfolio is in US tech stocks? Do my ETFs overlap?"
51
+
52
+ > "What has VWCE returned since 2021 in euros, compared with the S&P 500?"
53
+
54
+ Claude picks the right tools, fetches the data and explains the result.
55
+
56
+ ## What's inside
57
+
58
+ | Area | What it gives you | Data source |
59
+ | ------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------ |
60
+ | **Portfolio** | Risk and return of a mixed portfolio in one currency: volatility, drawdown, beta, risk per position | Yahoo Finance + justETF |
61
+ | **ETFs** | Costs (TER), fund size, country/sector/stock exposure, listings, similar funds, portfolio look-through | [justETF](https://www.justetf.com) |
62
+ | **Markets** | Price history, quotes, FX rates, performance statistics, correlations, dividends | [Yahoo Finance](https://finance.yahoo.com) |
63
+
64
+ 20 tools in total, all read-only. No API key or account needed. See the
65
+ [user guide](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/docs/USER_GUIDE.md) for the full list.
66
+
67
+ ## Quickstart
68
+
69
+ You need [uv](https://docs.astral.sh/uv/getting-started/installation/). It
70
+ downloads Python 3.12, the server and its dependencies on first run, and
71
+ checks for a new release each time the server starts.
72
+
73
+ **1. Connect it to Claude**
74
+
75
+ Claude Code:
76
+
77
+ ```bash
78
+ claude mcp add finance -- uvx portfolio-analytics-mcp@latest
79
+ ```
80
+
81
+ Claude Desktop: add this to `claude_desktop_config.json`, then restart the
82
+ app. If it can't find `uvx`, use the full path that `which uvx` prints.
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "finance": {
88
+ "command": "uvx",
89
+ "args": ["portfolio-analytics-mcp@latest"]
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ To stay on one version instead, use `portfolio-analytics-mcp==0.2.0`.
96
+
97
+ The server runs on your machine. Only symbols and ISINs go out, to Yahoo
98
+ Finance and justETF; your quantities and amounts never leave it.
99
+
100
+ **2. Ask a question**, for example _"What is the TER of IE00B4L5Y983?"_
101
+
102
+ To work on the code instead, see [Contributing](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/CONTRIBUTING.md#setup).
103
+
104
+ Want to run it as a shared remote server instead? See
105
+ [Remote deployment](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/docs/USER_GUIDE.md#remote-deployment-http).
106
+
107
+ ## Important to know
108
+
109
+ - **Not financial advice.** The tools report data and statistics; past
110
+ performance does not predict future results. Data can be delayed,
111
+ incomplete or wrong, and is provided as is, without warranty.
112
+ - **Not affiliated** with Yahoo, justETF or any fund provider. Names and
113
+ trademarks belong to their owners.
114
+ - **Personal use only.** Yahoo Finance (through the unofficial
115
+ [yfinance](https://pypi.org/project/yfinance/) library) and justETF are
116
+ third-party sites. This server makes polite, on-demand requests
117
+ (rate-limited and cached) and is not meant for bulk downloads or
118
+ redistributing their data. Check their terms before using it.
119
+ - Quotes can be delayed by up to ~20 minutes, and Yahoo's coverage of
120
+ European ETF holdings is patchy (the justETF tools fill that gap).
121
+
122
+ ## Learn more
123
+
124
+ - [User guide](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/docs/USER_GUIDE.md): every tool, example workflows,
125
+ configuration, remote deployment and limitations.
126
+ - [Agent skill](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/skill/portfolio-analytics/SKILL.md): tells an agent when
127
+ and how to use the tools, and how to present results.
128
+ - [Contributing](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/CONTRIBUTING.md): development setup, tests and project
129
+ layout.
130
+
131
+ ## License
132
+
133
+ [MIT](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/LICENSE)
@@ -0,0 +1,108 @@
1
+ # Portfolio Analytics MCP
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/portfolio-analytics-mcp.svg)](https://pypi.org/project/portfolio-analytics-mcp/)
4
+ [![CI](https://github.com/RugSec/portfolio-analytics-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/RugSec/portfolio-analytics-mcp/actions/workflows/ci.yml)
5
+ [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/pyproject.toml)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/LICENSE)
7
+
8
+ **Ask Claude about your investments in plain language.** This is an
9
+ [MCP](https://modelcontextprotocol.io) server that gives Claude (or any MCP
10
+ client) read-only tools for market data and portfolio analysis: prices, FX,
11
+ ETF costs and exposure, and risk for a whole portfolio of stocks and ETFs,
12
+ measured in your own currency.
13
+
14
+ It is built for European investors as much as US ones: it understands ISINs,
15
+ UCITS ETFs listed on several exchanges, and prices quoted in pence.
16
+
17
+ ## What you can ask
18
+
19
+ > "I hold 30k EUR of IE00B4L5Y983, 10 ASML.AS and 25 AAPL. How volatile is
20
+ > this portfolio, and which position contributes most to the risk?"
21
+
22
+ > "Compare the costs of the iShares Core MSCI World and the Vanguard FTSE
23
+ > All-World. Which is cheaper and bigger?"
24
+
25
+ > "How much of my ETF portfolio is in US tech stocks? Do my ETFs overlap?"
26
+
27
+ > "What has VWCE returned since 2021 in euros, compared with the S&P 500?"
28
+
29
+ Claude picks the right tools, fetches the data and explains the result.
30
+
31
+ ## What's inside
32
+
33
+ | Area | What it gives you | Data source |
34
+ | ------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------ |
35
+ | **Portfolio** | Risk and return of a mixed portfolio in one currency: volatility, drawdown, beta, risk per position | Yahoo Finance + justETF |
36
+ | **ETFs** | Costs (TER), fund size, country/sector/stock exposure, listings, similar funds, portfolio look-through | [justETF](https://www.justetf.com) |
37
+ | **Markets** | Price history, quotes, FX rates, performance statistics, correlations, dividends | [Yahoo Finance](https://finance.yahoo.com) |
38
+
39
+ 20 tools in total, all read-only. No API key or account needed. See the
40
+ [user guide](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/docs/USER_GUIDE.md) for the full list.
41
+
42
+ ## Quickstart
43
+
44
+ You need [uv](https://docs.astral.sh/uv/getting-started/installation/). It
45
+ downloads Python 3.12, the server and its dependencies on first run, and
46
+ checks for a new release each time the server starts.
47
+
48
+ **1. Connect it to Claude**
49
+
50
+ Claude Code:
51
+
52
+ ```bash
53
+ claude mcp add finance -- uvx portfolio-analytics-mcp@latest
54
+ ```
55
+
56
+ Claude Desktop: add this to `claude_desktop_config.json`, then restart the
57
+ app. If it can't find `uvx`, use the full path that `which uvx` prints.
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "finance": {
63
+ "command": "uvx",
64
+ "args": ["portfolio-analytics-mcp@latest"]
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ To stay on one version instead, use `portfolio-analytics-mcp==0.2.0`.
71
+
72
+ The server runs on your machine. Only symbols and ISINs go out, to Yahoo
73
+ Finance and justETF; your quantities and amounts never leave it.
74
+
75
+ **2. Ask a question**, for example _"What is the TER of IE00B4L5Y983?"_
76
+
77
+ To work on the code instead, see [Contributing](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/CONTRIBUTING.md#setup).
78
+
79
+ Want to run it as a shared remote server instead? See
80
+ [Remote deployment](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/docs/USER_GUIDE.md#remote-deployment-http).
81
+
82
+ ## Important to know
83
+
84
+ - **Not financial advice.** The tools report data and statistics; past
85
+ performance does not predict future results. Data can be delayed,
86
+ incomplete or wrong, and is provided as is, without warranty.
87
+ - **Not affiliated** with Yahoo, justETF or any fund provider. Names and
88
+ trademarks belong to their owners.
89
+ - **Personal use only.** Yahoo Finance (through the unofficial
90
+ [yfinance](https://pypi.org/project/yfinance/) library) and justETF are
91
+ third-party sites. This server makes polite, on-demand requests
92
+ (rate-limited and cached) and is not meant for bulk downloads or
93
+ redistributing their data. Check their terms before using it.
94
+ - Quotes can be delayed by up to ~20 minutes, and Yahoo's coverage of
95
+ European ETF holdings is patchy (the justETF tools fill that gap).
96
+
97
+ ## Learn more
98
+
99
+ - [User guide](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/docs/USER_GUIDE.md): every tool, example workflows,
100
+ configuration, remote deployment and limitations.
101
+ - [Agent skill](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/skill/portfolio-analytics/SKILL.md): tells an agent when
102
+ and how to use the tools, and how to present results.
103
+ - [Contributing](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/CONTRIBUTING.md): development setup, tests and project
104
+ layout.
105
+
106
+ ## License
107
+
108
+ [MIT](https://github.com/RugSec/portfolio-analytics-mcp/blob/main/LICENSE)