greenpick 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.
- greenpick-0.1.0/LICENSE +21 -0
- greenpick-0.1.0/PKG-INFO +271 -0
- greenpick-0.1.0/README.md +241 -0
- greenpick-0.1.0/pyproject.toml +59 -0
- greenpick-0.1.0/setup.cfg +4 -0
- greenpick-0.1.0/src/greenpick/__init__.py +7 -0
- greenpick-0.1.0/src/greenpick/__main__.py +18 -0
- greenpick-0.1.0/src/greenpick/config.py +58 -0
- greenpick-0.1.0/src/greenpick/data/__init__.py +28 -0
- greenpick-0.1.0/src/greenpick/data/auto_repository.py +47 -0
- greenpick-0.1.0/src/greenpick/data/eia_repository.py +156 -0
- greenpick-0.1.0/src/greenpick/data/electricitymaps_repository.py +104 -0
- greenpick-0.1.0/src/greenpick/data/emission_factors.json +35 -0
- greenpick-0.1.0/src/greenpick/data/entsoe_repository.py +401 -0
- greenpick-0.1.0/src/greenpick/data/gpu_power.json +26 -0
- greenpick-0.1.0/src/greenpick/data/inference_energy.json +50 -0
- greenpick-0.1.0/src/greenpick/data/instance_families.json +32 -0
- greenpick-0.1.0/src/greenpick/data/mock_repository.py +53 -0
- greenpick-0.1.0/src/greenpick/data/network.json +7 -0
- greenpick-0.1.0/src/greenpick/data/power.json +7 -0
- greenpick-0.1.0/src/greenpick/data/pricing.json +31 -0
- greenpick-0.1.0/src/greenpick/data/regions.json +22 -0
- greenpick-0.1.0/src/greenpick/data/repository.py +27 -0
- greenpick-0.1.0/src/greenpick/data/static_data.py +105 -0
- greenpick-0.1.0/src/greenpick/models.py +342 -0
- greenpick-0.1.0/src/greenpick/server.py +349 -0
- greenpick-0.1.0/src/greenpick/services/__init__.py +5 -0
- greenpick-0.1.0/src/greenpick/services/carbon_service.py +28 -0
- greenpick-0.1.0/src/greenpick/services/cost_service.py +21 -0
- greenpick-0.1.0/src/greenpick/services/forecast_service.py +72 -0
- greenpick-0.1.0/src/greenpick/services/inference_service.py +100 -0
- greenpick-0.1.0/src/greenpick/services/instance_service.py +132 -0
- greenpick-0.1.0/src/greenpick/services/latency_service.py +33 -0
- greenpick-0.1.0/src/greenpick/services/locality_service.py +160 -0
- greenpick-0.1.0/src/greenpick/services/metric_scaffold_service.py +149 -0
- greenpick-0.1.0/src/greenpick/services/recommender.py +203 -0
- greenpick-0.1.0/src/greenpick/services/residency_service.py +53 -0
- greenpick-0.1.0/src/greenpick/services/rightsizing_service.py +93 -0
- greenpick-0.1.0/src/greenpick/services/scheduling_service.py +211 -0
- greenpick-0.1.0/src/greenpick/services/serving_service.py +202 -0
- greenpick-0.1.0/src/greenpick/services/training_service.py +209 -0
- greenpick-0.1.0/src/greenpick.egg-info/PKG-INFO +271 -0
- greenpick-0.1.0/src/greenpick.egg-info/SOURCES.txt +46 -0
- greenpick-0.1.0/src/greenpick.egg-info/dependency_links.txt +1 -0
- greenpick-0.1.0/src/greenpick.egg-info/entry_points.txt +2 -0
- greenpick-0.1.0/src/greenpick.egg-info/requires.txt +8 -0
- greenpick-0.1.0/src/greenpick.egg-info/top_level.txt +1 -0
- greenpick-0.1.0/tests/test_services.py +1078 -0
greenpick-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Data Science Advisers, LLC
|
|
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.
|
greenpick-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: greenpick
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Design-time sustainability co-pilot (MCP server): greener, cheaper cloud infrastructure decisions with carbon + cost + latency tradeoffs.
|
|
5
|
+
Author-email: "Data Science Advisers, LLC" <info@datascienceadvisers.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/bithug01/greenpick
|
|
8
|
+
Project-URL: Repository, https://github.com/bithug01/greenpick
|
|
9
|
+
Project-URL: Issues, https://github.com/bithug01/greenpick/issues
|
|
10
|
+
Keywords: mcp,sustainability,carbon,cloud,finops,developer-tools,green-software
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: mcp<2,>=1.2
|
|
23
|
+
Requires-Dist: pydantic>=2.0
|
|
24
|
+
Requires-Dist: httpx>=0.27
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
28
|
+
Requires-Dist: ijson>=3.0; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img src="docs/img/logo.svg" alt="GreenPick logo — a leaf whose veins are circuit traces" width="120" />
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<h1 align="center">GreenPick</h1>
|
|
36
|
+
|
|
37
|
+
<p align="center"><strong>Write greener, cheaper cloud infrastructure — before you deploy.</strong></p>
|
|
38
|
+
|
|
39
|
+
<!-- mcp-name: io.github.bithug01/greenpick -->
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<img src="https://img.shields.io/pypi/v/greenpick" alt="PyPI version" />
|
|
44
|
+
<img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT" />
|
|
45
|
+
<img src="https://img.shields.io/badge/tests-passing-brightgreen" alt="Tests: passing" />
|
|
46
|
+
<img src="https://img.shields.io/badge/python-3.11%2B-blue" alt="Python 3.11+" />
|
|
47
|
+
<img src="https://img.shields.io/badge/MCP%20tools-15-0ea5e9" alt="MCP tools: 15" />
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
A **design-time sustainability co-pilot** that runs as an MCP server inside your vibe-coding
|
|
51
|
+
environment (Cursor / Claude Code / Kiro). Ask it where to deploy, when to run a job, or how to
|
|
52
|
+
right-size — and it answers with an honest **carbon + cost + latency** tradeoff, in-editor, in
|
|
53
|
+
seconds. (It responds when you ask; auto-nudging on infra-code changes is on the roadmap.)
|
|
54
|
+
|
|
55
|
+
> **Status: working — 15 tools.** Live carbon for US (EIA-930) and EU (ENTSO-E), cross-cloud cost
|
|
56
|
+
> parity (Vantage-refreshed), per-axis R/Y/G ratings, carbon-aware scheduling + day-ahead forecast,
|
|
57
|
+
> GPU-training **and LLM-inference** carbon, right-sizing, serving-pattern and data-locality/residency
|
|
58
|
+
> checks — all shipped. Falls back to clearly-labelled mock data offline or without API keys.
|
|
59
|
+
|
|
60
|
+
<p align="center">
|
|
61
|
+
<img src="docs/img/region-carbon-30x.svg" alt="Same H100 training run, ~30× the carbon depending only on region (Stockholm vs Sydney)" width="560" />
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
*The same 40-GPU-hour training run emits ~0.7 kg CO₂ in Stockholm vs ~19 kg in Sydney — a ~30×
|
|
65
|
+
difference from region choice alone. Ask GreenPick and it surfaces that (with the cost and latency
|
|
66
|
+
tradeoff) while you're still in the editor, before you commit.*
|
|
67
|
+
|
|
68
|
+
**▶ [See the 5-minute demo](docs/demo.md)** — three scenarios with real tool output (training placement, the egress backfire, the forecast).
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
- 🧮 **Right-sizing that cuts cost *and* carbon together** — the FinOps win with a carbon twin. The money saved is the reason to run it; the carbon comes free.
|
|
73
|
+
- ⏱ **Carbon-aware scheduling** — run deferrable jobs (ETL, batch, training) when the grid is cleanest, now or day-ahead. A decision you make for *every* recurring job.
|
|
74
|
+
- ⚡ **GPU training & LLM inference carbon** — estimate a run's footprint and the greener *where* + *when*; the size/placement choices that actually move the number.
|
|
75
|
+
- 🌍 **Greener region picks** — ranked by carbon, with the cost + latency tradeoff shown, not hidden.
|
|
76
|
+
- 🛡 **Backfire guards** — flags when a greener move loses to egress, or crosses a data-residency line.
|
|
77
|
+
- 🔌 **Live US + EU grid data**, honest mock fallback — **no API keys required to start**.
|
|
78
|
+
|
|
79
|
+
## Contents
|
|
80
|
+
|
|
81
|
+
- [Why this exists](#why-this-exists)
|
|
82
|
+
- [What it is / is NOT](#what-it-is--is-not) · [How it differs](#how-it-differs-from-whats-out-there)
|
|
83
|
+
- [Scope](#scope)
|
|
84
|
+
- [MCP tools](#mcp-tools)
|
|
85
|
+
- [Data sources](#data-sources-free-swappable-behind-one-interface)
|
|
86
|
+
- [Honest limitations](#honest-limitations-shipped-in-the-tool-itself)
|
|
87
|
+
- [Quick start](#quick-start)
|
|
88
|
+
- [FAQ](#faq)
|
|
89
|
+
- [Contributing](#contributing)
|
|
90
|
+
- [License](#license)
|
|
91
|
+
|
|
92
|
+
## Why this exists
|
|
93
|
+
|
|
94
|
+
The same web service emits very different CO₂ depending on **which region** it runs in, because
|
|
95
|
+
electricity grids differ in carbon intensity. Existing tools either rank regions in the abstract,
|
|
96
|
+
or measure carbon *after* you deploy. GreenPick does it **at the moment you choose**, and tells you
|
|
97
|
+
what the greener choice *costs you* in latency and dollars — so you can accept or reject it with
|
|
98
|
+
eyes open.
|
|
99
|
+
|
|
100
|
+
## What it is / is NOT
|
|
101
|
+
|
|
102
|
+
- **IS:** directional "greener choice" guidance for a developer picking a cloud region while
|
|
103
|
+
building. Guidance, with tradeoffs stated.
|
|
104
|
+
- **IS NOT:** audited carbon accounting, ESG/Scope-2 reporting, or a real-time scheduler.
|
|
105
|
+
GreenPick does **not** claim GHG-Protocol or ISO compliance — that's what the paid data vendors
|
|
106
|
+
(Electricity Maps, WattTime) provide. GreenPick is for *decisions*, not *disclosures*.
|
|
107
|
+
|
|
108
|
+
### How it differs from what's out there
|
|
109
|
+
|
|
110
|
+
- **Measurement tools** (Cloud Carbon Footprint, CodeCarbon, Kepler) report what you *already*
|
|
111
|
+
emitted, *after* you deploy. GreenPick advises *before* — at the choice.
|
|
112
|
+
- **Cloud providers' own tools** (AWS CCFT, Azure, Google's "Low CO₂" region labels) cover *one*
|
|
113
|
+
cloud and show carbon alone. GreenPick is **cross-cloud** and weighs carbon **against cost and
|
|
114
|
+
latency** so you see the tradeoff, not just a green badge.
|
|
115
|
+
- **CI/CD carbon tools** act at merge time on a pipeline job. GreenPick works earlier, in the
|
|
116
|
+
editor, across more decisions (scheduling, right-sizing, training/inference, egress & residency).
|
|
117
|
+
- **Grid-data SDKs** (Electricity Maps, WattTime, GSF Carbon Aware SDK) are building blocks;
|
|
118
|
+
GreenPick is the decision layer on top of that kind of data.
|
|
119
|
+
|
|
120
|
+
The combination — **cross-cloud, carbon + cost + latency, at design time, in the editor, with
|
|
121
|
+
backfire guards** — is the part nothing else puts together.
|
|
122
|
+
|
|
123
|
+
## Scope
|
|
124
|
+
|
|
125
|
+
- Providers: **AWS, GCP, Azure** regions.
|
|
126
|
+
- Workloads: long-running **web/API services**, **GPU training** runs, and **deferrable jobs**
|
|
127
|
+
(ETL / batch / backups) — placement and timing for each.
|
|
128
|
+
- Carbon = **grid carbon intensity by region** (directional, point-in-time; live US + EU), plus a
|
|
129
|
+
**day-ahead forecast** (EU) for forward-looking scheduling.
|
|
130
|
+
- Cost = **compute + egress ballpark** (deterministic static table, apples-to-apples across
|
|
131
|
+
clouds; never LLM-invented).
|
|
132
|
+
- Latency = **geographic estimate** to a stated user location.
|
|
133
|
+
- Efficiency levers: **greener instance family** (perf-per-watt), **right-sizing** (cost + carbon
|
|
134
|
+
together), and a **carbon-metric scaffold** to track your app over time.
|
|
135
|
+
- Guardrails: **data-locality / egress** backfire checks and **cross-jurisdiction residency** flags.
|
|
136
|
+
- **Free data only.** No flow-traced consumption accounting; carbon forecast is relative, not absolute.
|
|
137
|
+
|
|
138
|
+
Roadmap: data-format/engine efficiency advice, sub-national grid zones, CI/CD integration.
|
|
139
|
+
See `docs/user-questions-backlog.md`.
|
|
140
|
+
|
|
141
|
+
## MCP tools
|
|
142
|
+
|
|
143
|
+
15 tools, grouped by what you're trying to do.
|
|
144
|
+
|
|
145
|
+
### Pick a region
|
|
146
|
+
|
|
147
|
+
| Tool | What it does |
|
|
148
|
+
|------|--------------|
|
|
149
|
+
| `compare_regions_tri_axis` | Rank candidate regions by carbon with cost + latency tradeoffs; recommend a pick, each axis rated R/Y/G. Pass `regions` to rank only the ones you'd actually consider. |
|
|
150
|
+
| `greener_alternative_to` | "You picked X — the greenest region within +N ms latency is Y (−Z% carbon, Δcost)." The core nudge. |
|
|
151
|
+
| `region_carbon_now` | Current gCO₂/kWh for a region, with source + timestamp + freshness. |
|
|
152
|
+
|
|
153
|
+
### Time a job (scheduling)
|
|
154
|
+
|
|
155
|
+
| Tool | What it does |
|
|
156
|
+
|------|--------------|
|
|
157
|
+
| `cleanest_hours_to_run` | Cleanest recent hours to time a deferrable job (ETL, backups, training), + % reduction. Pass `window_hours` for a job of known duration → cleanest contiguous window to start at. |
|
|
158
|
+
| `cleanest_time_of_day` | For a **recurring** job (nightly batch): the region's cleanest time of day, averaged across recent days. A daily pattern, not a 7-day weekly one. |
|
|
159
|
+
| `carbon_forecast` | Forward-looking: which **upcoming** hours will be cleanest, from the EU day-ahead wind+solar forecast (ENTSO-E). Relative ranking; US/uncovered zones degrade to the recent historical pattern. |
|
|
160
|
+
|
|
161
|
+
### Estimate a workload's carbon
|
|
162
|
+
|
|
163
|
+
| Tool | What it does |
|
|
164
|
+
|------|--------------|
|
|
165
|
+
| `estimate_workload_carbon` | Rough kgCO₂/month for a workload in a region (an *estimate*, not a measurement). |
|
|
166
|
+
| `estimate_training_carbon` | Carbon of a GPU training run (TDP-based energy × live grid), with greener **where** (region ranking) + **when** (cleanest hours) — the two levers that compound for portable, deferrable training. |
|
|
167
|
+
| `estimate_inference_carbon` | Energy + CO₂ of an LLM **inference** workload, by model size class × output tokens × requests (× live grid). A low–high band; smaller size class is the big lever. Self-hosted-friendly; not a named-model leaderboard. |
|
|
168
|
+
|
|
169
|
+
### Efficiency & guardrails
|
|
170
|
+
|
|
171
|
+
| Tool | What it does |
|
|
172
|
+
|------|--------------|
|
|
173
|
+
| `greener_instance_family` | A greener same-size family in the same region via perf-per-watt (newer generation / ARM Graviton-class does the same work on less energy). |
|
|
174
|
+
| `rightsizing_check` | Right-sizing (the #1 FinOps win) with a carbon twin: if you're over-provisioned, a smaller size cuts **both** cost and carbon → the right-sized target with monthly $ and kg CO₂ saving. |
|
|
175
|
+
| `data_locality_egress_check` | Warn when running compute away from where your data lives backfires: directional egress $ + coarse transfer carbon, and whether a greener-region move is still a net win. |
|
|
176
|
+
| `serving_pattern_advice` | For a user-facing platform: serve from one region or several? Traffic-weighted latency + carbon, with the multi-region data-sync egress and cross-jurisdiction residency catches. |
|
|
177
|
+
|
|
178
|
+
### Instrument & understand
|
|
179
|
+
|
|
180
|
+
| Tool | What it does |
|
|
181
|
+
|------|--------------|
|
|
182
|
+
| `carbon_metric_scaffold` | Emits paste-in instrumentation (Python) so your app reports its own **estimated** carbon over time — observable proxies × GreenPick's power model × live grid. Self-tracking, directional; not a runtime meter. |
|
|
183
|
+
| `explain_methodology_and_limits` | The assumptions and what GreenPick explicitly does **not** claim. |
|
|
184
|
+
|
|
185
|
+
## Data sources (free; swappable behind one interface)
|
|
186
|
+
|
|
187
|
+
- **EIA-930** (US balancing authorities) and **ENTSO-E** (EU zones) — live grid carbon,
|
|
188
|
+
auto-routed by region. Both also drive `cleanest_hours_to_run` from recent hourly history.
|
|
189
|
+
- **Mock** — deterministic, offline default; clearly labelled `quality: "mock"` so nothing is
|
|
190
|
+
mistaken for a real reading. Used wherever a key is missing or a region isn't covered.
|
|
191
|
+
- Cost: a **dated static pricing table** (`data/pricing.json`), refreshed from live Vantage
|
|
192
|
+
pricing via `scripts/refresh_pricing.py` using one matched method across all three clouds.
|
|
193
|
+
- Instance-family efficiency: directional perf-per-watt multipliers (`data/instance_families.json`).
|
|
194
|
+
- Latency: great-circle distance from region coordinates to the user's location.
|
|
195
|
+
|
|
196
|
+
Set `EIA_API_KEY` and `ENTSOE_TOKEN` in `.env` (both free) for live carbon; `GREENPICK_CARBON_SOURCE`
|
|
197
|
+
selects the source (`auto` routes US→EIA, EU→ENTSO-E, else mock).
|
|
198
|
+
|
|
199
|
+
The data layer is a swappable repository (`MOCK` by default, works offline). Nothing here invents
|
|
200
|
+
numbers: the LLM writes the *rationale*, the code supplies the *figures*.
|
|
201
|
+
|
|
202
|
+
## Honest limitations (shipped in the tool itself)
|
|
203
|
+
|
|
204
|
+
Directional, not audited. Region→grid-zone mapping is approximate. Carbon is point-in-time, not
|
|
205
|
+
flow-traced consumption. Cost is a ballpark, not a quote. Latency is a geographic estimate.
|
|
206
|
+
"Greener" assumes grid intensity dominates and ignores embodied/hardware carbon and provider RECs.
|
|
207
|
+
|
|
208
|
+
## Quick start
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# Python 3.11+
|
|
212
|
+
pip install greenpick # from PyPI
|
|
213
|
+
python -m greenpick # run the MCP server (stdio)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Or from source, for development (editable install + tests):
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
git clone https://github.com/bithug01/greenpick.git
|
|
220
|
+
cd greenpick
|
|
221
|
+
pip install -e ".[dev]"
|
|
222
|
+
cp .env.example .env # defaults to mock data — works offline
|
|
223
|
+
python -m greenpick # run the MCP server (stdio)
|
|
224
|
+
pytest # run tests
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Connect it to an MCP client (e.g. Kiro / Claude Code / Cursor) by pointing the client at
|
|
228
|
+
`python -m greenpick` in this directory. See `.env.example` for switching the data source.
|
|
229
|
+
|
|
230
|
+
## FAQ
|
|
231
|
+
|
|
232
|
+
**Do I need API keys?** No — GreenPick runs on clearly-labelled mock data out of the box. For *live*
|
|
233
|
+
carbon, set two free keys in `.env` (`EIA_API_KEY` for US, `ENTSOE_TOKEN` for EU) and
|
|
234
|
+
`GREENPICK_CARBON_SOURCE=auto`. Without them it still works; it just says `quality: "mock"`.
|
|
235
|
+
|
|
236
|
+
**Why "directional" and not audited numbers?** Because it's for a *design-time decision*, not a
|
|
237
|
+
compliance report. "Stockholm is ~30× cleaner than Sydney" is what you need to pick a region in
|
|
238
|
+
seconds — a certified figure is a different job for a different tool (Electricity Maps, WattTime).
|
|
239
|
+
GreenPick is for *decisions*, not *disclosures*, and says so in every tool's limitations.
|
|
240
|
+
|
|
241
|
+
**My cloud says this region is already 100% renewable — so does region even matter?** That's
|
|
242
|
+
*market-based* accounting (the provider matches usage with renewable certificates/PPAs over a year).
|
|
243
|
+
GreenPick uses *location-based* accounting — the actual carbon intensity of the grid you physically
|
|
244
|
+
draw from, hour to hour. Both are legitimate (the GHG Protocol asks for both), and they answer
|
|
245
|
+
different questions: market-based is about procurement claims; location-based is about the real grid
|
|
246
|
+
your workload leans on right now. GreenPick is deliberately location-based because that's what a
|
|
247
|
+
*placement/timing* decision actually affects — you can't change the provider's annual REC portfolio,
|
|
248
|
+
but you *can* choose a cleaner grid or a cleaner hour. We ignore RECs by design, not oversight.
|
|
249
|
+
|
|
250
|
+
**What happens for a region with no live data?** It falls back to the recent historical pattern or
|
|
251
|
+
to mock, and labels which — it never presents a fallback as a live reading. Forecast likewise degrades
|
|
252
|
+
to historical (labelled) where no day-ahead feed exists (e.g. US).
|
|
253
|
+
|
|
254
|
+
**Can it rank Claude vs GPT vs Llama for carbon?** No, by design. `estimate_inference_carbon` works by
|
|
255
|
+
model *size class* (self-hosted-friendly), not a named-model leaderboard — vendors don't disclose the
|
|
256
|
+
serving details that would make such a ranking honest.
|
|
257
|
+
|
|
258
|
+
**How do I ask it something?** You don't call tools directly — you talk to your MCP client in plain
|
|
259
|
+
language ("where's the greenest region to run this?") and it invokes the right tool. See the
|
|
260
|
+
[demo](docs/demo.md) for the kinds of questions that trigger each one.
|
|
261
|
+
|
|
262
|
+
## Contributing
|
|
263
|
+
|
|
264
|
+
Contributions of any kind are welcome — a bug report, a data-source correction, a sharper caveat, or
|
|
265
|
+
code. See [CONTRIBUTING.md](CONTRIBUTING.md) for the short version. The one thing GreenPick asks:
|
|
266
|
+
keep it **honest and directional** — no invented numbers, no precision the data can't back (that
|
|
267
|
+
discipline is the whole point).
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
MIT — see [LICENSE](LICENSE). © 2026 Data Science Advisers, LLC.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/img/logo.svg" alt="GreenPick logo — a leaf whose veins are circuit traces" width="120" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">GreenPick</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>Write greener, cheaper cloud infrastructure — before you deploy.</strong></p>
|
|
8
|
+
|
|
9
|
+
<!-- mcp-name: io.github.bithug01/greenpick -->
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<img src="https://img.shields.io/pypi/v/greenpick" alt="PyPI version" />
|
|
14
|
+
<img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT" />
|
|
15
|
+
<img src="https://img.shields.io/badge/tests-passing-brightgreen" alt="Tests: passing" />
|
|
16
|
+
<img src="https://img.shields.io/badge/python-3.11%2B-blue" alt="Python 3.11+" />
|
|
17
|
+
<img src="https://img.shields.io/badge/MCP%20tools-15-0ea5e9" alt="MCP tools: 15" />
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
A **design-time sustainability co-pilot** that runs as an MCP server inside your vibe-coding
|
|
21
|
+
environment (Cursor / Claude Code / Kiro). Ask it where to deploy, when to run a job, or how to
|
|
22
|
+
right-size — and it answers with an honest **carbon + cost + latency** tradeoff, in-editor, in
|
|
23
|
+
seconds. (It responds when you ask; auto-nudging on infra-code changes is on the roadmap.)
|
|
24
|
+
|
|
25
|
+
> **Status: working — 15 tools.** Live carbon for US (EIA-930) and EU (ENTSO-E), cross-cloud cost
|
|
26
|
+
> parity (Vantage-refreshed), per-axis R/Y/G ratings, carbon-aware scheduling + day-ahead forecast,
|
|
27
|
+
> GPU-training **and LLM-inference** carbon, right-sizing, serving-pattern and data-locality/residency
|
|
28
|
+
> checks — all shipped. Falls back to clearly-labelled mock data offline or without API keys.
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="docs/img/region-carbon-30x.svg" alt="Same H100 training run, ~30× the carbon depending only on region (Stockholm vs Sydney)" width="560" />
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
*The same 40-GPU-hour training run emits ~0.7 kg CO₂ in Stockholm vs ~19 kg in Sydney — a ~30×
|
|
35
|
+
difference from region choice alone. Ask GreenPick and it surfaces that (with the cost and latency
|
|
36
|
+
tradeoff) while you're still in the editor, before you commit.*
|
|
37
|
+
|
|
38
|
+
**▶ [See the 5-minute demo](docs/demo.md)** — three scenarios with real tool output (training placement, the egress backfire, the forecast).
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- 🧮 **Right-sizing that cuts cost *and* carbon together** — the FinOps win with a carbon twin. The money saved is the reason to run it; the carbon comes free.
|
|
43
|
+
- ⏱ **Carbon-aware scheduling** — run deferrable jobs (ETL, batch, training) when the grid is cleanest, now or day-ahead. A decision you make for *every* recurring job.
|
|
44
|
+
- ⚡ **GPU training & LLM inference carbon** — estimate a run's footprint and the greener *where* + *when*; the size/placement choices that actually move the number.
|
|
45
|
+
- 🌍 **Greener region picks** — ranked by carbon, with the cost + latency tradeoff shown, not hidden.
|
|
46
|
+
- 🛡 **Backfire guards** — flags when a greener move loses to egress, or crosses a data-residency line.
|
|
47
|
+
- 🔌 **Live US + EU grid data**, honest mock fallback — **no API keys required to start**.
|
|
48
|
+
|
|
49
|
+
## Contents
|
|
50
|
+
|
|
51
|
+
- [Why this exists](#why-this-exists)
|
|
52
|
+
- [What it is / is NOT](#what-it-is--is-not) · [How it differs](#how-it-differs-from-whats-out-there)
|
|
53
|
+
- [Scope](#scope)
|
|
54
|
+
- [MCP tools](#mcp-tools)
|
|
55
|
+
- [Data sources](#data-sources-free-swappable-behind-one-interface)
|
|
56
|
+
- [Honest limitations](#honest-limitations-shipped-in-the-tool-itself)
|
|
57
|
+
- [Quick start](#quick-start)
|
|
58
|
+
- [FAQ](#faq)
|
|
59
|
+
- [Contributing](#contributing)
|
|
60
|
+
- [License](#license)
|
|
61
|
+
|
|
62
|
+
## Why this exists
|
|
63
|
+
|
|
64
|
+
The same web service emits very different CO₂ depending on **which region** it runs in, because
|
|
65
|
+
electricity grids differ in carbon intensity. Existing tools either rank regions in the abstract,
|
|
66
|
+
or measure carbon *after* you deploy. GreenPick does it **at the moment you choose**, and tells you
|
|
67
|
+
what the greener choice *costs you* in latency and dollars — so you can accept or reject it with
|
|
68
|
+
eyes open.
|
|
69
|
+
|
|
70
|
+
## What it is / is NOT
|
|
71
|
+
|
|
72
|
+
- **IS:** directional "greener choice" guidance for a developer picking a cloud region while
|
|
73
|
+
building. Guidance, with tradeoffs stated.
|
|
74
|
+
- **IS NOT:** audited carbon accounting, ESG/Scope-2 reporting, or a real-time scheduler.
|
|
75
|
+
GreenPick does **not** claim GHG-Protocol or ISO compliance — that's what the paid data vendors
|
|
76
|
+
(Electricity Maps, WattTime) provide. GreenPick is for *decisions*, not *disclosures*.
|
|
77
|
+
|
|
78
|
+
### How it differs from what's out there
|
|
79
|
+
|
|
80
|
+
- **Measurement tools** (Cloud Carbon Footprint, CodeCarbon, Kepler) report what you *already*
|
|
81
|
+
emitted, *after* you deploy. GreenPick advises *before* — at the choice.
|
|
82
|
+
- **Cloud providers' own tools** (AWS CCFT, Azure, Google's "Low CO₂" region labels) cover *one*
|
|
83
|
+
cloud and show carbon alone. GreenPick is **cross-cloud** and weighs carbon **against cost and
|
|
84
|
+
latency** so you see the tradeoff, not just a green badge.
|
|
85
|
+
- **CI/CD carbon tools** act at merge time on a pipeline job. GreenPick works earlier, in the
|
|
86
|
+
editor, across more decisions (scheduling, right-sizing, training/inference, egress & residency).
|
|
87
|
+
- **Grid-data SDKs** (Electricity Maps, WattTime, GSF Carbon Aware SDK) are building blocks;
|
|
88
|
+
GreenPick is the decision layer on top of that kind of data.
|
|
89
|
+
|
|
90
|
+
The combination — **cross-cloud, carbon + cost + latency, at design time, in the editor, with
|
|
91
|
+
backfire guards** — is the part nothing else puts together.
|
|
92
|
+
|
|
93
|
+
## Scope
|
|
94
|
+
|
|
95
|
+
- Providers: **AWS, GCP, Azure** regions.
|
|
96
|
+
- Workloads: long-running **web/API services**, **GPU training** runs, and **deferrable jobs**
|
|
97
|
+
(ETL / batch / backups) — placement and timing for each.
|
|
98
|
+
- Carbon = **grid carbon intensity by region** (directional, point-in-time; live US + EU), plus a
|
|
99
|
+
**day-ahead forecast** (EU) for forward-looking scheduling.
|
|
100
|
+
- Cost = **compute + egress ballpark** (deterministic static table, apples-to-apples across
|
|
101
|
+
clouds; never LLM-invented).
|
|
102
|
+
- Latency = **geographic estimate** to a stated user location.
|
|
103
|
+
- Efficiency levers: **greener instance family** (perf-per-watt), **right-sizing** (cost + carbon
|
|
104
|
+
together), and a **carbon-metric scaffold** to track your app over time.
|
|
105
|
+
- Guardrails: **data-locality / egress** backfire checks and **cross-jurisdiction residency** flags.
|
|
106
|
+
- **Free data only.** No flow-traced consumption accounting; carbon forecast is relative, not absolute.
|
|
107
|
+
|
|
108
|
+
Roadmap: data-format/engine efficiency advice, sub-national grid zones, CI/CD integration.
|
|
109
|
+
See `docs/user-questions-backlog.md`.
|
|
110
|
+
|
|
111
|
+
## MCP tools
|
|
112
|
+
|
|
113
|
+
15 tools, grouped by what you're trying to do.
|
|
114
|
+
|
|
115
|
+
### Pick a region
|
|
116
|
+
|
|
117
|
+
| Tool | What it does |
|
|
118
|
+
|------|--------------|
|
|
119
|
+
| `compare_regions_tri_axis` | Rank candidate regions by carbon with cost + latency tradeoffs; recommend a pick, each axis rated R/Y/G. Pass `regions` to rank only the ones you'd actually consider. |
|
|
120
|
+
| `greener_alternative_to` | "You picked X — the greenest region within +N ms latency is Y (−Z% carbon, Δcost)." The core nudge. |
|
|
121
|
+
| `region_carbon_now` | Current gCO₂/kWh for a region, with source + timestamp + freshness. |
|
|
122
|
+
|
|
123
|
+
### Time a job (scheduling)
|
|
124
|
+
|
|
125
|
+
| Tool | What it does |
|
|
126
|
+
|------|--------------|
|
|
127
|
+
| `cleanest_hours_to_run` | Cleanest recent hours to time a deferrable job (ETL, backups, training), + % reduction. Pass `window_hours` for a job of known duration → cleanest contiguous window to start at. |
|
|
128
|
+
| `cleanest_time_of_day` | For a **recurring** job (nightly batch): the region's cleanest time of day, averaged across recent days. A daily pattern, not a 7-day weekly one. |
|
|
129
|
+
| `carbon_forecast` | Forward-looking: which **upcoming** hours will be cleanest, from the EU day-ahead wind+solar forecast (ENTSO-E). Relative ranking; US/uncovered zones degrade to the recent historical pattern. |
|
|
130
|
+
|
|
131
|
+
### Estimate a workload's carbon
|
|
132
|
+
|
|
133
|
+
| Tool | What it does |
|
|
134
|
+
|------|--------------|
|
|
135
|
+
| `estimate_workload_carbon` | Rough kgCO₂/month for a workload in a region (an *estimate*, not a measurement). |
|
|
136
|
+
| `estimate_training_carbon` | Carbon of a GPU training run (TDP-based energy × live grid), with greener **where** (region ranking) + **when** (cleanest hours) — the two levers that compound for portable, deferrable training. |
|
|
137
|
+
| `estimate_inference_carbon` | Energy + CO₂ of an LLM **inference** workload, by model size class × output tokens × requests (× live grid). A low–high band; smaller size class is the big lever. Self-hosted-friendly; not a named-model leaderboard. |
|
|
138
|
+
|
|
139
|
+
### Efficiency & guardrails
|
|
140
|
+
|
|
141
|
+
| Tool | What it does |
|
|
142
|
+
|------|--------------|
|
|
143
|
+
| `greener_instance_family` | A greener same-size family in the same region via perf-per-watt (newer generation / ARM Graviton-class does the same work on less energy). |
|
|
144
|
+
| `rightsizing_check` | Right-sizing (the #1 FinOps win) with a carbon twin: if you're over-provisioned, a smaller size cuts **both** cost and carbon → the right-sized target with monthly $ and kg CO₂ saving. |
|
|
145
|
+
| `data_locality_egress_check` | Warn when running compute away from where your data lives backfires: directional egress $ + coarse transfer carbon, and whether a greener-region move is still a net win. |
|
|
146
|
+
| `serving_pattern_advice` | For a user-facing platform: serve from one region or several? Traffic-weighted latency + carbon, with the multi-region data-sync egress and cross-jurisdiction residency catches. |
|
|
147
|
+
|
|
148
|
+
### Instrument & understand
|
|
149
|
+
|
|
150
|
+
| Tool | What it does |
|
|
151
|
+
|------|--------------|
|
|
152
|
+
| `carbon_metric_scaffold` | Emits paste-in instrumentation (Python) so your app reports its own **estimated** carbon over time — observable proxies × GreenPick's power model × live grid. Self-tracking, directional; not a runtime meter. |
|
|
153
|
+
| `explain_methodology_and_limits` | The assumptions and what GreenPick explicitly does **not** claim. |
|
|
154
|
+
|
|
155
|
+
## Data sources (free; swappable behind one interface)
|
|
156
|
+
|
|
157
|
+
- **EIA-930** (US balancing authorities) and **ENTSO-E** (EU zones) — live grid carbon,
|
|
158
|
+
auto-routed by region. Both also drive `cleanest_hours_to_run` from recent hourly history.
|
|
159
|
+
- **Mock** — deterministic, offline default; clearly labelled `quality: "mock"` so nothing is
|
|
160
|
+
mistaken for a real reading. Used wherever a key is missing or a region isn't covered.
|
|
161
|
+
- Cost: a **dated static pricing table** (`data/pricing.json`), refreshed from live Vantage
|
|
162
|
+
pricing via `scripts/refresh_pricing.py` using one matched method across all three clouds.
|
|
163
|
+
- Instance-family efficiency: directional perf-per-watt multipliers (`data/instance_families.json`).
|
|
164
|
+
- Latency: great-circle distance from region coordinates to the user's location.
|
|
165
|
+
|
|
166
|
+
Set `EIA_API_KEY` and `ENTSOE_TOKEN` in `.env` (both free) for live carbon; `GREENPICK_CARBON_SOURCE`
|
|
167
|
+
selects the source (`auto` routes US→EIA, EU→ENTSO-E, else mock).
|
|
168
|
+
|
|
169
|
+
The data layer is a swappable repository (`MOCK` by default, works offline). Nothing here invents
|
|
170
|
+
numbers: the LLM writes the *rationale*, the code supplies the *figures*.
|
|
171
|
+
|
|
172
|
+
## Honest limitations (shipped in the tool itself)
|
|
173
|
+
|
|
174
|
+
Directional, not audited. Region→grid-zone mapping is approximate. Carbon is point-in-time, not
|
|
175
|
+
flow-traced consumption. Cost is a ballpark, not a quote. Latency is a geographic estimate.
|
|
176
|
+
"Greener" assumes grid intensity dominates and ignores embodied/hardware carbon and provider RECs.
|
|
177
|
+
|
|
178
|
+
## Quick start
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Python 3.11+
|
|
182
|
+
pip install greenpick # from PyPI
|
|
183
|
+
python -m greenpick # run the MCP server (stdio)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Or from source, for development (editable install + tests):
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git clone https://github.com/bithug01/greenpick.git
|
|
190
|
+
cd greenpick
|
|
191
|
+
pip install -e ".[dev]"
|
|
192
|
+
cp .env.example .env # defaults to mock data — works offline
|
|
193
|
+
python -m greenpick # run the MCP server (stdio)
|
|
194
|
+
pytest # run tests
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Connect it to an MCP client (e.g. Kiro / Claude Code / Cursor) by pointing the client at
|
|
198
|
+
`python -m greenpick` in this directory. See `.env.example` for switching the data source.
|
|
199
|
+
|
|
200
|
+
## FAQ
|
|
201
|
+
|
|
202
|
+
**Do I need API keys?** No — GreenPick runs on clearly-labelled mock data out of the box. For *live*
|
|
203
|
+
carbon, set two free keys in `.env` (`EIA_API_KEY` for US, `ENTSOE_TOKEN` for EU) and
|
|
204
|
+
`GREENPICK_CARBON_SOURCE=auto`. Without them it still works; it just says `quality: "mock"`.
|
|
205
|
+
|
|
206
|
+
**Why "directional" and not audited numbers?** Because it's for a *design-time decision*, not a
|
|
207
|
+
compliance report. "Stockholm is ~30× cleaner than Sydney" is what you need to pick a region in
|
|
208
|
+
seconds — a certified figure is a different job for a different tool (Electricity Maps, WattTime).
|
|
209
|
+
GreenPick is for *decisions*, not *disclosures*, and says so in every tool's limitations.
|
|
210
|
+
|
|
211
|
+
**My cloud says this region is already 100% renewable — so does region even matter?** That's
|
|
212
|
+
*market-based* accounting (the provider matches usage with renewable certificates/PPAs over a year).
|
|
213
|
+
GreenPick uses *location-based* accounting — the actual carbon intensity of the grid you physically
|
|
214
|
+
draw from, hour to hour. Both are legitimate (the GHG Protocol asks for both), and they answer
|
|
215
|
+
different questions: market-based is about procurement claims; location-based is about the real grid
|
|
216
|
+
your workload leans on right now. GreenPick is deliberately location-based because that's what a
|
|
217
|
+
*placement/timing* decision actually affects — you can't change the provider's annual REC portfolio,
|
|
218
|
+
but you *can* choose a cleaner grid or a cleaner hour. We ignore RECs by design, not oversight.
|
|
219
|
+
|
|
220
|
+
**What happens for a region with no live data?** It falls back to the recent historical pattern or
|
|
221
|
+
to mock, and labels which — it never presents a fallback as a live reading. Forecast likewise degrades
|
|
222
|
+
to historical (labelled) where no day-ahead feed exists (e.g. US).
|
|
223
|
+
|
|
224
|
+
**Can it rank Claude vs GPT vs Llama for carbon?** No, by design. `estimate_inference_carbon` works by
|
|
225
|
+
model *size class* (self-hosted-friendly), not a named-model leaderboard — vendors don't disclose the
|
|
226
|
+
serving details that would make such a ranking honest.
|
|
227
|
+
|
|
228
|
+
**How do I ask it something?** You don't call tools directly — you talk to your MCP client in plain
|
|
229
|
+
language ("where's the greenest region to run this?") and it invokes the right tool. See the
|
|
230
|
+
[demo](docs/demo.md) for the kinds of questions that trigger each one.
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
Contributions of any kind are welcome — a bug report, a data-source correction, a sharper caveat, or
|
|
235
|
+
code. See [CONTRIBUTING.md](CONTRIBUTING.md) for the short version. The one thing GreenPick asks:
|
|
236
|
+
keep it **honest and directional** — no invented numbers, no precision the data can't back (that
|
|
237
|
+
discipline is the whole point).
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT — see [LICENSE](LICENSE). © 2026 Data Science Advisers, LLC.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "greenpick"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Design-time sustainability co-pilot (MCP server): greener, cheaper cloud infrastructure decisions with carbon + cost + latency tradeoffs."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Data Science Advisers, LLC", email = "info@datascienceadvisers.com" }]
|
|
10
|
+
keywords = ["mcp", "sustainability", "carbon", "cloud", "finops", "developer-tools", "green-software"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Topic :: Software Development :: Libraries",
|
|
19
|
+
"Topic :: Scientific/Engineering",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"mcp>=1.2,<2", # Model Context Protocol SDK (FastMCP lives here). Pinned <2: mcp 2.x
|
|
23
|
+
# renamed FastMCP -> MCPServer and changed APIs; this code targets the 1.x API.
|
|
24
|
+
"pydantic>=2.0",
|
|
25
|
+
"httpx>=0.27", # async HTTP for live data sources
|
|
26
|
+
# .env is parsed by config.py with no third-party dep (avoids the python-dotenv/dotenv
|
|
27
|
+
# name-collision that silently skipped loading under some interpreters).
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest>=8.0",
|
|
33
|
+
"pytest-asyncio>=0.23",
|
|
34
|
+
"ijson>=3.0", # used only by scripts/refresh_pricing.py (not a runtime dep)
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/bithug01/greenpick"
|
|
39
|
+
Repository = "https://github.com/bithug01/greenpick"
|
|
40
|
+
Issues = "https://github.com/bithug01/greenpick/issues"
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
greenpick = "greenpick.__main__:main"
|
|
44
|
+
|
|
45
|
+
[build-system]
|
|
46
|
+
requires = ["setuptools>=77"]
|
|
47
|
+
build-backend = "setuptools.build_meta"
|
|
48
|
+
|
|
49
|
+
[tool.setuptools.packages.find]
|
|
50
|
+
where = ["src"]
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.package-data]
|
|
53
|
+
# Bundle the static JSON models into the wheel. Without this, a pip install from
|
|
54
|
+
# PyPI ships no data files and every tool fails at Path(__file__).parent / "*.json".
|
|
55
|
+
"greenpick.data" = ["*.json"]
|
|
56
|
+
|
|
57
|
+
[tool.pytest.ini_options]
|
|
58
|
+
asyncio_mode = "auto"
|
|
59
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Entry point: run the GreenPick MCP server over stdio.
|
|
2
|
+
|
|
3
|
+
python -m greenpick
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from .config import SETTINGS
|
|
9
|
+
from .server import mcp
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
logging.basicConfig(level=getattr(logging, SETTINGS.log_level, logging.INFO))
|
|
14
|
+
mcp.run() # stdio transport by default — what MCP clients expect
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == "__main__":
|
|
18
|
+
main()
|