Or: How I spent a Saturday building MindfulMapper instead of doing literally anything else
The Problem That Started It All
Picture this: You're running a small cafe. 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) superpowers. 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.
Think of it like this:
- Without MCP: Claude is a really smart friend who can only give advice
- With MCP: 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)' to name.en and 'Name (TH)' to 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. Seemed innocent enough:
import dotenv from 'dotenv';
dotenv.config();
Turns out, 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: Either suppress the message or just hardcode the env vars in the Claude Desktop config. I went with option 2.
Pain Point #2: SDK Version Hell
The MCP SDK is evolving fast. Like, really fast. Version 1.26.0 uses completely different syntax than what's in the examples online.
What the examples showed:
server.addTool({
name: "my_tool",
description: "Does a thing",
parameters: z.object({...}),
execute: async ({...}) => {...}
});
What actually works (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
});
Yeah. Completely different. Spent hours on this one.
Pain Point #3: Auto-Generating IDs
I wanted IDs like spb-0001, spb-0002, etc. Seems simple, right?
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
This is the magic part. 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 right 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 cafe menu system. The fact that it works reliably enough for production use still surprises me.
How to Use It
If you want to try it yourself:
1. Install
git clone https://github.com/kie-sp/mindful-mapper.git
cd mindful-mapper
npm install
2. Configure Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"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
Restart Claude Desktop, then:
"Import /path/to/menu.xlsx into products collection. Use prefix 'spb'."
That's it.
Lessons Learned
1. MCP is Still Early Days
The SDK is changing fast. Code from 2 months ago might not work today. Always check the version you're using.
2. Debugging MCP Servers is... Interesting
Your server crashes silently. No stack traces in Claude. Your only friend is:
node your-server.js 2>&1
And the logs 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, not dreading them at least).
What's Next?
Current limitations I want to fix:
- No schema validation - It'll 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 - First sheet only
But honestly? For 90% of my use cases, it works perfectly as-is.
Try It Yourself
- GitHub: github.com/kie-sp/mindful-mapper
- 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 this new thing where you're building tools for an AI to use on your behalf.
But when it works? When you can just 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

Top comments (1)
Cool