yazio-mcp 0.0.3 → 0.0.6
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/README.md +9 -1
- package/dist/index.js +240 -188
- package/dist/schemas.d.ts +69 -102
- package/dist/schemas.js +30 -11
- package/package.json +4 -5
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ Easily log meals you forgot to track in the Yazio app directly from Claude or Cu
|
|
|
77
77
|
## Test Connection
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
|
-
YAZIO_USERNAME=your_email YAZIO_PASSWORD=your_password npx yazio-mcp
|
|
80
|
+
YAZIO_USERNAME='your_email' YAZIO_PASSWORD='your_password' npx yazio-mcp
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
## ⚠️ Important Disclaimers
|
|
@@ -92,6 +92,14 @@ YAZIO_USERNAME=your_email YAZIO_PASSWORD=your_password npx yazio-mcp
|
|
|
92
92
|
- Valid Yazio account
|
|
93
93
|
- MCP-compatible client (Claude Desktop, Cursor, etc.)
|
|
94
94
|
|
|
95
|
+
# Development
|
|
96
|
+
1. Download the repository
|
|
97
|
+
2. Point to local copy in your mcp config
|
|
98
|
+
3. Debugging:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
YAZIO_USERNAME=X YAZIO_PASSWORD=X npx -y @modelcontextprotocol/inspector npx <local-path>/yazio-mcp
|
|
102
|
+
```
|
|
95
103
|
---
|
|
96
104
|
|
|
97
105
|
## 📄 License
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
-
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
4
|
import { Yazio } from 'yazio';
|
|
6
|
-
import {
|
|
7
|
-
import { GetFoodEntriesInputSchema, GetDailySummaryInputSchema, GetUserInfoInputSchema, GetUserWeightInputSchema, GetWaterIntakeInputSchema, SearchProductsInputSchema, GetProductInputSchema, GetUserExercisesInputSchema, GetUserSettingsInputSchema, GetUserSuggestedProductsInputSchema, AddConsumedItemInputSchema, RemoveConsumedItemInputSchema, GetDietaryPreferencesInputSchema, GetUserGoalsInputSchema } from './schemas.js';
|
|
5
|
+
import { v4 as uuidv4 } from "uuid";
|
|
6
|
+
import { GetFoodEntriesInputSchema, GetDailySummaryInputSchema, GetUserInfoInputSchema, GetUserWeightInputSchema, GetWaterIntakeInputSchema, SearchProductsInputSchema, GetProductInputSchema, GetUserExercisesInputSchema, GetUserSettingsInputSchema, GetUserSuggestedProductsInputSchema, AddConsumedItemInputSchema, RemoveConsumedItemInputSchema, GetDietaryPreferencesInputSchema, GetUserGoalsInputSchema, } from './schemas.js';
|
|
8
7
|
class YazioMcpServer {
|
|
9
8
|
server;
|
|
10
9
|
yazioClient = null;
|
|
11
10
|
constructor() {
|
|
12
|
-
this.server = new
|
|
11
|
+
this.server = new McpServer({
|
|
13
12
|
name: 'yazio-mcp',
|
|
14
|
-
version: '0.0.
|
|
15
|
-
}, {
|
|
16
|
-
capabilities: {
|
|
17
|
-
tools: {},
|
|
18
|
-
},
|
|
13
|
+
version: '0.0.6',
|
|
19
14
|
});
|
|
20
15
|
this.setupToolHandlers();
|
|
16
|
+
this.setupPromptHandlers();
|
|
21
17
|
this.setupErrorHandling();
|
|
22
18
|
this.initializeClient();
|
|
23
19
|
}
|
|
@@ -47,187 +43,241 @@ class YazioMcpServer {
|
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
45
|
setupErrorHandling() {
|
|
50
|
-
this.server.onerror = (error) => console.error('[MCP Error]', error);
|
|
51
46
|
process.on('SIGINT', async () => {
|
|
52
47
|
await this.server.close();
|
|
53
48
|
process.exit(0);
|
|
54
49
|
});
|
|
55
50
|
}
|
|
56
51
|
setupToolHandlers() {
|
|
57
|
-
this.server.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
52
|
+
this.server.registerTool('get_user', {
|
|
53
|
+
description: 'Get Yazio user profile information',
|
|
54
|
+
inputSchema: GetUserInfoInputSchema,
|
|
55
|
+
annotations: {
|
|
56
|
+
readOnlyHint: true,
|
|
57
|
+
idempotentHint: true,
|
|
58
|
+
},
|
|
59
|
+
}, async () => {
|
|
60
|
+
return await this.getUser();
|
|
61
|
+
});
|
|
62
|
+
this.server.registerTool('get_user_consumed_items', {
|
|
63
|
+
description: 'Get food entries for a specific date',
|
|
64
|
+
inputSchema: GetFoodEntriesInputSchema,
|
|
65
|
+
annotations: {
|
|
66
|
+
readOnlyHint: true,
|
|
67
|
+
idempotentHint: true,
|
|
68
|
+
},
|
|
69
|
+
}, async (args) => {
|
|
70
|
+
return await this.getUserConsumedItems(args);
|
|
71
|
+
});
|
|
72
|
+
this.server.registerTool('get_user_dietary_preferences', {
|
|
73
|
+
description: 'Get user dietary preferences and restrictions',
|
|
74
|
+
inputSchema: GetDietaryPreferencesInputSchema,
|
|
75
|
+
annotations: {
|
|
76
|
+
readOnlyHint: true,
|
|
77
|
+
idempotentHint: true,
|
|
78
|
+
},
|
|
79
|
+
}, async () => {
|
|
80
|
+
return await this.getUserDietaryPreferences();
|
|
81
|
+
});
|
|
82
|
+
this.server.registerTool('get_user_exercises', {
|
|
83
|
+
description: 'Get user exercise data for a date or date range',
|
|
84
|
+
inputSchema: GetUserExercisesInputSchema,
|
|
85
|
+
annotations: {
|
|
86
|
+
readOnlyHint: true,
|
|
87
|
+
idempotentHint: true,
|
|
88
|
+
},
|
|
89
|
+
}, async (args) => {
|
|
90
|
+
return await this.getUserExercises(args);
|
|
91
|
+
});
|
|
92
|
+
this.server.registerTool('get_user_goals', {
|
|
93
|
+
description: 'Get user nutrition and fitness goals',
|
|
94
|
+
inputSchema: GetUserGoalsInputSchema,
|
|
95
|
+
annotations: {
|
|
96
|
+
readOnlyHint: true,
|
|
97
|
+
idempotentHint: true,
|
|
98
|
+
},
|
|
99
|
+
}, async () => {
|
|
100
|
+
return await this.getUserGoals();
|
|
101
|
+
});
|
|
102
|
+
this.server.registerTool('get_user_settings', {
|
|
103
|
+
description: 'Get user settings and preferences',
|
|
104
|
+
inputSchema: GetUserSettingsInputSchema,
|
|
105
|
+
annotations: {
|
|
106
|
+
readOnlyHint: true,
|
|
107
|
+
idempotentHint: true,
|
|
108
|
+
},
|
|
109
|
+
}, async () => {
|
|
110
|
+
return await this.getUserSettings();
|
|
111
|
+
});
|
|
112
|
+
this.server.registerTool('get_user_suggested_products', {
|
|
113
|
+
description: 'Get product suggestions for the user',
|
|
114
|
+
inputSchema: GetUserSuggestedProductsInputSchema,
|
|
115
|
+
annotations: {
|
|
116
|
+
readOnlyHint: true,
|
|
117
|
+
idempotentHint: true,
|
|
118
|
+
openWorldHint: true,
|
|
119
|
+
},
|
|
120
|
+
}, async (args) => {
|
|
121
|
+
return await this.getUserSuggestedProducts(args);
|
|
122
|
+
});
|
|
123
|
+
this.server.registerTool('get_user_water_intake', {
|
|
124
|
+
description: 'Get water intake data for a specific date',
|
|
125
|
+
inputSchema: GetWaterIntakeInputSchema,
|
|
126
|
+
annotations: {
|
|
127
|
+
readOnlyHint: true,
|
|
128
|
+
idempotentHint: true,
|
|
129
|
+
},
|
|
130
|
+
}, async (args) => {
|
|
131
|
+
return await this.getUserWaterIntake(args);
|
|
132
|
+
});
|
|
133
|
+
this.server.registerTool('get_user_weight', {
|
|
134
|
+
description: 'Get user weight data',
|
|
135
|
+
inputSchema: GetUserWeightInputSchema,
|
|
136
|
+
annotations: {
|
|
137
|
+
readOnlyHint: true,
|
|
138
|
+
idempotentHint: true,
|
|
139
|
+
},
|
|
140
|
+
}, async () => {
|
|
141
|
+
return await this.getUserWeight();
|
|
142
|
+
});
|
|
143
|
+
this.server.registerTool('get_user_daily_summary', {
|
|
144
|
+
description: 'Get daily nutrition summary for a specific date',
|
|
145
|
+
inputSchema: GetDailySummaryInputSchema,
|
|
146
|
+
annotations: {
|
|
147
|
+
readOnlyHint: true,
|
|
148
|
+
idempotentHint: true,
|
|
149
|
+
},
|
|
150
|
+
}, async (args) => {
|
|
151
|
+
return await this.getUserDailySummary(args);
|
|
152
|
+
});
|
|
153
|
+
this.server.registerTool('search_products', {
|
|
154
|
+
description: 'Search for food products in Yazio database',
|
|
155
|
+
inputSchema: SearchProductsInputSchema,
|
|
156
|
+
// outputSchema: SearchProductsOutputSchema,
|
|
157
|
+
annotations: {
|
|
158
|
+
readOnlyHint: true,
|
|
159
|
+
idempotentHint: true,
|
|
160
|
+
openWorldHint: true,
|
|
161
|
+
},
|
|
162
|
+
}, async (args) => {
|
|
163
|
+
return await this.searchProducts(args);
|
|
164
|
+
});
|
|
165
|
+
this.server.registerTool('get_product', {
|
|
166
|
+
description: 'Get detailed information about a specific product by ID',
|
|
167
|
+
inputSchema: GetProductInputSchema,
|
|
168
|
+
annotations: {
|
|
169
|
+
readOnlyHint: true,
|
|
170
|
+
idempotentHint: true,
|
|
171
|
+
openWorldHint: true,
|
|
172
|
+
},
|
|
173
|
+
}, async (args) => {
|
|
174
|
+
return await this.getProduct(args);
|
|
175
|
+
});
|
|
176
|
+
this.server.registerTool('add_user_consumed_item', {
|
|
177
|
+
description: 'Add a food item to user consumption log',
|
|
178
|
+
inputSchema: AddConsumedItemInputSchema,
|
|
179
|
+
annotations: {
|
|
180
|
+
readOnlyHint: false,
|
|
181
|
+
idempotentHint: false,
|
|
182
|
+
},
|
|
183
|
+
}, async (args) => {
|
|
184
|
+
return await this.addUserConsumedItem(args);
|
|
185
|
+
});
|
|
186
|
+
this.server.registerTool('remove_user_consumed_item', {
|
|
187
|
+
description: 'Remove a food item from user consumption log',
|
|
188
|
+
inputSchema: RemoveConsumedItemInputSchema,
|
|
189
|
+
annotations: {
|
|
190
|
+
readOnlyHint: false,
|
|
191
|
+
destructiveHint: true,
|
|
192
|
+
idempotentHint: true,
|
|
193
|
+
},
|
|
194
|
+
}, async (args) => {
|
|
195
|
+
return await this.removeUserConsumedItem(args);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
setupPromptHandlers() {
|
|
199
|
+
this.server.registerPrompt('add_food_item', {
|
|
200
|
+
title: 'Add Food Item to Log',
|
|
201
|
+
description: 'Guide for adding a food item to the user\'s consumption log',
|
|
202
|
+
}, async () => {
|
|
203
|
+
return {
|
|
204
|
+
messages: [
|
|
205
|
+
{
|
|
206
|
+
role: 'user',
|
|
207
|
+
content: {
|
|
208
|
+
type: 'text',
|
|
209
|
+
text: `To add a food item to the user's consumption log, follow these steps:
|
|
210
|
+
|
|
211
|
+
1. **Search for the product**: Use the \`search_products\` tool with a query string (e.g., "chicken breast", "apple", "pasta"). This will return a list of matching products with their IDs.
|
|
212
|
+
|
|
213
|
+
2. **Clarify the product**: If multiple products are found, ask the user to clarify which product they want to use.
|
|
214
|
+
|
|
215
|
+
3. **Get product details**: Use the \`get_product\` tool with the \`product_id\` from the search results. This will show you:
|
|
216
|
+
- Available serving types (e.g., "portion", "gram", "piece", "cup") and their amounts in base units (g or ml)
|
|
217
|
+
- Base unit (g or ml)
|
|
218
|
+
- Full nutritional information
|
|
219
|
+
|
|
220
|
+
4. **Clarify the serving**: If the user doesn't provide a serving type and quantity, ask them to clarify the serving type provided by previous step and quantity they want to add.
|
|
221
|
+
|
|
222
|
+
5. **Add the consumed item**: Use the \`add_user_consumed_item\` tool with:
|
|
223
|
+
- \`product_id\`: The UUID from step 1
|
|
224
|
+
- \`date\`: Date in YYYY-MM-DD format
|
|
225
|
+
- \`daytime\`: One of: "breakfast", "lunch", "dinner", or "snack"
|
|
226
|
+
- \`serving\`: Use a serving type from step 2 (e.g., "portion", "piece", "cup") OR base unit (g or ml)
|
|
227
|
+
- \`serving_quantity\`: Quantity of the serving type (e.g., 1, 2, 0.5)
|
|
228
|
+
- \`amount\`: Direct amount in base units (g or ml). If serving type is provided, use the amount of the serving type * serving_quantity. If serving type is not provided, use the amount of the base unit.
|
|
229
|
+
|
|
230
|
+
**Important Notes**:
|
|
231
|
+
- Always search first if you don't have a product_id
|
|
232
|
+
- Check product details to understand available serving types, base unit (g or ml) and amount in serving
|
|
233
|
+
- The date should be in ISO format (YYYY-MM-DD)
|
|
234
|
+
- You can use serving or base unit approach:
|
|
235
|
+
1. serving type + serving quantity + amount (amount for selected serving type multiplied by serving quantity)
|
|
236
|
+
2. amount in g/ml - serving fields could be omitted
|
|
237
|
+
Example:
|
|
238
|
+
1. "I ate 2 apples" - serving type "piece" which has 100g amount (from product details) + serving quantity 2 + amount 200g
|
|
239
|
+
2. "I ate 200g of chicken breast" - amount 200g
|
|
240
|
+
- Always provide amount in base units (g or ml), not in servings.
|
|
241
|
+
`
|
|
242
|
+
}
|
|
177
243
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
244
|
+
]
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
this.server.registerPrompt('remove_food_item', {
|
|
248
|
+
title: 'Remove Food Item from Log',
|
|
249
|
+
description: 'Guide for removing a food item from the user\'s consumption log',
|
|
250
|
+
}, async () => {
|
|
251
|
+
return {
|
|
252
|
+
messages: [
|
|
253
|
+
{
|
|
254
|
+
role: 'user',
|
|
255
|
+
content: {
|
|
256
|
+
type: 'text',
|
|
257
|
+
text: `To remove a food item from the user's consumption log, follow these steps:
|
|
258
|
+
|
|
259
|
+
1. **Get consumed items**: Use the \`get_user_consumed_items\` tool with the \`date\` parameter (in YYYY-MM-DD format) to retrieve all food entries for that date.
|
|
260
|
+
|
|
261
|
+
2. **Identify the item**: From the returned list of consumed items, identify the specific item you want to remove. Each item will have:
|
|
262
|
+
- \`id\`: The unique identifier for the consumed item (this is what you need for removal)
|
|
263
|
+
- \`product_id\`: The product identifier
|
|
264
|
+
- \`name\`: The product name
|
|
265
|
+
- \`date\`: The date it was consumed
|
|
266
|
+
- \`daytime\`: The meal type (breakfast, lunch, dinner, snack)
|
|
267
|
+
- Other details like amount, serving, etc.
|
|
268
|
+
|
|
269
|
+
3. **Remove the item**: Use the \`remove_user_consumed_item\` tool with:
|
|
270
|
+
- \`itemId\`: The \`id\` field from the consumed item you identified in step 2
|
|
271
|
+
|
|
272
|
+
**Important Notes**:
|
|
273
|
+
- You must first retrieve the consumed items to get the item ID
|
|
274
|
+
- The \`itemId\` is different from \`product_id\` - use the \`id\` field from the consumed item
|
|
275
|
+
- The date should be in ISO format (YYYY-MM-DD)
|
|
276
|
+
- If multiple items match the description, you may need to ask the user to clarify which specific item to remove`
|
|
277
|
+
}
|
|
187
278
|
}
|
|
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
|
-
}
|
|
279
|
+
]
|
|
280
|
+
};
|
|
231
281
|
});
|
|
232
282
|
}
|
|
233
283
|
async ensureAuthenticated() {
|
|
@@ -330,9 +380,10 @@ class YazioMcpServer {
|
|
|
330
380
|
content: [
|
|
331
381
|
{
|
|
332
382
|
type: 'text',
|
|
333
|
-
text: `
|
|
383
|
+
text: `Products:\n\n${JSON.stringify(products, null, 2)}`,
|
|
334
384
|
},
|
|
335
385
|
],
|
|
386
|
+
products,
|
|
336
387
|
};
|
|
337
388
|
}
|
|
338
389
|
catch (error) {
|
|
@@ -418,14 +469,15 @@ class YazioMcpServer {
|
|
|
418
469
|
async addUserConsumedItem(args) {
|
|
419
470
|
const client = await this.ensureAuthenticated();
|
|
420
471
|
try {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
472
|
+
await client.user.addConsumedItem({
|
|
473
|
+
...args,
|
|
474
|
+
id: uuidv4(),
|
|
475
|
+
});
|
|
424
476
|
return {
|
|
425
477
|
content: [
|
|
426
478
|
{
|
|
427
479
|
type: 'text',
|
|
428
|
-
text: `Successfully added consumed item
|
|
480
|
+
text: `Successfully added consumed item`,
|
|
429
481
|
},
|
|
430
482
|
],
|
|
431
483
|
};
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1,126 +1,93 @@
|
|
|
1
|
-
import
|
|
2
|
-
export declare const DaytimeSchema: z.ZodEnum<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export declare const DaytimeSchema: z.ZodEnum<{
|
|
3
|
+
breakfast: "breakfast";
|
|
4
|
+
lunch: "lunch";
|
|
5
|
+
dinner: "dinner";
|
|
6
|
+
snack: "snack";
|
|
7
|
+
}>;
|
|
8
|
+
export declare const DateStringSchema: z.ZodISODate;
|
|
9
|
+
export declare const ProductIdSchema: z.ZodUUID;
|
|
10
|
+
export declare const ItemIdSchema: z.ZodUUID;
|
|
11
|
+
export declare const ServingTypeSchema: z.ZodString;
|
|
7
12
|
export declare const QueryStringSchema: z.ZodString;
|
|
8
13
|
export declare const LimitSchema: z.ZodOptional<z.ZodNumber>;
|
|
9
14
|
export declare const DateInputSchema: z.ZodObject<{
|
|
10
|
-
date: z.
|
|
11
|
-
},
|
|
12
|
-
date: string;
|
|
13
|
-
}, {
|
|
14
|
-
date: string;
|
|
15
|
-
}>;
|
|
15
|
+
date: z.ZodISODate;
|
|
16
|
+
}, z.core.$strip>;
|
|
16
17
|
export declare const OptionalDateInputSchema: z.ZodObject<{
|
|
17
|
-
date: z.ZodOptional<z.
|
|
18
|
-
},
|
|
19
|
-
date?: string | undefined;
|
|
20
|
-
}, {
|
|
21
|
-
date?: string | undefined;
|
|
22
|
-
}>;
|
|
18
|
+
date: z.ZodOptional<z.ZodISODate>;
|
|
19
|
+
}, z.core.$strip>;
|
|
23
20
|
export declare const QueryInputSchema: z.ZodObject<{
|
|
24
21
|
query: z.ZodString;
|
|
25
|
-
},
|
|
26
|
-
query: string;
|
|
27
|
-
}, {
|
|
28
|
-
query: string;
|
|
29
|
-
}>;
|
|
22
|
+
}, z.core.$strip>;
|
|
30
23
|
export declare const OptionalQueryInputSchema: z.ZodObject<{
|
|
31
24
|
query: z.ZodOptional<z.ZodString>;
|
|
32
25
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
limit?: number | undefined;
|
|
36
|
-
}, {
|
|
37
|
-
query?: string | undefined;
|
|
38
|
-
limit?: number | undefined;
|
|
39
|
-
}>;
|
|
40
|
-
export declare const EmptyInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export declare const EmptyInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
41
28
|
export declare const GetFoodEntriesInputSchema: z.ZodObject<{
|
|
42
|
-
date: z.
|
|
43
|
-
},
|
|
44
|
-
date: string;
|
|
45
|
-
}, {
|
|
46
|
-
date: string;
|
|
47
|
-
}>;
|
|
29
|
+
date: z.ZodISODate;
|
|
30
|
+
}, z.core.$strip>;
|
|
48
31
|
export declare const GetDailySummaryInputSchema: z.ZodObject<{
|
|
49
|
-
date: z.
|
|
50
|
-
},
|
|
51
|
-
|
|
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, {}, {}>;
|
|
32
|
+
date: z.ZodISODate;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
export declare const GetUserInfoInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
35
|
+
export declare const GetUserWeightInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
57
36
|
export declare const GetWaterIntakeInputSchema: z.ZodObject<{
|
|
58
|
-
date: z.
|
|
59
|
-
},
|
|
60
|
-
date: string;
|
|
61
|
-
}, {
|
|
62
|
-
date: string;
|
|
63
|
-
}>;
|
|
37
|
+
date: z.ZodISODate;
|
|
38
|
+
}, z.core.$strip>;
|
|
64
39
|
export declare const SearchProductsInputSchema: z.ZodObject<{
|
|
65
40
|
query: z.ZodString;
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
export declare const SearchProductsOutputSchema: z.ZodObject<{
|
|
43
|
+
products: z.ZodArray<z.ZodObject<{
|
|
44
|
+
score: z.ZodNumber;
|
|
45
|
+
name: z.ZodString;
|
|
46
|
+
product_id: z.ZodUUID;
|
|
47
|
+
serving: z.ZodString;
|
|
48
|
+
serving_quantity: z.ZodNumber;
|
|
49
|
+
amount: z.ZodNumber;
|
|
50
|
+
base_unit: z.ZodEnum<{
|
|
51
|
+
g: "g";
|
|
52
|
+
ml: "ml";
|
|
53
|
+
}>;
|
|
54
|
+
producer: z.ZodNullable<z.ZodString>;
|
|
55
|
+
is_verified: z.ZodBoolean;
|
|
56
|
+
nutrients: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
57
|
+
countries: z.ZodArray<z.ZodString>;
|
|
58
|
+
language: z.ZodString;
|
|
59
|
+
}, z.core.$strip>>;
|
|
60
|
+
}, z.core.$strip>;
|
|
71
61
|
export declare const GetProductInputSchema: z.ZodObject<{
|
|
72
|
-
id: z.
|
|
73
|
-
},
|
|
74
|
-
id: string;
|
|
75
|
-
}, {
|
|
76
|
-
id: string;
|
|
77
|
-
}>;
|
|
62
|
+
id: z.ZodUUID;
|
|
63
|
+
}, z.core.$strip>;
|
|
78
64
|
export declare const GetUserExercisesInputSchema: z.ZodObject<{
|
|
79
|
-
date: z.ZodOptional<z.
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
}, {
|
|
83
|
-
date?: string | undefined;
|
|
84
|
-
}>;
|
|
85
|
-
export declare const GetUserSettingsInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
65
|
+
date: z.ZodOptional<z.ZodISODate>;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
export declare const GetUserSettingsInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
86
68
|
export declare const GetUserSuggestedProductsInputSchema: z.ZodObject<{
|
|
87
69
|
query: z.ZodOptional<z.ZodString>;
|
|
88
70
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
89
|
-
},
|
|
90
|
-
query?: string | undefined;
|
|
91
|
-
limit?: number | undefined;
|
|
92
|
-
}, {
|
|
93
|
-
query?: string | undefined;
|
|
94
|
-
limit?: number | undefined;
|
|
95
|
-
}>;
|
|
71
|
+
}, z.core.$strip>;
|
|
96
72
|
export declare const AddConsumedItemInputSchema: z.ZodObject<{
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
amount
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
}>;
|
|
73
|
+
product_id: z.ZodUUID;
|
|
74
|
+
date: z.ZodISODate;
|
|
75
|
+
daytime: z.ZodEnum<{
|
|
76
|
+
breakfast: "breakfast";
|
|
77
|
+
lunch: "lunch";
|
|
78
|
+
dinner: "dinner";
|
|
79
|
+
snack: "snack";
|
|
80
|
+
}>;
|
|
81
|
+
amount: z.ZodNumber;
|
|
82
|
+
serving: z.ZodOptional<z.ZodString>;
|
|
83
|
+
serving_quantity: z.ZodOptional<z.ZodNumber>;
|
|
84
|
+
}, z.core.$strip>;
|
|
115
85
|
export declare const RemoveConsumedItemInputSchema: z.ZodObject<{
|
|
116
|
-
itemId: z.
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
}>;
|
|
122
|
-
export declare const GetDietaryPreferencesInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
123
|
-
export declare const GetUserGoalsInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
86
|
+
itemId: z.ZodUUID;
|
|
87
|
+
}, z.core.$strip>;
|
|
88
|
+
export declare const GetDietaryPreferencesInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
89
|
+
export declare const GetUserGoalsInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
90
|
+
export type Daytime = z.infer<typeof DaytimeSchema>;
|
|
124
91
|
export type GetFoodEntriesInput = z.infer<typeof GetFoodEntriesInputSchema>;
|
|
125
92
|
export type GetDailySummaryInput = z.infer<typeof GetDailySummaryInputSchema>;
|
|
126
93
|
export type GetUserInfoInput = z.infer<typeof GetUserInfoInputSchema>;
|
package/dist/schemas.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as z from "zod";
|
|
2
2
|
export const DaytimeSchema = z.enum(['breakfast', 'lunch', 'dinner', 'snack']);
|
|
3
|
-
export const DateStringSchema = z.
|
|
4
|
-
export const ProductIdSchema = z.
|
|
5
|
-
export const ItemIdSchema =
|
|
3
|
+
export const DateStringSchema = z.iso.date().describe('Date in YYYY-MM-DD format');
|
|
4
|
+
export const ProductIdSchema = z.uuid().describe('Product UUID v1/v4 (e.g. 4ceff6e9-78ce-441b-964a-22e81c1dee92)');
|
|
5
|
+
export const ItemIdSchema = ProductIdSchema.describe('Unique item identifier');
|
|
6
|
+
export const ServingTypeSchema = z.string().describe('Serving type (e.g. portion, fruit, glass, cup, slice, piece, bar, gram, bottle, can, etc.)');
|
|
6
7
|
export const QueryStringSchema = z.string().describe('Search query string');
|
|
7
8
|
export const LimitSchema = z.number().optional().describe('Maximum number of results to return');
|
|
8
9
|
export const DateInputSchema = z.object({
|
|
9
|
-
date: DateStringSchema
|
|
10
|
+
date: DateStringSchema
|
|
10
11
|
});
|
|
11
12
|
export const OptionalDateInputSchema = z.object({
|
|
12
|
-
date: DateStringSchema.optional()
|
|
13
|
+
date: DateStringSchema.optional()
|
|
13
14
|
});
|
|
14
15
|
export const QueryInputSchema = z.object({
|
|
15
16
|
query: QueryStringSchema.describe('Search query')
|
|
@@ -25,6 +26,22 @@ export const GetUserInfoInputSchema = EmptyInputSchema;
|
|
|
25
26
|
export const GetUserWeightInputSchema = EmptyInputSchema; // Yazio getWeight doesn't accept parameters
|
|
26
27
|
export const GetWaterIntakeInputSchema = DateInputSchema;
|
|
27
28
|
export const SearchProductsInputSchema = QueryInputSchema;
|
|
29
|
+
export const SearchProductsOutputSchema = z.object({
|
|
30
|
+
products: z.array(z.object({
|
|
31
|
+
score: z.number(),
|
|
32
|
+
name: z.string(),
|
|
33
|
+
product_id: ProductIdSchema,
|
|
34
|
+
serving: ServingTypeSchema,
|
|
35
|
+
serving_quantity: z.number(),
|
|
36
|
+
amount: z.number(),
|
|
37
|
+
base_unit: z.enum(['g', 'ml']).describe('Base unit: grams (g) or milliliters (ml)'),
|
|
38
|
+
producer: z.string().nullable().describe('Producer name'),
|
|
39
|
+
is_verified: z.boolean(),
|
|
40
|
+
nutrients: z.record(z.string(), z.number()).describe('Nutrients object with keys like energy.energy, nutrient.carb, etc.'),
|
|
41
|
+
countries: z.array(z.string()).describe('Array of country codes (e.g. ["US", "DE"])'),
|
|
42
|
+
language: z.string().describe('Language code (e.g. "en", "de")'),
|
|
43
|
+
})),
|
|
44
|
+
});
|
|
28
45
|
export const GetProductInputSchema = z.object({
|
|
29
46
|
id: ProductIdSchema.describe('Product ID to get details for')
|
|
30
47
|
});
|
|
@@ -32,11 +49,13 @@ export const GetUserExercisesInputSchema = OptionalDateInputSchema; // Only supp
|
|
|
32
49
|
export const GetUserSettingsInputSchema = EmptyInputSchema;
|
|
33
50
|
export const GetUserSuggestedProductsInputSchema = OptionalQueryInputSchema;
|
|
34
51
|
export const AddConsumedItemInputSchema = z.object({
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
// id: ProductIdSchema.describe('Random identifier for the consumed item'),
|
|
53
|
+
product_id: ProductIdSchema,
|
|
54
|
+
date: DateStringSchema.describe('Date when the food was consumed'),
|
|
55
|
+
daytime: DaytimeSchema.describe('Type of meal (breakfast, lunch, dinner, snack)'),
|
|
56
|
+
amount: z.number().describe('Amount of the product consumed in base units (g or ml)'),
|
|
57
|
+
serving: ServingTypeSchema.optional(),
|
|
58
|
+
serving_quantity: z.number().optional().describe('Quantity of servings')
|
|
40
59
|
});
|
|
41
60
|
export const RemoveConsumedItemInputSchema = z.object({
|
|
42
61
|
itemId: ItemIdSchema.describe('ID of the consumed item to remove')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yazio-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "MCP server for accessing Yazio user & nutrition data (unofficial)",
|
|
5
5
|
"mcpName": "io.github.fliptheweb/yazio-mcp",
|
|
6
6
|
"author": "fliptheweb",
|
|
@@ -47,16 +47,15 @@
|
|
|
47
47
|
"node": ">=18.0.0"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
51
|
+
"uuid": "^13.0.0",
|
|
51
52
|
"yazio": "^1.0.0",
|
|
52
|
-
"zod": "^
|
|
53
|
-
"zod-to-json-schema": "^3.24.6"
|
|
53
|
+
"zod": "^4.2.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/node": "^20.0.0",
|
|
57
57
|
"@typescript-eslint/eslint-plugin": "^8.44.1",
|
|
58
58
|
"@typescript-eslint/parser": "^8.44.1",
|
|
59
|
-
"ajv-cli": "^5.0.0",
|
|
60
59
|
"eslint": "^9.36.0",
|
|
61
60
|
"globals": "^16.4.0",
|
|
62
61
|
"prettier": "^3.6.2",
|