wellness-nourish 0.1.0

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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/SECURITY.md +9 -0
  4. package/dist/cli/commands.d.ts +3 -0
  5. package/dist/cli/commands.js +467 -0
  6. package/dist/cli/commands.js.map +1 -0
  7. package/dist/constants.d.ts +8 -0
  8. package/dist/constants.js +9 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.js +153 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/prompts/nourish-prompts.d.ts +2 -0
  14. package/dist/prompts/nourish-prompts.js +17 -0
  15. package/dist/prompts/nourish-prompts.js.map +1 -0
  16. package/dist/providers/open-food-facts.d.ts +5 -0
  17. package/dist/providers/open-food-facts.js +141 -0
  18. package/dist/providers/open-food-facts.js.map +1 -0
  19. package/dist/providers/usda.d.ts +6 -0
  20. package/dist/providers/usda.js +157 -0
  21. package/dist/providers/usda.js.map +1 -0
  22. package/dist/resources/nourish-resources.d.ts +2 -0
  23. package/dist/resources/nourish-resources.js +26 -0
  24. package/dist/resources/nourish-resources.js.map +1 -0
  25. package/dist/schemas/common.d.ts +224 -0
  26. package/dist/schemas/common.js +224 -0
  27. package/dist/schemas/common.js.map +1 -0
  28. package/dist/services/agent-manifest.d.ts +27 -0
  29. package/dist/services/agent-manifest.js +80 -0
  30. package/dist/services/agent-manifest.js.map +1 -0
  31. package/dist/services/capabilities.d.ts +12 -0
  32. package/dist/services/capabilities.js +27 -0
  33. package/dist/services/capabilities.js.map +1 -0
  34. package/dist/services/config.d.ts +3 -0
  35. package/dist/services/config.js +32 -0
  36. package/dist/services/config.js.map +1 -0
  37. package/dist/services/connection-status.d.ts +13 -0
  38. package/dist/services/connection-status.js +34 -0
  39. package/dist/services/connection-status.js.map +1 -0
  40. package/dist/services/food-normalization.d.ts +3 -0
  41. package/dist/services/food-normalization.js +14 -0
  42. package/dist/services/food-normalization.js.map +1 -0
  43. package/dist/services/format.d.ts +13 -0
  44. package/dist/services/format.js +58 -0
  45. package/dist/services/format.js.map +1 -0
  46. package/dist/services/goals-store.d.ts +7 -0
  47. package/dist/services/goals-store.js +87 -0
  48. package/dist/services/goals-store.js.map +1 -0
  49. package/dist/services/hydration-store.d.ts +12 -0
  50. package/dist/services/hydration-store.js +96 -0
  51. package/dist/services/hydration-store.js.map +1 -0
  52. package/dist/services/intake-store.d.ts +15 -0
  53. package/dist/services/intake-store.js +170 -0
  54. package/dist/services/intake-store.js.map +1 -0
  55. package/dist/services/meal-estimator.d.ts +22 -0
  56. package/dist/services/meal-estimator.js +178 -0
  57. package/dist/services/meal-estimator.js.map +1 -0
  58. package/dist/services/nutrients.d.ts +4 -0
  59. package/dist/services/nutrients.js +31 -0
  60. package/dist/services/nutrients.js.map +1 -0
  61. package/dist/services/portion-engine.d.ts +4 -0
  62. package/dist/services/portion-engine.js +50 -0
  63. package/dist/services/portion-engine.js.map +1 -0
  64. package/dist/services/privacy-audit.d.ts +12 -0
  65. package/dist/services/privacy-audit.js +19 -0
  66. package/dist/services/privacy-audit.js.map +1 -0
  67. package/dist/services/summary.d.ts +28 -0
  68. package/dist/services/summary.js +84 -0
  69. package/dist/services/summary.js.map +1 -0
  70. package/dist/services/usage-guide.d.ts +12 -0
  71. package/dist/services/usage-guide.js +57 -0
  72. package/dist/services/usage-guide.js.map +1 -0
  73. package/dist/tools/nourish-tools.d.ts +2 -0
  74. package/dist/tools/nourish-tools.js +603 -0
  75. package/dist/tools/nourish-tools.js.map +1 -0
  76. package/dist/types.d.ts +97 -0
  77. package/dist/types.js +2 -0
  78. package/dist/types.js.map +1 -0
  79. package/examples/claude-desktop.json +13 -0
  80. package/examples/codex.json +13 -0
  81. package/examples/cursor.json +13 -0
  82. package/examples/hermes.md +18 -0
  83. package/examples/openclaw.md +18 -0
  84. package/examples/windsurf.json +13 -0
  85. package/fixtures/open-food-facts/barcode-peanut-butter.json +23 -0
  86. package/fixtures/usda/food-banana.json +16 -0
  87. package/fixtures/usda/search-banana.json +17 -0
  88. package/package.json +52 -0
  89. package/server.json +16 -0
  90. package/tsconfig.json +21 -0
