berbotu-mcp
Allows creating new demo files in the vault by committing to a GitHub repository via the GitHub API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@berbotu-mcp What demos are in the listening stage?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
berbotu-mcp
An MCP server that lets an AI read and write real records in a live repository — without being able to break anything quietly.
It sits over the vault behind a small record label: releases, demos, and label state, all markdown with YAML frontmatter. Four tools over stdio. Three read, one writes.
"what demos came in this week I haven't decided on yet?" → list_demos { stage: "Listening" }
"what's the next release scheduled?" → list_releases { stage: "Scheduled", limit: 1 }
"log the demo that just came in from X" → add_demo ✍️ writes a real git commitWhy it's built the way it is
The interesting problem isn't connecting an AI to data. That's an afternoon. The problem is that an AI with write access is an intern who never asks twice — so every design decision here is about what happens when it's wrong.
Every write is its own git commit, through the GitHub Contents API.
Not a filesystem write. A commit. Which means every single thing the AI ever did is attributable, diffable, and
revertible with one command. If it writes garbage at 3am, I don't need a backup — I need git revert. This costs
an API round-trip per write and it's worth it.
Existence is SHA-checked before anything is touched.
getVaultFile resolves the file's SHA first. Passing a sha to the create endpoint turns a create into an
overwrite — so the check isn't defensive, it's the difference between "this demo already exists" and silently
destroying a record.
Inputs are validated at the boundary, then again in the handler.
Tool inputs are zod schemas — stage is an enum, so a hallucinated stage gets a clean rejection with the valid
options instead of writing nonsense. Then addDemo re-validates the same fields itself. The code calls this
defence in depth: the schema is the contract, but a future caller might not go through it.
Tools carry honest annotations.
readOnlyHint: false — it writes
destructiveHint: true — appends a commit to a real git repo
idempotentHint: false — calling twice with the same args creates two demosThese are hints to the model about what it can safely retry. add_demo is not idempotent and saying otherwise
would invite exactly the double-write it warns about.
Read-only first, writes later.
Stages 1–2 shipped with no write path at all. add_demo landed only once the read tools had been running against
the real vault long enough to trust the parsing. There was no deadline — that's just the order that made the
mistakes cheap.
Errors return, they don't throw.
Every tool returns isError: true with a human-readable reason — missing env var, missing folder, malformed
frontmatter, 401, 422, network down. An MCP server that throws gives the model a stack trace to hallucinate
around. One that explains gives it something to say to the user.
Related MCP server: git-mcp
The bug that justifies all of it
While building the data layer, list_releases returned 1 of 12 releases. No error. No warning. Just a
confident, wrong, almost-empty list.
The cause: gray-matter's default YAML engine treats a duplicate map key as a fatal parse error and returns
{} for the whole file. The vault had duplicate keys in real files — a separate script had been appending
ig_posted: true twice. Eleven records were being silently dropped on the floor.
Fix was the yaml package with { uniqueKeys: false } — lenient, last-duplicate-wins, parses all twelve.
The point isn't the fix. The point is that nothing failed. No exception, no red text. If I'd trusted the output, an AI would have been confidently telling me I had one release. That's the whole reason this repo is paranoid: the dangerous failures are the quiet ones.
Quick start
npm install
npm run build # TS → dist/
npm run inspect # MCP Inspector web UI, call the tools by handAttach to Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"berbotu": {
"command": "node",
"args": ["/path/to/berbotu-mcp/dist/index.js"],
"env": { "BERBOTU_VAULT_PATH": "/path/to/vault" }
}
}
}Read tools need BERBOTU_VAULT_PATH. add_demo also needs VAULT_WRITE_PAT — a fine-grained GitHub PAT scoped
to one repo with Contents: Read and write. See .env.example.
Tools
Tool | Args | Returns |
| none | version, vault path, pid, node — confirms it's alive and pointed at the right vault |
|
|
|
|
|
|
|
| creates a demo file as a GitHub commit |
Honest limits
stdio only. Local. HTTP transport + JWT auth was the next stage and hasn't been built — there was no reason to.
One writer. No conflict handling beyond the SHA existence check. Fine for one operator, wrong for a team.
Read tools are filesystem, writes are API. A deliberate split — reads want to be fast and local, writes want to be auditable. It does mean a write isn't visible to a read until the repo syncs.
Four tools. Small on purpose. Every tool with write access is a thing that can be wrong at 3am.
Stack
TypeScript · @modelcontextprotocol/sdk · zod · yaml · GitHub Contents API · stdio
Built AI-assisted. I'm not an engineer and I'm not trying to be — I'm someone who knows what to build and how to keep it from breaking things.
Available Tools
4 toolsadd_demoAdd a new demoADestructive
Creates a new demo entry in the Berbotu vault by committing a Markdown file to the berbotu/vault GitHub repo (path: 00 Releases/Demos/{ARTIST} - {TITLE}.md). Use this when the user wants to log a fresh submission — e.g. 'add a demo from RULACID called UNTITLED', or 'log a new demo from the email I just pasted'. REQUIRED: artist + track. Both must be non-empty strings. OPTIONAL: stage (default 'Listening'), received_date (default today UTC), notes (default empty). Refuses to overwrite if a demo with the same artist+title already exists — in that case the user should edit via admin.berbotu.com instead. On success returns the created file path, the full frontmatter that was written, and a permalink to the GitHub commit so the user can audit the change.
Inputs: track (required), artist (required), notes, stage, +1 more.
list_demosList demosA
Lists demo submissions from the Berbotu vault, sorted newest-first by received_date. Each item has: artist, track title, status (stage), received date, and an optional 1-5 star score. Use this when the user asks about incoming submissions, the demo pipeline, A&R inbox, or anything like 'what demos have we got?'. Optional stage arg filters by stage substring (case-insensitive) — e.g. 'listening', 'interested', 'pass'.
Inputs: limit, stage.
list_releasesList releasesA
Lists track + EP releases from the Berbotu vault, sorted newest-first by release_date. Each item has: title, artist, release date, status (stage), and EP/single flag. Use this when the user asks about the label catalog, scheduled releases, what's coming out, what shipped, or anything about 'releases'. Optional stage filter (substring, case-insensitive) — common: 'Released', 'Scheduled', 'DITTO', 'On Hold'.
Inputs: limit, stage, includeEps, includeTracks.
pingHealth checkA
Returns 'OK' plus server name, version, vault path, current timestamp, process id, and Node.js version. Use this to confirm the Berbotu MCP server is reachable and configured correctly.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: ping for health check, list_demos for demo submissions, list_releases for catalog releases, and add_demo for creating new entries. No overlapping resource or action.
Tools follow a consistent verb_noun pattern with snake_case (list_demos, list_releases, add_demo). ping is a simple verb but is standard and does not disrupt the pattern.
Four tools is small but well-scoped for a niche vault/music label server. It covers health, listing, and creation, though could add more operations in the future.
The core workflow—check health, view demos and releases, add new demos—is covered. Missing update/delete operations, but this is intentionally delegated to the admin web interface, so no critical dead ends.
Related MCP Connectors
A MCP server built for developers enabling Git based project management with project and personal…
Create, deploy, and operate MCP servers directly from your GitHub repositories.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA unified MCP server with composable tools for GitHub operations, file management, shell execution, kanban boards, Discord messaging, and package management. Features role-based security, HTTP/stdio transports, and a web-based development UI.GPL 3.0
- FlicenseNot gradedqualityDmaintenanceStandalone MCP server for GitHub that enables repository management, branch operations, pull request handling, and commit retrieval via tools listed in the README.1-
- FlicenseNot gradedqualityDmaintenanceA minimal MCP server for homelab environments, providing demo tools like ping and echo over Streamable HTTP for testing client-server integration.-
- FlicenseNot gradedqualityDmaintenanceA minimal MCP server demo with tools for ping, addition, and fetching current UTC time.-