duoops 0.2.2 → 0.2.4

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.
@@ -11,6 +11,7 @@ import { fileURLToPath } from 'node:url';
11
11
  import { configManager } from '../lib/config.js';
12
12
  import { detectGcpProject, enableApis, validateProjectAccess } from '../lib/gcloud.js';
13
13
  import McpDeploy from './mcp/deploy.js';
14
+ const gitlabAuthHeaders = (token) => token.startsWith('glpat-') ? { 'PRIVATE-TOKEN': token } : { Authorization: `Bearer ${token}` };
14
15
  const hasBinary = (command) => {
15
16
  try {
16
17
  execSync(`${command} --version`, { stdio: 'ignore' });
@@ -50,7 +51,7 @@ const setGitlabVariable = async (auth, projectPath, variable) => {
50
51
  const apiUrl = `${base}/api/v4/projects/${project}/variables`;
51
52
  await axios
52
53
  .delete(`${apiUrl}/${variable.key}`, {
53
- headers: { 'PRIVATE-TOKEN': auth.token },
54
+ headers: gitlabAuthHeaders(auth.token),
54
55
  })
55
56
  .catch(() => { });
56
57
  await axios.post(apiUrl, {
@@ -58,7 +59,7 @@ const setGitlabVariable = async (auth, projectPath, variable) => {
58
59
  masked: Boolean(variable.masked),
59
60
  protected: false,
60
61
  value: variable.value,
61
- }, { headers: { 'PRIVATE-TOKEN': auth.token } });
62
+ }, { headers: gitlabAuthHeaders(auth.token) });
62
63
  };
63
64
  const ensureServiceAccount = (projectId, serviceAccount) => {
64
65
  try {
@@ -0,0 +1,3 @@
1
+ node_modules
2
+ dist
3
+ .git
@@ -0,0 +1,27 @@
1
+ FROM node:22-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Copy package files
6
+ COPY package*.json ./
7
+
8
+ # Install dependencies
9
+ RUN npm install
10
+
11
+ # Copy source code and config
12
+ COPY tsconfig.json ./
13
+ COPY src/ ./src/
14
+ COPY data/ ./data/
15
+
16
+ # Build
17
+ RUN npm run build
18
+
19
+ # Prune dev dependencies
20
+ RUN npm prune --production
21
+
22
+ # Expose port
23
+ EXPOSE 8080
24
+ ENV PORT=8080
25
+
26
+ # Start server
27
+ CMD ["node", "dist/index.js"]
@@ -0,0 +1,70 @@
1
+ # DuoOps MCP Server
2
+
3
+ This is a **Model Context Protocol (MCP)** server that exposes DuoOps carbon emissions data from BigQuery to AI agents like GitLab Duo Chat.
4
+
5
+ It allows developers to ask natural language questions like:
6
+ - "What was the carbon footprint of pipeline 12345?"
7
+ - "How do emissions compare for the last 10 builds?"
8
+ - "What is the power profile of an e2-standard-4 machine?"
9
+
10
+ ## Tools
11
+
12
+ - `get_job_emissions`: Retrieve emissions for a specific CI job
13
+ - `get_pipeline_emissions`: Retrieve aggregated emissions for a pipeline
14
+ - `get_project_emissions_summary`: Get emissions trends for a project
15
+ - `get_machine_profile`: Look up specs and power data for cloud instances
16
+ - `get_region_carbon_intensity`: Check grid carbon intensity for a region
17
+
18
+ ## Deployment
19
+
20
+ Deploy to Google Cloud Run:
21
+
22
+ ```bash
23
+ # Using the DuoOps CLI (recommended)
24
+ duoops mcp deploy --gcp-project <PROJECT_ID> --region us-central1
25
+
26
+ # OR manually with gcloud
27
+ gcloud run deploy duoops-mcp \
28
+ --image registry.gitlab.com/youneslaaroussi/duoops/mcp-server:latest \
29
+ --set-env-vars "GCP_PROJECT_ID=<PROJECT_ID>,BQ_DATASET=<DATASET>,BQ_TABLE=<TABLE>" \
30
+ --allow-unauthenticated \
31
+ --region us-central1
32
+ ```
33
+
34
+ ## Configuration in GitLab
35
+
36
+ Add this to your project's `.gitlab/duo/mcp.json`:
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "duoops-carbon": {
42
+ "type": "http",
43
+ "url": "https://<your-cloud-run-url>/mcp",
44
+ "approvedTools": true
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ Or if using `mcp-remote` bridge (for stdio-only clients):
51
+
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "duoops-carbon": {
56
+ "type": "stdio",
57
+ "command": "npx",
58
+ "args": ["mcp-remote", "https://<your-cloud-run-url>/mcp"],
59
+ "approvedTools": true
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Authentication
66
+
67
+ Auth is handled via **OAuth 2.0 Dynamic Client Registration** with GitLab.
68
+ 1. When Duo Chat connects, the server requests auth.
69
+ 2. GitLab handles the OAuth flow in your browser.
70
+ 3. Your identity is verified against the GitLab API.
@@ -0,0 +1,54 @@
1
+ {
2
+ "m5.large": {
3
+ "vcpus": 2,
4
+ "memory_gb": 8,
5
+ "platform_cpu": "Intel Xeon Platinum 8175",
6
+ "matched_cpu_profile": "Intel Xeon Platinum 8175",
7
+ "cpu_power_profile": [
8
+ { "percentage": 0, "watts": 11.5 },
9
+ { "percentage": 10, "watts": 23.0 },
10
+ { "percentage": 50, "watts": 82.0 },
11
+ { "percentage": 100, "watts": 150.0 }
12
+ ],
13
+ "scope3_emissions_hourly": 18
14
+ },
15
+ "c5.xlarge": {
16
+ "vcpus": 4,
17
+ "memory_gb": 8,
18
+ "platform_cpu": "Intel Xeon Platinum 8275",
19
+ "matched_cpu_profile": "Intel Xeon Platinum 8275",
20
+ "cpu_power_profile": [
21
+ { "percentage": 0, "watts": 14.0 },
22
+ { "percentage": 10, "watts": 33.0 },
23
+ { "percentage": 50, "watts": 115.0 },
24
+ { "percentage": 100, "watts": 195.0 }
25
+ ],
26
+ "scope3_emissions_hourly": 22
27
+ },
28
+ "m6g.large": {
29
+ "vcpus": 2,
30
+ "memory_gb": 8,
31
+ "platform_cpu": "AWS Graviton2",
32
+ "matched_cpu_profile": "AWS Graviton2",
33
+ "cpu_power_profile": [
34
+ { "percentage": 0, "watts": 8.0 },
35
+ { "percentage": 10, "watts": 16.0 },
36
+ { "percentage": 50, "watts": 55.0 },
37
+ { "percentage": 100, "watts": 95.0 }
38
+ ],
39
+ "scope3_emissions_hourly": 15
40
+ },
41
+ "r6i.2xlarge": {
42
+ "vcpus": 8,
43
+ "memory_gb": 64,
44
+ "platform_cpu": "Intel Xeon Ice Lake",
45
+ "matched_cpu_profile": "Intel Xeon Ice Lake",
46
+ "cpu_power_profile": [
47
+ { "percentage": 0, "watts": 26.0 },
48
+ { "percentage": 10, "watts": 52.0 },
49
+ { "percentage": 50, "watts": 200.0 },
50
+ { "percentage": 100, "watts": 360.0 }
51
+ ],
52
+ "scope3_emissions_hourly": 42
53
+ }
54
+ }
@@ -0,0 +1,105 @@
1
+ {
2
+ "_metadata": {
3
+ "description": "Physical CPU specifications with vCPU counts for accurate power-per-vCPU calculations",
4
+ "last_updated": "2025-01-22",
5
+ "methodology": "Power per VM vCPU = (TDP / physical_vcpus) * vm_vcpus * utilization_ratio"
6
+ },
7
+ "Intel Xeon Gold 6268CL": {
8
+ "cores": 24,
9
+ "threads": 48,
10
+ "tdp_watts": 205,
11
+ "architecture": "Cascade Lake",
12
+ "source": "https://www.ebay.com/p/2321792675",
13
+ "source_name": "eBay Product Listing (SRF80)"
14
+ },
15
+ "Intel Xeon Gold 6253CL": {
16
+ "cores": 18,
17
+ "threads": 36,
18
+ "tdp_watts": 205,
19
+ "architecture": "Cascade Lake",
20
+ "source": "https://www.cpubenchmark.net/cpu.php?cpu=Intel+Xeon+Gold+6253CL+@+3.10GHz&id=4539",
21
+ "source_name": "PassMark CPU Benchmark"
22
+ },
23
+ "Intel Xeon Platinum 8481C": {
24
+ "cores": 56,
25
+ "threads": 112,
26
+ "tdp_watts": 350,
27
+ "architecture": "Sapphire Rapids",
28
+ "source": "https://www.techpowerup.com/cpu-specs/xeon-platinum-8481c.c3992",
29
+ "source_name": "TechPowerUp CPU Database"
30
+ },
31
+ "Intel Xeon Platinum 8373C": {
32
+ "cores": 36,
33
+ "threads": 72,
34
+ "tdp_watts": 300,
35
+ "architecture": "Ice Lake",
36
+ "source": "https://en.wikipedia.org/wiki/List_of_Intel_Xeon_processors_(Ice_Lake-based)",
37
+ "source_name": "Wikipedia - Intel Xeon Ice Lake"
38
+ },
39
+ "Intel Xeon Platinum 8280L": {
40
+ "cores": 28,
41
+ "threads": 56,
42
+ "tdp_watts": 205,
43
+ "architecture": "Cascade Lake",
44
+ "source": "https://ark.intel.com/content/www/us/en/ark/products/192472/intel-xeon-platinum-8280l-processor-38-5m-cache-2-70-ghz.html",
45
+ "source_name": "Intel ARK"
46
+ },
47
+ "Intel Xeon Platinum 8273CL": {
48
+ "cores": 28,
49
+ "threads": 56,
50
+ "tdp_watts": 165,
51
+ "architecture": "Cascade Lake",
52
+ "source": "https://en.wikipedia.org/wiki/List_of_Intel_Xeon_processors_(Cascade_Lake-based)",
53
+ "source_name": "Wikipedia - Intel Xeon Cascade Lake"
54
+ },
55
+ "Intel Xeon Scalable Platinum 8173M": {
56
+ "cores": 28,
57
+ "threads": 56,
58
+ "tdp_watts": 165,
59
+ "architecture": "Skylake",
60
+ "source": "https://en.wikipedia.org/wiki/List_of_Intel_Xeon_processors#702Skylake-based_703Xeon_Scalable",
61
+ "source_name": "Wikipedia - Intel Xeon Skylake"
62
+ },
63
+ "Intel Skylake": {
64
+ "cores": 28,
65
+ "threads": 56,
66
+ "tdp_watts": 150,
67
+ "architecture": "Skylake",
68
+ "source": "https://cloud.google.com/compute/docs/cpu-platforms",
69
+ "source_name": "Google Cloud CPU Platforms",
70
+ "note": "Generic Skylake profile for e2 instances, estimated from typical Skylake server CPUs"
71
+ },
72
+ "Intel Xeon E7-8880V4": {
73
+ "cores": 22,
74
+ "threads": 44,
75
+ "tdp_watts": 150,
76
+ "architecture": "Broadwell",
77
+ "source": "https://www.intel.com/content/www/us/en/products/sku/93792/intel-xeon-processor-e78880-v4-55m-cache-2-20-ghz/specifications.html",
78
+ "source_name": "Intel ARK"
79
+ },
80
+ "AMD EPYC 7B12": {
81
+ "cores": 64,
82
+ "threads": 128,
83
+ "tdp_watts": 240,
84
+ "architecture": "Rome (Zen 2)",
85
+ "source": "https://www.newegg.com/p/1FR-00G6-00026",
86
+ "source_name": "Newegg Product Listing"
87
+ },
88
+ "AMD EPYC 7B13": {
89
+ "cores": 64,
90
+ "threads": 128,
91
+ "tdp_watts": 225,
92
+ "architecture": "Milan (Zen 3)",
93
+ "source": "https://www.amd.com/en/products/cpu/amd-epyc-7b13",
94
+ "source_name": "AMD Product Page"
95
+ },
96
+ "Q64-30": {
97
+ "cores": 64,
98
+ "threads": 64,
99
+ "tdp_watts": 180,
100
+ "architecture": "ARM Neoverse N1",
101
+ "source": "https://amperecomputing.com/en/briefs/ampere-altra-family-product-brief",
102
+ "source_name": "Ampere Altra Family Product Brief",
103
+ "note": "ARM cores have no hyperthreading, threads = cores"
104
+ }
105
+ }
@@ -0,0 +1,275 @@
1
+ {
2
+ "AMD EPYC 7B12": {
3
+ "tdp_watts": 240.0,
4
+ "power_profile": [
5
+ {
6
+ "percentage": 0,
7
+ "watts": 4.08
8
+ },
9
+ {
10
+ "percentage": 10,
11
+ "watts": 8.16
12
+ },
13
+ {
14
+ "percentage": 50,
15
+ "watts": 40.56
16
+ },
17
+ {
18
+ "percentage": 100,
19
+ "watts": 240.0
20
+ }
21
+ ]
22
+ },
23
+ "Intel Xeon E5-2689": {
24
+ "tdp_watts": 115.0,
25
+ "power_profile": [
26
+ {
27
+ "percentage": 0,
28
+ "watts": 2.07
29
+ },
30
+ {
31
+ "percentage": 10,
32
+ "watts": 4.14
33
+ },
34
+ {
35
+ "percentage": 50,
36
+ "watts": 20.47
37
+ },
38
+ {
39
+ "percentage": 100,
40
+ "watts": 115.0
41
+ }
42
+ ]
43
+ },
44
+ "Intel Xeon E5-2696V3": {
45
+ "tdp_watts": 145.0,
46
+ "power_profile": [
47
+ {
48
+ "percentage": 0,
49
+ "watts": 2.61
50
+ },
51
+ {
52
+ "percentage": 10,
53
+ "watts": 5.22
54
+ },
55
+ {
56
+ "percentage": 50,
57
+ "watts": 25.81
58
+ },
59
+ {
60
+ "percentage": 100,
61
+ "watts": 145.0
62
+ }
63
+ ]
64
+ },
65
+ "Intel Xeon E5-2696V4": {
66
+ "tdp_watts": 150.0,
67
+ "power_profile": [
68
+ {
69
+ "percentage": 0,
70
+ "watts": 2.5500000000000003
71
+ },
72
+ {
73
+ "percentage": 10,
74
+ "watts": 5.1000000000000005
75
+ },
76
+ {
77
+ "percentage": 50,
78
+ "watts": 25.35
79
+ },
80
+ {
81
+ "percentage": 100,
82
+ "watts": 150.0
83
+ }
84
+ ]
85
+ },
86
+ "Intel Xeon E7-8880V4": {
87
+ "tdp_watts": 150.0,
88
+ "power_profile": [
89
+ {
90
+ "percentage": 0,
91
+ "watts": 2.6999999999999997
92
+ },
93
+ {
94
+ "percentage": 10,
95
+ "watts": 5.3999999999999995
96
+ },
97
+ {
98
+ "percentage": 50,
99
+ "watts": 26.7
100
+ },
101
+ {
102
+ "percentage": 100,
103
+ "watts": 150.0
104
+ }
105
+ ]
106
+ },
107
+ "Intel Xeon Gold 6253CL": {
108
+ "tdp_watts": 205.0,
109
+ "power_profile": [
110
+ {
111
+ "percentage": 0,
112
+ "watts": 3.4850000000000003
113
+ },
114
+ {
115
+ "percentage": 10,
116
+ "watts": 6.970000000000001
117
+ },
118
+ {
119
+ "percentage": 50,
120
+ "watts": 34.645
121
+ },
122
+ {
123
+ "percentage": 100,
124
+ "watts": 205.0
125
+ }
126
+ ]
127
+ },
128
+ "Intel Xeon Gold 6268CL": {
129
+ "tdp_watts": 205.0,
130
+ "power_profile": [
131
+ {
132
+ "percentage": 0,
133
+ "watts": 3.4850000000000003
134
+ },
135
+ {
136
+ "percentage": 10,
137
+ "watts": 6.970000000000001
138
+ },
139
+ {
140
+ "percentage": 50,
141
+ "watts": 34.645
142
+ },
143
+ {
144
+ "percentage": 100,
145
+ "watts": 205.0
146
+ }
147
+ ]
148
+ },
149
+ "Intel Xeon Platinum 8273CL": {
150
+ "tdp_watts": 165.0,
151
+ "power_profile": [
152
+ {
153
+ "percentage": 0,
154
+ "watts": 2.805
155
+ },
156
+ {
157
+ "percentage": 10,
158
+ "watts": 5.61
159
+ },
160
+ {
161
+ "percentage": 50,
162
+ "watts": 27.885
163
+ },
164
+ {
165
+ "percentage": 100,
166
+ "watts": 165.0
167
+ }
168
+ ]
169
+ },
170
+ "Intel Xeon Platinum 8280L": {
171
+ "tdp_watts": 205.0,
172
+ "power_profile": [
173
+ {
174
+ "percentage": 0,
175
+ "watts": 3.4850000000000003
176
+ },
177
+ {
178
+ "percentage": 10,
179
+ "watts": 6.970000000000001
180
+ },
181
+ {
182
+ "percentage": 50,
183
+ "watts": 34.645
184
+ },
185
+ {
186
+ "percentage": 100,
187
+ "watts": 205.0
188
+ }
189
+ ]
190
+ },
191
+ "Intel Xeon Platinum 8373C": {
192
+ "tdp_watts": 300.0,
193
+ "power_profile": [
194
+ {
195
+ "percentage": 0,
196
+ "watts": 5.1000000000000005
197
+ },
198
+ {
199
+ "percentage": 10,
200
+ "watts": 10.200000000000001
201
+ },
202
+ {
203
+ "percentage": 50,
204
+ "watts": 50.7
205
+ },
206
+ {
207
+ "percentage": 100,
208
+ "watts": 300.0
209
+ }
210
+ ]
211
+ },
212
+ "Intel Xeon Platinum 8481C": {
213
+ "tdp_watts": 350.0,
214
+ "power_profile": [
215
+ {
216
+ "percentage": 0,
217
+ "watts": 4.9
218
+ },
219
+ {
220
+ "percentage": 10,
221
+ "watts": 9.8
222
+ },
223
+ {
224
+ "percentage": 50,
225
+ "watts": 49.349999999999994
226
+ },
227
+ {
228
+ "percentage": 100,
229
+ "watts": 350.0
230
+ }
231
+ ]
232
+ },
233
+ "Intel Xeon Scalable Platinum 8173M": {
234
+ "tdp_watts": 165.0,
235
+ "power_profile": [
236
+ {
237
+ "percentage": 0,
238
+ "watts": 2.805
239
+ },
240
+ {
241
+ "percentage": 10,
242
+ "watts": 5.61
243
+ },
244
+ {
245
+ "percentage": 50,
246
+ "watts": 27.885
247
+ },
248
+ {
249
+ "percentage": 100,
250
+ "watts": 165.0
251
+ }
252
+ ]
253
+ },
254
+ "Q64-30": {
255
+ "tdp_watts": 180.0,
256
+ "power_profile": [
257
+ {
258
+ "percentage": 0,
259
+ "watts": 3.06
260
+ },
261
+ {
262
+ "percentage": 10,
263
+ "watts": 6.12
264
+ },
265
+ {
266
+ "percentage": 50,
267
+ "watts": 30.42
268
+ },
269
+ {
270
+ "percentage": 100,
271
+ "watts": 180.0
272
+ }
273
+ ]
274
+ }
275
+ }