Skip to main content
Glama

usda-fdc-mcp

A stdio MCP server that answers food composition questions from USDA FoodData Central.

What it does

The server exposes four tools over the Model Context Protocol.

Tool

Purpose

search_foods

Search foods by name. Returns the FDC ID, description, data type, and a macro-completeness flag.

get_food

Return the nutrient panel for one FDC ID, scaled to a gram amount.

food_nutrition

Search and scale in one call. Prefers a record with a complete macro panel.

recipe_nutrition

Sum an ingredient list into per-serving totals with a per-ingredient breakdown.

FoodData Central reports every amount per 100 g. The server scales each amount to the grams that you request. The percent Daily Value uses the FDA adult values in 21 CFR 101.9.

Nutrient identifiers

FoodData Central gives each nutrient two identifiers. The modern nutrientId for protein is 1003. The legacy NDB nutrientNumber for protein is "203". A filter on the wrong identifier returns an empty nutrient table and no error. The server keys on nutrientId in every code path.

Response shapes

The two endpoints put nutrient values in different fields.

/foods/search  ->  [{ nutrientId: 1003, value: 16.5 }]
/food/{id}     ->  [{ nutrient: { id: 1003 }, amount: 16.5 }]

The server normalizes both shapes. Results from either endpoint are interchangeable.

Alias identifiers

A nutrient can arrive under a different identifier in a different data type. The value then reads as missing. The server resolves three known cases.

  • Foundation cashews carry energy as Atwater factors under 2048. The canonical energy identifier is 1008.

  • SR Legacy flaxseed carries omega-3 under the general PUFA 18:3 identifier 1270. The ALA-specific identifier is 1404.

  • Foundation raisins carry sugars under 1063. SR Legacy records use 2000.

Related MCP server: nutrition-mcp

Requirements

  • Node.js 20 or later.

  • An internet connection for live lookups.

  • A FoodData Central API key. Read the API key section below.

Install

npm install
npm run build

Configuration

API key

The server reads the key from the USDA_FDC_API_KEY environment variable. The server falls back to DEMO_KEY when that variable is absent.

DEMO_KEY is the shared key that USDA publishes. It allows about 30 requests per hour for each IP address. Use DEMO_KEY for light testing only.

Get a free personal key at https://fdc.nal.usda.gov/api-key-signup. A personal key allows 1,000 requests per hour.

Pass the key through the environment. Do not commit the key to a file.

Cache

The server writes every response to a disk cache at ~/.cache/usda-fdc-mcp. Set USDA_FDC_CACHE_DIR to move the cache. A cached food still answers after you reach the rate limit.

MCP client

Add the server to your MCP client configuration. Replace /path/to/usda-fdc-mcp with the path to your own clone.

{
  "mcpServers": {
    "usda-fdc": {
      "command": "node",
      "args": ["/path/to/usda-fdc-mcp/dist/index.js"],
      "env": {
        "USDA_FDC_API_KEY": "your_key_here"
      }
    }
  }
}

Usage

A name search can return a neighbouring food

search_foods ranks its results by relevance. It returns a plausible food when the exact food falls outside the result order. It reports no error in that case.

A query for raisins seedless returns golden raisins (168164) before dark seedless raisins (168165). The two records differ by nearly half on iron. Golden raisins hold 0.98 mg per 100 g. Dark seedless raisins hold 1.79 mg per 100 g.

Read the description field on each hit before you use the numbers. Call get_food with a known FDC ID when the exact food matters.

Ingredients that FoodData Central does not hold

FoodData Central holds few supplement powders and few branded products. Pass such an item through manual_items. Take its figures from the product label or from published literature.

{
  "items": [
    { "query": "bananas raw", "grams": 118, "label": "1 medium banana" },
    { "query": "seeds hemp seed hulled", "grams": 30 }
  ],
  "manual_items": [
    { "label": "whey isolate, 1 scoop", "nutrients": { "energy_kcal": 120, "protein_g": 30 } }
  ],
  "servings": 1
}

Source citation

Every get_food result carries a source string.

USDA FoodData Central, FDC ID 170554 (SR Legacy), https://fdc.nal.usda.gov/food-details/170554

Quote that string when you publish a nutrition figure. The figure then stays traceable to its source record.

Tests

