204 lines
7.4 KiB
Python
204 lines
7.4 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from fastapi import Depends, FastAPI, HTTPException
|
|
from mcp_common.auth import Principal, TokenStore, require_principal
|
|
from mcp_common.mcp_bridge import mount_mcp_endpoint
|
|
from mcp_common.server import build_app
|
|
from pydantic import BaseModel, Field
|
|
|
|
from mcp_macro.fetchers import (
|
|
fetch_asset_price,
|
|
fetch_breakeven_inflation,
|
|
fetch_cot_disaggregated,
|
|
fetch_cot_extreme_positioning,
|
|
fetch_cot_tff,
|
|
fetch_economic_indicators,
|
|
fetch_equity_futures,
|
|
fetch_macro_calendar,
|
|
fetch_market_overview,
|
|
fetch_treasury_yields,
|
|
fetch_yield_curve_slope,
|
|
)
|
|
|
|
# --- Body models ---
|
|
|
|
class GetEconomicIndicatorsReq(BaseModel):
|
|
indicators: list[str] | None = None
|
|
|
|
|
|
class GetMacroCalendarReq(BaseModel):
|
|
days: int = 7
|
|
country_filter: list[str] | None = None
|
|
importance_min: str | None = None
|
|
start: str | None = None
|
|
end: str | None = None
|
|
|
|
|
|
class GetMarketOverviewReq(BaseModel):
|
|
pass
|
|
|
|
|
|
class GetAssetPriceReq(BaseModel):
|
|
ticker: str
|
|
|
|
|
|
class GetTreasuryYieldsReq(BaseModel):
|
|
pass
|
|
|
|
|
|
class GetEquityFuturesReq(BaseModel):
|
|
pass
|
|
|
|
|
|
class GetYieldCurveSlopeReq(BaseModel):
|
|
pass
|
|
|
|
|
|
class GetBreakevenInflationReq(BaseModel):
|
|
pass
|
|
|
|
|
|
class GetCotTffReq(BaseModel):
|
|
symbol: str
|
|
lookback_weeks: int = Field(default=52, ge=4, le=520)
|
|
|
|
|
|
class GetCotDisaggregatedReq(BaseModel):
|
|
symbol: str
|
|
lookback_weeks: int = Field(default=52, ge=4, le=520)
|
|
|
|
|
|
class GetCotExtremeReq(BaseModel):
|
|
lookback_weeks: int = Field(default=156, ge=4, le=520)
|
|
|
|
|
|
# --- ACL helper ---
|
|
|
|
def _check(principal: Principal, *, core: bool = False, observer: bool = False) -> None:
|
|
allowed: set[str] = set()
|
|
if core:
|
|
allowed.add("core")
|
|
if observer:
|
|
allowed.add("observer")
|
|
if not (principal.capabilities & allowed):
|
|
raise HTTPException(403, f"capability required: {allowed}")
|
|
|
|
|
|
# --- App factory ---
|
|
|
|
def create_app(*, fred_api_key: str = "", finnhub_api_key: str = "", token_store: TokenStore) -> FastAPI:
|
|
app = build_app(name="mcp-macro", version="0.1.0", token_store=token_store)
|
|
|
|
@app.post("/tools/get_economic_indicators", tags=["reads"])
|
|
async def t_get_economic_indicators(
|
|
body: GetEconomicIndicatorsReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_economic_indicators(
|
|
fred_api_key=fred_api_key, indicators=body.indicators
|
|
)
|
|
|
|
@app.post("/tools/get_macro_calendar", tags=["reads"])
|
|
async def t_get_macro_calendar(
|
|
body: GetMacroCalendarReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_macro_calendar(
|
|
finnhub_api_key=finnhub_api_key,
|
|
days_ahead=body.days,
|
|
country_filter=body.country_filter,
|
|
importance_min=body.importance_min,
|
|
start=body.start,
|
|
end=body.end,
|
|
)
|
|
|
|
@app.post("/tools/get_market_overview", tags=["reads"])
|
|
async def t_get_market_overview(
|
|
body: GetMarketOverviewReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_market_overview()
|
|
|
|
@app.post("/tools/get_asset_price", tags=["reads"])
|
|
async def t_get_asset_price(
|
|
body: GetAssetPriceReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_asset_price(body.ticker)
|
|
|
|
@app.post("/tools/get_treasury_yields", tags=["reads"])
|
|
async def t_get_treasury_yields(
|
|
body: GetTreasuryYieldsReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_treasury_yields()
|
|
|
|
@app.post("/tools/get_equity_futures", tags=["reads"])
|
|
async def t_get_equity_futures(
|
|
body: GetEquityFuturesReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_equity_futures()
|
|
|
|
@app.post("/tools/get_yield_curve_slope", tags=["reads"])
|
|
async def t_get_yield_curve_slope(
|
|
body: GetYieldCurveSlopeReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_yield_curve_slope()
|
|
|
|
@app.post("/tools/get_breakeven_inflation", tags=["reads"])
|
|
async def t_get_breakeven_inflation(
|
|
body: GetBreakevenInflationReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_breakeven_inflation(fred_api_key=fred_api_key)
|
|
|
|
@app.post("/tools/get_cot_tff", tags=["reads"])
|
|
async def t_get_cot_tff(
|
|
body: GetCotTffReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_cot_tff(body.symbol, body.lookback_weeks)
|
|
|
|
@app.post("/tools/get_cot_disaggregated", tags=["reads"])
|
|
async def t_get_cot_disaggregated(
|
|
body: GetCotDisaggregatedReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_cot_disaggregated(body.symbol, body.lookback_weeks)
|
|
|
|
@app.post("/tools/get_cot_extreme_positioning", tags=["reads"])
|
|
async def t_get_cot_extreme(
|
|
body: GetCotExtremeReq, principal: Principal = Depends(require_principal)
|
|
):
|
|
_check(principal, core=True, observer=True)
|
|
return await fetch_cot_extreme_positioning(body.lookback_weeks)
|
|
|
|
# ───── MCP endpoint (/mcp) — bridge verso /tools/* ─────
|
|
port = int(os.environ.get("PORT", "9013"))
|
|
mount_mcp_endpoint(
|
|
app,
|
|
name="cerbero-macro",
|
|
version="0.1.0",
|
|
token_store=token_store,
|
|
internal_base_url=f"http://localhost:{port}",
|
|
tools=[
|
|
{"name": "get_economic_indicators", "description": "FRED economic indicators (Fed rate, CPI, ecc)."},
|
|
{"name": "get_macro_calendar", "description": "Eventi macro con filtri country/importance/date range."},
|
|
{"name": "get_market_overview", "description": "Snapshot overview mercato macro."},
|
|
{"name": "get_asset_price", "description": "Prezzo cross-asset: WTI, DXY, SPX, VIX, yields, FX, ecc."},
|
|
{"name": "get_treasury_yields", "description": "Curva US Treasury 2y/5y/10y/30y + shape detection."},
|
|
{"name": "get_equity_futures", "description": "Futures ES/NQ/YM/RTY con session status."},
|
|
{"name": "get_yield_curve_slope", "description": "Slope 2y10y/5y30y + butterfly + regime (steep/normal/flat/inverted)."},
|
|
{"name": "get_breakeven_inflation", "description": "Breakeven inflation 5Y/10Y + 5y5y forward (FRED T5YIE/T10YIE/T5YIFR)."},
|
|
{"name": "get_cot_tff", "description": "COT TFF report (CFTC) per equity/financial: ES/NQ/RTY/ZN/ZB/6E/6J/DX. Roles: dealer, asset manager, leveraged funds, other."},
|
|
{"name": "get_cot_disaggregated", "description": "COT Disaggregated report (CFTC) per commodities: CL/GC/SI/HG/ZW/ZC/ZS. Roles: producer/merchant, swap dealer, managed money, other."},
|
|
{"name": "get_cot_extreme_positioning", "description": "Scanner posizionamento estremo (percentile ≤5 o ≥95) sui simboli watchlist."},
|
|
],
|
|
)
|
|
|
|
return app
|