yazio-mcp 0.0.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Artur Kornakov
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.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Yazio MCP Server <img src="https://assets.yazio.com/frontend/images/yazio-logo.svg" alt="Yazio Logo" width="60" height="60" />
2
+
3
+ > [!IMPORTANT]
4
+ > This is **not an official MCP server** and Yazio does **not provide an official API**.
5
+ > This server uses an [unofficial reverse-engineered API](https://github.com/juriadams/yazio) and may stop working at any time.
6
+
7
+ An MCP (Model Context Protocol) server that connects Claude/Cursor to your Yazio nutrition data. Track your diet, search food products, and manage your nutrition goals directly from your AI assistant.
8
+
9
+ **Available on NPM**: `npx yazio-mcp`
10
+
11
+ ## ✨ Features
12
+
13
+ - 🔐 **Authentication** - Connect with your Yazio account
14
+ - 📊 **Nutrition Analysis** - Get comprehensive diet data and insights
15
+ - 🍎 **Food Tracking** - Search, add, and manage food entries
16
+ - 🏃‍♂️ **Fitness Data** - Track exercises and water intake
17
+ - ⚖️ **Weight Monitoring** - View weight history and trends
18
+ - 🎯 **Goal Management** - Access and manage nutrition goals
19
+ - 🔍 **Product Search** - Search Yazio's extensive food database
20
+
21
+ ## 🚀 Quick Start
22
+
23
+ Add to your MCP client configuration:
24
+
25
+ **Claude Desktop**: `~/Library/Application Support/Claude/claude_desktop_config.json`
26
+
27
+ **Cursor**: Your Cursor MCP configuration file
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "yazio-mcp": {
33
+ "command": "npx yazio-mcp",
34
+ "env": {
35
+ "YAZIO_USERNAME": "your-email@example.com",
36
+ "YAZIO_PASSWORD": "your-password"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## 💡 Use Cases
44
+
45
+ ### 📈 Analyze Your Nutrition Trends
46
+ > *"Get my nutrition data for the last week and analyze my eating patterns"*
47
+
48
+ Claude can retrieve your daily summaries, identify trends, and provide insights about your eating habits, macro distribution, and areas for improvement.
49
+
50
+ ### 🔍 Search Food Products
51
+ > *"Search for 'chicken breast' in the Yazio database"*
52
+
53
+ Find detailed nutritional information for any food product, including calories, macros, vitamins, and minerals.
54
+
55
+ ### 📝 Add Forgotten Meals
56
+ > *"Add 200g of grilled salmon for yesterday's dinner"*
57
+
58
+ Easily log meals you forgot to track in the Yazio app directly from Claude or Cursor.
59
+
60
+ ## 🛠️ Available Tools
61
+
62
+ | Tool | Description | Key Parameters |
63
+ |------|-------------|----------------|
64
+ | `get_user_daily_summary` | Get daily nutrition summary | `date` |
65
+ | `get_user_consumed_items` | Get food entries for a date | `date` |
66
+ | `get_user_weight` | Get weight data | - |
67
+ | `get_user_exercises` | Get exercise data | `date` |
68
+ | `get_user_water_intake` | Get water intake | `date` |
69
+ | `get_user_goals` | Get nutrition goals | - |
70
+ | `get_user_settings` | Get user preferences | - |
71
+ | `search_products` | Search food database | `query` |
72
+ | `get_product` | Get detailed product info | `id` |
73
+ | `add_user_consumed_item` | Add food to your log | `productId`, `amount`, `date`, `mealType` |
74
+ | `remove_user_consumed_item` | Remove food from log | `itemId` |
75
+
76
+ ## Test Connection
77
+
78
+ ```bash
79
+ YAZIO_USERNAME=your_email YAZIO_PASSWORD=your_password npx yazio-mcp
80
+ ```
81
+
82
+ ## ⚠️ Important Disclaimers
83
+
84
+ - **Unofficial API**: This uses a [reverse-engineered API](https://github.com/juriadams/yazio) that may break
85
+ - **Credentials**: Your Yazio credentials are only used for auth on Yazio servers
86
+ - **Use at Your Own Risk**: API changes could affect functionality
87
+
88
+ ## 📋 Requirements
89
+
90
+ - Node.js 18+ (for npx)
91
+ - Valid Yazio account
92
+ - MCP-compatible client (Claude Desktop, Cursor, etc.)
93
+
94
+ ---
95
+
96
+ ## 📄 License
97
+
98
+ MIT License - see [LICENSE](LICENSE) file for details.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,495 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
5
+ import { Yazio } from 'yazio';
6
+ import { zodToJsonSchema } from 'zod-to-json-schema';
7
+ import { GetFoodEntriesInputSchema, GetDailySummaryInputSchema, GetUserInfoInputSchema, GetUserWeightInputSchema, GetWaterIntakeInputSchema, SearchProductsInputSchema, GetProductInputSchema, GetUserExercisesInputSchema, GetUserSettingsInputSchema, GetUserSuggestedProductsInputSchema, AddConsumedItemInputSchema, RemoveConsumedItemInputSchema, GetDietaryPreferencesInputSchema, GetUserGoalsInputSchema } from './schemas.js';
8
+ class YazioMcpServer {
9
+ server;
10
+ yazioClient = null;
11
+ constructor() {
12
+ this.server = new Server({
13
+ name: 'yazio-mcp',
14
+ version: '1.0.0',
15
+ }, {
16
+ capabilities: {
17
+ tools: {},
18
+ },
19
+ });
20
+ this.setupToolHandlers();
21
+ this.setupErrorHandling();
22
+ this.initializeClient();
23
+ }
24
+ async initializeClient() {
25
+ const username = process.env.YAZIO_USERNAME;
26
+ const password = process.env.YAZIO_PASSWORD;
27
+ if (!username || !password) {
28
+ console.error('❌ YAZIO_USERNAME and YAZIO_PASSWORD environment variables are required');
29
+ console.error('💡 Please set these environment variables with your Yazio account credentials');
30
+ process.exit(1);
31
+ }
32
+ try {
33
+ this.yazioClient = new Yazio({
34
+ credentials: {
35
+ username,
36
+ password
37
+ }
38
+ });
39
+ // Test the connection
40
+ await this.yazioClient.user.get();
41
+ console.error('✅ Successfully authenticated with Yazio using environment variables');
42
+ }
43
+ catch (error) {
44
+ console.error('❌ Failed to authenticate with Yazio:', error.message);
45
+ console.error('💡 Please check your YAZIO_USERNAME and YAZIO_PASSWORD environment variables');
46
+ process.exit(1);
47
+ }
48
+ }
49
+ setupErrorHandling() {
50
+ this.server.onerror = (error) => console.error('[MCP Error]', error);
51
+ process.on('SIGINT', async () => {
52
+ await this.server.close();
53
+ process.exit(0);
54
+ });
55
+ }
56
+ setupToolHandlers() {
57
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
58
+ tools: [
59
+ {
60
+ name: 'get_product',
61
+ description: 'Get detailed information about a specific product by ID',
62
+ inputSchema: zodToJsonSchema(GetProductInputSchema),
63
+ annotations: {
64
+ readOnlyHint: true,
65
+ idempotentHint: true,
66
+ openWorldHint: true
67
+ }
68
+ },
69
+ {
70
+ name: 'get_user',
71
+ description: 'Get Yazio user profile information',
72
+ inputSchema: zodToJsonSchema(GetUserInfoInputSchema),
73
+ annotations: {
74
+ readOnlyHint: true,
75
+ idempotentHint: true
76
+ }
77
+ },
78
+ {
79
+ name: 'get_user_consumed_items',
80
+ description: 'Get food entries for a specific date',
81
+ inputSchema: zodToJsonSchema(GetFoodEntriesInputSchema),
82
+ annotations: {
83
+ readOnlyHint: true,
84
+ idempotentHint: true
85
+ }
86
+ },
87
+ {
88
+ name: 'get_user_dietary_preferences',
89
+ description: 'Get user dietary preferences and restrictions',
90
+ inputSchema: zodToJsonSchema(GetDietaryPreferencesInputSchema),
91
+ annotations: {
92
+ readOnlyHint: true,
93
+ idempotentHint: true
94
+ }
95
+ },
96
+ {
97
+ name: 'get_user_exercises',
98
+ description: 'Get user exercise data for a date or date range',
99
+ inputSchema: zodToJsonSchema(GetUserExercisesInputSchema),
100
+ annotations: {
101
+ readOnlyHint: true,
102
+ idempotentHint: true
103
+ }
104
+ },
105
+ {
106
+ name: 'get_user_goals',
107
+ description: 'Get user nutrition and fitness goals',
108
+ inputSchema: zodToJsonSchema(GetUserGoalsInputSchema),
109
+ annotations: {
110
+ readOnlyHint: true,
111
+ idempotentHint: true
112
+ }
113
+ },
114
+ {
115
+ name: 'get_user_settings',
116
+ description: 'Get user settings and preferences',
117
+ inputSchema: zodToJsonSchema(GetUserSettingsInputSchema),
118
+ annotations: {
119
+ readOnlyHint: true,
120
+ idempotentHint: true
121
+ }
122
+ },
123
+ {
124
+ name: 'get_user_suggested_products',
125
+ description: 'Get product suggestions for the user',
126
+ inputSchema: zodToJsonSchema(GetUserSuggestedProductsInputSchema),
127
+ annotations: {
128
+ readOnlyHint: true,
129
+ idempotentHint: true,
130
+ openWorldHint: true
131
+ }
132
+ },
133
+ {
134
+ name: 'get_user_water_intake',
135
+ description: 'Get water intake data for a specific date',
136
+ inputSchema: zodToJsonSchema(GetWaterIntakeInputSchema),
137
+ annotations: {
138
+ readOnlyHint: true,
139
+ idempotentHint: true
140
+ }
141
+ },
142
+ {
143
+ name: 'get_user_weight',
144
+ description: 'Get user weight data',
145
+ inputSchema: zodToJsonSchema(GetUserWeightInputSchema),
146
+ annotations: {
147
+ readOnlyHint: true,
148
+ idempotentHint: true
149
+ }
150
+ },
151
+ {
152
+ name: 'search_products',
153
+ description: 'Search for food products in Yazio database',
154
+ inputSchema: zodToJsonSchema(SearchProductsInputSchema),
155
+ annotations: {
156
+ readOnlyHint: true,
157
+ idempotentHint: true,
158
+ openWorldHint: true
159
+ }
160
+ },
161
+ {
162
+ name: 'get_user_daily_summary',
163
+ description: 'Get daily nutrition summary for a specific date',
164
+ inputSchema: zodToJsonSchema(GetDailySummaryInputSchema),
165
+ annotations: {
166
+ readOnlyHint: true,
167
+ idempotentHint: true
168
+ }
169
+ },
170
+ {
171
+ name: 'add_user_consumed_item',
172
+ description: 'Add a food item to user consumption log',
173
+ inputSchema: zodToJsonSchema(AddConsumedItemInputSchema),
174
+ annotations: {
175
+ readOnlyHint: false,
176
+ idempotentHint: false
177
+ }
178
+ },
179
+ {
180
+ name: 'remove_user_consumed_item',
181
+ description: 'Remove a food item from user consumption log',
182
+ inputSchema: zodToJsonSchema(RemoveConsumedItemInputSchema),
183
+ annotations: {
184
+ readOnlyHint: false,
185
+ destructiveHint: true,
186
+ idempotentHint: true
187
+ }
188
+ },
189
+ ],
190
+ }));
191
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
192
+ const { name, arguments: args } = request.params;
193
+ try {
194
+ switch (name) {
195
+ case 'get_product':
196
+ return await this.getProduct(GetProductInputSchema.parse(args));
197
+ case 'get_user':
198
+ return await this.getUser();
199
+ case 'get_user_consumed_items':
200
+ return await this.getUserConsumedItems(GetFoodEntriesInputSchema.parse(args));
201
+ case 'get_user_dietary_preferences':
202
+ return await this.getUserDietaryPreferences();
203
+ case 'get_user_exercises':
204
+ return await this.getUserExercises(GetUserExercisesInputSchema.parse(args));
205
+ case 'get_user_goals':
206
+ return await this.getUserGoals();
207
+ case 'get_user_settings':
208
+ return await this.getUserSettings();
209
+ case 'get_user_suggested_products':
210
+ return await this.getUserSuggestedProducts(GetUserSuggestedProductsInputSchema.parse(args));
211
+ case 'get_user_water_intake':
212
+ return await this.getUserWaterIntake(GetWaterIntakeInputSchema.parse(args));
213
+ case 'get_user_weight':
214
+ return await this.getUserWeight();
215
+ case 'search_products':
216
+ return await this.searchProducts(SearchProductsInputSchema.parse(args));
217
+ case 'get_user_daily_summary':
218
+ return await this.getUserDailySummary(GetDailySummaryInputSchema.parse(args));
219
+ case 'add_user_consumed_item':
220
+ return await this.addUserConsumedItem(AddConsumedItemInputSchema.parse(args));
221
+ case 'remove_user_consumed_item':
222
+ return await this.removeUserConsumedItem(RemoveConsumedItemInputSchema.parse(args));
223
+ default:
224
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
225
+ }
226
+ }
227
+ catch (error) {
228
+ const errorMessage = error instanceof Error ? error.message : String(error);
229
+ throw new McpError(ErrorCode.InternalError, errorMessage);
230
+ }
231
+ });
232
+ }
233
+ async ensureAuthenticated() {
234
+ if (!this.yazioClient) {
235
+ throw new Error('Yazio client not initialized. Check environment variables.');
236
+ }
237
+ return this.yazioClient;
238
+ }
239
+ async getUserConsumedItems(args) {
240
+ const client = await this.ensureAuthenticated();
241
+ try {
242
+ const foodEntries = await client.user.getConsumedItems({ date: new Date(args.date) });
243
+ return {
244
+ content: [
245
+ {
246
+ type: 'text',
247
+ text: `Food entries for ${args.date}:\n\n${JSON.stringify(foodEntries, null, 2)}`,
248
+ },
249
+ ],
250
+ };
251
+ }
252
+ catch (error) {
253
+ throw new Error(`Failed to get food entries: ${error}`);
254
+ }
255
+ }
256
+ async getUser() {
257
+ const client = await this.ensureAuthenticated();
258
+ try {
259
+ const userInfo = await client.user.get();
260
+ return {
261
+ content: [
262
+ {
263
+ type: 'text',
264
+ text: `User info:\n\n${JSON.stringify(userInfo, null, 2)}`,
265
+ },
266
+ ],
267
+ };
268
+ }
269
+ catch (error) {
270
+ throw new Error(`Failed to get user info: ${error}`);
271
+ }
272
+ }
273
+ async getUserDailySummary(args) {
274
+ const client = await this.ensureAuthenticated();
275
+ try {
276
+ const summary = await client.user.getDailySummary({ date: new Date(args.date) });
277
+ return {
278
+ content: [
279
+ {
280
+ type: 'text',
281
+ text: `Daily summary for ${args.date}:\n\n${JSON.stringify(summary, null, 2)}`,
282
+ },
283
+ ],
284
+ };
285
+ }
286
+ catch (error) {
287
+ throw new Error(`Failed to get daily summary: ${error}`);
288
+ }
289
+ }
290
+ async getUserWeight() {
291
+ const client = await this.ensureAuthenticated();
292
+ try {
293
+ // Yazio getWeight doesn't support date ranges, just single date
294
+ const weight = await client.user.getWeight();
295
+ return {
296
+ content: [
297
+ {
298
+ type: 'text',
299
+ text: `User weight data:\n\n${JSON.stringify(weight, null, 2)}`,
300
+ },
301
+ ],
302
+ };
303
+ }
304
+ catch (error) {
305
+ throw new Error(`Failed to get user weight: ${error}`);
306
+ }
307
+ }
308
+ async getUserWaterIntake(args) {
309
+ const client = await this.ensureAuthenticated();
310
+ try {
311
+ const waterIntake = await client.user.getWaterIntake({ date: new Date(args.date) });
312
+ return {
313
+ content: [
314
+ {
315
+ type: 'text',
316
+ text: `Water intake for ${args.date}:\n\n${JSON.stringify(waterIntake, null, 2)}`,
317
+ },
318
+ ],
319
+ };
320
+ }
321
+ catch (error) {
322
+ throw new Error(`Failed to get water intake: ${error}`);
323
+ }
324
+ }
325
+ async searchProducts(args) {
326
+ const client = await this.ensureAuthenticated();
327
+ try {
328
+ const products = await client.products.search(args);
329
+ return {
330
+ content: [
331
+ {
332
+ type: 'text',
333
+ text: `Search results for "${args.query}":\n\n${JSON.stringify(products, null, 2)}`,
334
+ },
335
+ ],
336
+ };
337
+ }
338
+ catch (error) {
339
+ throw new Error(`Failed to search products: ${error}`);
340
+ }
341
+ }
342
+ async getProduct(args) {
343
+ const client = await this.ensureAuthenticated();
344
+ try {
345
+ const product = await client.products.get(args.id);
346
+ return {
347
+ content: [
348
+ {
349
+ type: 'text',
350
+ text: `Product details for ID "${args.id}":\n\n${JSON.stringify(product, null, 2)}`,
351
+ },
352
+ ],
353
+ };
354
+ }
355
+ catch (error) {
356
+ throw new Error(`Failed to get product: ${error}`);
357
+ }
358
+ }
359
+ async getUserExercises(args) {
360
+ const client = await this.ensureAuthenticated();
361
+ try {
362
+ const apiOptions = {};
363
+ if (args.date) {
364
+ apiOptions.date = args.date;
365
+ }
366
+ const exercises = await client.user.getExercises(apiOptions);
367
+ return {
368
+ content: [
369
+ {
370
+ type: 'text',
371
+ text: `User exercises:\n\n${JSON.stringify(exercises, null, 2)}`,
372
+ },
373
+ ],
374
+ };
375
+ }
376
+ catch (error) {
377
+ throw new Error(`Failed to get user exercises: ${error}`);
378
+ }
379
+ }
380
+ async getUserSettings() {
381
+ const client = await this.ensureAuthenticated();
382
+ try {
383
+ const settings = await client.user.getSettings();
384
+ return {
385
+ content: [
386
+ {
387
+ type: 'text',
388
+ text: `User settings:\n\n${JSON.stringify(settings, null, 2)}`,
389
+ },
390
+ ],
391
+ };
392
+ }
393
+ catch (error) {
394
+ throw new Error(`Failed to get user settings: ${error}`);
395
+ }
396
+ }
397
+ async getUserSuggestedProducts(args) {
398
+ const client = await this.ensureAuthenticated();
399
+ try {
400
+ const options = {
401
+ daytime: 'breakfast',
402
+ ...args
403
+ };
404
+ const suggestions = await client.user.getSuggestedProducts(options);
405
+ return {
406
+ content: [
407
+ {
408
+ type: 'text',
409
+ text: `Product suggestions:\n\n${JSON.stringify(suggestions, null, 2)}`,
410
+ },
411
+ ],
412
+ };
413
+ }
414
+ catch (error) {
415
+ throw new Error(`Failed to get product suggestions: ${error}`);
416
+ }
417
+ }
418
+ async addUserConsumedItem(args) {
419
+ const client = await this.ensureAuthenticated();
420
+ try {
421
+ // The Yazio API expects specific parameters, we'll pass them directly
422
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
423
+ const result = await client.user.addConsumedItem(args);
424
+ return {
425
+ content: [
426
+ {
427
+ type: 'text',
428
+ text: `Successfully added consumed item:\n\n${JSON.stringify(result, null, 2)}`,
429
+ },
430
+ ],
431
+ };
432
+ }
433
+ catch (error) {
434
+ throw new Error(`Failed to add consumed item: ${error}`);
435
+ }
436
+ }
437
+ async removeUserConsumedItem(args) {
438
+ const client = await this.ensureAuthenticated();
439
+ try {
440
+ const result = await client.user.removeConsumedItem(args.itemId);
441
+ return {
442
+ content: [
443
+ {
444
+ type: 'text',
445
+ text: `Successfully removed consumed item with ID: ${args.itemId}\n\n${JSON.stringify(result, null, 2)}`,
446
+ },
447
+ ],
448
+ };
449
+ }
450
+ catch (error) {
451
+ throw new Error(`Failed to remove consumed item: ${error}`);
452
+ }
453
+ }
454
+ async getUserDietaryPreferences() {
455
+ const client = await this.ensureAuthenticated();
456
+ try {
457
+ const preferences = await client.user.getDietaryPreferences();
458
+ return {
459
+ content: [
460
+ {
461
+ type: 'text',
462
+ text: `Dietary preferences:\n\n${JSON.stringify(preferences, null, 2)}`,
463
+ },
464
+ ],
465
+ };
466
+ }
467
+ catch (error) {
468
+ throw new Error(`Failed to get dietary preferences: ${error}`);
469
+ }
470
+ }
471
+ async getUserGoals() {
472
+ const client = await this.ensureAuthenticated();
473
+ try {
474
+ const goals = await client.user.getGoals({});
475
+ return {
476
+ content: [
477
+ {
478
+ type: 'text',
479
+ text: `User goals:\n\n${JSON.stringify(goals, null, 2)}`,
480
+ },
481
+ ],
482
+ };
483
+ }
484
+ catch (error) {
485
+ throw new Error(`Failed to get user goals: ${error}`);
486
+ }
487
+ }
488
+ async run() {
489
+ const transport = new StdioServerTransport();
490
+ await this.server.connect(transport);
491
+ console.error('Yazio MCP server running on stdio');
492
+ }
493
+ }
494
+ const server = new YazioMcpServer();
495
+ server.run().catch(console.error);
@@ -0,0 +1,137 @@
1
+ import { z } from 'zod';
2
+ export declare const DaytimeSchema: z.ZodEnum<["breakfast", "lunch", "dinner", "snack"]>;
3
+ export type Daytime = z.infer<typeof DaytimeSchema>;
4
+ export declare const DateStringSchema: z.ZodString;
5
+ export declare const ProductIdSchema: z.ZodString;
6
+ export declare const ItemIdSchema: z.ZodString;
7
+ export declare const QueryStringSchema: z.ZodString;
8
+ export declare const LimitSchema: z.ZodOptional<z.ZodNumber>;
9
+ export declare const DateInputSchema: z.ZodObject<{
10
+ date: z.ZodString;
11
+ }, "strip", z.ZodTypeAny, {
12
+ date: string;
13
+ }, {
14
+ date: string;
15
+ }>;
16
+ export declare const OptionalDateInputSchema: z.ZodObject<{
17
+ date: z.ZodOptional<z.ZodString>;
18
+ }, "strip", z.ZodTypeAny, {
19
+ date?: string | undefined;
20
+ }, {
21
+ date?: string | undefined;
22
+ }>;
23
+ export declare const QueryInputSchema: z.ZodObject<{
24
+ query: z.ZodString;
25
+ }, "strip", z.ZodTypeAny, {
26
+ query: string;
27
+ }, {
28
+ query: string;
29
+ }>;
30
+ export declare const OptionalQueryInputSchema: z.ZodObject<{
31
+ query: z.ZodOptional<z.ZodString>;
32
+ limit: z.ZodOptional<z.ZodNumber>;
33
+ }, "strip", z.ZodTypeAny, {
34
+ query?: string | undefined;
35
+ limit?: number | undefined;
36
+ }, {
37
+ query?: string | undefined;
38
+ limit?: number | undefined;
39
+ }>;
40
+ export declare const EmptyInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
41
+ export declare const GetFoodEntriesInputSchema: z.ZodObject<{
42
+ date: z.ZodString;
43
+ }, "strip", z.ZodTypeAny, {
44
+ date: string;
45
+ }, {
46
+ date: string;
47
+ }>;
48
+ export declare const GetDailySummaryInputSchema: z.ZodObject<{
49
+ date: z.ZodString;
50
+ }, "strip", z.ZodTypeAny, {
51
+ date: string;
52
+ }, {
53
+ date: string;
54
+ }>;
55
+ export declare const GetUserInfoInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
56
+ export declare const GetUserWeightInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
57
+ export declare const GetWaterIntakeInputSchema: z.ZodObject<{
58
+ date: z.ZodString;
59
+ }, "strip", z.ZodTypeAny, {
60
+ date: string;
61
+ }, {
62
+ date: string;
63
+ }>;
64
+ export declare const SearchProductsInputSchema: z.ZodObject<{
65
+ query: z.ZodString;
66
+ }, "strip", z.ZodTypeAny, {
67
+ query: string;
68
+ }, {
69
+ query: string;
70
+ }>;
71
+ export declare const GetProductInputSchema: z.ZodObject<{
72
+ id: z.ZodString;
73
+ }, "strip", z.ZodTypeAny, {
74
+ id: string;
75
+ }, {
76
+ id: string;
77
+ }>;
78
+ export declare const GetUserExercisesInputSchema: z.ZodObject<{
79
+ date: z.ZodOptional<z.ZodString>;
80
+ }, "strip", z.ZodTypeAny, {
81
+ date?: string | undefined;
82
+ }, {
83
+ date?: string | undefined;
84
+ }>;
85
+ export declare const GetUserSettingsInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
86
+ export declare const GetUserSuggestedProductsInputSchema: z.ZodObject<{
87
+ query: z.ZodOptional<z.ZodString>;
88
+ limit: z.ZodOptional<z.ZodNumber>;
89
+ }, "strip", z.ZodTypeAny, {
90
+ query?: string | undefined;
91
+ limit?: number | undefined;
92
+ }, {
93
+ query?: string | undefined;
94
+ limit?: number | undefined;
95
+ }>;
96
+ export declare const AddConsumedItemInputSchema: z.ZodObject<{
97
+ productId: z.ZodOptional<z.ZodString>;
98
+ amount: z.ZodOptional<z.ZodNumber>;
99
+ unit: z.ZodOptional<z.ZodString>;
100
+ date: z.ZodOptional<z.ZodString>;
101
+ mealType: z.ZodOptional<z.ZodEnum<["breakfast", "lunch", "dinner", "snack"]>>;
102
+ }, "strip", z.ZodTypeAny, {
103
+ date?: string | undefined;
104
+ productId?: string | undefined;
105
+ amount?: number | undefined;
106
+ unit?: string | undefined;
107
+ mealType?: "breakfast" | "lunch" | "dinner" | "snack" | undefined;
108
+ }, {
109
+ date?: string | undefined;
110
+ productId?: string | undefined;
111
+ amount?: number | undefined;
112
+ unit?: string | undefined;
113
+ mealType?: "breakfast" | "lunch" | "dinner" | "snack" | undefined;
114
+ }>;
115
+ export declare const RemoveConsumedItemInputSchema: z.ZodObject<{
116
+ itemId: z.ZodString;
117
+ }, "strip", z.ZodTypeAny, {
118
+ itemId: string;
119
+ }, {
120
+ itemId: string;
121
+ }>;
122
+ export declare const GetDietaryPreferencesInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
123
+ export declare const GetUserGoalsInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
124
+ export type GetFoodEntriesInput = z.infer<typeof GetFoodEntriesInputSchema>;
125
+ export type GetDailySummaryInput = z.infer<typeof GetDailySummaryInputSchema>;
126
+ export type GetUserInfoInput = z.infer<typeof GetUserInfoInputSchema>;
127
+ export type GetUserWeightInput = z.infer<typeof GetUserWeightInputSchema>;
128
+ export type GetWaterIntakeInput = z.infer<typeof GetWaterIntakeInputSchema>;
129
+ export type SearchProductsInput = z.infer<typeof SearchProductsInputSchema>;
130
+ export type GetProductInput = z.infer<typeof GetProductInputSchema>;
131
+ export type GetUserExercisesInput = z.infer<typeof GetUserExercisesInputSchema>;
132
+ export type GetUserSettingsInput = z.infer<typeof GetUserSettingsInputSchema>;
133
+ export type GetUserSuggestedProductsInput = z.infer<typeof GetUserSuggestedProductsInputSchema>;
134
+ export type AddConsumedItemInput = z.infer<typeof AddConsumedItemInputSchema>;
135
+ export type RemoveConsumedItemInput = z.infer<typeof RemoveConsumedItemInputSchema>;
136
+ export type GetDietaryPreferencesInput = z.infer<typeof GetDietaryPreferencesInputSchema>;
137
+ export type GetUserGoalsInput = z.infer<typeof GetUserGoalsInputSchema>;
@@ -0,0 +1,45 @@
1
+ import { z } from 'zod';
2
+ export const DaytimeSchema = z.enum(['breakfast', 'lunch', 'dinner', 'snack']);
3
+ export const DateStringSchema = z.string().describe('Date in YYYY-MM-DD format');
4
+ export const ProductIdSchema = z.string().describe('Unique product identifier');
5
+ export const ItemIdSchema = z.string().describe('Unique item identifier');
6
+ export const QueryStringSchema = z.string().describe('Search query string');
7
+ export const LimitSchema = z.number().optional().describe('Maximum number of results to return');
8
+ export const DateInputSchema = z.object({
9
+ date: DateStringSchema.describe('Date to get data for')
10
+ });
11
+ export const OptionalDateInputSchema = z.object({
12
+ date: DateStringSchema.optional().describe('Specific date to get data for (optional)')
13
+ });
14
+ export const QueryInputSchema = z.object({
15
+ query: QueryStringSchema.describe('Search query')
16
+ });
17
+ export const OptionalQueryInputSchema = z.object({
18
+ query: QueryStringSchema.optional().describe('Search query (optional)'),
19
+ limit: LimitSchema
20
+ });
21
+ export const EmptyInputSchema = z.object({});
22
+ export const GetFoodEntriesInputSchema = DateInputSchema;
23
+ export const GetDailySummaryInputSchema = DateInputSchema;
24
+ export const GetUserInfoInputSchema = EmptyInputSchema;
25
+ export const GetUserWeightInputSchema = EmptyInputSchema; // Yazio getWeight doesn't accept parameters
26
+ export const GetWaterIntakeInputSchema = DateInputSchema;
27
+ export const SearchProductsInputSchema = QueryInputSchema;
28
+ export const GetProductInputSchema = z.object({
29
+ id: ProductIdSchema.describe('Product ID to get details for')
30
+ });
31
+ export const GetUserExercisesInputSchema = OptionalDateInputSchema; // Only supports single date, not date ranges
32
+ export const GetUserSettingsInputSchema = EmptyInputSchema;
33
+ export const GetUserSuggestedProductsInputSchema = OptionalQueryInputSchema;
34
+ export const AddConsumedItemInputSchema = z.object({
35
+ productId: z.string().optional().describe('ID of the product to add'),
36
+ amount: z.number().optional().describe('Amount of the product consumed'),
37
+ unit: z.string().optional().describe('Unit of measurement (g, ml, pieces, etc.)'),
38
+ date: z.string().optional().describe('Date when the food was consumed (defaults to today) in YYYY-MM-DD format'),
39
+ mealType: DaytimeSchema.optional().describe('Type of meal')
40
+ });
41
+ export const RemoveConsumedItemInputSchema = z.object({
42
+ itemId: ItemIdSchema.describe('ID of the consumed item to remove')
43
+ });
44
+ export const GetDietaryPreferencesInputSchema = EmptyInputSchema;
45
+ export const GetUserGoalsInputSchema = EmptyInputSchema;
@@ -0,0 +1,266 @@
1
+ export interface YazioProduct {
2
+ id: string;
3
+ name: string;
4
+ is_verified: boolean;
5
+ is_private: boolean;
6
+ is_deleted: boolean;
7
+ has_ean: boolean;
8
+ category: string;
9
+ producer: string | null;
10
+ nutrients: {
11
+ "energy.energy": number;
12
+ "mineral.calcium": number;
13
+ "mineral.chlorine": number;
14
+ "mineral.copper": number;
15
+ "mineral.fluorine": number;
16
+ "mineral.iron": number;
17
+ "mineral.magnesium": number;
18
+ "mineral.manganese": number;
19
+ "mineral.phosphorus": number;
20
+ "mineral.potassium": number;
21
+ "mineral.sulfur": number;
22
+ "mineral.zinc": number;
23
+ "nutrient.carb": number;
24
+ "nutrient.dietaryfiber": number;
25
+ "nutrient.fat": number;
26
+ "nutrient.protein": number;
27
+ "nutrient.sugar": number;
28
+ "vitamin.a": number;
29
+ "vitamin.b1": number;
30
+ "vitamin.b12": number;
31
+ "vitamin.b2": number;
32
+ "vitamin.b6": number;
33
+ "vitamin.d": number;
34
+ "vitamin.e": number;
35
+ };
36
+ updated_at: string;
37
+ servings: {
38
+ serving: string;
39
+ amount: number;
40
+ }[];
41
+ base_unit: string;
42
+ eans: string[];
43
+ language: string;
44
+ countries: string[];
45
+ }
46
+ export interface YazioProductSearchResult {
47
+ serving: string;
48
+ amount: number;
49
+ name: string;
50
+ is_verified: boolean;
51
+ producer: string;
52
+ nutrients: {
53
+ "energy.energy": number;
54
+ "nutrient.carb": number;
55
+ "nutrient.fat": number;
56
+ "nutrient.protein": number;
57
+ };
58
+ base_unit: string;
59
+ language: string;
60
+ countries: string[];
61
+ score: number;
62
+ product_id: string;
63
+ serving_quantity: number;
64
+ }
65
+ export interface YazioUserInfo {
66
+ sex: "male" | "female" | "other";
67
+ unit_mass: string;
68
+ unit_energy: string;
69
+ unit_serving: string;
70
+ unit_length: string;
71
+ start_weight: number;
72
+ goal: string;
73
+ diet: {
74
+ name: string;
75
+ carb_percentage: number;
76
+ fat_percentage: number;
77
+ protein_percentage: number;
78
+ } | null;
79
+ email: string;
80
+ premium_type: string;
81
+ first_name: string;
82
+ last_name: string;
83
+ city: string;
84
+ country: string;
85
+ weight_change_per_week: number;
86
+ body_height: number;
87
+ date_of_birth: string;
88
+ registration_date: string;
89
+ timezone_offset: number;
90
+ unit_glucose: string;
91
+ food_database_country: string;
92
+ profile_image: string;
93
+ user_token: string;
94
+ email_confirmation_status: "confirmed" | "unconfirmed";
95
+ newsletter_opt_in: boolean;
96
+ login_type: string;
97
+ siwa_user_id: string | null;
98
+ uuid: string;
99
+ reset_date: string | null;
100
+ activity_degree: string;
101
+ stripe_customer_id: string | null;
102
+ }
103
+ export interface YazioWeightEntry {
104
+ value: number | null;
105
+ date: string;
106
+ id: string;
107
+ external_id: string | null;
108
+ gateway: string | null;
109
+ source: string | null;
110
+ }
111
+ export interface YazioSuggestedProduct {
112
+ serving: string | null;
113
+ amount: number;
114
+ product_id: string;
115
+ serving_quantity: number | null;
116
+ }
117
+ export interface YazioDietaryPreferences {
118
+ restriction: string | null;
119
+ }
120
+ export interface YazioExercise {
121
+ date: string;
122
+ id: string;
123
+ name: string;
124
+ external_id: string | null;
125
+ gateway: string | null;
126
+ source: string | null;
127
+ note: string | null;
128
+ energy: number;
129
+ distance: number;
130
+ duration: number;
131
+ steps: number;
132
+ }
133
+ export interface YazioExercises {
134
+ training: YazioExercise[];
135
+ custom_training: YazioExercise[];
136
+ }
137
+ export interface YazioGoals {
138
+ "energy.energy": number;
139
+ "nutrient.carb": number;
140
+ "nutrient.fat": number;
141
+ "nutrient.protein": number;
142
+ "activity.step": number;
143
+ "bodyvalue.weight": number;
144
+ water: number;
145
+ }
146
+ export interface YazioSettings {
147
+ has_water_tracker: boolean;
148
+ has_diary_tipps: boolean;
149
+ has_meal_reminders: boolean;
150
+ has_usage_reminders: boolean;
151
+ has_weight_reminders: boolean;
152
+ has_water_reminders: boolean;
153
+ consume_activity_calories: boolean;
154
+ has_feelings: boolean;
155
+ has_fasting_tracker_reminders: boolean;
156
+ has_fasting_stage_reminders: boolean;
157
+ }
158
+ export interface YazioWaterIntake {
159
+ gateway: string | null;
160
+ source: string | null;
161
+ water_intake: number;
162
+ }
163
+ export interface YazioDailySummary {
164
+ steps: number;
165
+ activity_energy: number;
166
+ consume_activity_energy: boolean;
167
+ water_intake: number;
168
+ goals: YazioGoals;
169
+ units: {
170
+ unit_mass: string;
171
+ unit_energy: string;
172
+ unit_serving: string;
173
+ unit_length: string;
174
+ };
175
+ meals: {
176
+ breakfast: {
177
+ nutrients: {
178
+ "energy.energy": number;
179
+ "nutrient.carb": number;
180
+ "nutrient.fat": number;
181
+ "nutrient.protein": number;
182
+ };
183
+ energy_goal: number;
184
+ };
185
+ lunch: {
186
+ nutrients: {
187
+ "energy.energy": number;
188
+ "nutrient.carb": number;
189
+ "nutrient.fat": number;
190
+ "nutrient.protein": number;
191
+ };
192
+ energy_goal: number;
193
+ };
194
+ dinner: {
195
+ nutrients: {
196
+ "energy.energy": number;
197
+ "nutrient.carb": number;
198
+ "nutrient.fat": number;
199
+ "nutrient.protein": number;
200
+ };
201
+ energy_goal: number;
202
+ };
203
+ snack: {
204
+ nutrients: {
205
+ "energy.energy": number;
206
+ "nutrient.carb": number;
207
+ "nutrient.fat": number;
208
+ "nutrient.protein": number;
209
+ };
210
+ energy_goal: number;
211
+ };
212
+ };
213
+ user: {
214
+ start_weight?: number;
215
+ current_weight?: number;
216
+ goal?: string;
217
+ sex?: string;
218
+ };
219
+ active_fasting_countdown_template_key: string | null;
220
+ }
221
+ export interface YazioConsumedItem {
222
+ type: string;
223
+ date: string;
224
+ serving: string | null;
225
+ amount: number;
226
+ id: string;
227
+ product_id: string;
228
+ serving_quantity: number | null;
229
+ daytime: "breakfast" | "lunch" | "dinner" | "snack";
230
+ }
231
+ export interface YazioConsumedItems {
232
+ products: YazioConsumedItem[];
233
+ recipe_portions: unknown[];
234
+ simple_products: unknown[];
235
+ }
236
+ export interface YazioWeightOptions {
237
+ date?: string | Date;
238
+ }
239
+ export interface YazioExerciseOptions {
240
+ date?: string | Date;
241
+ }
242
+ export interface YazioSuggestedProductsOptions {
243
+ daytime: "breakfast" | "lunch" | "dinner" | "snack";
244
+ date?: string | Date;
245
+ }
246
+ export interface YazioWaterIntakeOptions {
247
+ date: string | Date;
248
+ }
249
+ export interface YazioDailySummaryOptions {
250
+ date: string | Date;
251
+ }
252
+ export interface YazioConsumedItemsOptions {
253
+ date: string | Date;
254
+ }
255
+ export interface YazioAddConsumedItemOptions {
256
+ date: string | Date;
257
+ serving: string;
258
+ amount: number;
259
+ id: string;
260
+ product_id: string;
261
+ serving_quantity: number;
262
+ daytime: "breakfast" | "lunch" | "dinner" | "snack";
263
+ }
264
+ export interface YazioRemoveConsumedItemOptions {
265
+ itemId: string;
266
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // Type definitions for Yazio API responses
2
+ // These are extracted from the yazio package types
3
+ export {};
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "yazio-mcp",
3
+ "version": "0.0.1",
4
+ "description": "MCP server for accessing Yazio user & nutrition data (unofficial)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "yazio-mcp": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist/**/*",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "dev": "tsx src/index.ts",
19
+ "start": "node dist/index.js",
20
+ "prepublishOnly": "npm run build",
21
+ "lint": "eslint src/**/*.ts",
22
+ "lint:fix": "eslint src/**/*.ts --fix",
23
+ "format": "prettier --write src/**/*.ts",
24
+ "type-check": "tsc --noEmit"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "yazio",
29
+ "nutrition",
30
+ "diet",
31
+ "model-context-protocol",
32
+ "health",
33
+ "fitness"
34
+ ],
35
+ "author": "fliptheweb",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/arturkornakov/yazio-mcp.git"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/arturkornakov/yazio-mcp/issues"
43
+ },
44
+ "homepage": "https://github.com/arturkornakov/yazio-mcp#readme",
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ },
48
+ "dependencies": {
49
+ "@modelcontextprotocol/sdk": "^1.18.2",
50
+ "yazio": "^1.0.0",
51
+ "zod": "^3.22.0",
52
+ "zod-to-json-schema": "^3.24.6"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^20.0.0",
56
+ "@typescript-eslint/eslint-plugin": "^8.44.1",
57
+ "@typescript-eslint/parser": "^8.44.1",
58
+ "eslint": "^9.36.0",
59
+ "globals": "^16.4.0",
60
+ "prettier": "^3.6.2",
61
+ "tsx": "^4.0.0",
62
+ "typescript": "^5.0.0"
63
+ }
64
+ }