Skip to main content
Glama
sanggggg

Record MCP Server

by sanggggg

Record MCP Server

A Model Context Protocol (MCP) server for storing and managing dynamic review records with user-defined schemas. Perfect for organizing reviews of coffee, whisky, wine, or any other category you can think of!

Features

  • Dynamic Schemas: Create review types with custom fields on-the-fly

  • Flexible Storage: Local filesystem (dev) or Cloudflare R2 (production)

  • Type-Safe: Built with TypeScript and runtime validation

  • Extensible: Add new fields to existing review types

  • Easy Migration: Switch from local to cloud storage with one environment variable

Quick Start

Installation

# Install dependencies
npm install

# Build the project
npm run build

Configuration

Copy the example environment file:

cp .env.example .env

For local development (default):

STORAGE_PROVIDER=local
LOCAL_DATA_PATH=./data

For production with Cloudflare R2:

STORAGE_PROVIDER=r2
R2_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_access_key
R2_SECRET_ACCESS_KEY=your_secret_key
R2_BUCKET_NAME=review-records

Running the Server

Development mode (with auto-reload):

npm run dev

Production mode:

npm run build
npm start

Running Tests

npm test

MCP Tools

The server provides the following MCP tools:

1. list_review_types

List all review types with their schemas and record counts.

Parameters: None

Example Response:

{
  "types": [
    {
      "name": "coffee",
      "schema": [
        { "name": "flavor", "type": "string" },
        { "name": "aroma", "type": "string" },
        { "name": "acidity", "type": "string" }
      ],
      "recordCount": 5,
      "createdAt": "2025-11-16T10:00:00Z",
      "updatedAt": "2025-11-16T12:00:00Z"
    }
  ]
}

2. get_review_type

Get detailed information about a specific review type including all records.

Parameters:

  • typeName (string): Name of the review type

Example:

{
  "typeName": "coffee"
}

3. add_review_type

Create a new review type with a custom schema.

Parameters:

  • name (string): Name of the review type (e.g., "coffee", "whisky")

  • fields (array): Array of field definitions

Supported Field Types:

  • string: Text values

  • number: Numeric values

  • boolean: True/false values

  • date: ISO 8601 date strings

Example:

{
  "name": "coffee",
  "fields": [
    { "name": "flavor", "type": "string" },
    { "name": "aroma", "type": "string" },
    { "name": "acidity", "type": "string" },
    { "name": "rating", "type": "number" }
  ]
}

4. add_field_to_type

Add a new field to an existing review type's schema.

Parameters:

  • typeName (string): Name of the review type

  • fieldName (string): Name of the new field

  • fieldType (string): Type of the field (string, number, boolean, date)

Example:

{
  "typeName": "coffee",
  "fieldName": "body",
  "fieldType": "string"
}

5. add_review_record

Add a new review record to a type.

Parameters:

  • typeName (string): Name of the review type

  • data (object): Review data matching the type's schema

Example:

{
  "typeName": "coffee",
  "data": {
    "flavor": "nutty",
    "aroma": "strong",
    "acidity": "medium",
    "rating": 8.5
  }
}

Usage Examples

Complete Workflow

// 1. Create a new review type
await mcp.callTool("add_review_type", {
  name: "whisky",
  fields: [
    { name: "taste", type: "string" },
    { name: "age", type: "number" },
    { name: "peated", type: "boolean" },
    { name: "tasted_on", type: "date" }
  ]
});

// 2. Add a review
await mcp.callTool("add_review_record", {
  typeName: "whisky",
  data: {
    taste: "smoky and complex",
    age: 12,
    peated: true,
    tasted_on: "2025-11-16T10:00:00Z"
  }
});

// 3. Add more fields later
await mcp.callTool("add_field_to_type", {
  typeName: "whisky",
  fieldName: "region",
  fieldType: "string"
});

// 4. List all types and their data
const result = await mcp.callTool("list_review_types", {});

Architecture

Project Structure

record-mcp/
├── src/
│   ├── index.ts              # MCP server entry point
│   ├── types.ts              # TypeScript type definitions
│   ├── storage/
│   │   ├── interface.ts      # Storage provider interface
│   │   ├── local.ts          # Local file system storage
│   │   ├── r2.ts             # Cloudflare R2 storage
│   │   └── factory.ts        # Storage provider factory
│   ├── tools/
│   │   ├── list-types.ts     # List and get review types
│   │   ├── add-type.ts       # Create new review type
│   │   ├── add-field.ts      # Add field to type
│   │   └── add-record.ts     # Add review record
│   └── utils/
│       └── validation.ts     # Schema and data validation
├── data/                     # Local storage (when using local provider)
│   ├── types/
│   │   ├── coffee.json
│   │   └── whisky.json
│   └── index.json
└── tests/
    ├── storage.test.ts       # Storage provider tests
    └── tools.test.ts         # MCP tools tests

Storage Abstraction

The server uses a storage abstraction layer that allows easy switching between local files and Cloudflare R2:

  • Local Storage (Development): Uses Node.js fs/promises to store JSON files

  • R2 Storage (Production): Uses AWS S3-compatible API to store in Cloudflare R2

Both providers implement the same StorageProvider interface, making migration seamless.

Data Format

Each review type is stored as a separate JSON file:

{
  "name": "coffee",
  "schema": [
    { "name": "flavor", "type": "string" },
    { "name": "aroma", "type": "string" }
  ],
  "records": [
    {
      "id": "1234567890-abc123",
      "data": {
        "flavor": "nutty",
        "aroma": "strong"
      },
      "createdAt": "2025-11-16T10:00:00Z"
    }
  ],
  "createdAt": "2025-11-15T09:00:00Z",
  "updatedAt": "2025-11-16T10:00:00Z"
}

Migration from Local to R2

When you're ready to move to production:

  1. Set up your Cloudflare R2 bucket

  2. Update your .env file with R2 credentials

  3. Change STORAGE_PROVIDER=r2

  4. Restart the server

Optional: Use a migration script to copy existing data:

// Copy all local files to R2
const localStorage = new LocalStorageProvider('./data');
const r2Storage = new R2StorageProvider(r2Config);

const types = await localStorage.listTypes();
for (const typeName of types) {
  const data = await localStorage.readType(typeName);
  await r2Storage.writeType(typeName, data);
}

Validation

The server provides comprehensive validation:

  • Type Names: Alphanumeric, hyphens, and underscores only

  • Field Types: Must be one of: string, number, boolean, date

  • Required Fields: All schema fields must be present in records

  • Extra Fields: Records cannot have fields not in the schema

  • Type Checking: Field values must match their declared types

Error Handling

All tools return structured error messages:

{
  "error": "Review type \"coffee\" already exists"
}

Common errors:

  • Duplicate type names

  • Duplicate field names

  • Missing required fields in records

  • Type mismatches

  • Invalid type/field names

Development

Building

npm run build

Watching for Changes

npm run watch

Testing

Run all tests:

npm test

Run specific test file:

tsx tests/storage.test.ts
tsx tests/tools.test.ts

License

MIT

Contributing

Contributions welcome! Please ensure tests pass before submitting PRs.

Support

For issues or questions, please open a GitHub issue.

Install Server
A
security – no known vulnerabilities
F
license - not found
A
quality - confirmed to work

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sanggggg/record-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server