---
title: "How we built the AssetHoard MCP server"
slug: how-we-built-the-assethoard-mcp-server
url: https://listedarticles.com/articles/how-we-built-the-assethoard-mcp-server
canonical_url: https://assethoard.com/blog/how-we-built-the-assethoard-mcp-server
content_type: blog_post
language: en
published_at: 2026-10-13T00:00:00.000Z
updated_at: 2026-10-13T20:15:42.875Z
author: "Mark Gandolfo"
authored_by: human
publisher: "AssetHoard"
publisher_url: https://assethoard.com/
topics: ["AI Agents", "Games", "Developer Tools", "Programming"]
license: all-rights-reserved
word_count: 2254
reading_minutes: 10
citation: "Mark Gandolfo, AssetHoard. \"How we built the AssetHoard MCP server.\" 13 Oct 2026. https://assethoard.com/blog/how-we-built-the-assethoard-mcp-server (all-rights-reserved)"
# The full text follows. The web page shows an extract and sends readers
# to the source above; quote the citation and link the canonical URL.
---

# How we built the AssetHoard MCP server

> AssetHoard’s Mark Gandolfo explains how the library’s built-in MCP server lets Claude Code, Cursor, and other agents search owned game assets and export into a project—and why the server is locked down so file contents stay on the user’s machine.

You're three hours into building a level. You need a barrel. You know you own at least four barrel packs, because you bought them in three different bundle sales and one of them was "a steal". Finding them means leaving the editor, opening a file browser, and digging through folders called `Downloads (2)`.

Meanwhile there's an AI assistant sitting in your editor that can write a state machine in eight seconds but has no idea what's on your hard drive.

