hf-publish-mcp
v1.0.3
Published
MCP server for the fine-tuner's publish workflow on Hugging Face Hub — upload models, inspect repos, and maintain model cards.
Downloads
696
Maintainers
Readme
Intended for fine-tuners and researchers who publish models to HF Hub. This is not a general-purpose Hub CLI wrapper - it is scoped to your own repos: uploading checkpoints and adapters, inspecting file completeness, and maintaining model cards. For browsing and discovering other people's models, use the official HF MCP instead.
Tools · Getting Started · Auth · Client Config · How It Works · Stack · Development · Contributing
vs Official HF MCP
The official HF MCP and this server are complementary, not overlapping.
| | Official HF MCP | hf-publish-mcp |
|---|---|---|
| Transport | Remote HTTP/SSE | Local stdio |
| Auth | HF account (OAuth via settings) | Write-scoped token |
| Search models, datasets, spaces, papers | Yes | No |
| Search HF documentation | Yes | No |
| Run Gradio Space tools | Yes | No |
| Run jobs on HF infrastructure | Yes | No |
| Repo details + README (read) | Yes | Yes (inspect_repo) |
| Upload local model/adapter files | No | Yes |
| Edit model cards | No | Yes |
| Track background upload jobs | No | Yes |
The overlap is inspect_repo vs the official "Hub Repository Details" tool - both return repo metadata and the README. Everything else is distinct: the official MCP is for exploring the Hub, this one is for pushing to it.
Tools
| Tool | Description |
|---|---|
| list_model_repos | List your HF models with likes, downloads, and last modified date |
| inspect_repo | Verify expected files exist (config, tokenizer, weights) and return the model card |
| upload_model | Upload a model or adapter directory to HF. Non-blocking - returns a jobId immediately |
| get_model_upload_status | Poll a background upload by jobId. Shows phase, current file, and elapsed time |
| update_model_card | Patch a model card README via surgical section edits, frontmatter merges, or full rewrite (dry run support: review changes before agent commits) |
| manage_upload_jobs | List, delete, or batch-clean upload job history across active and dated archive files |
Getting Started
Requires Bun
No install needed - run directly with bunx:
bunx hf-publish-mcpOr clone for local development..
Development
git clone https://github.com/CodeStrate/hf-publish-mcp
cd hf-publish-mcp
bun install
bun run dev # watch mode - restarts on file changesTo build from source:
bun run build # compiles to dist/index.jsThen point your MCP client at the local build:
{
"command": "bun",
"args": ["/absolute/path/to/hf-publish-mcp/dist/index.js"],
"env": { "HF_TOKEN": "hf_..." }
}Logs go to stderr (structured JSON via pino). To read them while developing:
HF_TOKEN=hf_... bun run dev 2>&1 | bunx pino-prettyAuth
On startup the server resolves your HF token in order:
HF_TOKENenvironment variable- HF CLI token at
~/.cache/huggingface/tokenIf neither is present the server exits immediately with an error message rather than hanging.
The token requires write scope.
Client Config
Claude Desktop
{
"mcpServers": {
"hf-publish": {
"command": "bunx",
"args": ["hf-publish-mcp"],
"env": {
"HF_TOKEN": "hf_..."
}
}
}
}Claude Code
claude mcp add hf-publish -- bunx hf-publish-mcpVS Code (.vscode/mcp.json) - token via secrets UI
{
"inputs": [
{
"id": "hf-token",
"type": "promptString",
"description": "HuggingFace write-scoped token",
"password": true
}
],
"servers": {
"hf-publish": {
"type": "stdio",
"command": "bunx",
"args": ["hf-publish-mcp"],
"env": {
"HF_TOKEN": "${input:hf-token}"
}
}
}
}Generic stdio client (Cursor, PiCode, OpenCode, etc.)
{
"command": "bunx",
"args": ["hf-publish-mcp"],
"env": {
"HF_TOKEN": "hf_..."
}
}How It Works
Upload
upload_model is non-blocking. It creates the repo if absent, starts the upload in the background, and returns a jobId immediately. Poll with get_model_upload_status.
Jobs persist to ~/.hf_mcp/upload-jobs.json - status survives server restarts. Jobs interrupted mid-upload are marked Error on next start rather than left in a stale Running state. Completed jobs are archived to dated files once the active file exceeds the limit.
Progress is phase-level (preuploading → uploadingLargeFiles → committing) and file-level, powered by uploadFilesWithProgress from @huggingface/hub.
Model Card Editing
update_model_card operates in two modes:
Surgical - pass frontmatter and/or sections. Only the specified parts change; everything else is returned byte-for-byte. The remark AST is used purely as a position map to locate section boundaries, then the raw string is spliced directly. No formatting drift.
Full rewrite - pass content with the complete README body. frontmatter and removeFields are still applied on top if provided.
Dry Run Support - A dryRun flag for when you would like to review changes before you'd want the agent to commit the changes. Allowing for manual adjustments in case something isn't right.
Stack
- TypeScript + Bun
@modelcontextprotocol/sdk- MCP SDK + stdio transport@huggingface/hub- repo ops, uploads, file downloadgray-matter- YAML frontmatter round-trippingremark+remark-gfm- markdown AST for section position mappingpino- structured logging to stderr (stdout reserved for MCP JSON-RPC)diff- reviewing model card changes in a diff before committing (through a dry run option)
Contributing
PRs welcome. A few guidelines:
- One concern per PR - keep diffs reviewable
- Open an issue first for anything beyond a bug fix or small improvement
update_model_cardis the most sensitive tool - changes there should be tested against a real card;dryRun: trueexists for thistrigger_gguf_quantis experimental and currently deferred - the Gradio Space requires browser OAuth that can't be satisfied headlessly; skip unless you have a concrete solution
Bug reports: open an issue with the tool name, inputs (redact your token), and the error message or unexpected output.
