Portfolio Rotation MCP Server
# Portfolio Rotation MCP Server
[](https://pypi.org/project/portfolio-rotation-mcp/)
[](https://pypi.org/project/portfolio-rotation-mcp/)
MCP server for portfolio rotation analysis. Score holdings and candidates across 5 dimensions, identify optimal swaps, validate with risk checks and backtests.
**Works with any MCP client**: Claude Desktop, ChatGPT, Gemini, LangChain, Cursor, Windsurf, VS Code, Ollama clients, and more.
## What It Does
You give it a portfolio and candidate tickers. It returns:
```
ROTATION SCORECARD (GARP Style)
Ticker | Thesis | Valuation | Momentum | Catalyst | Technical | Composite | Action
META | 75 | 80 | 78 | 85 | 74 | 78.4 | Strong Buy
AVGO | 70 | 72 | 75 | 70 | 80 | 73.1 | Buy
AAPL | 70 | 65 | 62 | 60 | 68 | 65.5 | Hold
MSFT | 65 | 60 | 58 | 55 | 62 | 60.2 | Hold
JPM | 50 | 55 | 45 | 40 | 42 | 47.4 | Watch
SWAP RECOMMENDATIONS
Sell JPM (47.4) → Buy META (78.4) | Delta: +31.0 | Strong Swap
Sell JPM (47.4) → Buy AVGO (73.1) | Delta: +25.7 | Strong Swap
RISK FLAGS
⚠️ Technology sector: 35% (>30% limit)
BACKTEST (2y)
Strategy: +42.3% | Benchmark (SPY): +28.1% | Sharpe: 1.24 | Max Drawdown: -14.2%
```
## Quick Start
```bash
# Install from PyPI
pip install portfolio-rotation-mcp
# Or run directly (no install needed)
uvx portfolio-rotation-mcp
# Set API key (optional -- falls back to yfinance without it)
export FINANCIAL_DATASETS_API_KEY=your-key
```
### Prerequisites
- Python >= 3.10
- Optional: [financial-datasets.ai](https://financial-datasets.ai) API key for premium data (without it, prices come from yfinance and financial statements are unavailable)
## 11 Tools
| Tool | Description |
|------|-------------|
| `fetch_prices` | Historical OHLCV prices (API + yfinance fallback) |
| `fetch_financials` | Income/balance/cashflow statements |
| `fetch_ff_factors` | Fama-French 5-factor + momentum data |
| `score_tickers` | 5-dimension scoring (auto + manual) |
| `analyze_risk` | Concentration, correlation, volatility |
| `compare_swaps` | Pairwise swap recommendations (delta >= 15) |
| `run_backtest` | Historical strategy simulation |
| `stress_test` | Scenario replay, Monte Carlo, factor decomposition |
| `compute_attribution` | Trade attribution and swap alpha |
| `run_pipeline` | Full 6-stage rotation analysis |
| `get_skill` | Retrieve domain knowledge (scoring rules, swap logic, risk thresholds) |
## Platform Setup
### Claude Desktop
Add to your config file:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
- Linux: `~/.config/claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"portfolio-rotation": {
"command": "uvx",
"args": ["portfolio-rotation-mcp"],
"env": {
"FINANCIAL_DATASETS_API_KEY": "your-key"
}
}
}
}
```
Then in Claude Desktop, just say:
> My portfolio is AAPL 20%, MSFT 15%, JPM 10%. Evaluate META and AVGO as swap candidates.
Claude will automatically call the MCP tools.
### Claude Code (CLI)
```bash
claude mcp add portfolio-rotation -- uvx portfolio-rotation-mcp
```
### Cursor / Windsurf / VS Code
Add to your MCP settings (`.cursor/mcp.json`, `.windsurf/mcp.json`, or VS Code MCP config):
```json
{
"mcpServers": {
"portfolio-rotation": {
"command": "uvx",
"args": ["portfolio-rotation-mcp"],
"env": {
"FINANCIAL_DATASETS_API_KEY": "your-key"
}
}
}
}
```
### LangChain (any model: DeepSeek, GPT, Llama, etc.)
```python
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI
# Use any model -- DeepSeek, GPT, Llama, etc.
llm = ChatOpenAI(
model="deepseek-chat", # or "gpt-4o", etc.
base_url="https://api.deepseek.com/v1",
api_key="sk-...",
)
async with MultiServerMCPClient({
"portfolio-rotation": {
"command": "uvx",
"args": ["portfolio-rotation-mcp"],
"env": {"FINANCIAL_DATASETS_API_KEY": "your-key"},
}
}) as client:
tools = client.get_tools()
# Create agent with tools and invoke
```
### OpenAI Agents SDK
```python
from agents import Agent
from agents.mcp import MCPServerStdio
async with MCPServerStdio(
command="uvx",
args=["portfolio-rotation-mcp"],
) as server:
tools = await server.list_tools()
agent = Agent(name="Rotation Analyst", tools=tools)
```
### Ollama + Continue / LibreChat
Configure in the MCP settings of your Ollama frontend:
```json
{
"command": "uvx",
"args": ["portfolio-rotation-mcp"],
"env": {
"FINANCIAL_DATASETS_API_KEY": "your-key"
}
}
```
## Usage Examples
### Quick: Full Pipeline (one tool call)
Ask your AI agent:
> Analyze my portfolio: AAPL 20% (Technology), MSFT 15% (Technology), JPM 10% (Financials). Candidates: META, AVGO. Use GARP style.
The agent will call `run_pipeline` which runs all 6 stages automatically: data fetch -> scoring -> risk check -> swap comparison -> backtest -> report.
### Targeted: Score Specific Tickers
> Score AAPL, META, and AVGO. My thesis score for META is 80 and catalyst is 85.
The agent will call `fetch_prices`, then `score_tickers` with your manual overrides.
### Deep Dive: Stress Test
> Stress test my portfolio under a 2008-style crash scenario. Include Monte Carlo simulation.
The agent will call `fetch_prices`, `fetch_ff_factors`, then `stress_test`.
### Post-Trade: Attribution
> I sold INTC and bought NVDA on Jan 15 at $120. How did that swap perform?
The agent will call `fetch_prices`, then `compute_attribution` to measure swap alpha.
## Development
```bash
# Clone and install in development mode
git clone git@github.com:mothanaprime/Rebalance-MCP.git
cd Rebalance-MCP
pip install -e .
# Run the server
portfolio-rotation-mcp
# Test with MCP inspector
mcp dev src/portfolio_rotation/server.py
```
## Scoring Framework
5 dimensions, 0-100 each, weighted by investment style:
| Dimension | GARP Weight | Auto? |
|-----------|------------|-------|
| Thesis Integrity | 25% | Manual (via overrides) |
| Valuation Attractiveness | 25% | Auto (needs financials) |
| Fundamental Momentum | 20% | Auto (from prices) |
| Catalyst Proximity | 15% | Manual (via overrides) |
| Technical Trend | 15% | Auto (MA/RSI/relative strength) |
**Swap threshold**: Buy Score - Hold Score >= 15
**Style presets**: `garp` (default), `value`, `growth`, `momentum`, `event_driven` -- each has different dimension weights.
See [docs/scoring-framework.md](docs/scoring-framework.md) for full details.
## Agent Prompt
See [docs/agent-prompt.md](docs/agent-prompt.md) for a model-agnostic system prompt you can use to configure any AI agent for rotation analysis.
## Environment Variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `FINANCIAL_DATASETS_API_KEY` | No | -- | API key for [financial-datasets.ai](https://financial-datasets.ai). Without it, prices fall back to yfinance and financials are unavailable. |
| `PORTFOLIO_ROTATION_SOURCE` | No | `auto` | Data source: `auto` (API first, yfinance fallback), `api`, `financial-datasets`, or `yfinance`. Can be overridden per-call. |
## License
MIT
TDQS
Scored across 11 tools
Each tool has a clearly distinct purpose, from data fetching (fetch_prices, fetch_financials, fetch_ff_factors) to analysis (analyze_risk, score_tickers, compare_swaps, compute_attribution, stress_test, run_backtest) and orchestration (run_pipeline, get_skill). No two tools overlap in functionality; the pipeline tool is explicitly a meta-orchestrator, avoiding confusion.
All tool names follow a consistent verb_noun pattern with lowercase and underscores: analyze_risk, compare_swaps, compute_attribution, fetch_ff_factors, fetch_financials, fetch_prices, get_skill, run_backtest, run_pipeline, score_tickers, stress_test. The naming is predictable and uniform.
11 tools is well-scoped for a portfolio rotation analysis server. The count covers essential data retrieval, scoring, risk assessment, swap comparison, backtesting, attribution, stress testing, and a full pipeline orchestrator. No tools feel redundant or extraneous.
The tool surface covers the entire portfolio rotation workflow: data acquisition (prices, financials, factors), scoring, risk analysis, swap recommendations, backtesting, attribution, stress testing, and a knowledge skill. The pipeline tool ties everything together. No obvious gaps exist for the stated purpose.