mcp嵌入式ui(Rust)
这是什么?
如果你用Rust构建一个MCP服务器,你的用户会通过原始JSON与工具交互——没有视觉反馈,没有模式浏览器,也没有快速的测试方法。此库为您的服务器添加了一个完整的浏览器UI 一个导入,一个挂载.
┌───────────────────────────────────┐
│ Browser │
│ Tool list → Schema → Try it │
└──────────────┬────────────────────┘
│ HTTP / JSON
┌──────────────▼────────────────────┐
│ Your Rust MCP Server │
│ + mcp-embedded-ui │
│ (Axum) │
└───────────────────────────────────┘UI提供了什么?
- 工具列表 --浏览所有带有描述和注释徽章的注册工具
- 模式检查器 --展开任何工具以查看其完整的JSON模式(
inputSchema) - 试试控制台 --键入JSON参数,执行工具,立即查看结果
- cURL导出 --复制现成的cURL命令以执行任何操作
- 身份验证支持 --在UI中输入与所有请求一起发送的Bearer令牌
无构建步骤。没有CDN。没有外部依赖关系。整个UI是一个嵌入在crate中的独立HTML页面。
安装
添加到您的 Cargo.toml:
[dependencies]
mcp-embedded-ui = "0.4"快速开始
阿克苏姆
use std::sync::Arc;
use mcp_embedded_ui::{create_mount, ToolsProvider, UiConfig};
// Mount at /explorer (default), enable tool execution
let tools: Arc = Arc::new(my_tools);
let config = UiConfig {
allow_execute: true,
..UiConfig::default()
};
let app = create_mount(None, tools, my_handler, config);
// Or specify a custom prefix
let app = create_mount(Some("/mcp-ui"), tools, my_handler, config);
// Visit http://localhost:8000/explorer/独立路由器
use mcp_embedded_ui::{create_app, UiConfig};
// Returns an Axum Router — nest in any Axum application
let app = create_app(tools, my_handler, UiConfig::default());完整工作示例
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use mcp_embedded_ui::{
create_mount, Content, HandlerResult, Tool, ToolCallError,
ToolCallHandler, ToolsProvider, UiConfig,
};
// 1. Define your tools (implement the Tool trait)
struct GreetTool;
impl Tool for GreetTool {
fn name(&self) -> &str { "greet" }
fn description(&self) -> &str { "Say hello" }
fn input_schema(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": { "name": { "type": "string" } }
})
}
}
// 2. Define a handler: (name, args) -> (content, is_error, trace_id)
let handler = ToolCallHandler::Basic(Arc::new(|name, args| -> Pin + Send>> {
Box::pin(async move {
let msg = args.get("name").and_then(|v| v.as_str()).unwrap_or("world");
Ok((
vec![Content { content_type: "text".into(), text: Some(format!("Hello, {}!", msg)), mime_type: None, data: None }],
false,
None,
))
})
}));
// 3. Mount the UI
let tools: Arc = Arc::new(vec![Arc::new(GreetTool) as Arc]);
let config = UiConfig { allow_execute: true, ..UiConfig::default() };
let app = create_mount(None, tools, handler, config);带身份验证挂钩
use mcp_embedded_ui::{AuthHook, AuthError};
let config = UiConfig {
allow_execute: true,
auth_hook: AuthHook(Some(Arc::new(|parts| {
Box::pin(async move {
let auth = parts.headers
.get("authorization")
.and_then(|v| v.to_str().ok())
.unwrap_or("");
if auth.starts_with("Bearer ") {
Ok(())
} else {
Err(AuthError)
}
})
}))),
..UiConfig::default()
};仅授权警卫 POST /tools/{name}/call发现端点始终是公开的。UI有一个内置的令牌输入字段——在那里输入你的Bearer令牌,它会随着每个执行请求一起发送。
附带的演示(examples/axum_demo.rs)使用硬编码 Bearer demo-secret-token --令牌在启动时打印,因此您知道要粘贴到UI中的内容。
动态工具
use mcp_embedded_ui::DynamicToolsProvider;
// Async callable — re-evaluated on every request
let provider = DynamicToolsProvider::new(|| {
Box::pin(async { registry.list_tools().await })
});
let tools: Arc = Arc::new(provider);API
三倍API
| 函数 | 返回 | 用例 |
|---|---|---|
create_mount(prefix, tools, handler, config) | Router | Axum--在URL前缀下嵌套 |
create_app(tools, handler, config) | Router | 独立Axum路由器 |
build_ui_routes(tools, handler, config) | Router | 高级用户——细粒度路由控制 |
参数(UiConfig)
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
allow_execute | bool | false | 启用/禁用工具执行(强制服务器端) |
title | String | "MCP Tool Explorer" | 页面标题(HTML自动转义) |
project_name | Option | None | 页脚中显示的项目名称 |
project_url | Option | None | 页脚中链接的项目URL(需要 project_name) |
auth_hook | AuthHook | None | 传统异步身份验证保护(仅验证) |
authenticator | Option> | None | 具有身份传播的完全身份验证(推荐) |
身份验证器(推荐)
实施 Authenticator 用于对请求进行身份验证和传播 Identity 通过工具调用处理程序 AUTH_IDENTITY 任务本地:
use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
use mcp_embedded_ui::{Authenticator, Identity, AUTH_IDENTITY, UiConfig};
struct MyAuth;
#[async_trait]
impl Authenticator for MyAuth {
async fn authenticate(&self, headers: &HashMap) -> Option {
let token = headers.get("authorization")?.strip_prefix("Bearer ")?;
// Validate token, return Identity on success
Some(Identity {
id: "user-123".into(),
identity_type: "human".into(),
roles: vec!["user".into()],
attrs: Default::default(),
})
}
}
let config = UiConfig {
allow_execute: true,
authenticator: Some(Arc::new(MyAuth)),
..UiConfig::default()
};在工具调用处理程序中,读取经过身份验证的标识:
let identity = AUTH_IDENTITY.try_with(|id| id.clone()).ok().flatten();当 authenticator 已设置,它优先于 auth_hook.返回 None 从 authenticate() 答案是401。
Auth Hook(传统)
这 auth_hook 接收请求 Parts (headers、URI、方法)并返回一个未来的解析结果 Result.返回 Err(AuthError) 以401拒绝。不像 Authenticator,它不会将身份传播给处理程序。错误响应总是 {"error": "Unauthorized"} --内部细节从未泄露。
仅授权警卫 POST /tools/{name}/call.发现端点(GET /tools, GET /tools/{name})总是公开的。
端点
| 方法 | 路径 | 描述 |
|---|---|---|
| 得到 | / | 独立的HTML资源管理器页面 |
| 得到 | /tools | 所有工具的摘要列表 |
| 得到 | /tools/{name} | 完整的工具细节 inputSchema |
| 职位 | /tools/{name}/call | 执行工具,返回MCP CallToolResult |
发展
# Run the demo (auth enabled with a demo token)
cargo run --example axum_demo
# Visit http://localhost:8000/explorer/
# Paste "Bearer demo-secret-token" in the UI's token field to execute tools
# Run tests
cargo test --all-features
# Lint
cargo clippy --all-targets --all-features -- -D warnings跨语言规范
这个板条箱实现了 mcp嵌入式ui 规范。规范仓库包含:
- 协议.md --端点规范、数据形状、安全检查表
- explorer.html --共享HTML模板(所有语言实现都相同)
- 功能规格 --详细要求和测试标准
许可证
阿帕奇-2.0
