Back to MCP Servers

Foodblock

17 MCP tools for the food industry. Describe food in plain English and get structured, content-addressed data blocks back. Covers actors, places, ingredients, products, transforms, transfers, and observations. Works standalone with zero config via `npx foodblock-mcp`.

other-tools-and-integrationsai
By FoodXDevelopment
02Updated 3 months agoJavaScriptMIT

Installation

npx foodblock-mcp

Configuration

{
  "mcpServers": {
    "foodblock": {
      "command": "npx",
      "args": ["-y", "foodblock"]
    }
  }
}

How to use

  1. Run the installation command above (if needed)
  2. Open your Claude Code settings file (~/.claude/settings.json)
  3. Add the configuration to the mcpServers section
  4. Restart Claude Code to apply changes

FoodBlock

A content-addressable protocol for universal food data.

One axiom. Three fields. Six base types. Every food industry operation.

{
  "type": "substance.product",
  "state": { "name": "Sourdough", "price": 4.50, "allergens": { "gluten": true } },
  "refs": { "seller": "a1b2c3...", "inputs": ["flour_hash", "water_hash", "yeast_hash"] }
}

id = SHA-256(canonical(type + state + refs))

Why

The food industry spans 14 sectors — farming, processing, distribution, retail, hospitality, regulation, sustainability, and more. Every sector models food data differently. There is no shared primitive.

FoodBlock is that primitive. One data structure that can represent a farm harvest, a restaurant menu item, a food safety certification, a cold chain reading, a grocery order, or a consumer review. Same three fields. Same hashing. Same protocol.

The Primitive

Every FoodBlock has exactly three fields:

FieldTypeDescription
typestringWhat kind of block (dot-notated subtypes)
stateobjectThe block's data (schemaless, any valid JSON)
refsobjectNamed references to other blocks by hash

Identity is derived from content: SHA-256(canonical(type + state + refs)). Same content always produces the same hash, regardless of where or when the block is created.

Six Base Types

Entities — things that exist:

  • actor — farmer, restaurant, retailer, regulator, consumer, device
  • place — farm, factory, store, warehouse, kitchen, vehicle
  • substance — ingredient, product, meal, surplus, commodity

Actions — things that happen:

  • transform — cooking, milling, harvesting, fermenting, composting
  • transfer — sale, shipment, donation, booking, subscription
  • observe — review, certification, inspection, post, sensor reading

Subtypes via dot notation: actor.producer, substance.product, observe.review, transfer.order.

Install

npm install foodblock

Quick Start — fb()

The fastest way to use FoodBlock. Describe food in plain English, get structured blocks back.

const { fb } = require('foodblock')

fb("Sourdough bread, $4.50, organic, contains gluten")
// => { type: 'substance.product', state: { name: 'Sourdough bread', price: { value: 4.5, unit: 'USD' }, organic: true, allergens: { gluten: true } }, blocks: [...] }

fb("Amazing pizza at Luigi's, 5 stars")
// => { type: 'observe.review', state: { name: "Luigi's", rating: 5, text: "..." }, blocks: [...] }

fb("Green Acres Farm, 200 acres, organic wheat in Oregon")
// => { type: 'actor.producer', state: { name: 'Green Acres Farm', acreage: 200, crop: 'organic wheat', region: 'Oregon' }, blocks: [...] }

fb("Walk-in cooler temperature 4 celsius")
// => { type: 'observe.reading', state: { temperature: { value: 4, unit: 'celsius' } }, blocks: [...] }

fb("Ordered 50kg flour from Stone Mill")
// => { type: 'transfer.order', state: { weight: { value: 50, unit: 'kg' } }, blocks: [...] }

No types to memorize. No schemas to configure. No API calls — fb() is pure pattern matching, runs locally, costs nothing.

Programmatic API

const fb = require('foodblock')

// Create a farm
const farm = fb.create('actor.producer', { name: 'Green Acres Farm' })
// => { hash: 'e3b0c4...', type: 'actor.producer', state: {...}, refs: {} }

// Create a product with provenance
const wheat = fb.create('substance.ingredient', { name: 'Organic Wheat' }, { source: farm.hash })
const flour = fb.create('substance.product', { name: 'Stoneground Flour' }, { source: wheat.hash })
const bread = fb.create('substance.product', {
  name: 'Sourdough',
  price: 4.50
}, {
  seller: bakery.hash,
  inputs: [flour.hash, water.hash, yeast.hash]
})

// Update (creates new block, old one preserved)
const updated = fb.update(bread.hash, 'substance.product', {
  name: 'Sourdough',
  price: 5.00
}, { seller: bakery.hash })
// updated.refs.updates === bread.hash

// Sign and verify
const keys = fb.generateKeypair()
const signed = fb.sign(bread, farm.hash, keys.privateKey)
// signed.protocol_version === '0.4.0'
const valid = fb.verify(signed, keys.publicKey) // true

// Provenance chain
const history = await fb.chain(updated.hash, resolve)
// [{ price: 5.00 }, { price: 4.50 }] — newest to oldest

// Validate against schema
const errors = fb.validate(bread)  // [] if valid

// Tombstone (GDPR erasure)
const ts = fb.tombstone(bread.hash, user.hash, { reason: 'gdpr_erasure' })

// Offline queue
const queue = fb.offlineQueue()
queue.create('transfer.order', { total: 12.00 }, { seller: farmHash })
await queue.sync('https://api.example.com/foodblock')

// --- Human Interface ---

// Aliases: use @names instead of hashes
const reg = fb.registry()
const myFarm = reg.create('actor.producer', { name: 'Green Acres' }, {}, { alias: 'farm' })
const myWheat = reg.create('substance.ingredient', { name: 'Wheat' }, { source: '@farm' })
// '@farm' resolves to myFarm.hash automatically

// FoodBlock Notation: one-line text format
const blocks = fb.parseAll(`
@farm = actor.producer { "name": "Green Acres Farm" }
@wheat = substance.ingredient { "name": "Wheat" } -> source: @farm
`)

// Explain: human-readable narrative from graph
const story = await fb.explain(bread.hash, resolve)
// "Sourdough ($4.50). By Green Acres Bakery. Made from Organic Flour (Green Acres Farm)."

// URIs: shareable block references
fb.toURI(bread)                          // 'fb:a1b2c3...'
fb.toURI(bread, { alias: 'sourdough' })  // 'fb:substance.product/sourdough'

// --- Templates ---

// Use built-in templates for common patterns
const chain = fb.fromTemplate(fb.TEMPLATES['supply-chain'], {
  farm: { state: { name: 'Green Acres Farm' } },
  crop: { state: { name: 'Organic Wheat' } },
  processing: { state: { name: 'Stone Milling' } },
  product: { state: { name: 'Flour', price: 3.20 } }
})
// Returns 5 blocks in dependency order, with @alias refs auto-resolved

// Create custom templates
const myTemplate = fb.createTemplate('Bakery Review', 'Review a bakery product', [
  { type: 'actor.venue', alias: 'bakery', required: ['name'] },
  { type: 'substance.product', alias: 'item', refs: { seller: '@bakery' } },
  { type: 'observe.review', alias: 'review', refs: { subject: '@item' }, required: ['rating'] }
])

// --- Federation ---

// Discover another FoodBlock server
const info = await fb.discover('https://farm.example.com')
// { protocol: 'foodblock', version: '0.4.0', types: [...], count: 142 }

// Resolve blocks across multiple servers
const resolve = fb.federatedResolver([
  'http://localhost:3111',
  'https://farm.example.com',
  'https://market.example.com'
])
const block = await resolve('a1b2c3...')  // tries each server in order

Sandbox

Try it locally with zero setup:

cd sandbox
node server.js
# List all blocks
curl localhost:3111/blocks

# Filter by type
curl localhost:3111/blocks?type=substance.product

# Get head blocks only (latest versions)
curl localhost:3111/blocks?type=substance.product&heads=true

# Provenance chain
curl localhost:3111/chain/<hash>

# Create a block
curl -X POST localhost:3111/blocks \
  -H "Content-Type: application/json" \
  -d '{"type":"observe.review","state":{"rating":5,"text":"Amazing"},"refs":{"subject":"<product_hash>"}}'

# Batch create (offline sync)
curl -X POST localhost:3111/blocks/batch \
  -H "Content-Type: application/json" \
  -d '{"blocks":[...]}'

# Tombstone (content erasure)
curl -X DELETE localhost:3111/blocks/<hash>

# Federation discovery
curl localhost:3111/.well-known/foodblock

# List templates
curl localhost:3111/blocks?type=observe.template

# Natural language entry point
curl -X POST localhost:3111/fb \
  -H "Content-Type: application/json" \
  -d '{"text":"Sourdough bread, $4.50, organic, contains gluten"}'

# Forward traversal (what references this block?)
curl localhost:3111/forward/<hash>

# Natural language → blocks
curl -X POST localhost:3111/fb \
  -H "Content-Type: application/json" \
  -d '{"text":"Sourdough bread, $4.50, organic, contains gluten"}'

# List vocabularies
curl localhost:3111/blocks?type=observe.vocabulary

The sandbox ships preloaded with 47 blocks modelling a complete bakery supply chain — from farm to consumer, including certifications, shipments, cold chain readings, reviews, and operational vocabularies.

API

fb(text) → { blocks, primary, type, state, text }

The natural language entry point. Pass any food-related text, get FoodBlocks back. Detects intent (product, review, farm, order, certification, reading, process, venue, ingredient), extracts quantities (price, weight, volume, temperature, rating), flags (organic, gluten-free, kosher, etc.), and relationships ("from X", "at Y", "by Z"). No LLM — pure regex pattern matching against built-in vocabularies.

create(type, state, refs) → block

Create a new FoodBlock. Returns { hash, type, state, refs }.

update(previousHash, type, state, refs) → block

Create an update block that supersedes a previous version. Automatically adds refs.updates.

hash(type, state, refs) → string

Compute the SHA-256 hash without creating a block object.

chain(hash, resolve, opts) → block[]

Follow the update chain backwards. resolve is async (hash) => block | null.

tree(hash, resolve, opts) → { block, ancestors }

Follow ALL refs recursively to build the full provenance tree.

head(hash, resolveForward) → string

Find the latest version in an update chain.

sign(block, authorHash, privateKey) → wrapper

Sign a block with Ed25519. Returns { foodblock, author_hash, signature, protocol_version }.

verify(wrapper, publicKey) → boolean

Verify a signed block wrapper.

generateKeypair() → { publicKey, privateKey }

Generate a new Ed25519 keypair for signing.

encrypt(value, recipientPublicKeys) → envelope

Encrypt a value for multiple recipients using envelope encryption (Section 7.2).

decrypt(envelope, privateKey, publicKey) → value

Decrypt an encryption envelope.

validate(block, schema?) → string[]

Validate a block against its declared schema or a provided schema. Returns an array of error messages (empty = valid).

tombstone(targetHash, requestedBy, opts?) → block

Create a tombstone block for content erasure (Section 5.4).

offlineQueue() → Queue

Create an offline queue for local-first block creation with batch sync.

query(resolve) → Query

Fluent query builder:

const results = await fb.query(resolver)
  .type('substance.product')
  .byRef('seller', bakeryHash)
  .whereLt('price', 10)
  .latest()
  .limit(20)
  .exec()

registry() → Registry

Alias registry for human-readable references. Use @name in refs instead of hashes.

parse(line) → { alias, type, state, refs }

Parse a single line of FoodBlock Notation (FBN).

parseAll(text) → block[]

Parse multiple lines of FBN.

format(block, opts?) → string

Format a block as FBN text.

explain(hash, resolve) → string

Generate a human-readable narrative from a block's provenance graph.

toURI(block, opts?) → string

Convert a block to a fb: URI. toURI(block)fb:<hash>, toURI(block, { alias: 'name' })fb:<type>/<alias>.

fromURI(uri) → object

Parse a fb: URI into { hash } or { type, alias }.

createTemplate(name, description, steps, opts?) → block

Create a template block (observe.template) that defines a reusable workflow pattern.

fromTemplate(template, values) → block[]

Instantiate a template into real blocks. values maps step aliases to { state, refs } overrides. @alias references between steps are resolved automatically.

TEMPLATES

Built-in templates: supply-chain, review, certification.

discover(serverUrl, opts?) → info

Fetch a server's /.well-known/foodblock discovery document.

`federatedResolver(servers,

View source on GitHub