@@ -0,0 +1,8 @@
1
+ export declare const SERVER_NAME = "nourish-mcp";
2
+ export declare const SERVER_VERSION = "0.1.0";
3
+ export declare const DEFAULT_HOST = "127.0.0.1";
4
+ export declare const DEFAULT_PORT = 3000;
5
+ export declare const LOCAL_DIR_NAME = ".wellness-nourish";
6
+ export declare const USER_AGENT = "wellness-nourish/0.1.0 (https://wellness.delx.ai; contact: david@delx.ai)";
7
+ export declare const USDA_BASE_URL = "https://api.nal.usda.gov/fdc/v1";
8
+ export declare const OFF_BASE_URL = "https://world.openfoodfacts.org";
@@ -0,0 +1,9 @@
1
+ export const SERVER_NAME = "nourish-mcp";
2
+ export const SERVER_VERSION = "0.1.0";
3
+ export const DEFAULT_HOST = "127.0.0.1";
4
+ export const DEFAULT_PORT = 3000;
5
+ export const LOCAL_DIR_NAME = ".wellness-nourish";
6
+ export const USER_AGENT = "wellness-nourish/0.1.0 (https://wellness.delx.ai; contact: david@delx.ai)";
7
+ export const USDA_BASE_URL = "https://api.nal.usda.gov/fdc/v1";
8
+ export const OFF_BASE_URL = "https://world.openfoodfacts.org";
9
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AACzC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AACtC,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC;AACxC,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG,2EAA2E,CAAC;AACtG,MAAM,CAAC,MAAM,aAAa,GAAG,iCAAiC,CAAC;AAC/D,MAAM,CAAC,MAAM,YAAY,GAAG,iCAAiC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ export declare function createServer(): McpServer;
package/dist/index.js ADDED
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ import http from "node:http";
3
+ import cors from "cors";
4
+ import express from "express";
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
8
+ import { isCliCommand, isUnknownCliCommand, runCliCommand } from "./cli/commands.js";
9
+ import { DEFAULT_HOST, DEFAULT_PORT, SERVER_NAME, SERVER_VERSION } from "./constants.js";
10
+ import { registerNourishPrompts } from "./prompts/nourish-prompts.js";
11
+ import { registerNourishResources } from "./resources/nourish-resources.js";
12
+ import { registerNourishTools } from "./tools/nourish-tools.js";
13
+ export function createServer() {
14
+ const server = new McpServer({
15
+ name: SERVER_NAME,
16
+ version: SERVER_VERSION,
17
+ });
18
+ registerNourishTools(server);
19
+ registerNourishResources(server);
20
+ registerNourishPrompts(server);
21
+ return server;
22
+ }
23
+ function helpText() {
24
+ return [
25
+ "Usage: nourish-mcp [--http] [--help] [--version]",
26
+ " nourish-mcp <command> [args]",
27
+ "",
28
+ "Starts the Nourish MCP server over stdio by default.",
29
+ "",
30
+ "Options:",
31
+ " --http Start Streamable HTTP transport at POST /mcp.",
32
+ " --help Print this usage text without starting the server.",
33
+ " --version Print the package name and version.",
34
+ "",
35
+ "Commands:",
36
+ " status Print connection status.",
37
+ " doctor Run local DX checks.",
38
+ " setup --client <name> Print MCP client config.",
39
+ " search <query> Search USDA foods.",
40
+ " barcode <barcode> Lookup an Open Food Facts barcode.",
41
+ " log [--preview] <text...> Estimate or log a meal.",
42
+ " list [date] List intake entries.",
43
+ " edit --entry <id> [flags] Edit intake metadata.",
44
+ " today [--format markdown] Print today's intake summary.",
45
+ " weekly [--format markdown] Print seven-day intake summary.",
46
+ " export [--format csv|jsonl] Export intake data.",
47
+ " water <ml>|today Log or summarize hydration.",
48
+ " goals [--set-calories n] Show or update local goals.",
49
+ " clear-day <date> --yes Delete all intake entries for a day.",
50
+ " delete --entry <id> Delete an intake entry.",
51
+ ].join("\n");
52
+ }
53
+ async function startStdio() {
54
+ const server = createServer();
55
+ const transport = new StdioServerTransport();
56
+ await server.connect(transport);
57
+ }
58
+ async function startHttp() {
59
+ const host = process.env.NOURISH_MCP_HOST ?? DEFAULT_HOST;
60
+ const port = parsePort(process.env.NOURISH_MCP_PORT);
61
+ const allowedOrigin = process.env.NOURISH_MCP_ALLOWED_ORIGIN ?? `http://${host}:${port}`;
62
+ const app = express();
63
+ app.use(cors({
64
+ origin: allowedOrigin,
65
+ }));
66
+ app.use(express.json({ limit: "1mb" }));
67
+ app.get("/health", (_req, res) => {
68
+ res.json({
69
+ ok: true,
70
+ name: SERVER_NAME,
71
+ version: SERVER_VERSION,
72
+ });
73
+ });
74
+ app.post("/mcp", async (req, res) => {
75
+ const server = createServer();
76
+ const transportOptions = {
77
+ enableJsonResponse: true,
78
+ sessionIdGenerator: undefined,
79
+ };
80
+ const transport = new StreamableHTTPServerTransport(transportOptions);
81
+ let closed = false;
82
+ const close = async () => {
83
+ if (closed) {
84
+ return;
85
+ }
86
+ closed = true;
87
+ await transport.close();
88
+ await server.close();
89
+ };
90
+ res.on("close", () => {
91
+ void close();
92
+ });
93
+ try {
94
+ await server.connect(transport);
95
+ await transport.handleRequest(req, res, req.body);
96
+ }
97
+ catch (error) {
98
+ if (!res.headersSent) {
99
+ res.status(500).json({
100
+ jsonrpc: "2.0",
101
+ error: {
102
+ code: -32603,
103
+ message: error instanceof Error ? error.message : "Internal server error",
104
+ },
105
+ id: null,
106
+ });
107
+ }
108
+ await close();
109
+ }
110
+ });
111
+ const httpServer = http.createServer(app);
112
+ await new Promise((resolve, reject) => {
113
+ httpServer.once("error", reject);
114
+ httpServer.listen(port, host, () => {
115
+ httpServer.off("error", reject);
116
+ resolve();
117
+ });
118
+ });
119
+ process.on("SIGTERM", () => {
120
+ httpServer.close(() => process.exit(0));
121
+ });
122
+ process.on("SIGINT", () => {
123
+ httpServer.close(() => process.exit(0));
124
+ });
125
+ }
126
+ function parsePort(value) {
127
+ if (value === undefined) {
128
+ return DEFAULT_PORT;
129
+ }
130
+ const parsed = Number.parseInt(value, 10);
131
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_PORT;
132
+ }
133
+ const args = process.argv.slice(2);
134
+ if (args.includes("--version")) {
135
+ console.log(`${SERVER_NAME} ${SERVER_VERSION}`);
136
+ }
137
+ else if (args.includes("--help") || args.includes("-h")) {
138
+ console.log(helpText());
139
+ }
140
+ else if (isCliCommand(args)) {
141
+ process.exitCode = await runCliCommand(args);
142
+ }
143
+ else if (isUnknownCliCommand(args)) {
144
+ console.error("Unknown command");
145
+ process.exitCode = 1;
146
+ }
147
+ else if (args.includes("--http") || process.env.NOURISH_MCP_TRANSPORT === "http") {
148
+ await startHttp();
149
+ }
150
+ else {
151
+ await startStdio();
152
+ }
153
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerNourishPrompts(server: McpServer): void;
@@ -0,0 +1,17 @@
1
+ export function registerNourishPrompts(server) {
2
+ server.registerPrompt("nourish_daily_review", {
3
+ title: "Nourish daily review",
4
+ description: "Review a day of logged nutrition while preserving confidence and source coverage.",
5
+ }, async () => ({
6
+ messages: [
7
+ {
8
+ role: "user",
9
+ content: {
10
+ type: "text",
11
+ text: "Call nourish_daily_summary for the requested date or today's date. Summarize total nutrients, meal distribution, confidence, and source coverage. Preserve uncertainty, source quality, and license/attribution context. Do not provide medical advice, diagnosis, treatment, or emergency guidance.",
12
+ },
13
+ },
14
+ ],
15
+ }));
16
+ }
17
+ //# sourceMappingURL=nourish-prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nourish-prompts.js","sourceRoot":"","sources":["../../src/prompts/nourish-prompts.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,cAAc,CACnB,sBAAsB,EACtB;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,mFAAmF;KACjG,EACD,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EACF,sSAAsS;iBACzS;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { FoodItem } from "../types.js";
2
+ export declare function lookupOpenFoodFactsBarcode(barcode: string): Promise<{
3
+ food: FoodItem;
4
+ provider: "open_food_facts";
5
+ }>;
@@ -0,0 +1,141 @@
1
+ /// <reference types="node" />
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { OFF_BASE_URL, USER_AGENT } from "../constants.js";
5
+ import { foodCompleteness, makeFoodId } from "../services/food-normalization.js";
6
+ import { nutrientsForGrams } from "../services/portion-engine.js";
7
+ import { roundNutrient } from "../services/nutrients.js";
8
+ import { getConfig, getFixtureDir } from "../services/config.js";
9
+ const OFF_LICENSE = {
10
+ name: "Open Food Facts ODbL",
11
+ attribution: "Food data sourced from Open Food Facts. Open Food Facts data is available under ODbL.",
12
+ share_alike: true,
13
+ url: "https://world.openfoodfacts.org/",
14
+ };
15
+ const NUTRIENT_KEYS = {
16
+ "energy-kcal_100g": "calories_kcal",
17
+ proteins_100g: "protein_g",
18
+ carbohydrates_100g: "carbohydrates_g",
19
+ fat_100g: "fat_g",
20
+ fiber_100g: "fiber_g",
21
+ sugars_100g: "sugar_g",
22
+ "saturated-fat_100g": "saturated_fat_g",
23
+ };
24
+ function finiteNumber(value) {
25
+ if (typeof value === "number" && Number.isFinite(value)) {
26
+ return value;
27
+ }
28
+ if (typeof value === "string" && value.trim() !== "") {
29
+ const parsed = Number.parseFloat(value);
30
+ return Number.isFinite(parsed) ? parsed : undefined;
31
+ }
32
+ return undefined;
33
+ }
34
+ async function readFixture(barcode) {
35
+ const fixture = JSON.parse(await readFile(join(getFixtureDir(), "open-food-facts", "barcode-peanut-butter.json"), "utf8"));
36
+ if (fixture.code !== barcode || fixture.product?.code !== barcode) {
37
+ throw new Error(`Open Food Facts fixture not found for barcode ${barcode}`);
38
+ }
39
+ return fixture;
40
+ }
41
+ async function fetchBarcode(barcode) {
42
+ const url = new URL(`${OFF_BASE_URL}/api/v2/product/${encodeURIComponent(barcode)}`);
43
+ url.searchParams.set("fields", "code,product_name,brands,url,quantity,serving_size,serving_quantity,nutriments");
44
+ const response = await fetch(url, {
45
+ headers: {
46
+ "user-agent": USER_AGENT,
47
+ accept: "application/json",
48
+ },
49
+ });
50
+ if (!response.ok) {
51
+ throw new Error(`Open Food Facts request failed: ${response.status} ${response.statusText}`);
52
+ }
53
+ return (await response.json());
54
+ }
55
+ function mapNutrients(nutriments = {}) {
56
+ const nutrients = {};
57
+ for (const [offKey, nutrientKey] of Object.entries(NUTRIENT_KEYS)) {
58
+ const value = finiteNumber(nutriments[offKey]);
59
+ if (value !== undefined) {
60
+ nutrients[nutrientKey] = roundNutrient(value);
61
+ }
62
+ }
63
+ const sodiumGrams = finiteNumber(nutriments.sodium_100g);
64
+ if (sodiumGrams !== undefined) {
65
+ nutrients.sodium_mg = roundNutrient(sodiumGrams * 1000);
66
+ }
67
+ return nutrients;
68
+ }
69
+ function sourceUrl(product, sourceId) {
70
+ return product.url ?? `${OFF_BASE_URL}/product/${encodeURIComponent(sourceId)}`;
71
+ }
72
+ function mapProduct(response, barcode) {
73
+ const product = response.product;
74
+ if (product === undefined) {
75
+ throw new Error(`Open Food Facts product not found for barcode ${barcode}`);
76
+ }
77
+ const sourceId = product.code ?? response.code ?? barcode;
78
+ const servingQuantity = finiteNumber(product.serving_quantity);
79
+ const nutrients = mapNutrients(product.nutriments);
80
+ const availablePortions = [
81
+ {
82
+ label: "100g",
83
+ quantity: 100,
84
+ unit: "g",
85
+ grams: 100,
86
+ },
87
+ ];
88
+ if (servingQuantity !== undefined) {
89
+ availablePortions.push({
90
+ label: product.serving_size ?? "serving",
91
+ quantity: 1,
92
+ unit: "serving",
93
+ grams: roundNutrient(servingQuantity),
94
+ });
95
+ }
96
+ const itemBase = {
97
+ id: makeFoodId("open_food_facts", sourceId),
98
+ source: "open_food_facts",
99
+ source_id: sourceId,
100
+ source_url: sourceUrl(product, sourceId),
101
+ name: product.product_name ?? "Unknown Open Food Facts product",
102
+ barcode,
103
+ available_portions: availablePortions,
104
+ nutrients_per_100g: nutrients,
105
+ license: OFF_LICENSE,
106
+ };
107
+ if (product.brands !== undefined) {
108
+ itemBase.brand = product.brands;
109
+ }
110
+ if (servingQuantity !== undefined) {
111
+ itemBase.serving = {
112
+ quantity: 1,
113
+ unit: "serving",
114
+ grams: roundNutrient(servingQuantity),
115
+ };
116
+ itemBase.nutrients_per_serving = nutrientsForGrams(nutrients, servingQuantity);
117
+ }
118
+ return {
119
+ ...itemBase,
120
+ data_quality: {
121
+ completeness: foodCompleteness(itemBase),
122
+ confidence: 0.75,
123
+ warnings: [],
124
+ },
125
+ };
126
+ }
127
+ export async function lookupOpenFoodFactsBarcode(barcode) {
128
+ const config = getConfig();
129
+ if (!config.off_enabled) {
130
+ throw new Error("Open Food Facts provider is disabled");
131
+ }
132
+ const response = config.fixture_mode ? await readFixture(barcode) : await fetchBarcode(barcode);
133
+ if (response.product === undefined || response.status === 0) {
134
+ throw new Error(`Open Food Facts product not found for barcode ${barcode}`);
135
+ }
136
+ return {
137
+ provider: "open_food_facts",
138
+ food: mapProduct(response, barcode),
139
+ };
140
+ }
141
+ //# sourceMappingURL=open-food-facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-food-facts.js","sourceRoot":"","sources":["../../src/providers/open-food-facts.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAoBjE,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EAAE,uFAAuF;IACpG,WAAW,EAAE,IAAI;IACjB,GAAG,EAAE,kCAAkC;CAC/B,CAAC;AAEX,MAAM,aAAa,GAAgD;IACjE,kBAAkB,EAAE,eAAe;IACnC,aAAa,EAAE,WAAW;IAC1B,kBAAkB,EAAE,iBAAiB;IACrC,QAAQ,EAAE,OAAO;IACjB,UAAU,EAAE,SAAS;IACrB,WAAW,EAAE,SAAS;IACtB,oBAAoB,EAAE,iBAAiB;CACxC,CAAC;AAEF,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACxC,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACtD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,OAAe;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,MAAM,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,iBAAiB,EAAE,4BAA4B,CAAC,EAAE,MAAM,CAAC,CACtE,CAAC;IAE3B,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,iDAAiD,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,OAAe;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,YAAY,mBAAmB,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrF,GAAG,CAAC,YAAY,CAAC,GAAG,CAClB,QAAQ,EACR,gFAAgF,CACjF,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,OAAO,EAAE;YACP,YAAY,EAAE,UAAU;YACxB,MAAM,EAAE,kBAAkB;SAC3B;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA0B,CAAC;AAC1D,CAAC;AAED,SAAS,YAAY,CAAC,aAAiD,EAAE;IACvE,MAAM,SAAS,GAAgB,EAAE,CAAC;IAElC,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QAClE,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,SAAS,CAAC,WAAW,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IACzD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,SAAS,CAAC,SAAS,GAAG,aAAa,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAC,OAA6B,EAAE,QAAgB;IAChE,OAAO,OAAO,CAAC,GAAG,IAAI,GAAG,YAAY,YAAY,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;AAClF,CAAC;AAED,SAAS,UAAU,CAAC,QAA+B,EAAE,OAAe;IAClE,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,iDAAiD,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,IAAI,OAAO,CAAC;IAC1D,MAAM,eAAe,GAAG,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,iBAAiB,GAAmC;QACxD;YACE,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,GAAG;YACb,IAAI,EAAE,GAAG;YACT,KAAK,EAAE,GAAG;SACX;KACF,CAAC;IAEF,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,iBAAiB,CAAC,IAAI,CAAC;YACrB,KAAK,EAAE,OAAO,CAAC,YAAY,IAAI,SAAS;YACxC,QAAQ,EAAE,CAAC;YACX,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC;SACtC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAmC;QAC/C,EAAE,EAAE,UAAU,CAAC,iBAAiB,EAAE,QAAQ,CAAC;QAC3C,MAAM,EAAE,iBAA0B;QAClC,SAAS,EAAE,QAAQ;QACnB,UAAU,EAAE,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC;QACxC,IAAI,EAAE,OAAO,CAAC,YAAY,IAAI,iCAAiC;QAC/D,OAAO;QACP,kBAAkB,EAAE,iBAAiB;QACrC,kBAAkB,EAAE,SAAS;QAC7B,OAAO,EAAE,WAAW;KACrB,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,QAAQ,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAClC,CAAC;IAED,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,QAAQ,CAAC,OAAO,GAAG;YACjB,QAAQ,EAAE,CAAC;YACX,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC;SACtC,CAAC;QACF,QAAQ,CAAC,qBAAqB,GAAG,iBAAiB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACjF,CAAC;IAED,OAAO;QACL,GAAG,QAAQ;QACX,YAAY,EAAE;YACZ,YAAY,EAAE,gBAAgB,CAAC,QAAQ,CAAC;YACxC,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,EAAE;SACb;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAe;IAEf,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IAEhG,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,iDAAiD,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,iBAAiB;QAC3B,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC;KACpC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { FoodItem } from "../types.js";
2
+ export declare function searchUsdaFoods(query: string, limit?: number): Promise<{
3
+ foods: FoodItem[];
4
+ provider: "usda";
5
+ }>;
6
+ export declare function getUsdaFood(sourceId: string): Promise<FoodItem>;
@@ -0,0 +1,157 @@
1
+ /// <reference types="node" />
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { USDA_BASE_URL, USER_AGENT } from "../constants.js";
5
+ import { foodCompleteness, makeFoodId } from "../services/food-normalization.js";
6
+ import { roundNutrient, scaleNutrients } from "../services/nutrients.js";
7
+ import { getConfig, getFixtureDir } from "../services/config.js";
8
+ const USDA_ATTRIBUTION = "Food data sourced from USDA FoodData Central.";
9
+ const NUTRIENT_KEYS = {
10
+ 1008: "calories_kcal",
11
+ 1003: "protein_g",
12
+ 1005: "carbohydrates_g",
13
+ 1004: "fat_g",
14
+ 1079: "fiber_g",
15
+ 1063: "sugar_g",
16
+ 1258: "saturated_fat_g",
17
+ 1093: "sodium_mg",
18
+ };
19
+ async function readFixture(fileName) {
20
+ const raw = await readFile(join(getFixtureDir(), "usda", fileName), "utf8");
21
+ return JSON.parse(raw);
22
+ }
23
+ async function fetchJson(path, params) {
24
+ const config = getConfig();
25
+ const url = new URL(`${USDA_BASE_URL}${path}`);
26
+ url.searchParams.set("api_key", config.usda_api_key ?? "DEMO_KEY");
27
+ for (const [key, value] of Object.entries(params)) {
28
+ url.searchParams.set(key, value);
29
+ }
30
+ const response = await fetch(url, {
31
+ headers: {
32
+ "user-agent": USER_AGENT,
33
+ accept: "application/json",
34
+ },
35
+ });
36
+ if (!response.ok) {
37
+ throw new Error(`USDA request failed: ${response.status} ${response.statusText}`);
38
+ }
39
+ return (await response.json());
40
+ }
41
+ function nutrientAmount(nutrient) {
42
+ const nutrientId = nutrient.nutrientId ?? nutrient.nutrient?.id;
43
+ const key = nutrientId === undefined ? undefined : NUTRIENT_KEYS[nutrientId];
44
+ const amount = nutrient.amount ?? nutrient.value;
45
+ if (key === undefined || typeof amount !== "number" || !Number.isFinite(amount)) {
46
+ return undefined;
47
+ }
48
+ return [key, roundNutrient(amount)];
49
+ }
50
+ function mapNutrients(foodNutrients = []) {
51
+ const nutrients = {};
52
+ for (const foodNutrient of foodNutrients) {
53
+ const mapped = nutrientAmount(foodNutrient);
54
+ if (mapped !== undefined) {
55
+ const [key, amount] = mapped;
56
+ nutrients[key] = amount;
57
+ }
58
+ }
59
+ return nutrients;
60
+ }
61
+ function portionLabel(portion) {
62
+ return (portion.modifier ??
63
+ portion.portionDescription ??
64
+ portion.measureUnit?.name ??
65
+ portion.measureUnit?.abbreviation ??
66
+ "serving");
67
+ }
68
+ function availablePortions(food) {
69
+ const portions = [
70
+ {
71
+ label: "100g",
72
+ quantity: 100,
73
+ unit: "g",
74
+ grams: 100,
75
+ },
76
+ ];
77
+ for (const portion of food.foodPortions ?? []) {
78
+ if (typeof portion.gramWeight === "number" && Number.isFinite(portion.gramWeight)) {
79
+ portions.push({
80
+ label: portionLabel(portion),
81
+ quantity: 1,
82
+ unit: "serving",
83
+ grams: roundNutrient(portion.gramWeight),
84
+ });
85
+ }
86
+ }
87
+ return portions;
88
+ }
89
+ function sourceUrl(sourceId) {
90
+ return `https://fdc.nal.usda.gov/fdc-app.html#/food-details/${sourceId}/nutrients`;
91
+ }
92
+ function mapFood(food) {
93
+ const sourceId = String(food.fdcId ?? "");
94
+ const name = food.description ?? "Unknown USDA food";
95
+ const nutrients = mapNutrients(food.foodNutrients);
96
+ const portions = availablePortions(food);
97
+ const serving = portions[1] ?? portions[0] ?? {
98
+ label: "100g",
99
+ quantity: 100,
100
+ unit: "g",
101
+ grams: 100,
102
+ };
103
+ const servingGrams = serving.grams ?? 100;
104
+ const itemBase = {
105
+ id: makeFoodId("usda", sourceId),
106
+ source: "usda",
107
+ source_id: sourceId,
108
+ source_url: sourceUrl(sourceId),
109
+ name,
110
+ serving: {
111
+ quantity: serving.quantity,
112
+ unit: serving.unit,
113
+ grams: servingGrams,
114
+ },
115
+ available_portions: portions,
116
+ nutrients_per_100g: nutrients,
117
+ nutrients_per_serving: scaleNutrients(nutrients, servingGrams / 100),
118
+ license: {
119
+ name: "USDA FoodData Central",
120
+ attribution: USDA_ATTRIBUTION,
121
+ share_alike: false,
122
+ url: "https://fdc.nal.usda.gov/",
123
+ },
124
+ };
125
+ return {
126
+ ...itemBase,
127
+ data_quality: {
128
+ completeness: foodCompleteness(itemBase),
129
+ confidence: 0.9,
130
+ warnings: [],
131
+ },
132
+ };
133
+ }
134
+ export async function searchUsdaFoods(query, limit = 10) {
135
+ const config = getConfig();
136
+ const search = config.fixture_mode
137
+ ? await readFixture("search-banana.json")
138
+ : await fetchJson("/foods/search", {
139
+ query,
140
+ pageSize: String(Math.min(limit, config.max_results)),
141
+ });
142
+ return {
143
+ provider: "usda",
144
+ foods: (search.foods ?? []).slice(0, limit).map(mapFood),
145
+ };
146
+ }
147
+ export async function getUsdaFood(sourceId) {
148
+ const config = getConfig();
149
+ const food = config.fixture_mode
150
+ ? await readFixture("food-banana.json")
151
+ : await fetchJson(`/food/${encodeURIComponent(sourceId)}`, {});
152
+ if (config.fixture_mode && String(food.fdcId) !== sourceId) {
153
+ throw new Error(`USDA fixture not found for source_id ${sourceId}`);
154
+ }
155
+ return mapFood(food);
156
+ }
157
+ //# sourceMappingURL=usda.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usda.js","sourceRoot":"","sources":["../../src/providers/usda.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerNourishResources(server: McpServer): void;
@@ -0,0 +1,26 @@
1
+ import { buildAgentManifest } from "../services/agent-manifest.js";
2
+ import { buildCapabilities } from "../services/capabilities.js";
3
+ import { buildPrivacyAudit } from "../services/privacy-audit.js";
4
+ import { buildUsageGuide } from "../services/usage-guide.js";
5
+ export function registerNourishResources(server) {
6
+ registerJsonResource(server, "nourish-agent-manifest", "nourish://agent-manifest", "Nourish agent manifest", "Agent-facing install, safety, tool, and resource manifest.", buildAgentManifest("generic"));
7
+ registerJsonResource(server, "nourish-capabilities", "nourish://capabilities", "Nourish capabilities", "Supported nutrition providers and workflows.", buildCapabilities());
8
+ registerJsonResource(server, "nourish-privacy-audit", "nourish://privacy-audit", "Nourish privacy audit", "Local storage, secret handling, safety, and source license boundaries.", buildPrivacyAudit());
9
+ registerJsonResource(server, "nourish-usage-guide", "nourish://usage-guide", "Nourish usage guide", "Agent and human workflows for safe previews, writes, edits, hydration, goals, and exports.", buildUsageGuide());
10
+ }
11
+ function registerJsonResource(server, name, uri, title, description, value) {
12
+ server.registerResource(name, uri, {
13
+ title,
14
+ description,
15
+ mimeType: "application/json",
16
+ }, async () => ({
17
+ contents: [
18
+ {
19
+ uri,
20
+ mimeType: "application/json",
21
+ text: JSON.stringify(value),
22
+ },
23
+ ],
24
+ }));
25
+ }
26
+ //# sourceMappingURL=nourish-resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nourish-resources.js","sourceRoot":"","sources":["../../src/resources/nourish-resources.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,oBAAoB,CAClB,MAAM,EACN,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,4DAA4D,EAC5D,kBAAkB,CAAC,SAAS,CAAC,CAC9B,CAAC;IAEF,oBAAoB,CAClB,MAAM,EACN,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,8CAA8C,EAC9C,iBAAiB,EAAE,CACpB,CAAC;IAEF,oBAAoB,CAClB,MAAM,EACN,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,EACvB,wEAAwE,EACxE,iBAAiB,EAAE,CACpB,CAAC;IAEF,oBAAoB,CAClB,MAAM,EACN,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,4FAA4F,EAC5F,eAAe,EAAE,CAClB,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAC3B,MAAiB,EACjB,IAAY,EACZ,GAAW,EACX,KAAa,EACb,WAAmB,EACnB,KAAc;IAEd,MAAM,CAAC,gBAAgB,CACrB,IAAI,EACJ,GAAG,EACH;QACE,KAAK;QACL,WAAW;QACX,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE;YACR;gBACE,GAAG;gBACH,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;aAC5B;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}