When I looked at how AI tools were building image placeholders, the pattern was familiar: string concatenation and half‑remembered URL formats for services like placehold.co and picsum.photos. Each integration had its own way of doing it, and small mistakes were easy to make.
I didn’t need a full image service. I wanted a small, predictable way to ask for a placeholder image URL without thinking about provider quirks.
MCP Image Placeholder is that piece: an MCP server exposing a single tool, image_placeholder, over JSON‑RPC. You give it a provider and some parameters, it returns a URL string.
Why an MCP Server
In the MCP world, tools run alongside editors and AI agents, speaking over standard input and output. Many clients already talk to MCP servers, so adding a tool there is often simpler than deploying another HTTP API.
For this project that meant wrapping the MCP SDK’s server, registering one image_placeholder tool with a clear input schema, and returning a plain text URL on success. There’s no UI and no separate web server. The process answers one kind of request and exits cleanly when asked to stop.
Configuration Once, Validation Always
Configuration reads environment variables once, applies defaults, and checks for obvious issues like invalid log levels or dimension ranges. After that, the rest of the code deals with a structured config object and never touches process.env directly.
Validation sits between the incoming request and the URL builders. It checks that the provider is supported, that width and height fall within configured bounds, and that provider‑specific options aren’t mixed up — picsum options being passed to placehold, for example. Anything that fails is rejected with a clear error before a URL is ever constructed.
A Builder Per Provider
Each provider has its own URL rules: different base URLs, query parameters, and options for colors or blur. Rather than baking all of that into one function, a small factory returns the provider‑specific builder. Validation makes sure the request is reasonable, the factory picks the right builder, and the builder turns the options into a URL string.
That separation keeps the common logic simple. When I’ve added or adjusted a provider, nothing else in the system was surprised.
Errors You Can Actually Read
Because this runs inside AI tools, errors have to be straightforward to interpret. The server uses a small set of error types covering configuration issues, validation failures, provider problems, and unexpected server errors. Logs are written in a simple structured format, so they can be inspected during development or forwarded somewhere in more complex setups.
The intent isn’t to be fancy. It’s to make it easy to see what went wrong when something does.
Tests Instead of a Provider Guide
There’s no long provider guide for this project. The tests cover the main behaviors: basic URLs for each provider, how dimensions are handled, common combinations of options, and failure cases when inputs are out of range or mismatched. A few more tests cover configuration and error handling.
Together they act as a living description of what the tool expects and returns, which is more than most READMEs can say.
What I Left Out
The server does not fetch images, cache anything, or manage user state. It only builds URLs. That was the decision.
Browsers, HTTP clients, and downstream services are free to fetch and cache images however they want. Keeping the scope small keeps the server easy to understand and nearly free to run.
From my side, the goal was giving AI tools a straightforward way to say “I need a placeholder image with these dimensions and style” and get back a usable URL. A single MCP tool turns out to be enough for that.