AssetHoard is a local-first desktop asset manager for indie game developers and digital artists, and version 0.2.3 fixes that with a built-in [MCP server](https://assethoard.com/mcp-server). This post covers how we built it, why it's locked down the way it is, and the things we've found it genuinely useful for.

## What MCP is, briefly

The Model Context Protocol is an open standard for letting AI tools call other programs. A program exposes a set of named tools with typed arguments ("search", "export", "create_bundle"), and any MCP client (Claude Code, Cursor, VS Code, Windsurf, Claude Desktop) can discover and call them.

For an asset manager that's a natural fit. AssetHoard already knows every model, texture, sprite and sound you own, what's in which bundle, what it's tagged, and what each file depends on. MCP lets your assistant ask it.

## The decisions that shaped it

### Built into the app, not a separate program

The obvious shortcut would have been a little standalone server that opens AssetHoard's SQLite database and reads it directly. We didn't do that, for two reasons.

First, two programs writing to one SQLite file is how you end up with a corrupted library and a very bad afternoon. Second, the app would never find out about changes. You'd ask your assistant to tag forty rocks and the open window would keep showing them untagged until you restarted.

So the server runs inside AssetHoard itself, and the app has to be open for it to answer. That turned out to be a feature: every change the assistant makes shows up in the window straight away.

Living inside the app also means you stay in charge of it from the app:

- **Turn it on and off.** One switch in Settings > MCP Server. It's off until you flip it, and a plug icon sits in the toolbar whenever it's running, so you're never guessing.
- **See what changed.** When an assistant exports files or edits your library, AssetHoard shows a notification in the app saying what it did, and the settings page keeps a list of recent calls.
- **Decide how much the assistant can do.** Out of the box it can only search, look and export. Changing your library needs "Allow write tools" switched on, and importing files pops up a prompt you have to approve. If you'd rather keep it read-only forever, just leave the write switch off.

### One rule: MCP never touches the database directly

The MCP code lives in its own module, and it isn't allowed to call app commands or SQL. Everything goes through a small internal library API that sits underneath both the UI and the MCP server.

That sounds like bureaucracy, but it's what makes the write tools trustworthy. When an assistant moves an asset into a bundle, it runs exactly the same function as when you drag it there yourself. Same validation, same audit log, same undo entry. There's no second, slightly different code path quietly drifting out of sync with the real one.

It also makes adding a tool cheap. A new tool is a typed argument struct (whose doc comments become the descriptions the model reads) and a thin method that calls the library API. The interesting logic stays in one place and gets tested once.

### Rust, rmcp and streamable HTTP

AssetHoard's backend is Rust, so we used [rmcp](https://github.com/modelcontextprotocol/rust-sdk?utm_source=assethoard&utm_medium=referral), the official Rust SDK for MCP, with its streamable HTTP transport mounted on axum. Database work runs on blocking worker threads so a big search never stalls the app's async runtime, and each call is recorded in a recent-activity list you can watch in Settings.

We picked HTTP over stdio because the server lives inside a desktop app that's already running. Claude Code, Cursor, VS Code and Windsurf all connect to a local HTTP endpoint with a header, which is a one-line setup. Claude Desktop is the odd one out: it only launches stdio servers, so for now it connects through the `mcp-remote` bridge.

### A fixed port, on purpose

The server listens on port `47823` by default. You can change it, but AssetHoard will never pick a different one on its own if that port is busy. Auto-switching sounds helpful until every client config you've written silently stops matching. Instead, a taken port shows up as an error with a readable message, and you choose what to do.

## Making it safe to leave on

A local server that can read your files and write to your library deserves some paranoia. Here's what's in place:

- **Off by default.** You turn it on in Settings > MCP Server.
- **Local only.** It binds to`127.0.0.1` , so nothing on your network or the internet can reach it.
- **Token required.** Every request needs a bearer token: 48 random hex characters, compared in constant time. Regenerating it disconnects every client.
- **Browsers are refused.** Any request with an`Origin` header is rejected, and the`Host` header must be a loopback address. Browsers always send`Origin` ; CLI and IDE clients don't. This blocks DNS rebinding, where a malicious web page tries to talk to a server on your machine, and it's what the MCP spec asks local servers to do.
- **Write tools are a second opt-in.** "Allow write tools" is a separate toggle, and it's checked on every call, so switching it off takes effect immediately, even for clients that are already connected.
- **No deleting your stuff.** There are no tools for deleting assets or bundles. The only deletes are for categories nothing uses and projects that are already empty.
- **Exports never overwrite.** If a file already exists at the destination, it's skipped and reported.
- **Imports ask first.** When an assistant wants to import a folder, AssetHoard pops up a prompt with the path, file count, size and target bundle, and flashes the window. No answer within 60 seconds counts as no. If you trust your setup, "Import without asking" turns this off.
- **Everything is undoable.** Writes go on the normal undo stack with an`MCP:` label, like`MCP: Moved 1 asset into 'Rocks'` , and a toast tells you what changed. Ctrl+Z (Cmd+Z on a Mac) works exactly as it does for your own edits.

A plug icon appears in the toolbar whenever the server is running, so you always know it's on.

## Small things that made a big difference

**Search returns text, thumbnails are separate.** Search results are ids, names, types, paths and tags, which keeps them small. If the assistant wants to actually look at something, it calls `get_thumbnail` and gets a preview image of at most 256 pixels. That means it can check that the "mossy rock" really is mossy before suggesting it, without flooding its context with every result's picture.

**Dependencies come along.** Exporting a model brings its textures. Exporting a Godot `.tres` brings the files it references, and Unreal assets bring theirs. Exporting a whole bundle keeps its folder layout. Assets inside zip archives or `.unitypackage` files are pulled out first.

**Clickable links.** Every asset, bundle and project the server returns includes an `assethoard://` link. The assistant can hand you a link, you click it, and AssetHoard jumps to that item. We added the link scheme to the app specifically for this.

**Errors the model can read.** An unknown id, a bundle inside a package, or write tools being switched off all come back as plain error messages rather than protocol failures, so the assistant can explain what happened or try something else.

## What you can do with it

Here's what this looks like in practice. These are the kinds of things you'd type into Claude Code, Cursor or similar with AssetHoard running.

### Set dressing without leaving the editor

"Find three different barrel models and a wood texture that matches, and copy them into `Assets/Props`."


The assistant searches your library, looks at the thumbnails of the best few, picks a set and exports them, textures included. You keep building the level. This was the main use case we designed for, and it's the one in the [demo video](https://assethoard.com/mcp-server).

### Search by what it looks like, not what it's called

"Do I have any mossy stone wall textures?"


Search works the same way as AssetHoard's search bar: by name with typo tolerance, and by meaning when semantic search is turned on. Since 0.2.3 that includes embedded audio metadata too, so "glass shatter" can find `SFX_0472_FINAL.wav` if that's what its description says.

### Narrow it down like you would in the app

"Show me Godot UI sprites from my Kenney bundle."


Results can be filtered by file type, asset class, engine, tag, category or bundle. The assistant works out the bundle id itself and filters inside it.

### Drop a whole tileset into a project

"Copy my 'Dungeon Tileset' bundle into the Godot project at `C:/dev/crawler`."


The bundle's sub-bundles become folders in the destination, so the structure you set up in AssetHoard carries over.

### Tidy up the library (write tools on)

"Make a bundle called 'Rocks' under 'Environment', move every rock model into it and tag them 'nature'."


The assistant creates the bundle, searches, moves and tags. Each step appears live in the app and is its own undo entry. If it gets carried away and moves a boulder that was actually a potato, Ctrl+Z.

A slower but satisfying variation: "Find the untagged textures in my Downloads bundle, look at each one and suggest tags." Review the suggestions, say yes, and let it apply them.

### Keep track of what a game uses

"Start a project called 'Crawler' and add the dungeon tileset and the footstep sounds to it."


Projects in AssetHoard only record references. Nothing moves, and an item can belong to several projects. Once a project is set up, you can ask questions like "list everything in Crawler and tell me which assets have no licence recorded", which is a much nicer way to find out before release than after.

### Onboard a new pack

"Import `C:/Users/me/Downloads/kenney_platformer-pack` into my Kenney bundle, then categorise the new assets by type."


AssetHoard asks you to allow the import, runs it through the normal import queue with the usual progress notification, then the assistant categorises what came in. The whole import is one undo entry.

## What's next

The main gap right now is Claude Desktop needing the `mcp-remote` bridge. A small native shim that lets it connect directly is on the list. We'd also like to hear what you end up using the server for, because the tool list was shaped by our own workflow and yours is probably weirder.

## Try it

The MCP server is in [AssetHoard 0.2.3](https://assethoard.com/releases/0.2.3) and later. Open Settings > MCP Server, switch it on, and paste the setup command into your client. The [MCP docs](https://assethoard.com/docs/mcp) cover each client, and the [tool reference](https://assethoard.com/docs/mcp-tools) lists every tool and its arguments. AssetHoard is free to download during the open beta, so the only thing it'll cost you is finally finding out how many barrel packs you own.

*The AssetHoard Team*

## Frequently asked questions

It's a small server built into the AssetHoard desktop app that speaks the Model Context Protocol (MCP), the open standard AI tools use to talk to other programs. When it's switched on, AI clients such as Claude Code, Cursor, VS Code, Windsurf and Claude Desktop can search your asset library, look at thumbnails, browse bundles, tags and projects, and copy assets into your game project. Optional write tools let them organise the library and import files too.

Claude Code, Cursor, VS Code and Windsurf connect directly over HTTP using the setup snippet from Settings > MCP Server. Claude Desktop only launches local stdio servers, so for now it connects through the mcp-remote bridge, which needs Node.js.

It's off by default and built to be boring from a security point of view. It only listens on 127.0.0.1, so nothing on your network can reach it. Every request needs a 48-character random token. Requests from web browsers are refused outright, which blocks DNS rebinding attacks. Write tools are a separate opt-in, imports need you to click Allow in the app, exports never overwrite files, and every change the assistant makes can be undone with Ctrl+Z.

No. There are no tools for deleting assets or bundles. The only deletes are for categories nothing uses and projects that are already empty. Everything else the write tools do goes on AssetHoard's normal undo stack, labelled with MCP:, so you can reverse it.

Yes. The server runs inside the app, so close AssetHoard and the tools go away. That's deliberate: it means there's only ever one program writing to your library database, and the open window updates live when the assistant changes something.

AssetHoard itself never sends anything off your machine. The assistant sees what the tools return: names, paths, tags, categories, metadata and small preview images. Your AI client then sends that to its model provider like any other context, so treat it the same way you'd treat pasting a file listing into a chat. Raw file contents are only copied into a folder you name, on your own disk.
