I Built an MCP Server So I'd Never Have to Manually Import Excel Data Again

Published: (February 9, 2026 at 11:55 PM EST)
6 min read
Source: Dev.to

Source: Dev.to

The Problem That Started It All

Picture this: you’re running a small café. You’ve got your menu in an Excel spreadsheet (because that’s what everyone uses, right?). Now you need to get that data into MongoDB for your new web app.

Your options

  • Copy‑paste each item manually (soul‑crushing)
  • Write a one‑off Node.js script (works once, breaks next time)
  • Ask ChatGPT to write the script (gets you 80 % there, then you’re on your own)

I wanted option 4: Talk to Claude like a human and have it just… work.

That’s where MCP (Model Context Protocol) comes in.

What Even Is MCP?

MCP is basically a way to give Claude (or any AI) super‑powers. Instead of Claude just answering questions, it can actually do things—like reading files, calling APIs, or, in my case, importing Excel data into databases.

Without MCPWith MCP
Claude is a really smart friend who can only give advice.Claude is a really smart friend who can actually SSH into your server and fix things.

The catch? You have to build the “server” that does the actual work.

Building MindfulMapper

The Vision

I wanted to be able to say:

“Hey Claude, import menu.xlsx into my products collection. Map ‘Name (EN)’name.en and ‘Name (TH)’name.th. Oh, and auto‑generate IDs with prefix ‘spb’.”

…and have it just work.

The Reality (aka Pain Points)

Pain Point #1 – The Dotenv Disaster

My first version used dotenv to load environment variables:

import dotenv from 'dotenv';
dotenv.config();

dotenv prints a helpful message to stdout:

[dotenv@17.2.4] injecting env (4) from .env

Claude Desktop saw this message, tried to parse it as JSON (because MCP uses JSON‑RPC), and promptly died. Took me WAY too long to figure this out.

Solution: suppress the message or hard‑code the env vars in the Claude Desktop config. I went with the latter.

Pain Point #2 – SDK Version Hell

The MCP SDK evolves fast—really fast. Version 1.26.0 uses completely different syntax than the examples online.

What the examples showed (pre‑1.26.0):

server.addTool({
  name: "my_tool",
  description: "Does a thing",
  parameters: z.object({ /* … */ }),
  execute: async ({ /* … */ }) => { /* … */ }
});

What actually works in v1.26.0:

const server = new Server(
  { name: "my-server", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [/* … */]
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  // Handle tool calls
});

Completely different. Spent hours on this one.

Pain Point #3 – Auto‑Generating IDs

I wanted IDs like spb-0001, spb-0002, etc. The trick is maintaining a counter in MongoDB:

async function getNextId(prefix = 'spb') {
  const counterCollection = db.collection('counters');
  const result = await counterCollection.findOneAndUpdate(
    { _id: 'item_id' },
    { $inc: { seq: 1 } },
    { upsert: true, returnDocument: 'after' }
  );
  const num = result.seq || 1;
  return `${prefix}-${String(num).padStart(4, '0')}`;
}

This ensures:

  • No duplicate IDs (even if you import the same file multiple times)
  • Sequential numbering
  • Custom prefixes for different item types

The Cool Parts

1. Flexible Column Mapping

Want to map Excel columns to nested MongoDB objects? Easy:

// Excel columns: "Name (EN)", "Name (TH)"
// Mapping: { "name.en": "Name (EN)", "name.th": "Name (TH)" }

// Result in MongoDB:
{
  id: "spb-0001",
  name: {
    en: "Americano",
    th: "อเมริกาโน่"
  }
}

The mapper handles the dot‑notation automatically.

2. Natural Language Interface

Instead of writing code every time, I just tell Claude:

“Import menu.xlsx into products collection. Use prefix ‘spb’. Clear existing data.”

Claude translates that into the right MCP tool call with the correct parameters. It’s like having a very patient assistant who never gets tired of your data imports.

3. It Actually Works in Production

I’m using this with MongoDB Atlas (cloud) for a real café menu system. The fact that it works reliably enough for production still surprises me.

How to Use It

1. Install

git clone https://github.com/kie-sp/mindful-mapper.git
cd mindful-mapper
npm install

2. Configure Claude Desktop

Add the following to ~/Library/Application Support/Claude/claude_desktop_config.json (adjust the paths/values to your environment):

{
  "mcpServers": {
    "mindful-mapper": {
      "command": "node",
      "args": ["/full/path/to/mindful-mapper/upload-excel.js"],
      "env": {
        "MONGODB_URI": "your-mongodb-connection-string",
        "MONGODB_DB_NAME": "your_db",
        "ID_PREFIX": "spb"
      }
    }
  }
}

3. Use It

  1. Restart Claude Desktop.

  2. Say, for example:

    “Import /path/to/menu.xlsx into products collection. Use prefix ‘spb’.”

That’s it.

MindfulMapper demo

MCP illustration

Lessons Learned

1. MCP is Still Early Days

The SDK is changing fast. Code that worked two months ago might break today. Always check the version you’re using.

2. Debugging MCP Servers Is… Interesting

When your server crashes silently you won’t see a stack trace in Claude. Your best friend becomes:

node your-server.js 2>&1

and the logs located at:

~/Library/Logs/Claude/mcp*.log

3. The Payoff Is Worth It

Once it works, it’s magic. I went from dreading data imports to actually enjoying them (well, at least not dreading them).

What’s Next?

Current limitations I want to fix:

  • No schema validation – It will happily import garbage data.
  • No update/upsert mode – Only “insert” or “clear‑and‑insert”.
  • MongoDB only – PostgreSQL support exists but needs love.
  • No multi‑sheet support – Only the first sheet is processed.

But honestly, for ~90 % of my use cases it works perfectly as‑is.

Try It Yourself

  • GitHub:
  • Requirements: Node.js 18+, MongoDB, Claude Desktop
  • License: MIT (do whatever you want with it)

If you build something cool with it, let me know! Or if you hit the same pain points I did, at least now you know you’re not alone.

Final Thoughts

Building MCP servers is weird. It’s not quite backend development, not quite AI engineering – it’s a new kind of tool‑building for an AI to use on your behalf.

When it works, you can casually tell Claude to handle your data imports while you go make coffee. That’s pretty cool.

If you end up using this or building something similar, I’d love to hear about it! Feel free to open an issue on GitHub or reach out.

Happy importing! 🎉

Built with: Node.js, MongoDB, MCP SDK, and an unreasonable amount of trial and error

0 views
Back to Blog

Related posts

Read more »

New article

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as we...

Build a Serverless RAG Engine for $0

Introduction: The Problem with “Toy” RAG Apps Most RAG tutorials skip the hard parts that actually matter in production: - No security model: Users can access...

Set up Ollama, NGROK, and LangChain

markdown !Breno A. V.https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...