Skip to content

mcp-embedded-ui

A cross-language specification and shared assets for embedding a browser-based tool explorer into any MCP (Model Context Protocol) server.

Official SDKs: Python (PyPI) | TypeScript (npm) | Rust (crates.io) | [Go (Coming Soon)]


Quick Start

SDK: aiperceivable/mcp-embedded-ui-python

pip install mcp-embedded-ui
from fastapi import FastAPI
from mcp_embedded_ui import create_mount

app = FastAPI()

# Mount the explorer UI to your FastAPI app
app.routes.append(create_mount(
    tools=my_tools,
    handle_call=my_handler,
    prefix="/explorer"
))

# Visit http://localhost:8000/explorer/

SDK: aiperceivable/mcp-embedded-ui-typescript

npm install mcp-embedded-ui
import http from "node:http";
import { createNodeHandler } from "mcp-embedded-ui";

const handler = createNodeHandler(myTools, myHandler, {
  prefix: "/explorer",
});

http.createServer(handler).listen(8000);
// Visit http://localhost:8000/explorer/

SDK: aiperceivable/mcp-embedded-ui-rust

# Cargo.toml
[dependencies]
mcp-embedded-ui = "0.5.0"
use std::sync::Arc;
use mcp_embedded_ui::{create_mount, ToolsProvider, UiConfig};

// Mount the explorer UI at /explorer (pass Some("/ui") for a custom prefix)
let tools: Arc<dyn ToolsProvider> = Arc::new(my_tools);
let app = create_mount(None, tools, my_handler, UiConfig::default());

// Visit http://localhost:8000/explorer/

What is this?

If you build an MCP server, your users interact with tools through JSON — no visual feedback, no schema browser, no quick way to test. mcp-embedded-ui solves this by defining a standard set of HTTP endpoints and a self-contained HTML page that any MCP server can serve, in any language.

┌───────────────────────────────────┐
│  Browser                          │
│  Tool list → Schema → Try it      │
└──────────────┬────────────────────┘
               │ HTTP / JSON
┌──────────────▼────────────────────┐
│  Your MCP Server                  │
│  + mcp-embedded-ui library        │
│    (Python / TypeScript / Go / …) │
└───────────────────────────────────┘

One import. One mount. Full UI.

Key Features

The embedded explorer page provides:

  • Tool list — browse all registered tools with descriptions and annotations.
  • Schema inspector — expand any tool to view its full JSON Schema (inputSchema).
  • Try-it console — type JSON arguments, execute the tool, see results instantly.
  • cURL export — copy a ready-made cURL command for any execution.
  • Auth support — enter a Bearer token in the UI, sent with all requests.

No build step. No CDN. No external dependencies. The entire UI is a single HTML string embedded in your server binary/package.

Documentation for Developers

Document Description
Protocol Spec Endpoint spec, data shapes, cross-language abstraction mapping.
Feature Manifest Implementation roadmap and dependency graph for new SDKs.
HTML Template The shared "source of truth" HTML file used by all SDKs.

Feature Deep Dives

How to Add a New Language

  1. Read the Protocol Specification — the authoritative source for endpoints and data shapes.
  2. Follow the Feature Manifest implementation order: F1 → F2 → F3 → F4 → F6 → F5.
  3. Use the explorer.html template (do not modify the HTML content).
  4. Ensure you follow the Security Checklist.
  5. Open a PR to add your implementation to this list!

Working on the Shared Template

docs/explorer.html is the source of truth. Each SDK ships a byte-identical copy and asserts it in its own suite (the "drift check"), so a change here is not finished until the copies follow.

make sync-html      # copy into every checked-out SDK repo, then commit there
make install-hooks  # one-time per clone: sync automatically after each commit

make install-hooks sets core.hooksPath to .githooks, whose post-commit runs the same script — but only for commits that actually touch docs/explorer.html. Both entry points call scripts/sync-explorer.sh; there is no second implementation to drift.

The script is deliberately conservative:

  • An SDK repo that is not checked out beside this one is skipped, not an error.
  • A copy already matching the template is left untouched.
  • A copy matching neither this working tree nor the last commit here is refused, not overwritten — that means someone edited the SDK's copy directly, which is exactly what the drift check exists to surface.
  • Copies are written but never committed; the script prints the git -C ... command for each repo that changed.

Design Principles

  • Zero frontend build — No npm/webpack/CDN. Just one HTML string.
  • Framework-agnostic — Standard HTTP routes that mount anywhere.
  • Cross-language consistency — Identical UX across Python, TS, Go, etc.
  • Secure by default — XSS protection and auth sanitization built-in.

License

Apache-2.0