Run the offline test. It needs no network access and no API quota.

npm test

The offline test replays four cached FoodData Central records from test/fixtures. It asserts that each alias case resolves to the correct number.

Run the smoke test to check the live API contract. It consumes API quota.

npm run smoke

The smoke test confirms that both endpoint shapes parse to the same numbers. It confirms that gram scaling is linear. It confirms that the percent Daily Value and the source string are populated.

Development

npm run dev     # run the server from source through tsx
npm run build   # compile TypeScript into dist/
npm start       # run the compiled server

Licence

Licensed under the PolyForm Noncommercial License 1.0.0. Copyright 2026 Seraphine Renard.

Available Tools

4 tools
food_nutritionLook up a food by name and scale it in one stepA

Search by name, pick the best match with a complete macro panel, and return its nutrients scaled to the given grams. Use this for ordinary 'how much magnesium is in 30g of pumpkin seeds' questions. Also returns runner-up matches so you can correct the choice.

ParametersJSON Schema
NameRequiredDescriptionDefault
gramsNoServing size in grams. Default 100.
queryYes
data_typesNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the burden of disclosure. It explains key behavior: automatic best-match selection, nutrient scaling, and returning runner-up matches for correction. However, it does not mention how data_types affects the search or what happens on no match, but the core behavior is transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences: the first defines the core action, the second gives a concrete use case, and the third discloses a valuable feature. Every sentence earns its place, and the most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description does a good job of explaining what is returned: nutrients scaled to grams and runner-up matches. It is reasonably complete for a simple lookup tool, though it omits details about the data_types parameter and ambiguity handling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds meaning to 'query' (search by name) and 'grams' (scaled to given grams), but the 'data_types' parameter is entirely unexplained. With schema coverage at only 33%, the description should compensate for all parameters, leaving one key filter without any semantic guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches by name, picks the best match, and returns nutrients scaled to grams. It also distinguishes itself from siblings by emphasizing the one-step scaling feature, making the purpose specific and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides an explicit use case: "Use this for ordinary 'how much magnesium is in 30g of pumpkin seeds' questions." While it doesn't explicitly state when not to use it or name alternative sibling tools, the example strongly conveys the intended scenario.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_foodGet a food's nutrients scaled to a servingA

Full nutrient panel for one fdcId, scaled from FDC's per-100g basis to the grams you ask for, with %DV against FDA adult Daily Values. Includes a citable source line.

ParametersJSON Schema
NameRequiredDescriptionDefault
gramsNoServing size in grams. Default 100.
fdc_idYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It explains the scaling behavior from per-100g basis, the %DV calculation against FDA values, and the inclusion of a citable source line. These are meaningful behavioral details that go beyond a simple 'get data' statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the core purpose, and every phrase adds value: fdcId scoping, scaling, %DV, and source line. There is no redundant or generic wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter tool without an output schema, the description provides sufficient context: what it returns (full nutrient panel), how it behaves (scaling), and an extra output (source line). It does not cover error cases or return format, but these are less critical given the tool's simplicity and the description's clarity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema documents 'grams' with a description and default, but leaves 'fdc_id' undocumented. The description clarifies that the tool targets 'one fdcId' and explains how grams are used ('scaled to the grams you ask for'), adding meaning to both parameters beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'get' and the resource: a full nutrient panel for a single fdcId, scaled from FDC's per-100g basis to requested grams with %DV. This specificity distinguishes it from siblings like search_foods and recipe_nutrition, and the focus on one fdcId separates it from a generic food_nutrition tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly implies when to use this tool: when you need nutrient data for a known fdcId, scaled to a serving size. It does not explicitly name alternatives or provide exclusion criteria, but the context is clear and the distinction from siblings is evident.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recipe_nutritionSum an ingredient list into per-serving nutritionA

Give an ingredient list as {query or fdc_id, grams} and get summed totals divided by servings, with %DV and a per-ingredient breakdown of who contributed what. Ingredients absent from FDC (supplement powders, branded products) can be passed in manual_items with nutrients already known.

