@schaferandrew/mealie-mcp-server 0.1.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/.env.example +19 -0
- package/LICENSE +201 -0
- package/README.md +138 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +110 -0
- package/dist/index.js.map +1 -0
- package/dist/mealie-client.d.ts +26 -0
- package/dist/mealie-client.d.ts.map +1 -0
- package/dist/mealie-client.js +231 -0
- package/dist/mealie-client.js.map +1 -0
- package/dist/test-connection.d.ts +11 -0
- package/dist/test-connection.d.ts.map +1 -0
- package/dist/test-connection.js +119 -0
- package/dist/test-connection.js.map +1 -0
- package/dist/tools.d.ts +69 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +357 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +161 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MealieClient = void 0;
|
|
37
|
+
const axios_1 = __importStar(require("axios"));
|
|
38
|
+
// ─── Mealie API Client ─────────────────────────────────────────────────────────
|
|
39
|
+
class MealieClient {
|
|
40
|
+
http;
|
|
41
|
+
constructor(baseUrl, apiKey) {
|
|
42
|
+
this.http = axios_1.default.create({
|
|
43
|
+
baseURL: `${baseUrl}/api`,
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `Bearer ${apiKey}`,
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
Accept: "application/json",
|
|
48
|
+
},
|
|
49
|
+
timeout: 30_000,
|
|
50
|
+
});
|
|
51
|
+
// Sanitize API key from error messages
|
|
52
|
+
this.http.interceptors.response.use((response) => response, (error) => {
|
|
53
|
+
if (error.config?.headers?.["Authorization"]) {
|
|
54
|
+
error.config.headers["Authorization"] = "Bearer [REDACTED]";
|
|
55
|
+
}
|
|
56
|
+
return Promise.reject(error);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ─── Health Check ────────────────────────────────────────────────────────────
|
|
60
|
+
async healthCheck() {
|
|
61
|
+
try {
|
|
62
|
+
const response = await this.http.get("/app/about");
|
|
63
|
+
return { status: "ok", version: response.data.version };
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw this.wrapError("health check", error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ─── Recipe Search ────────────────────────────────────────────────────────────
|
|
70
|
+
async searchRecipes(query, tags, limit = 20) {
|
|
71
|
+
try {
|
|
72
|
+
const params = {
|
|
73
|
+
search: query,
|
|
74
|
+
perPage: limit,
|
|
75
|
+
page: 1,
|
|
76
|
+
orderBy: "name",
|
|
77
|
+
orderDirection: "asc",
|
|
78
|
+
};
|
|
79
|
+
if (tags && tags.length > 0) {
|
|
80
|
+
params["tags"] = tags.join(",");
|
|
81
|
+
}
|
|
82
|
+
const response = await this.http.get("/recipes", { params });
|
|
83
|
+
return response.data.items ?? [];
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw this.wrapError("search recipes", error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// ─── Get Full Recipe ──────────────────────────────────────────────────────────
|
|
90
|
+
async getRecipe(recipeSlugOrId) {
|
|
91
|
+
try {
|
|
92
|
+
const response = await this.http.get(`/recipes/${recipeSlugOrId}`);
|
|
93
|
+
return response.data;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
throw this.wrapError(`get recipe '${recipeSlugOrId}'`, error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// ─── List Recipes ─────────────────────────────────────────────────────────────
|
|
100
|
+
async listRecipes(options = {}) {
|
|
101
|
+
try {
|
|
102
|
+
const { tags, categories, limit = 50, offset = 0 } = options;
|
|
103
|
+
const page = Math.floor(offset / limit) + 1;
|
|
104
|
+
const params = {
|
|
105
|
+
perPage: limit,
|
|
106
|
+
page,
|
|
107
|
+
orderBy: "name",
|
|
108
|
+
orderDirection: "asc",
|
|
109
|
+
};
|
|
110
|
+
if (tags && tags.length > 0) {
|
|
111
|
+
params["tags"] = tags.join(",");
|
|
112
|
+
}
|
|
113
|
+
if (categories && categories.length > 0) {
|
|
114
|
+
params["categories"] = categories.join(",");
|
|
115
|
+
}
|
|
116
|
+
const response = await this.http.get("/recipes", { params });
|
|
117
|
+
return {
|
|
118
|
+
items: response.data.items ?? [],
|
|
119
|
+
total: response.data.total ?? 0,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
throw this.wrapError("list recipes", error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ─── Create Recipe from URL ───────────────────────────────────────────────────
|
|
127
|
+
async createRecipeFromUrl(url, includeTags = false, includeCategories = false) {
|
|
128
|
+
try {
|
|
129
|
+
const response = await this.http.post("/recipes/create/url", {
|
|
130
|
+
url,
|
|
131
|
+
includeTags,
|
|
132
|
+
includeCategories,
|
|
133
|
+
});
|
|
134
|
+
const slug = typeof response.data === "string"
|
|
135
|
+
? response.data.replace(/^"|"$/g, "")
|
|
136
|
+
: response.data;
|
|
137
|
+
return await this.getRecipe(slug);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw this.wrapError(`create recipe from URL '${url}'`, error);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// ─── Search by Ingredient ─────────────────────────────────────────────────────
|
|
144
|
+
async searchByIngredient(ingredient, limit = 20) {
|
|
145
|
+
try {
|
|
146
|
+
// Mealie's search endpoint searches across name, description, ingredients, and instructions
|
|
147
|
+
const response = await this.http.get("/recipes", {
|
|
148
|
+
params: {
|
|
149
|
+
search: ingredient,
|
|
150
|
+
perPage: limit,
|
|
151
|
+
page: 1,
|
|
152
|
+
orderBy: "name",
|
|
153
|
+
orderDirection: "asc",
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
const items = response.data.items ?? [];
|
|
157
|
+
// Filter to only recipes that actually contain the ingredient in their text
|
|
158
|
+
// We do a loose client-side filter since the API search is broad
|
|
159
|
+
const lowerIngredient = ingredient.toLowerCase();
|
|
160
|
+
return items.filter((recipe) => {
|
|
161
|
+
const searchText = [
|
|
162
|
+
recipe.name,
|
|
163
|
+
recipe.description,
|
|
164
|
+
]
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
.join(" ")
|
|
167
|
+
.toLowerCase();
|
|
168
|
+
return searchText.includes(lowerIngredient);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
throw this.wrapError(`search by ingredient '${ingredient}'`, error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
176
|
+
toTagSlug(name) {
|
|
177
|
+
return name
|
|
178
|
+
.toLowerCase()
|
|
179
|
+
.replace(/\s+/g, "-")
|
|
180
|
+
.replace(/[^a-z0-9-]/g, "");
|
|
181
|
+
}
|
|
182
|
+
// ─── Tags ─────────────────────────────────────────────────────────────────────
|
|
183
|
+
async listTags() {
|
|
184
|
+
try {
|
|
185
|
+
const response = await this.http.get("/organizers/tags", {
|
|
186
|
+
params: { perPage: 200, page: 1 },
|
|
187
|
+
});
|
|
188
|
+
return response.data.items ?? [];
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
throw this.wrapError("list tags", error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// ─── Error Handling ───────────────────────────────────────────────────────────
|
|
195
|
+
wrapError(operation, error) {
|
|
196
|
+
if (error instanceof axios_1.AxiosError) {
|
|
197
|
+
const status = error.response?.status;
|
|
198
|
+
const statusText = error.response?.statusText;
|
|
199
|
+
if (!error.response) {
|
|
200
|
+
return new Error(`Mealie is unreachable during ${operation}. ` +
|
|
201
|
+
`Check that MEALIE_URL is correct and Mealie is running. ` +
|
|
202
|
+
`Original error: ${error.message}`);
|
|
203
|
+
}
|
|
204
|
+
switch (status) {
|
|
205
|
+
case 401:
|
|
206
|
+
return new Error(`Authentication failed during ${operation}. ` +
|
|
207
|
+
`Check that MEALIE_API_KEY is correct and has not expired.`);
|
|
208
|
+
case 403:
|
|
209
|
+
return new Error(`Permission denied during ${operation}. ` +
|
|
210
|
+
`The API key may not have sufficient permissions.`);
|
|
211
|
+
case 404:
|
|
212
|
+
return new Error(`Resource not found during ${operation}. ` +
|
|
213
|
+
`The recipe ID or slug may be incorrect.`);
|
|
214
|
+
case 422: {
|
|
215
|
+
const detail = error.response?.data?.detail;
|
|
216
|
+
return new Error(`Validation error during ${operation}: ${JSON.stringify(detail)}`);
|
|
217
|
+
}
|
|
218
|
+
case 429:
|
|
219
|
+
return new Error(`Rate limit exceeded during ${operation}. Please try again later.`);
|
|
220
|
+
default:
|
|
221
|
+
return new Error(`Mealie API error during ${operation}: ${status} ${statusText}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (error instanceof Error) {
|
|
225
|
+
return new Error(`Error during ${operation}: ${error.message}`);
|
|
226
|
+
}
|
|
227
|
+
return new Error(`Unknown error during ${operation}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
exports.MealieClient = MealieClient;
|
|
231
|
+
//# sourceMappingURL=mealie-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mealie-client.js","sourceRoot":"","sources":["../src/mealie-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
/**
|
|
3
|
+
* Connection test script for the Mealie MCP Server.
|
|
4
|
+
*
|
|
5
|
+
* Run with:
|
|
6
|
+
* npx ts-node src/test-connection.ts
|
|
7
|
+
* # or after building:
|
|
8
|
+
* node dist/test-connection.js
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=test-connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-connection.d.ts","sourceRoot":"","sources":["../src/test-connection.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Connection test script for the Mealie MCP Server.
|
|
5
|
+
*
|
|
6
|
+
* Run with:
|
|
7
|
+
* npx ts-node src/test-connection.ts
|
|
8
|
+
* # or after building:
|
|
9
|
+
* node dist/test-connection.js
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
const dotenv = __importStar(require("dotenv"));
|
|
46
|
+
dotenv.config();
|
|
47
|
+
const mealie_client_js_1 = require("./mealie-client.js");
|
|
48
|
+
const config_js_1 = require("./config.js");
|
|
49
|
+
const RESET = "\x1b[0m";
|
|
50
|
+
const GREEN = "\x1b[32m";
|
|
51
|
+
const RED = "\x1b[31m";
|
|
52
|
+
const YELLOW = "\x1b[33m";
|
|
53
|
+
const BOLD = "\x1b[1m";
|
|
54
|
+
function pass(msg) {
|
|
55
|
+
console.log(`${GREEN}✓${RESET} ${msg}`);
|
|
56
|
+
}
|
|
57
|
+
function fail(msg) {
|
|
58
|
+
console.log(`${RED}✗${RESET} ${msg}`);
|
|
59
|
+
}
|
|
60
|
+
function info(msg) {
|
|
61
|
+
console.log(`${YELLOW}→${RESET} ${msg}`);
|
|
62
|
+
}
|
|
63
|
+
async function runTests() {
|
|
64
|
+
console.log(`\n${BOLD}Mealie MCP Server — Connection Test${RESET}`);
|
|
65
|
+
console.log("=".repeat(40));
|
|
66
|
+
// ── Config Check ──────────────────────────────────────────────────────────────
|
|
67
|
+
console.log(`\n${BOLD}1. Configuration${RESET}`);
|
|
68
|
+
info(`MEALIE_URL: ${config_js_1.config.mealieUrl}`);
|
|
69
|
+
info(`MEALIE_API_KEY: ${config_js_1.config.mealieApiKey.slice(0, 8)}${"*".repeat(Math.max(0, config_js_1.config.mealieApiKey.length - 8))}`);
|
|
70
|
+
info(`MCP_PORT: ${config_js_1.config.port}`);
|
|
71
|
+
pass("Configuration loaded successfully");
|
|
72
|
+
const client = new mealie_client_js_1.MealieClient(config_js_1.config.mealieUrl, config_js_1.config.mealieApiKey);
|
|
73
|
+
// ── Health Check ──────────────────────────────────────────────────────────────
|
|
74
|
+
console.log(`\n${BOLD}2. Health Check${RESET}`);
|
|
75
|
+
try {
|
|
76
|
+
const health = await client.healthCheck();
|
|
77
|
+
pass(`Mealie is reachable${health.version ? ` (version: ${health.version})` : ""}`);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
fail(`Cannot reach Mealie: ${err instanceof Error ? err.message : String(err)}`);
|
|
81
|
+
console.log("\nCheck that:");
|
|
82
|
+
console.log(" • MEALIE_URL is correct");
|
|
83
|
+
console.log(" • Mealie is running");
|
|
84
|
+
console.log(" • There are no firewall rules blocking the connection");
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
// ── List Recipes ──────────────────────────────────────────────────────────────
|
|
88
|
+
console.log(`\n${BOLD}3. List Recipes${RESET}`);
|
|
89
|
+
try {
|
|
90
|
+
const result = await client.listRecipes({ limit: 5 });
|
|
91
|
+
pass(`Retrieved recipe list (${result.total} recipes total)`);
|
|
92
|
+
if (result.items.length > 0) {
|
|
93
|
+
info(`First recipe: "${result.items[0].name}" (slug: ${result.items[0].slug})`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
info("No recipes found in your Mealie instance yet.");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
fail(`Could not list recipes: ${err instanceof Error ? err.message : String(err)}`);
|
|
101
|
+
}
|
|
102
|
+
// ── Search Recipes ────────────────────────────────────────────────────────────
|
|
103
|
+
console.log(`\n${BOLD}4. Search Recipes${RESET}`);
|
|
104
|
+
try {
|
|
105
|
+
const results = await client.searchRecipes("a", undefined, 3);
|
|
106
|
+
pass(`Search returned ${results.length} result(s)`);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
fail(`Search failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
110
|
+
}
|
|
111
|
+
// ── Summary ───────────────────────────────────────────────────────────────────
|
|
112
|
+
console.log(`\n${BOLD}All tests complete!${RESET}`);
|
|
113
|
+
console.log("Your Mealie MCP Server is configured correctly and ready to use.\n");
|
|
114
|
+
}
|
|
115
|
+
runTests().catch((err) => {
|
|
116
|
+
console.error(`${RED}Fatal error during tests:${RESET}`, err instanceof Error ? err.message : err);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=test-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-connection.js","sourceRoot":"","sources":["../src/test-connection.ts"],"names":[],"mappings":";;AAEA;;;;;;;GAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,+CAAiC;AACjC,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,yDAAkD;AAClD,2CAAqC;AAErC,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,KAAK,GAAG,UAAU,CAAC;AACzB,MAAM,GAAG,GAAG,UAAU,CAAC;AACvB,MAAM,MAAM,GAAG,UAAU,CAAC;AAC1B,MAAM,IAAI,GAAG,SAAS,CAAC;AAEvB,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,QAAQ;IACrB,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,sCAAsC,KAAK,EAAE,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,iFAAiF;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,mBAAmB,KAAK,EAAE,CAAC,CAAC;IACjD,IAAI,CAAC,mBAAmB,kBAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5C,IAAI,CAAC,mBAAmB,kBAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrH,IAAI,CAAC,mBAAmB,kBAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAE1C,MAAM,MAAM,GAAG,IAAI,+BAAY,CAAC,kBAAM,CAAC,SAAS,EAAE,kBAAM,CAAC,YAAY,CAAC,CAAC;IAEvE,iFAAiF;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,kBAAkB,KAAK,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,sBAAsB,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,wBAAwB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjF,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,iFAAiF;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,kBAAkB,KAAK,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,0BAA0B,MAAM,CAAC,KAAK,iBAAiB,CAAC,CAAC;QAC9D,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,kBAAkB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,GAAG,CAAC,CAAC;QACpF,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,+CAA+C,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,iFAAiF;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,oBAAoB,KAAK,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,mBAAmB,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,kBAAkB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,iFAAiF;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,sBAAsB,KAAK,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;AACpF,CAAC;AAED,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACvB,OAAO,CAAC,KAAK,CACX,GAAG,GAAG,4BAA4B,KAAK,EAAE,EACzC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { MealieClient } from "./mealie-client.js";
|
|
3
|
+
export declare const SearchRecipesSchema: z.ZodObject<{
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
6
|
+
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
limit: number;
|
|
9
|
+
query: string;
|
|
10
|
+
tags?: string[] | undefined;
|
|
11
|
+
}, {
|
|
12
|
+
query: string;
|
|
13
|
+
tags?: string[] | undefined;
|
|
14
|
+
limit?: number | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const GetRecipeSchema: z.ZodObject<{
|
|
17
|
+
recipe_id: z.ZodString;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
recipe_id: string;
|
|
20
|
+
}, {
|
|
21
|
+
recipe_id: string;
|
|
22
|
+
}>;
|
|
23
|
+
export declare const ListRecipesSchema: z.ZodObject<{
|
|
24
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
25
|
+
categories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
26
|
+
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
27
|
+
offset: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
28
|
+
}, "strip", z.ZodTypeAny, {
|
|
29
|
+
limit: number;
|
|
30
|
+
offset: number;
|
|
31
|
+
tags?: string[] | undefined;
|
|
32
|
+
categories?: string[] | undefined;
|
|
33
|
+
}, {
|
|
34
|
+
tags?: string[] | undefined;
|
|
35
|
+
categories?: string[] | undefined;
|
|
36
|
+
limit?: number | undefined;
|
|
37
|
+
offset?: number | undefined;
|
|
38
|
+
}>;
|
|
39
|
+
export declare const AddRecipeFromUrlSchema: z.ZodObject<{
|
|
40
|
+
url: z.ZodString;
|
|
41
|
+
includeTags: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
42
|
+
includeCategories: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
43
|
+
}, "strip", z.ZodTypeAny, {
|
|
44
|
+
url: string;
|
|
45
|
+
includeTags: boolean;
|
|
46
|
+
includeCategories: boolean;
|
|
47
|
+
}, {
|
|
48
|
+
url: string;
|
|
49
|
+
includeTags?: boolean | undefined;
|
|
50
|
+
includeCategories?: boolean | undefined;
|
|
51
|
+
}>;
|
|
52
|
+
export declare const SearchByIngredientSchema: z.ZodObject<{
|
|
53
|
+
ingredient: z.ZodString;
|
|
54
|
+
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
limit: number;
|
|
57
|
+
ingredient: string;
|
|
58
|
+
}, {
|
|
59
|
+
ingredient: string;
|
|
60
|
+
limit?: number | undefined;
|
|
61
|
+
}>;
|
|
62
|
+
export interface ToolDefinition {
|
|
63
|
+
name: string;
|
|
64
|
+
description: string;
|
|
65
|
+
inputSchema: object;
|
|
66
|
+
}
|
|
67
|
+
export declare const TOOL_DEFINITIONS: ToolDefinition[];
|
|
68
|
+
export declare function handleTool(name: string, args: unknown, client: MealieClient): Promise<string>;
|
|
69
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAc9B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;EAK1B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;EAwB5B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;EAYjC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;EAanC,CAAC;AAIH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,gBAAgB,EAAE,cAAc,EA8H5C,CAAC;AAIF,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,MAAM,CAAC,CA6CjB"}
|