Skip to main content

A lightweight, minimal-dependency embedded Web UI for any MCP Server.

Project description

mcp-embedded-ui (Python)

The Python implementation of mcp-embedded-ui — a browser-based tool explorer for any MCP (Model Context Protocol) server.

What is this?

If you build an MCP server in Python, your users interact with tools through raw JSON — no visual feedback, no schema browser, no quick way to test. This library adds a full browser UI to your server with one import and one mount.

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

What does the UI provide?

  • Tool list — browse all registered tools with descriptions and annotation badges
  • 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 self-contained HTML page embedded in the package.

Install

pip install mcp-embedded-ui

Requires Python 3.10+ and Starlette >= 0.35.

Quick Start

FastAPI / Starlette

from fastapi import FastAPI
from mcp_embedded_ui import create_mount

app = FastAPI()

# Mount at /explorer (default)
app.routes.append(create_mount(tools=my_tools, handle_call=my_handler))

# Or specify a custom prefix
app.routes.append(create_mount("/mcp-ui", tools=my_tools, handle_call=my_handler))

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

Any ASGI framework

from mcp_embedded_ui import create_app

# Returns a standard ASGI app — mount in any ASGI-compatible framework
ui_app = create_app(tools=my_tools, handle_call=my_handler)

Full working example

from fastapi import FastAPI
from mcp_embedded_ui import create_mount

# 1. Define your tools (any object with .name, .description, .inputSchema)
class MyTool:
    def __init__(self, name, description, input_schema):
        self.name = name
        self.description = description
        self.inputSchema = input_schema

tools = [
    MyTool("greet", "Say hello", {
        "type": "object",
        "properties": {"name": {"type": "string"}},
    }),
]

# 2. Define a handler: (name, args) -> (content, is_error, trace_id)
async def handle_call(name, args):
    if name == "greet":
        return [{"type": "text", "text": f"Hello, {args.get('name', 'world')}!"}], False, None
    return [{"type": "text", "text": f"Unknown tool: {name}"}], True, None

# 3. Mount the UI
app = FastAPI()
app.routes.append(create_mount(tools=tools, handle_call=handle_call))

Dynamic tools

# Sync callable — re-evaluated on every request
def get_tools():
    return registry.list_tools()

# Async callable
async def get_tools():
    return await registry.async_list_tools()

app = create_app(tools=get_tools, handle_call=my_handler)

API

Three-tier API

Function Returns Use case
create_mount(prefix, *, tools, handle_call, **config) Mount FastAPI / Starlette — mount under a URL prefix
create_app(tools, handle_call, **config) ASGIApp Any ASGI framework — standalone app
build_ui_routes(tools, handle_call, **config) list[Route] Power users — fine-grained route control

Parameters

Parameter Type Default Description
tools list | Callable | AsyncCallable required MCP Tool objects (.name, .description, .inputSchema)
handle_call ToolCallHandler required async (name, args) -> (content, is_error, trace_id)
allow_execute bool True Enable/disable tool execution (enforced server-side)
auth_hook AuthHook | None None Sync/async context manager factory for auth
title str "MCP Tool Explorer" Page title (HTML-escaped automatically)

Auth Hook

The auth_hook receives a Starlette Request and returns a context manager (sync or async). Raise inside to reject with 401. The error response is always {"error": "Unauthorized"} — internal details are never leaked.

from contextlib import contextmanager

@contextmanager
def my_auth(request):
    token = request.headers.get("Authorization")
    if not valid(token):
        raise ValueError("Bad token")
    my_identity_var.set(decode(token))
    yield

Auth only guards POST /tools/{name}/call. Discovery endpoints (GET /tools, GET /tools/{name}, GET /meta) are always public.

Endpoints

Method Path Description
GET / Self-contained HTML explorer page
GET /meta JSON config — { title, allow_execute }
GET /tools Summary list of all tools
GET /tools/{name} Full tool detail with inputSchema
POST /tools/{name}/call Execute a tool, returns MCP CallToolResult

Development

# Install in editable mode with dev dependencies
pip install -e ".[dev]"

# Run the demo
python examples/fastapi_demo.py
# Visit http://localhost:8000/explorer/

# Run tests
pytest

Cross-Language Specification

This package implements the mcp-embedded-ui specification. The spec repo contains:

  • PROTOCOL.md — endpoint spec, data shapes, security checklist
  • explorer.html — shared HTML template (identical across all language implementations)
  • Feature specs — detailed requirements and test criteria

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_embedded_ui-0.1.0.tar.gz (16.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_embedded_ui-0.1.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file mcp_embedded_ui-0.1.0.tar.gz.

File metadata

  • Download URL: mcp_embedded_ui-0.1.0.tar.gz
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for mcp_embedded_ui-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b282039ae94d4481a2cb25fbbbdd75b22dbea9dfad5c717ea6e53e2f3a69bcfb
MD5 ad1330409e96b745459e778cfd2fae39
BLAKE2b-256 44a0af9f7cdae32b8cb42e3b041e8d4a27b0c4c93de0bdf6dfb7c83342fe55a4

See more details on using hashes here.

File details

Details for the file mcp_embedded_ui-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mcp_embedded_ui-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 45f562d1c23a867951d8b0b0280728c610c2f245a2bace1af3785d312244811a
MD5 37728958671d627181ab27961e87a0c2
BLAKE2b-256 ea17574182311a528c23e5bf9e53094d93cee81e36028673a18ae4243f3f7c9e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page