serve-mcp
This server is a local, MCP-controlled artifact shelf for AI agents to publish, manage, and preview content at stable browser URLs.
Publish Artifacts (artifact_publish): Snapshot and publish files, folders, or inline content, supporting:
File paths, inline content, or folders (as static sites with index resolution)
Stable slugs — custom or auto-generated from title/filename
Revisions — push updates to the same slug via
updateExisting: true, creating immutable revision historyTagging, descriptions, and script control (off by default; per-artifact opt-in)
Provenance capture: git branch, commit, and remote recorded automatically
List Publications (artifact_list): Filter by content kind (HTML, Markdown, JSON, CSV, image, SVG, etc.), tags, or text search; paginate and sort by date or title.
Delete Publications (artifact_delete): Permanently remove a slug and all its revisions/stored files.
Secure Previews: Content is sandboxed in iframes with strict CSPs (script-src 'none'). Markdown renders with GFM and Mermaid diagrams, CSVs become tables, and JSON is pretty-printed.
Multi-Agent Support: Multiple MCP processes share one shelf with automatic port discovery and coordination.
Deployment & Access: Install as a persistent service (launchd/systemd), configure host/port, and enable Tailscale/LAN access with automatic URL advertisement. Restrict path publishing to allowed root directories for security.
CLI: Check server status, manage configuration, publish content, and list artifacts without an agent.
Click on "Install 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., "@serve-mcppublish the file ./report.html as 'Weekly Report'"
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.
serve-mcp
A local, MCP-controlled artifact shelf. Your AI agents publish the HTML, Markdown, folders, CSV, and JSON they generate; you get stable, safely-rendered browser URLs to look at them. Built for a machine running several agents at once: each agent gets its own MCP process, and they all publish to one shared shelf.