ParametersJSON Schema
NameRequiredDescriptionDefault
itemsYes
servingsNoDefault 1.
manual_itemsNoOff-database items such as protein powder, creatine, or a branded spread.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full responsibility for behavioral transparency. It clearly discloses the outputs: summed totals divided by servings, %DV, and per-ingredient contribution breakdown. It also explains how to handle off-database ingredients via manual_items. It does not cover failure modes or error handling for missing foods, but the main behaviors are well described.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences—front-loaded with the main action, then a concise caveat about off-database items. Every phrase adds value, covering input, output, and special-case handling without unnecessary words. It is a model of efficient specification.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema, the description adequately communicates the return values (totals, %DV, per-ingredient breakdown) and the main input pattern. It addresses the special case of manual items. It does miss potential edge cases like what happens if a query matches no FDC entry and no manual_items is provided, but overall the description is complete enough for typical use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents servings and manual_items with descriptions, and the description adds semantic context for the items structure: {query or fdc_id, grams}. It clarifies the mutually exclusive lookup identifier choice and explains manual_items as ingredients with known nutrients. This enriches the 67% schema coverage, making the parameters clearer than the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Sum') and identifies the resource ('ingredient list'), clearly stating the core action: return per-serving nutrition. It distinguishes itself from siblings by emphasizing the recipe-level aggregation and per-ingredient breakdown, which contrasts with the likely single-item or lookup nature of get_food, search_foods, and food_nutrition.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the primary usage context explicit: supply an ingredient list with grams, get summed nutrition. It also provides guidance for a sub-case (ingredients not in FDC) by pointing to manual_items. While it does not explicitly name alternatives or exclusion criteria, the title and phrasing clearly separate it from the sibling tools, so the guidance is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_foodsSearch USDA FoodData CentralA

Find foods by name in USDA FoodData Central. Returns fdcId, description, dataType, and hasCoreMacros. Prefer entries where hasCoreMacros is true: Foundation records are analytically detailed but frequently omit Energy, while SR Legacy records carry a complete macro panel. Cached on disk.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesFood name, e.g. 'chia seeds dried'
page_sizeNo
data_typesNoDefaults to Foundation + SR Legacy. Add 'Branded' for commercial products.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the transparency burden. It adds useful behavior beyond the schema: it names return fields, reveals that Foundation records may omit Energy while SR Legacy has complete macros, and discloses that results are cached on disk. It does not mention auth or rate limits, but the disclosure of data caveats and caching is solid.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core purpose, then specific return fields and a data-quality caveat. No filler or repeated schema details. Every sentence provides distinct value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with no output schema, the description explains the return fields and gives practical advice for selecting between data types. It does not cover pagination or default page_size, but the schema documents page_size constraints and data_types defaults. Overall it gives enough context to use the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 67%, with query and data_types documented. The description does not add extra meaning for any parameters beyond what the schema already provides. It mentions hasCoreMacros, which is a return field, not a parameter. Baseline 3 is appropriate since the schema covers most parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource: 'Find foods by name in USDA FoodData Central.' It clearly differentiates from sibling tools like get_food (retrieval by id) and food_nutrition (nutrition facts) by focusing on searching by name and returning identifiers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or when-not-to-use guidance relative to siblings is provided. The description offers advice on preferring hasCoreMacros entries, but that relates to result interpretation, not tool selection. It does not mention alternatives such as get_food or food_nutrition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observedfood_nutrition
    • First observedget_food
    • First observedrecipe_nutrition
    • First observedsearch_foods

TDQS

A4.1/5.0

Scored across 4 tools

Disambiguation4/5

Each tool has a distinct role: get_food for known IDs, search_foods for discovery, food_nutrition for a name-based shortcut with nutrients, and recipe_nutrition for multi-ingredient calculations. However, the overlap between food_nutrition and search_foods/get_food could cause some initial confusion, but descriptions clarify the intended use.

Naming Consistency3/5

Names mix verb_noun (get_food, search_foods) and noun_noun (food_nutrition, recipe_nutrition) patterns, which is inconsistent and less predictable. The mixed conventions make it harder to infer a tool's function from its name alone.

Tool Count5/5

Four tools is well-scoped for a USDA food data server, covering search, ID-based lookup, convenience queries, and recipe analysis. Each tool earns its place without unnecessary bloat.

Completeness5/5

The surface covers the core workflow of finding a food, retrieving its nutrients, and combining foods into recipes. For a read-only database, there are no obvious gaps or dead ends.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers