Skip to main content
Glama
bbwrl

Shopping List MCP Server

by bbwrl

Shopping List App

Eine einfache Einkaufslisten-App, erstellt mit Next.js 15 (App Router). Jedes Produkt gehört zu einer Person, kann als gekauft markiert und gelöscht werden.

Dieses Projekt ist bewusst klein gehalten – es ist ein Lern-/Übungsprojekt für IMS Praxis 5.

Funktionen

  • Produkte hinzufügen, als gekauft markieren, löschen

  • Nach Person filtern

  • Persistenz über eine einfache JSON-Datei (kein Datenbankserver erforderlich)

  • Drei Arten, mit den Daten zu arbeiten:

    • Server Actions – werden direkt vom Frontend verwendet (src/app/actions.ts)

    • REST-API – verfügbar unter /api/products, z. B. für externe Clients oder curl

    • MCP-Server – stellt dieselben Daten als MCP-Tools bereit (z. B. für ChatGPT), indem er die REST-API aufruft

Related MCP server: lista-compras-mcp

Technologie-Stack

  • Next.js 15 / React 19, App Router

  • TypeScript

  • Keine Datenbank, kein ORM – Persistenz über eine JSON-Datei (data/products.json)

  • MCP TypeScript SDK via mcp-handler, mit Streamable HTTP Transport

Erste Schritte

npm install
npm run dev

Öffnen Sie die App unter http://localhost:3000.

Für den lokalen Betrieb ist keine Konfiguration oder .env-Datei erforderlich. Siehe Umgebungsvariablen für die eine optionale Einstellung, die vom MCP-Server verwendet wird.

Projektstruktur

src/
  app/
    page.tsx            # Home page (Server Component), loads products server-side
    actions.ts           # Server Actions: addProductAction, togglePurchasedAction, deleteProductAction
    api/
      products/
        route.ts          # GET /api/products, POST /api/products
        [id]/route.ts      # GET/PATCH/DELETE /api/products/:id
      [transport]/
        route.ts          # MCP endpoint (Streamable HTTP), served at /api/mcp
  components/
    ProductForm.tsx        # Add-product form (uses a Server Action)
    ProductList.tsx        # List incl. toggle/delete (uses Server Actions)
  lib/
    productRepository.ts   # the only place that touches the filesystem (data/products.json)
    mcp/
      server.ts             # registers the MCP tools
      shoppingApiClient.ts   # MCP's only way to reach the data — calls the REST API, never the repository directly
  types/
    product.ts             # Product type

data/
  products.json            # data store (created automatically if missing)

Datenmodell

interface Product {
  id: string;
  name: string;
  person: string;
  purchased: boolean;
  createdAt: string; // ISO date
}

Persistenz

Alle Produkte befinden sich in data/products.json. Der gesamte Dateizugriff ist in src/lib/productRepository.ts gekapselt – weder die UI noch die API-Routen lesen oder schreiben die Datei direkt. Das Repository stellt bereit:

getProducts()
getProductsByPerson(person)
getProductById(id)
addProduct(product)
updateProduct(id, changes)
deleteProduct(id)

Hinweis: Diese dateibasierte Persistenz ist bewusst nur eine Prototyp-/Entwicklungslösung. Auf Vercel (und anderen serverlosen Plattformen) ist das lokale Dateisystem nicht zuverlässig persistent über mehrere Anfragen oder Deployments hinweg – Schreibvorgänge können verloren gehen. Für den Produktionseinsatz sollte productRepository.ts durch eine echte, persistente Datenbank ersetzt werden (z. B. Turso). Da der Rest der App (UI, Server Actions, API-Routen) nur über die exportierten Repository-Funktionen mit den Daten spricht, betrifft dieser Austausch nur diese eine Datei.

Frontend ↔ Backend

Das Frontend (page.tsx, ProductForm, ProductList) verwendet Next.js Server Actions (src/app/actions.ts), um Produkte zu erstellen, zu aktualisieren und zu löschen. Es gibt keinen fetch-Aufruf im Client – die Server Actions rufen das Repository direkt auf und lösen dann eine Aktualisierung der servergerenderten Daten mittels revalidatePath("/") aus.

Die REST-API unter /api/products ist unabhängig und kann separat verwendet werden (z. B. von externen Tools, Skripten oder zum Testen) – sie liest und schreibt dieselbe Datenquelle.

REST-API

Produkte lesen

GET /api/products
GET /api/products?person=Rinaldo   # filter by person, case-insensitive
GET /api/products/:id

Ein Produkt hinzufügen

POST /api/products
Content-Type: application/json

{ "name": "Milk", "person": "Rinaldo" }

id, purchased (false) und createdAt werden automatisch gesetzt.

Ein Produkt aktualisieren

PATCH /api/products/:id
Content-Type: application/json

{ "purchased": true }

Es müssen nicht alle Felder angegeben werden (name, person, purchased sind jeweils optional und unabhängig aktualisierbar).

Ein Produkt löschen

DELETE /api/products/:id

Fehlerantworten

{ "error": "Product not found" }

Fall

Status

Ungültige/leere Anfrage

400

Unbekannte ID

404

Interner Fehler

500

curl-Beispiele

# Add a product
curl -X POST http://localhost:3000/api/products \
  -H "Authorization: Bearer $SHOPPING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Milk","person":"Rinaldo"}'

# List a person's products
curl "http://localhost:3000/api/products?person=Rinaldo" \
  -H "Authorization: Bearer $SHOPPING_API_KEY"

# Mark a product as purchased
curl -X PATCH http://localhost:3000/api/products/PRODUCT_ID \
  -H "Authorization: Bearer $SHOPPING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"purchased":true}'

# Delete a product
curl -X DELETE http://localhost:3000/api/products/PRODUCT_ID \
  -H "Authorization: Bearer $SHOPPING_API_KEY"

MCP-Server

Ein Model Context Protocol-Server stellt die Einkaufsliste MCP-Clients (z. B. ChatGPT) zur Verfügung. Er kommuniziert nur mit der oben genannten REST-API – niemals direkt mit productRepository.ts oder data/products.json –, sodass er unabhängig von dem verwendeten Persistenz-Backend der API bleibt.

MCP client → MCP server → REST API → productRepository → data/products.json

Endpunkt: /api/mcp (Streamable HTTP Transport), implementiert in src/app/api/[transport]/route.ts über mcp-handler.

Tools:

Tool

Beschreibung

list_products

Produkte auflisten, optional gefiltert nach Person

add_product

Ein Produkt für eine Person hinzufügen

update_product

Name/Person/Gekauft-Status eines Produkts ändern

mark_product_purchased

Bequemes Tool, um ein Produkt als (nicht) gekauft zu markieren

delete_product

Ein Produkt löschen

Erfordert dasselbe Bearer-Token wie die REST-API (siehe Authentifizierung). Testen Sie ihn lokal mit dem MCP Inspector:

npx @modelcontextprotocol/inspector --cli http://localhost:3000/api/mcp --method tools/list \
  --header "Authorization: Bearer $SHOPPING_API_KEY"

Umgebungsvariablen

Variable

Erforderlich

Beschreibung

SHOPPING_API_BASE_URL

Nein

Basis-URL, die der MCP-Server zum Aufrufen der REST-API verwendet. Standardmäßig http://localhost:3000 lokal bzw. https://$VERCEL_URL auf Vercel. Explizit setzen, wenn Sie in der Produktion eine benutzerdefinierte Domain verwenden.

SHOPPING_API_KEY

Ja

Gemeinsames Geheimnis, das als Authorization: Bearer <key> von der REST-API und dem MCP-Endpunkt benötigt wird. Anfragen ohne passendes Token werden abgelehnt.

Siehe .env.example.

Authentifizierung

Die REST-API und der MCP-Endpunkt erfordern beide ein Bearer-Token – ein einzelnes gemeinsames Geheimnis, das über SHOPPING_API_KEY konfiguriert wird. Es gibt keinen benutzerbezogenen Login; dies ist eine einfache statische Token-Prüfung, die für einen Prototyp geeignet ist, nicht für eine vollständige OAuth-Implementierung.

curl http://localhost:3000/api/products \
  -H "Authorization: Bearer $SHOPPING_API_KEY"

Eine Anfrage mit fehlendem oder falschem Token erhält 401 Unauthorized. Wenn SHOPPING_API_KEY auf dem Server überhaupt nicht gesetzt ist, werden Anfragen mit 500 abgelehnt (Fail-Closed, nicht Open).

Server Actions (src/app/actions.ts) sind davon nicht betroffen – sie rufen productRepository direkt auf dem Server auf und durchlaufen niemals die REST-API, daher benötigen sie kein Token.

Bekannte Einschränkungen

  • Keine Authentifizierung/Autorisierung weder auf der REST-API noch auf dem MCP-Server – jeder kann alle Produkte sehen und bearbeiten. Als Folgearbeit geplant.

  • Gleichzeitige Schreibvorgänge werden innerhalb eines einzelnen Prozesses serialisiert (eine einfache Warteschlange in productRepository.ts), was für einen Prototyp in Ordnung ist, aber nicht für Produktionsumgebungen mit mehreren Instanzen.

  • Wie oben erwähnt, ist die Persistenz auf serverlosen Plattformen wie Vercel nicht deployment-sicher – eine echte Datenbank (z. B. Turso) ist der nächste geplante Schritt.

Deployment

Die App kann wie jedes Next.js-Projekt bereitgestellt werden, z. B. auf Vercel. Vor dem Einsatz in der Produktion sollte die Datenpersistenzschicht (siehe oben) gegen eine echte Datenbank ausgetauscht werden.

Mehr zu Next.js: Next.js-Dokumentation · Next.js lernen

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that gives AI agents full control over grocery lists, todos, and packing lists. Your AI creates lists, adds items, checks them off, and shares with family/friends.
    4
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to manage shopping lists and items (create, edit, delete, mark as purchased) via integration with a backend API.
    8
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to read current pantry inventory and low-stock shopping needs, export a shopping queue, and perform idempotent inventory adjustments and catalog link management through remote MCP tools.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to manage Bring! shopping lists through MCP, including adding, removing, renaming, and batch-updating items while resolving them against Bring's real catalog so they render with the correct language, icon, and aisle.
    MIT