Quickstart
npm install -g @saidmukhamad/serve-mcpAdd it to whatever agents you run — they all publish into the same shelf (the first process starts the HTTP server, the rest find it):
# Claude Code
claude mcp add serve-mcp -- npx -y @saidmukhamad/serve-mcp mcp
# Codex
codex mcp add serve-mcp -- npx -y @saidmukhamad/serve-mcp mcp
# Gemini CLI
gemini mcp add serve-mcp npx -y @saidmukhamad/serve-mcp mcpAnything else that speaks MCP (Cursor, Windsurf, ...) — the usual mcpServers block:
{
"mcpServers": {
"serve-mcp": { "command": "npx", "args": ["-y", "@saidmukhamad/serve-mcp", "mcp"] }
}
}That's it. Ask any agent to publish something and open the URL it returns — one gallery for everything, whoever made it.
The permanent setup
One always-on server that every agent and human on the machine works against:
serve-mcp config host 0.0.0.0 # reachable over your tailnet/LAN (skip for localhost-only)
serve-mcp config port 7331 # fixed port, stable URLs
serve-mcp service install # launchd / systemd --user / Task Scheduler
loginctl enable-linger $USER # Linux only: keep it alive after you log outWithout this the shelf still works — it just lives and dies with your MCP sessions (details in Lifecycle).
Proactive publishing
The server's MCP instructions already tell agents to publish viewable output on their own. For the strongest nudge in Claude Code, install the bundled skill — it auto-triggers whenever the agent produces something viewable:
mkdir -p ~/.claude/skills/publish-artifact
curl -fsSL https://raw.githubusercontent.com/saidmukhamad/serve-mcp/main/skills/publish-artifact/SKILL.md \
-o ~/.claude/skills/publish-artifact/SKILL.mdRelated MCP server: artifacty
How it works
MCP = control plane (artifact_publish, artifact_list, resources)
HTTP = human preview plane (gallery, /p/:slug, sandboxed previews)
Registry = SQLite (stable publications -> revisions)
Store = live | snapshot (path/folder serve live by default; live:false freezes a copy)The tools
artifact_publish
{
"source": { "type": "path", "path": "./report.md" }, // or content / folder
"title": "Training run explanation",
"slug": "training-run-explanation", // stable /p/<slug>; generated if omitted
"updateExisting": true, // add a revision; false = conflict on an existing slug
"live": true, // default for path/folder: edits show on refresh; false = frozen snapshot
"tags": ["ml", "report"],
"renderer": { "options": { "allowScripts": false } } // optional: disable scripts for this artifact
}Returns the preview URL, a raw URL, an MCP resource_link, and structured artifact/publication objects. Publications are stable slots; every publish is an immutable revision at /p/:slug/r/:artifactId.
artifact_list
Filter by query, tags, kind; paginate with cursor; order by createdAt | updatedAt | title.
artifact_delete
Remove a publication by slug — all revisions and stored files go with it. Irreversible.
Resources
Only registry://publications (JSON list of everything on the shelf) appears in resources/list, so host UIs stay clean no matter how many publications exist. Two more resolve when read directly (tool results link to them): publication://<slug> (compact JSON) and artifact://<id> (raw source of a revision).
Multi-agent port discovery
N agents, one shelf, no coordination. The first serve-mcp to start binds a port (--port/SERVE_MCP_PORT, else ephemeral) and records its reachable URL in <dataDir>/server.json; every other serve-mcp process — agents, the CLI — finds that record, checks the pid is alive, and publishes into the running shelf instead of starting its own.
Rendering & safety
Path and folder sources serve live by default — the shelf reads straight from the source on every request, so edits show on refresh (and the page breaks if the source moves). Publish with live: false (CLI: --snapshot) to freeze an immutable copy into the store (~/.local/share/serve-mcp) instead; inline content sources are always stored. Markdown/MDX renders through Sätteri (GFM, frontmatter, live mermaid diagrams); JSON pretty-prints; CSV becomes a table; folders serve as static sites.
HTML files and static folders run inline and same-shelf JavaScript by default inside a sandboxed iframe (without allow-same-origin). Set stripScripts to true to block scripts server-wide with CSP plus the iframe sandbox, or publish one artifact with renderer.options.allowScripts: false. Markdown and the other rendered formats stay script-blocked; Mermaid uses nonce-gated scripts.
The server binds 127.0.0.1 unless you opt into 0.0.0.0, and there is no auth — only expose it to networks you trust (a Tailscale tailnet qualifies; the open internet does not). Restrict path publishing with SERVE_MCP_ALLOWED_ROOTS=/path/a:/path/b.
Folder navigation
Folders behave like a classic file server: each directory serves its own index.html / index.md / README.md (or pass entrypoint), dir redirects to dir/ so relative and ../ links resolve, and directories without an index get a browsable listing with a ../ entry. In-folder Markdown/CSV/JSON render on the fly, and any file is downloadable with ?raw.
Provenance capture
Every publish records where it came from — source directory plus git branch, remote, and commit — read straight from .git files (no git subprocess, works even without git installed). This shows on the gallery cards and the preview subbar.
HTTP routes
GET / gallery (search, pinned, recent)
GET /p/:slug latest revision, rendered
GET /p/:slug/r/:artifactId a specific revision
GET /raw/:artifactId original source
GET /meta/:artifactId artifact metadata JSON
GET /api/publications JSON list (query, cursor, limit)
DELETE /api/publications/:slug remove a publication and all its revisionsLifecycle: who keeps the shelf alive
A shelf runs in one of three modes:
Session-managed (default) — the first MCP session on the machine becomes the shelf as a side effect and it lives as long as that session; the next session takes over. Zero setup, but the shelf has gaps when no session is open, and the URL changes unless you set a fixed port.
Foreground —
serve-mcp servein a terminal. Ctrl-C kills it, nothing respawns it.Service-managed (recommended) — the OS supervises it: starts at login, restarts on crash, independent of any session or terminal.
serve-mcp shows which one is running; serve-mcp restart (alias apply) restarts it — through the supervisor when the service is installed, by pid otherwise. The service mode is the permanent setup from the top. Manage it with serve-mcp service start|stop|restart|status|logs|uninstall. Everything is user-level — no root/admin:
macOS — launchd agent (
io.github.saidmukhamad.serve-mcpin~/Library/LaunchAgents), KeepAlive supervision, logs in<dataDir>/serve.log.Linux — systemd user unit,
Restart=on-failure, logs in the journal. To survive logout:loginctl enable-linger $USER. On WSL, systemd user services are often unavailable — runserve-mcp servein tmux instead.Windows — Task Scheduler task registered from XML (no admin): starts hidden at logon via
wscript, restarts on failure, logs in<dataDir>\serve.log.
The service pins the current runtime and package paths (shown on install) — re-run service install after upgrading either.
Tailscale / LAN access
To reach the shelf from other machines, set host to 0.0.0.0 (the permanent setup above does this). Advertised URLs then pick the best reachable name automatically: MagicDNS name (learned via reverse DNS through Quad100 and verified with the system resolver, so it's only used when peers can actually resolve it) → Tailscale IP (100.64.0.0/10) → first LAN address. Tailnet detection needs no Tailscale tooling — it keys off the interface's CGNAT address and Tailscale's ULA prefix.
CLI
serve-mcp ./report.md # publish anything, get its URL
serve-mcp . # serve this directory, live
serve-mcp # status: running shelf + what's on it
serve-mcp config host 0.0.0.0 # set config (host, port, baseUrl)
serve-mcp serve # HTTP shelf only
serve-mcp publish ./report.md --title "Report" # the longhand, with options
serve-mcp list # (also discovers a running shelf)Config
serve-mcp config shows it, serve-mcp config <key> <value> sets it (empty value unsets). Stored in <dataDir>/config.json (default ~/.local/share/serve-mcp/config.json), everything optional:
{
"host": "0.0.0.0",
"port": 7331,
"baseUrl": "http://my-machine.tailnet.ts.net:7331",
"allowedRoots": ["~/projects", "/srv/artifacts"],
"stripScripts": false
}host— bind host, default127.0.0.1port— fixed port; omit for an ephemeral port + discovery viaserver.jsonbaseUrl— advertised-URL override (e.g. a MagicDNS name)allowedRoots— restrict wherepath/folderpublishing may read from (default: anywhere readable)stripScripts— block JavaScript in HTML and static-folder previews, defaultfalse
Env vars (SERVE_MCP_HOST, SERVE_MCP_PORT, SERVE_MCP_BASE_URL, SERVE_MCP_DATA_DIR, SERVE_MCP_ALLOWED_ROOTS, SERVE_MCP_STRIP_SCRIPTS) override the file; --host/--port flags override both.
Development
npm install
npm test # typecheck + node:test — core, http, mcp round-trip
npm start # HTTP server
npm run build # tsc -> dist/Written in TypeScript; dev and tests run .ts directly via Node's native type stripping. The published package runs on Node ≥ 22.5 (built-in node:sqlite); developing needs Node ≥ 22.18 (type stripping).
Changes live in CHANGELOG.md; bleeding edge installs with @dev instead of @latest.
MIT.
Available Tools
3 toolsartifact_deleteDelete publicationA
Remove a publication and ALL of its revisions from the shelf, including stored files. Irreversible.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | Publication slug (or publication id) to delete |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description transparently reveals destructive behavior (irreversible, removes all revisions and files). It could mention authorization needs but is sufficiently clear for a simple tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences; front-loaded with the action. No extraneous text. Every word adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (single parameter, no output schema). The description fully covers behavior, irreversibility, and scope. No gaps remain for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the description does not add additional parameter meaning beyond the schema's explanation of 'slug'. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool removes a publication and all its revisions, including files. It uses a specific verb 'Remove' and distinguishes from siblings (list, publish) by being the deletion action.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description notes irreversibility, implying careful use, but does not explicitly state when to use this tool over alternatives or provide prerequisites. It implicitly guides cautious usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
artifact_listList publicationsB
List published artifacts on the shelf, newest first. Returns preview URLs humans can open.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | ||
| tags | No | ||
| limit | No | ||
| order | No | desc | |
| query | No | Substring match on title/slug/description | |
| cursor | No | ||
| orderBy | No | updatedAt |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description discloses that it returns preview URLs and default ordering, but does not state that it's a read-only operation or mention pagination behavior. Some transparency but incomplete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose and output, no redundant text. Highly concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 7 parameters and no output schema, the description omits filtering, pagination, ordering options, and return format details. Leaves significant gaps for the agent to infer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Description does not explain any of the 7 parameters despite only 14% schema coverage. It adds no meaning beyond the input schema, failing to compensate for the low coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists published artifacts, ordered newest first, and returns preview URLs. It distinguishes itself from sibling tools (delete, publish) which are different actions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance on when to use vs alternatives, but the purpose is clear and siblings are unrelated actions. Basic usage is implied but lacks exclusions or context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
artifact_publishPublish artifactA
Publish a file, folder, or inline content to the local artifact shelf and get a stable browser preview URL back. Call this whenever you produce something viewable — a report, HTML page, diagram, dataset — so the user gets a URL without having to ask. Use the same slug with updateExisting:true to push new revisions of the same page. path/folder sources are read from the machine running the shelf; over remote MCP connections use content sources.
| Name | Required | Description | Default |
|---|---|---|---|
| live | No | Serve straight from the source path — edits show on refresh (default for path/folder sources). Pass false to freeze an immutable snapshot instead. Not applicable to content sources. | |
| slug | No | Stable URL slot (/p/<slug>). Generated from title/filename if omitted. | |
| tags | No | ||
| title | No | ||
| source | Yes | ||
| renderer | No | ||
| description | No | ||
| updateExisting | No | If the slug already exists, add a new revision instead of failing |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, description carries full burden. Describes live vs snapshot behavior, remote vs local behavior. Does not disclose error handling, capacity limits, or exact return format. Adequate but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each valuable. Front-loaded purpose, then usage, then technical constraint. No redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and 8 parameters, description covers core purpose and key usage but lacks mention of return value (URL) and error scenarios. Adequate for typical use but not fully comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 38%; description adds meaning: explains live parameter, updateExisting usage, source types (path, content, folder), and slug generation. Compensates for schema gaps but not fully for all 8 parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb (publish), resource (artifact shelf), and output (stable browser preview URL). It distinguishes from siblings artifact_delete and artifact_list by specifying the action of publishing viewable content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-call: whenever producing viewable content so user gets a URL without asking. Mentions using same slug with updateExisting:true for revisions. Notes path/folder sources vs remote content sources. Lacks explicit when-not-to-call but context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.0.9- Changed
artifact_publish1 field changed- added
Input schema / properties / liveAdded value: +{ + "description": "Serve straight from the source path — edits show on refresh (default for path/folder sources). Pass false to freeze an immutable snapshot instead. Not applicable to content sources.", + "type": "boolean" +}
3 tool updates
v0.1.0- First observed
artifact_delete - First observed
artifact_list - First observed
artifact_publish
TDQS
Scored across 3 tools
Each tool targets a distinct action: publish, list, or delete artifacts. There is no overlap in purpose, making it clear which tool to use for each operation.
All tools follow the consistent 'artifact_verb' pattern in snake_case, making the naming predictable and easy to navigate.
With only 3 tools, the server is well-scoped for its purpose: publishing, listing, and deleting artifacts. This is a focused set without unnecessary clutter.
The set covers core CRUD operations: create/update via artifact_publish, read via artifact_list, and delete via artifact_delete. A minor gap is the lack of a dedicated tool to retrieve a single artifact's details beyond the list.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
- mcpOAuthio.artifacta
Artifact store for AI agents. Hosted OAuth at mcp.artifacta.io/mcp; local stdio via npm/PyPI.
Artifact store for AI agents — read, write, and search files by path; share by rendered URL.
Shared, governed long-term memory for AI agents across tools and sessions via MCP and REST.
Registry of MCP servers, agent skills and plugins: search, filter, comments, likes, publish.
Related MCP Servers
- AlicenseAqualityAmaintenanceThe artifact store for AI agents. Every output your agents produce — persisted, retrievable, shareable. Across runs, sessions, and tools. Session/agent metadata, content-hash dedup, and expiring share links; available on npm (@artifacta-mcp/mcp) and PyPI (artifacta-mcp).81MIT
- AlicenseNot gradedqualityAmaintenanceA local, agent-to-agent artifact exchange for LLM workflows. Enables MCP-capable tools like Claude, Codex, and Gemini to publish, list, read, update, and continue from artifacts without copying content through chat.167MIT
- AlicenseNot gradedqualityAmaintenanceThis MCP server enables AI agents to manage artifacts across sessions by providing tools for searching, retrieving, and registering entries in a persistent ledger, ensuring consistency and traceability of agent outputs.MIT
- AlicenseNot gradedqualityAmaintenanceAn artifact store that lets coding agents and small teams publish, version, and review web artifacts through an MCP server or CLI, with stable URLs, access gates, and comments.4MIT