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 +21 -0
- package/README.md +98 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +495 -0
- package/dist/schemas.d.ts +137 -0
- package/dist/schemas.js +45 -0
- package/dist/types.d.ts +266 -0
- package/dist/types.js +3 -0
- package/package.json +64 -0
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.
|
package/dist/index.d.ts
ADDED
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>;
|
package/dist/schemas.js
ADDED
|
@@ -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;
|
package/dist/types.d.ts
ADDED
|
@@ -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
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
|
+
}
|