us-macro-mcp 0.1.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.
- us_macro_mcp-0.1.0/LICENSE +21 -0
- us_macro_mcp-0.1.0/PKG-INFO +152 -0
- us_macro_mcp-0.1.0/README.md +129 -0
- us_macro_mcp-0.1.0/pyproject.toml +36 -0
- us_macro_mcp-0.1.0/src/us_macro_mcp/__init__.py +22 -0
- us_macro_mcp-0.1.0/src/us_macro_mcp/catalog.py +254 -0
- us_macro_mcp-0.1.0/src/us_macro_mcp/fomc.py +80 -0
- us_macro_mcp-0.1.0/src/us_macro_mcp/fred.py +295 -0
- us_macro_mcp-0.1.0/src/us_macro_mcp/server.py +445 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Harish Gupta
|
|
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,152 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: us-macro-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server exposing US macroeconomic indicators - inflation, employment, growth, housing, rates and recession signals - from the Federal Reserve's FRED database.
|
|
5
|
+
Keywords: mcp,model-context-protocol,economics,fred,macro,inflation,llm
|
|
6
|
+
Author: Harish Gupta
|
|
7
|
+
Author-email: Harish Gupta <hgus107@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
16
|
+
Requires-Dist: httpx>=0.27
|
|
17
|
+
Requires-Dist: mcp[cli]>=1.2
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Project-URL: Homepage, https://github.com/hgus107/US-Macro-MCP
|
|
20
|
+
Project-URL: Repository, https://github.com/hgus107/US-Macro-MCP
|
|
21
|
+
Project-URL: Issues, https://github.com/hgus107/US-Macro-MCP/issues
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# US-Macro-MCP
|
|
25
|
+
|
|
26
|
+
An MCP server that gives AI assistants clean access to US macroeconomic data — 58 indicators covering inflation, employment, growth, housing, consumer behaviour, interest rates, financial stress, markets and federal finances, sourced from the Federal Reserve's FRED database.
|
|
27
|
+
|
|
28
|
+
It is built so the assistant never has to know a FRED series ID, and never has to do arithmetic. Ask for `cpi` and you get the latest reading, the previous one, the year-ago value, and the percentage changes already calculated.
|
|
29
|
+
|
|
30
|
+
## What it does
|
|
31
|
+
|
|
32
|
+
| Tool | What you use it for |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `list_indicators` | See every indicator available, grouped by category |
|
|
35
|
+
| `get_indicator` | The current reading of one indicator, with its changes |
|
|
36
|
+
| `get_history` | A full time series, for trends and charting |
|
|
37
|
+
| `compare_indicators` | Two or more indicators over the same window, normalised for comparison |
|
|
38
|
+
| `release_calendar` | Which economic reports are scheduled over the coming days |
|
|
39
|
+
| `macro_snapshot` | The whole economy — or one category — in a single call |
|
|
40
|
+
| `recession_signals` | The Sahm rule, yield curve, credit spreads, claims and financial conditions, each graded |
|
|
41
|
+
| `search_indicators` | Find an indicator by keyword when you don't know its name |
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
44
|
+
|
|
45
|
+
A free FRED API key. Request one at [fredaccount.stlouisfed.org/apikeys](https://fredaccount.stlouisfed.org/apikeys) — it takes about a minute and costs nothing.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
### Claude Desktop
|
|
50
|
+
|
|
51
|
+
Add this to your `claude_desktop_config.json`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"us-macro": {
|
|
57
|
+
"command": "uvx",
|
|
58
|
+
"args": ["us-macro-mcp"],
|
|
59
|
+
"env": { "FRED_API_KEY": "your_key_here" }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Claude Code
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
claude mcp add us-macro --env FRED_API_KEY=your_key_here -- uvx us-macro-mcp
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Any other MCP client
|
|
72
|
+
|
|
73
|
+
Run `uvx us-macro-mcp` with `FRED_API_KEY` set in the environment. The server speaks MCP over stdio.
|
|
74
|
+
|
|
75
|
+
## How it behaves
|
|
76
|
+
|
|
77
|
+
**It runs locally.** Nothing is hosted. Your client launches the server as a subprocess on your own machine, using your own API key. No data leaves your computer except the read-only requests to FRED.
|
|
78
|
+
|
|
79
|
+
**It caches.** A single `macro_snapshot` fetches 19 indicators at once, and conversations tend to ask for the same series repeatedly. Answers are held in memory for a period matched to how often the number can actually change — an hour for daily series like Treasury yields, half a day for monthly series like CPI. The cache is discarded when the process exits. Adjust `CACHE_SECONDS` in `fred.py` if you want different behaviour.
|
|
80
|
+
|
|
81
|
+
**It never logs your API key.** Requests are logged as endpoint, series and status code only, and any error text is stripped of the key before it is written or returned.
|
|
82
|
+
|
|
83
|
+
## Known limitations
|
|
84
|
+
|
|
85
|
+
- **The ISM Manufacturing and Services PMI are not available.** ISM licenses its data commercially and withdrew it from FRED. The same applies to the Conference Board Consumer Confidence Index. There is no free source for either.
|
|
86
|
+
- **Rates are national averages, not per-bank.** The 30-year mortgage rate is Freddie Mac's weekly survey across thousands of lenders — not any particular bank's advertised rate. Per-institution rates are not published free by anyone.
|
|
87
|
+
- **FOMC meeting dates are not included.** FRED publishes data release schedules, not the Federal Reserve's meeting calendar.
|
|
88
|
+
- **Michigan consumer sentiment lags.** As of this writing FRED's `UMCSENT` and `MICH` series are running about two months behind other monthly indicators. The `latest_date` field always tells you what you actually got.
|
|
89
|
+
- **Data is reported for the period it covers.** June CPI is dated `2026-06-01` and publishes in mid-July. Always read `latest_date` rather than assuming the most recent month exists yet.
|
|
90
|
+
|
|
91
|
+
## Data source and disclaimer
|
|
92
|
+
|
|
93
|
+
All data comes from [FRED](https://fred.stlouisfed.org/), maintained by the Federal Reserve Bank of St. Louis, which aggregates it from the Bureau of Labor Statistics, the Bureau of Economic Analysis, the Census Bureau, the Federal Reserve Board and others.
|
|
94
|
+
|
|
95
|
+
The `recession_signals` tool applies well-known statistical thresholds to public data. It is not a forecast, and nothing this server returns is investment advice.
|
|
96
|
+
|
|
97
|
+
## Annual maintenance checklist
|
|
98
|
+
|
|
99
|
+
The Federal Reserve publishes its meeting schedule about two years ahead, and Python, the MCP SDK and
|
|
100
|
+
FRED's own catalog all drift over a year. Work through this list every January and cut a new release.
|
|
101
|
+
|
|
102
|
+
**Data**
|
|
103
|
+
|
|
104
|
+
- [ ] Refresh the FOMC schedule in `src/us_macro_mcp/fomc.py` from
|
|
105
|
+
[federalreserve.gov/monetarypolicy/fomccalendars.htm](https://www.federalreserve.gov/monetarypolicy/fomccalendars.htm),
|
|
106
|
+
and move `VALID_THROUGH` forward. The `next_fomc_meeting` field goes empty once the list runs out.
|
|
107
|
+
- [ ] Re-validate every series ID in the catalog. FRED retires series without warning — the ADP
|
|
108
|
+
employment series was discontinued this way, returning a valid response with zero observations:
|
|
109
|
+
|
|
110
|
+
cd ~/Downloads/Apps/US-Macro-MCP && uv run python -c "
|
|
111
|
+
import asyncio, logging
|
|
112
|
+
logging.getLogger('us_macro_mcp').setLevel(logging.WARNING)
|
|
113
|
+
from us_macro_mcp import catalog, fred
|
|
114
|
+
async def main():
|
|
115
|
+
sem = asyncio.Semaphore(8)
|
|
116
|
+
async def check(i):
|
|
117
|
+
async with sem:
|
|
118
|
+
try:
|
|
119
|
+
p = await fred.get_observations(i.series_id, start='2025-01-01', frequency_hint=i.frequency)
|
|
120
|
+
return (i.name, 'OK' if p else 'EMPTY', p[-1]['date'] if p else '-')
|
|
121
|
+
except Exception as e:
|
|
122
|
+
return (i.name, 'FAIL: ' + str(e)[:70], '-')
|
|
123
|
+
rows = await asyncio.gather(*(check(i) for i in catalog.CATALOG))
|
|
124
|
+
print('problems:', [r for r in rows if r[1] != 'OK'])
|
|
125
|
+
asyncio.run(main())
|
|
126
|
+
"
|
|
127
|
+
|
|
128
|
+
- [ ] Check whether anything previously unavailable has become free — particularly the ISM PMI and the
|
|
129
|
+
Conference Board Consumer Confidence Index, both currently absent from FRED.
|
|
130
|
+
- [ ] Check FRED's API terms and rate limit (currently 120 requests per minute per key) for changes.
|
|
131
|
+
|
|
132
|
+
**Dependencies**
|
|
133
|
+
|
|
134
|
+
- [ ] Bump the `mcp` SDK and read its changelog for breaking changes. FastMCP is part of the official
|
|
135
|
+
SDK, so a major version there can change how tools are declared or how the server starts.
|
|
136
|
+
- [ ] Check whether the MCP specification has revised its transports or tool schema.
|
|
137
|
+
- [ ] Bump `httpx`.
|
|
138
|
+
- [ ] Review `requires-python`. Drop versions that have reached end of life, and confirm the current
|
|
139
|
+
floor still installs cleanly.
|
|
140
|
+
|
|
141
|
+
**Release**
|
|
142
|
+
|
|
143
|
+
- [ ] Run the full test sweep: all eight tools, plus the negative and boundary cases.
|
|
144
|
+
- [ ] Bump the version in `pyproject.toml` and in `server.json`. They must match or the registry
|
|
145
|
+
rejects the publish.
|
|
146
|
+
- [ ] `uv build` and `uv publish` to PyPI.
|
|
147
|
+
- [ ] `mcp-publisher publish` to the official MCP registry.
|
|
148
|
+
- [ ] Tag the release on GitHub.
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
MIT
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# US-Macro-MCP
|
|
2
|
+
|
|
3
|
+
An MCP server that gives AI assistants clean access to US macroeconomic data — 58 indicators covering inflation, employment, growth, housing, consumer behaviour, interest rates, financial stress, markets and federal finances, sourced from the Federal Reserve's FRED database.
|
|
4
|
+
|
|
5
|
+
It is built so the assistant never has to know a FRED series ID, and never has to do arithmetic. Ask for `cpi` and you get the latest reading, the previous one, the year-ago value, and the percentage changes already calculated.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
| Tool | What you use it for |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `list_indicators` | See every indicator available, grouped by category |
|
|
12
|
+
| `get_indicator` | The current reading of one indicator, with its changes |
|
|
13
|
+
| `get_history` | A full time series, for trends and charting |
|
|
14
|
+
| `compare_indicators` | Two or more indicators over the same window, normalised for comparison |
|
|
15
|
+
| `release_calendar` | Which economic reports are scheduled over the coming days |
|
|
16
|
+
| `macro_snapshot` | The whole economy — or one category — in a single call |
|
|
17
|
+
| `recession_signals` | The Sahm rule, yield curve, credit spreads, claims and financial conditions, each graded |
|
|
18
|
+
| `search_indicators` | Find an indicator by keyword when you don't know its name |
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
A free FRED API key. Request one at [fredaccount.stlouisfed.org/apikeys](https://fredaccount.stlouisfed.org/apikeys) — it takes about a minute and costs nothing.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
### Claude Desktop
|
|
27
|
+
|
|
28
|
+
Add this to your `claude_desktop_config.json`:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"mcpServers": {
|
|
33
|
+
"us-macro": {
|
|
34
|
+
"command": "uvx",
|
|
35
|
+
"args": ["us-macro-mcp"],
|
|
36
|
+
"env": { "FRED_API_KEY": "your_key_here" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Claude Code
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
claude mcp add us-macro --env FRED_API_KEY=your_key_here -- uvx us-macro-mcp
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Any other MCP client
|
|
49
|
+
|
|
50
|
+
Run `uvx us-macro-mcp` with `FRED_API_KEY` set in the environment. The server speaks MCP over stdio.
|
|
51
|
+
|
|
52
|
+
## How it behaves
|
|
53
|
+
|
|
54
|
+
**It runs locally.** Nothing is hosted. Your client launches the server as a subprocess on your own machine, using your own API key. No data leaves your computer except the read-only requests to FRED.
|
|
55
|
+
|
|
56
|
+
**It caches.** A single `macro_snapshot` fetches 19 indicators at once, and conversations tend to ask for the same series repeatedly. Answers are held in memory for a period matched to how often the number can actually change — an hour for daily series like Treasury yields, half a day for monthly series like CPI. The cache is discarded when the process exits. Adjust `CACHE_SECONDS` in `fred.py` if you want different behaviour.
|
|
57
|
+
|
|
58
|
+
**It never logs your API key.** Requests are logged as endpoint, series and status code only, and any error text is stripped of the key before it is written or returned.
|
|
59
|
+
|
|
60
|
+
## Known limitations
|
|
61
|
+
|
|
62
|
+
- **The ISM Manufacturing and Services PMI are not available.** ISM licenses its data commercially and withdrew it from FRED. The same applies to the Conference Board Consumer Confidence Index. There is no free source for either.
|
|
63
|
+
- **Rates are national averages, not per-bank.** The 30-year mortgage rate is Freddie Mac's weekly survey across thousands of lenders — not any particular bank's advertised rate. Per-institution rates are not published free by anyone.
|
|
64
|
+
- **FOMC meeting dates are not included.** FRED publishes data release schedules, not the Federal Reserve's meeting calendar.
|
|
65
|
+
- **Michigan consumer sentiment lags.** As of this writing FRED's `UMCSENT` and `MICH` series are running about two months behind other monthly indicators. The `latest_date` field always tells you what you actually got.
|
|
66
|
+
- **Data is reported for the period it covers.** June CPI is dated `2026-06-01` and publishes in mid-July. Always read `latest_date` rather than assuming the most recent month exists yet.
|
|
67
|
+
|
|
68
|
+
## Data source and disclaimer
|
|
69
|
+
|
|
70
|
+
All data comes from [FRED](https://fred.stlouisfed.org/), maintained by the Federal Reserve Bank of St. Louis, which aggregates it from the Bureau of Labor Statistics, the Bureau of Economic Analysis, the Census Bureau, the Federal Reserve Board and others.
|
|
71
|
+
|
|
72
|
+
The `recession_signals` tool applies well-known statistical thresholds to public data. It is not a forecast, and nothing this server returns is investment advice.
|
|
73
|
+
|
|
74
|
+
## Annual maintenance checklist
|
|
75
|
+
|
|
76
|
+
The Federal Reserve publishes its meeting schedule about two years ahead, and Python, the MCP SDK and
|
|
77
|
+
FRED's own catalog all drift over a year. Work through this list every January and cut a new release.
|
|
78
|
+
|
|
79
|
+
**Data**
|
|
80
|
+
|
|
81
|
+
- [ ] Refresh the FOMC schedule in `src/us_macro_mcp/fomc.py` from
|
|
82
|
+
[federalreserve.gov/monetarypolicy/fomccalendars.htm](https://www.federalreserve.gov/monetarypolicy/fomccalendars.htm),
|
|
83
|
+
and move `VALID_THROUGH` forward. The `next_fomc_meeting` field goes empty once the list runs out.
|
|
84
|
+
- [ ] Re-validate every series ID in the catalog. FRED retires series without warning — the ADP
|
|
85
|
+
employment series was discontinued this way, returning a valid response with zero observations:
|
|
86
|
+
|
|
87
|
+
cd ~/Downloads/Apps/US-Macro-MCP && uv run python -c "
|
|
88
|
+
import asyncio, logging
|
|
89
|
+
logging.getLogger('us_macro_mcp').setLevel(logging.WARNING)
|
|
90
|
+
from us_macro_mcp import catalog, fred
|
|
91
|
+
async def main():
|
|
92
|
+
sem = asyncio.Semaphore(8)
|
|
93
|
+
async def check(i):
|
|
94
|
+
async with sem:
|
|
95
|
+
try:
|
|
96
|
+
p = await fred.get_observations(i.series_id, start='2025-01-01', frequency_hint=i.frequency)
|
|
97
|
+
return (i.name, 'OK' if p else 'EMPTY', p[-1]['date'] if p else '-')
|
|
98
|
+
except Exception as e:
|
|
99
|
+
return (i.name, 'FAIL: ' + str(e)[:70], '-')
|
|
100
|
+
rows = await asyncio.gather(*(check(i) for i in catalog.CATALOG))
|
|
101
|
+
print('problems:', [r for r in rows if r[1] != 'OK'])
|
|
102
|
+
asyncio.run(main())
|
|
103
|
+
"
|
|
104
|
+
|
|
105
|
+
- [ ] Check whether anything previously unavailable has become free — particularly the ISM PMI and the
|
|
106
|
+
Conference Board Consumer Confidence Index, both currently absent from FRED.
|
|
107
|
+
- [ ] Check FRED's API terms and rate limit (currently 120 requests per minute per key) for changes.
|
|
108
|
+
|
|
109
|
+
**Dependencies**
|
|
110
|
+
|
|
111
|
+
- [ ] Bump the `mcp` SDK and read its changelog for breaking changes. FastMCP is part of the official
|
|
112
|
+
SDK, so a major version there can change how tools are declared or how the server starts.
|
|
113
|
+
- [ ] Check whether the MCP specification has revised its transports or tool schema.
|
|
114
|
+
- [ ] Bump `httpx`.
|
|
115
|
+
- [ ] Review `requires-python`. Drop versions that have reached end of life, and confirm the current
|
|
116
|
+
floor still installs cleanly.
|
|
117
|
+
|
|
118
|
+
**Release**
|
|
119
|
+
|
|
120
|
+
- [ ] Run the full test sweep: all eight tools, plus the negative and boundary cases.
|
|
121
|
+
- [ ] Bump the version in `pyproject.toml` and in `server.json`. They must match or the registry
|
|
122
|
+
rejects the publish.
|
|
123
|
+
- [ ] `uv build` and `uv publish` to PyPI.
|
|
124
|
+
- [ ] `mcp-publisher publish` to the official MCP registry.
|
|
125
|
+
- [ ] Tag the release on GitHub.
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "us-macro-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server exposing US macroeconomic indicators - inflation, employment, growth, housing, rates and recession signals - from the Federal Reserve's FRED database."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Harish Gupta", email = "hgus107@gmail.com" }
|
|
11
|
+
]
|
|
12
|
+
keywords = ["mcp", "model-context-protocol", "economics", "fred", "macro", "inflation", "llm"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Topic :: Office/Business :: Financial",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"httpx>=0.27",
|
|
23
|
+
"mcp[cli]>=1.2",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/hgus107/US-Macro-MCP"
|
|
28
|
+
Repository = "https://github.com/hgus107/US-Macro-MCP"
|
|
29
|
+
Issues = "https://github.com/hgus107/US-Macro-MCP/issues"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
us-macro-mcp = "us_macro_mcp:main"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["uv_build>=0.11.32,<0.12.0"]
|
|
36
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
US-Macro-MCP - the package entry point.
|
|
3
|
+
|
|
4
|
+
What this file does, in order:
|
|
5
|
+
1. Exposes the version number to anything that imports this package.
|
|
6
|
+
2. Defines main(), the command the operating system runs when someone types "us-macro-mcp".
|
|
7
|
+
3. main() starts the MCP server, which then waits for an AI client to connect and call its tools.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# The command line entry point: starts the MCP server and hands control to it.
|
|
16
|
+
def main() -> None:
|
|
17
|
+
from .server import run
|
|
18
|
+
|
|
19
|
+
run()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__all__ = ["main", "__version__"]
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The indicator catalog for US-Macro-MCP.
|
|
3
|
+
|
|
4
|
+
What this file does, in order:
|
|
5
|
+
1. Defines one Indicator record per economic statistic we support - its friendly
|
|
6
|
+
name, its FRED series ID, which category it belongs to, and how often it updates.
|
|
7
|
+
2. Lists all 58 indicators, grouped by category, in the CATALOG tuple.
|
|
8
|
+
3. Builds lookup dictionaries so the rest of the program can find an indicator
|
|
9
|
+
by its friendly name (for example "cpi") or by its FRED series ID.
|
|
10
|
+
4. Provides small helper functions to search the catalog and to list the categories.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
|
|
17
|
+
# One economic indicator: the friendly name users ask for, plus everything we need to fetch and label it.
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class Indicator:
|
|
20
|
+
name: str # friendly name used in tool arguments, e.g. "core_cpi"
|
|
21
|
+
series_id: str # the FRED series ID we actually request, e.g. "CPILFESL"
|
|
22
|
+
title: str # human-readable title shown in results
|
|
23
|
+
category: str # one of the CATEGORIES below
|
|
24
|
+
units: str # what the numbers mean, e.g. "Percent" or "Index 1982-84=100"
|
|
25
|
+
frequency: str # how often FRED updates it: Daily, Weekly, Monthly, Quarterly
|
|
26
|
+
major: bool = False # True for headline indicators included in snapshots and the calendar
|
|
27
|
+
notes: str = "" # optional one-line explanation of how to read the number
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
CATEGORIES = (
|
|
31
|
+
"inflation",
|
|
32
|
+
"employment",
|
|
33
|
+
"growth",
|
|
34
|
+
"housing",
|
|
35
|
+
"consumer",
|
|
36
|
+
"rates",
|
|
37
|
+
"stress",
|
|
38
|
+
"markets",
|
|
39
|
+
"fiscal",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
CATALOG: tuple[Indicator, ...] = (
|
|
44
|
+
# ---------------------------------------------------------------- inflation
|
|
45
|
+
Indicator("cpi", "CPIAUCSL", "Consumer Price Index (All Items)", "inflation",
|
|
46
|
+
"Index 1982-84=100", "Monthly", major=True,
|
|
47
|
+
notes="Headline inflation; read the year-over-year percent change."),
|
|
48
|
+
Indicator("core_cpi", "CPILFESL", "Core CPI (Excluding Food and Energy)", "inflation",
|
|
49
|
+
"Index 1982-84=100", "Monthly", major=True,
|
|
50
|
+
notes="Strips out volatile food and energy prices."),
|
|
51
|
+
Indicator("pce", "PCEPI", "PCE Price Index", "inflation",
|
|
52
|
+
"Index 2017=100", "Monthly",
|
|
53
|
+
notes="The broader price measure the Federal Reserve prefers."),
|
|
54
|
+
Indicator("core_pce", "PCEPILFE", "Core PCE Price Index", "inflation",
|
|
55
|
+
"Index 2017=100", "Monthly", major=True,
|
|
56
|
+
notes="The Federal Reserve's official 2 percent inflation target measure."),
|
|
57
|
+
Indicator("ppi", "PPIFIS", "Producer Price Index (Final Demand)", "inflation",
|
|
58
|
+
"Index 2009=100", "Monthly", major=True,
|
|
59
|
+
notes="Prices producers receive; often leads consumer prices."),
|
|
60
|
+
Indicator("breakeven_5y", "T5YIE", "5-Year Breakeven Inflation Rate", "inflation",
|
|
61
|
+
"Percent", "Daily",
|
|
62
|
+
notes="What the bond market expects inflation to average over 5 years."),
|
|
63
|
+
Indicator("breakeven_10y", "T10YIE", "10-Year Breakeven Inflation Rate", "inflation",
|
|
64
|
+
"Percent", "Daily"),
|
|
65
|
+
|
|
66
|
+
# --------------------------------------------------------------- employment
|
|
67
|
+
Indicator("unemployment_rate", "UNRATE", "Unemployment Rate", "employment",
|
|
68
|
+
"Percent", "Monthly", major=True),
|
|
69
|
+
Indicator("nonfarm_payrolls", "PAYEMS", "Total Nonfarm Payrolls", "employment",
|
|
70
|
+
"Thousands of Persons", "Monthly", major=True,
|
|
71
|
+
notes="Read the month-over-month change - that is the 'jobs number'."),
|
|
72
|
+
Indicator("private_payrolls", "USPRIV", "All Employees, Total Private", "employment",
|
|
73
|
+
"Thousands of Persons", "Monthly",
|
|
74
|
+
notes="Jobs at private employers only - excludes government hiring."),
|
|
75
|
+
Indicator("jobless_claims", "ICSA", "Initial Jobless Claims", "employment",
|
|
76
|
+
"Number", "Weekly", major=True,
|
|
77
|
+
notes="Weekly new unemployment filings; the fastest labor market signal."),
|
|
78
|
+
Indicator("continuing_claims", "CCSA", "Continuing Jobless Claims", "employment",
|
|
79
|
+
"Number", "Weekly",
|
|
80
|
+
notes="People still collecting benefits; shows how hard it is to get rehired."),
|
|
81
|
+
Indicator("job_openings", "JTSJOL", "Job Openings (JOLTS)", "employment",
|
|
82
|
+
"Thousands", "Monthly", major=True),
|
|
83
|
+
Indicator("labor_participation", "CIVPART", "Labor Force Participation Rate", "employment",
|
|
84
|
+
"Percent", "Monthly"),
|
|
85
|
+
Indicator("avg_hourly_earnings", "CES0500000003", "Average Hourly Earnings", "employment",
|
|
86
|
+
"Dollars per Hour", "Monthly",
|
|
87
|
+
notes="Wage growth; compare its year-over-year change against CPI."),
|
|
88
|
+
|
|
89
|
+
# ------------------------------------------------------------------- growth
|
|
90
|
+
Indicator("gdp", "GDPC1", "Real Gross Domestic Product", "growth",
|
|
91
|
+
"Billions of Chained 2017 Dollars", "Quarterly", major=True,
|
|
92
|
+
notes="Inflation-adjusted output; the headline growth number."),
|
|
93
|
+
Indicator("gdp_nominal", "GDP", "Nominal Gross Domestic Product", "growth",
|
|
94
|
+
"Billions of Dollars", "Quarterly"),
|
|
95
|
+
Indicator("industrial_production", "INDPRO", "Industrial Production Index", "growth",
|
|
96
|
+
"Index 2017=100", "Monthly"),
|
|
97
|
+
Indicator("capacity_utilization", "TCU", "Capacity Utilization", "growth",
|
|
98
|
+
"Percent of Capacity", "Monthly"),
|
|
99
|
+
Indicator("durable_goods", "DGORDER", "Durable Goods New Orders", "growth",
|
|
100
|
+
"Millions of Dollars", "Monthly",
|
|
101
|
+
notes="Business orders for long-lasting goods; a capital spending gauge."),
|
|
102
|
+
Indicator("productivity", "OPHNFB", "Nonfarm Business Labor Productivity", "growth",
|
|
103
|
+
"Index 2017=100", "Quarterly"),
|
|
104
|
+
Indicator("philly_fed", "GACDFSA066MSFRBPHI", "Philadelphia Fed Manufacturing Survey", "growth",
|
|
105
|
+
"Diffusion Index", "Monthly",
|
|
106
|
+
notes="Above zero means more factories reporting growth than decline."),
|
|
107
|
+
Indicator("empire_state", "GACDISA066MSFRBNY", "Empire State Manufacturing Survey", "growth",
|
|
108
|
+
"Diffusion Index", "Monthly",
|
|
109
|
+
notes="New York Fed factory survey; the earliest monthly read on manufacturing."),
|
|
110
|
+
Indicator("national_activity", "CFNAI", "Chicago Fed National Activity Index", "growth",
|
|
111
|
+
"Index", "Monthly",
|
|
112
|
+
notes="85 indicators combined; zero is average growth, negative is below trend."),
|
|
113
|
+
|
|
114
|
+
# ------------------------------------------------------------------ housing
|
|
115
|
+
Indicator("housing_starts", "HOUST", "Housing Starts", "housing",
|
|
116
|
+
"Thousands of Units (Annual Rate)", "Monthly", major=True),
|
|
117
|
+
Indicator("building_permits", "PERMIT", "Building Permits", "housing",
|
|
118
|
+
"Thousands of Units (Annual Rate)", "Monthly",
|
|
119
|
+
notes="Leads housing starts by a month or two."),
|
|
120
|
+
Indicator("new_home_sales", "HSN1F", "New One-Family Home Sales", "housing",
|
|
121
|
+
"Thousands of Units (Annual Rate)", "Monthly"),
|
|
122
|
+
Indicator("existing_home_sales", "EXHOSLUSM495S", "Existing Home Sales", "housing",
|
|
123
|
+
"Number of Units (Annual Rate)", "Monthly"),
|
|
124
|
+
Indicator("home_prices", "CSUSHPINSA", "Case-Shiller National Home Price Index", "housing",
|
|
125
|
+
"Index Jan 2000=100", "Monthly",
|
|
126
|
+
notes="Reported with a two-month lag."),
|
|
127
|
+
Indicator("mortgage_30y", "MORTGAGE30US", "30-Year Fixed Mortgage Rate", "housing",
|
|
128
|
+
"Percent", "Weekly", major=True,
|
|
129
|
+
notes="Freddie Mac national average, not any single lender's rate."),
|
|
130
|
+
Indicator("mortgage_15y", "MORTGAGE15US", "15-Year Fixed Mortgage Rate", "housing",
|
|
131
|
+
"Percent", "Weekly"),
|
|
132
|
+
|
|
133
|
+
# ----------------------------------------------------------------- consumer
|
|
134
|
+
Indicator("retail_sales", "RSAFS", "Retail and Food Services Sales", "consumer",
|
|
135
|
+
"Millions of Dollars", "Monthly", major=True),
|
|
136
|
+
Indicator("consumer_sentiment", "UMCSENT", "University of Michigan Consumer Sentiment", "consumer",
|
|
137
|
+
"Index 1966Q1=100", "Monthly", major=True),
|
|
138
|
+
Indicator("inflation_expectations", "MICH", "Michigan 1-Year Inflation Expectations", "consumer",
|
|
139
|
+
"Percent", "Monthly",
|
|
140
|
+
notes="What households think inflation will be over the next year."),
|
|
141
|
+
Indicator("personal_income", "PI", "Personal Income", "consumer",
|
|
142
|
+
"Billions of Dollars (Annual Rate)", "Monthly"),
|
|
143
|
+
Indicator("personal_spending", "PCE", "Personal Consumption Expenditures", "consumer",
|
|
144
|
+
"Billions of Dollars (Annual Rate)", "Monthly"),
|
|
145
|
+
Indicator("savings_rate", "PSAVERT", "Personal Saving Rate", "consumer",
|
|
146
|
+
"Percent of Disposable Income", "Monthly"),
|
|
147
|
+
Indicator("consumer_credit", "TOTALSL", "Total Consumer Credit Outstanding", "consumer",
|
|
148
|
+
"Billions of Dollars", "Monthly",
|
|
149
|
+
notes="How much household borrowing is building up."),
|
|
150
|
+
|
|
151
|
+
# -------------------------------------------------------------------- rates
|
|
152
|
+
Indicator("fed_funds", "DFF", "Effective Federal Funds Rate", "rates",
|
|
153
|
+
"Percent", "Daily", major=True,
|
|
154
|
+
notes="The overnight rate the Federal Reserve steers with policy decisions."),
|
|
155
|
+
Indicator("sofr", "SOFR", "Secured Overnight Financing Rate", "rates",
|
|
156
|
+
"Percent", "Daily"),
|
|
157
|
+
Indicator("treasury_3m", "DGS3MO", "3-Month Treasury Yield", "rates",
|
|
158
|
+
"Percent", "Daily"),
|
|
159
|
+
Indicator("treasury_2y", "DGS2", "2-Year Treasury Yield", "rates",
|
|
160
|
+
"Percent", "Daily"),
|
|
161
|
+
Indicator("treasury_10y", "DGS10", "10-Year Treasury Yield", "rates",
|
|
162
|
+
"Percent", "Daily", major=True),
|
|
163
|
+
Indicator("treasury_30y", "DGS30", "30-Year Treasury Yield", "rates",
|
|
164
|
+
"Percent", "Daily"),
|
|
165
|
+
Indicator("yield_curve", "T10Y2Y", "10-Year Minus 2-Year Treasury Spread", "rates",
|
|
166
|
+
"Percent", "Daily", major=True,
|
|
167
|
+
notes="Below zero is an inverted curve, historically a recession warning."),
|
|
168
|
+
Indicator("fed_balance_sheet", "WALCL", "Federal Reserve Total Assets", "rates",
|
|
169
|
+
"Millions of Dollars", "Weekly",
|
|
170
|
+
notes="Shrinking means the Federal Reserve is draining liquidity."),
|
|
171
|
+
|
|
172
|
+
# ------------------------------------------------------------------- stress
|
|
173
|
+
Indicator("high_yield_spread", "BAMLH0A0HYM2", "High Yield Bond Spread", "stress",
|
|
174
|
+
"Percent", "Daily", major=True,
|
|
175
|
+
notes="Extra yield demanded on risky corporate debt; widens when credit is stressed."),
|
|
176
|
+
Indicator("financial_conditions", "NFCI", "Chicago Fed National Financial Conditions Index", "stress",
|
|
177
|
+
"Index", "Weekly",
|
|
178
|
+
notes="Above zero means conditions are tighter than average."),
|
|
179
|
+
Indicator("sahm_rule", "SAHMREALTIME", "Sahm Rule Recession Indicator", "stress",
|
|
180
|
+
"Percentage Points", "Monthly", major=True,
|
|
181
|
+
notes="At or above 0.50 has historically meant a recession has begun."),
|
|
182
|
+
Indicator("lending_standards", "DRTSCILM", "Banks Tightening Business Lending Standards", "stress",
|
|
183
|
+
"Net Percent of Banks", "Quarterly",
|
|
184
|
+
notes="From the Fed's Senior Loan Officer Survey; rising means credit is getting harder to get."),
|
|
185
|
+
|
|
186
|
+
# ------------------------------------------------------------------ markets
|
|
187
|
+
Indicator("sp500", "SP500", "S&P 500 Index", "markets",
|
|
188
|
+
"Index", "Daily", major=True),
|
|
189
|
+
Indicator("vix", "VIXCLS", "CBOE Volatility Index (VIX)", "markets",
|
|
190
|
+
"Index", "Daily",
|
|
191
|
+
notes="Expected stock market volatility; spikes signal fear."),
|
|
192
|
+
Indicator("dollar_index", "DTWEXBGS", "Trade Weighted US Dollar Index", "markets",
|
|
193
|
+
"Index Jan 2006=100", "Daily"),
|
|
194
|
+
Indicator("wti_crude", "DCOILWTICO", "WTI Crude Oil Price", "markets",
|
|
195
|
+
"Dollars per Barrel", "Daily"),
|
|
196
|
+
Indicator("gas_price", "GASREGW", "US Regular Gasoline Price", "markets",
|
|
197
|
+
"Dollars per Gallon", "Weekly"),
|
|
198
|
+
|
|
199
|
+
# ------------------------------------------------------------------- fiscal
|
|
200
|
+
Indicator("federal_debt", "GFDEBTN", "Total Federal Public Debt", "fiscal",
|
|
201
|
+
"Millions of Dollars", "Quarterly"),
|
|
202
|
+
Indicator("federal_deficit", "MTSDS133FMS", "Federal Surplus or Deficit", "fiscal",
|
|
203
|
+
"Millions of Dollars", "Monthly",
|
|
204
|
+
notes="Negative values are deficits."),
|
|
205
|
+
Indicator("debt_to_gdp", "GFDEGDQ188S", "Federal Debt as Percent of GDP", "fiscal",
|
|
206
|
+
"Percent of GDP", "Quarterly"),
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# Fast lookups built once at import: friendly name -> Indicator, and FRED series ID -> Indicator.
|
|
211
|
+
BY_NAME: dict[str, Indicator] = {item.name: item for item in CATALOG}
|
|
212
|
+
BY_SERIES_ID: dict[str, Indicator] = {item.series_id: item for item in CATALOG}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# Finds one indicator by friendly name, or by FRED series ID if the caller passed that instead.
|
|
216
|
+
def find(name: str) -> Indicator | None:
|
|
217
|
+
key = name.strip().lower().replace("-", "_").replace(" ", "_")
|
|
218
|
+
if key in BY_NAME:
|
|
219
|
+
return BY_NAME[key]
|
|
220
|
+
return BY_SERIES_ID.get(name.strip().upper())
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# Returns every indicator in one category, or the whole catalog when no category is given.
|
|
224
|
+
def in_category(category: str | None) -> tuple[Indicator, ...]:
|
|
225
|
+
if not category or category.lower() == "all":
|
|
226
|
+
return CATALOG
|
|
227
|
+
wanted = category.strip().lower()
|
|
228
|
+
return tuple(item for item in CATALOG if item.category == wanted)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# Scores each indicator against a free-text query and returns the best matches first.
|
|
232
|
+
def search(query: str, limit: int = 10) -> list[Indicator]:
|
|
233
|
+
words = [w for w in query.strip().lower().split() if w]
|
|
234
|
+
if not words:
|
|
235
|
+
return []
|
|
236
|
+
|
|
237
|
+
scored: list[tuple[int, Indicator]] = []
|
|
238
|
+
for item in CATALOG:
|
|
239
|
+
haystack = " ".join(
|
|
240
|
+
(item.name, item.title, item.category, item.notes, item.series_id)
|
|
241
|
+
).lower()
|
|
242
|
+
score = 0
|
|
243
|
+
for word in words:
|
|
244
|
+
if word in item.name.lower():
|
|
245
|
+
score += 3 # a hit on the friendly name is the strongest signal
|
|
246
|
+
elif word in item.title.lower():
|
|
247
|
+
score += 2 # a hit in the official title is next best
|
|
248
|
+
elif word in haystack:
|
|
249
|
+
score += 1 # a hit anywhere else still counts a little
|
|
250
|
+
if score:
|
|
251
|
+
scored.append((score, item))
|
|
252
|
+
|
|
253
|
+
scored.sort(key=lambda pair: (-pair[0], pair[1].name))
|
|
254
|
+
return [item for _, item in scored[:limit]]
|