Flutter MCP UI Runtime
🙌 Support This Project
If you find this package useful, consider supporting ongoing development on Patreon.
🔗 MCP Dart Package Family
mcp_server
: Exposes tools, resources, and prompts to LLMs. Acts as the AI server.mcp_client
: Connects Flutter/Dart apps to MCP servers. Acts as the client interface.mcp_llm
: Bridges LLMs (Claude, OpenAI, etc.) to MCP clients/servers. Acts as the LLM brain.flutter_mcp
: Complete Flutter plugin for MCP integration with platform features.flutter_mcp_ui_core
: Core models, constants, and utilities for Flutter MCP UI system.flutter_mcp_ui_runtime
: Comprehensive runtime for building dynamic, reactive UIs through JSON specifications.flutter_mcp_ui_generator
: JSON generation toolkit for creating UI definitions with templates and fluent API.
A comprehensive Flutter runtime for building server-driven UIs using the MCP (Model Context Protocol) UI DSL v1.0 specification. This package provides a complete runtime environment with lifecycle management, services, and advanced state management.
📋 Based on MCP UI DSL v1.0 Specification - The standard specification for Model Context Protocol UI Definition Language.
Features
- 🎨 77+ Flutter widgets supported out of the box
- 🔄 Reactive State Management: Built-in state management with automatic UI updates
- 🧮 Expression Binding: Support for dynamic data binding with expressions
- ⚡ Action System: Handle user interactions with configurable actions
- 🔧 Extensible: Easy to add custom widgets and tool executors
- 🎯 Pure Architecture: No external dependencies, tool executors are injected
- 🔀 Multiple Instance Support: Run multiple MCP servers/apps simultaneously
- 🧩 MCP Protocol Ready: Designed for AI-powered UI generation
- 📐 Standardized Structure: Follows MCP UI DSL v1.0 specification
Installation
Add this to your package's pubspec.yaml
file:
dependencies:
flutter_mcp_ui_runtime: ^0.2.2
Quick Start
Basic Usage
import 'package:flutter_mcp_ui_runtime/flutter_mcp_ui_runtime.dart';
// Define your UI in JSON
final uiDefinition = {
"type": "page",
"content": {
"type": "linear",
"direction": "vertical",
"padding": {"all": 20},
"children": [
{
"type": "label",
"content": "Hello {{name}}!",
"style": {
"fontSize": 24,
"fontWeight": "bold"
}
},
{"type": "box", "height": 16},
{
"type": "button",
"label": "Click me",
"variant": "elevated",
"click": {
"type": "state",
"action": "set",
"binding": "name",
"value": "World"
}
}
]
},
"state": {
"initial": {
"name": "Flutter"
}
}
};
// Create and initialize runtime
final runtime = MCPUIRuntime();
await runtime.initialize(uiDefinition);
// Build the UI
Widget ui = runtime.buildUI();
Full Application Example
// Define a complete application with navigation and theme
final appDefinition = {
"type": "application",
"title": "My MCP App",
"version": "1.0.0",
"theme": {
"mode": "light",
"colors": {
"primary": "#2196F3",
"secondary": "#FF4081",
"background": "#FFFFFF",
"surface": "#F5F5F5"
},
"typography": {
"h1": {"fontSize": 32, "fontWeight": "bold"},
"body1": {"fontSize": 16}
},
"spacing": {
"sm": 8,
"md": 16,
"lg": 24
}
},
"navigation": {
"type": "drawer",
"items": [
{"title": "Home", "icon": "home", "route": "/home"},
{"title": "Settings", "icon": "settings", "route": "/settings"}
]
},
"routes": {
"/home": "ui://pages/home",
"/settings": "ui://pages/settings"
},
"initialRoute": "/home",
"state": {
"initial": {
"user": {"name": "Guest", "isAuthenticated": false}
}
}
};
// Initialize and run the application
final runtime = MCPUIRuntime();
await runtime.initialize(appDefinition);
Widget app = runtime.buildUI();
Multiple MCP Servers
// Create separate runtime instances for different MCP servers
final tradingRuntime = MCPUIRuntime(debugMode: true);
final analyticsRuntime = MCPUIRuntime(debugMode: true);
// Initialize each runtime with their definitions
await tradingRuntime.initialize(tradingDefinition);
await analyticsRuntime.initialize(analyticsDefinition);
// Each runtime maintains independent state and configuration
final tradingUI = tradingRuntime.buildUI();
final analyticsUI = analyticsRuntime.buildUI();
With Tool Executors
// Define tool executors for external API calls
final runtime = MCPUIRuntime();
// Register tool executors
runtime.registerToolExecutor('getCurrentTime', (Map<String, dynamic> args) async {
return DateTime.now().toString();
});
runtime.registerToolExecutor('fetchUserData', (Map<String, dynamic> args) async {
final userId = args['userId'];
// Make API call here
return {"name": "John", "email": "john@example.com"};
});
// UI definition with tool actions
final uiDefinition = {
"type": "page",
"content": {
"type": "linear",
"direction": "vertical",
"padding": {"all": 20},
"children": [
{
"type": "text",
"content": "Time: {{currentTime}}",
"style": {"fontSize": 18}
},
{"type": "box", "height": 16},
{
"type": "button",
"label": "Get Time",
"variant": "elevated",
"click": {
"type": "tool",
"tool": "getCurrentTime",
"bindTo": "currentTime"
}
}
]
},
"state": {
"initial": {
"currentTime": "Not loaded"
}
}
};
// Initialize and build UI
await runtime.initialize(uiDefinition);
Widget ui = runtime.buildUI();
Supported Widgets (77+)
The Flutter MCP UI Runtime supports 77+ widgets across 9 categories:
Layout Widgets (19)
box
,linear
,stack
,positioned
padding
,center
,align
,sizedbox
expanded
,flexible
,spacer
wrap
,aspectratio
,fittedbox
constrainedbox
,limitedbox
intrinsicheight
,intrinsicwidth
Display Widgets (16)
text
,richtext
,icon
,image
card
,chip
,avatar
,badge
progressbar
,divider
,placeholder
decoratedbox
,banner
,cliprrect
tooltip
,visibility
Input Widgets (12)
button
,textfield
,textformfield
checkbox
,switch
,slider
,rangeslider
radio
,dropdown
datepicker
,timepicker
,stepper
List Widgets (3)
listview
- Dynamic list with data bindinggridview
- Grid layout with fixed/max cross axis extentlisttile
- Material design list item
Navigation Widgets (7)
appbar
,bottomnavigationbar
,drawer
tabbar
,navigationrail
floatingactionbutton
,popupmenubutton
Scroll Widgets (2)
singlechildscrollview
- Scrollable single childpageview
- Swipeable pages
Animation Widgets (1)
animatedcontainer
- Animated property transitions
Interactive Widgets (2)
gesturedetector
- Gesture detectioninkwell
- Material ripple effect
Dialog Widgets (3)
alertdialog
- Alert dialogsnackbar
- Temporary message barbottomsheet
- Bottom sheet modal
For complete widget reference with properties and examples, see the MCP UI DSL Complete Specification.
Expression Binding
The renderer supports dynamic data binding using double curly braces:
{
"type": "text",
"content": "{{user.name}}",
"style": {
"fontSize": 16,
"color": "{{theme.colors.onBackground}}"
}
}
Supported Expressions
- Simple binding:
{{variable}}
- Nested paths:
{{user.profile.name}}
- Array indexing:
{{items[0]}}
- Dynamic array indexing:
{{products[index].name}}
- Arithmetic:
{{count + 1}}
- Comparison:
{{count > 0}}
- Conditional:
{{count > 0 ? 'Has items' : 'Empty'}}
- Transforms:
{{name | uppercase}}
Built-in Transforms
uppercase
,lowercase
,capitalize
round
,floor
,ceil
,abs
Action System
State Actions
{
"type": "state",
"action": "set",
"binding": "counter",
"value": 42
}
Actions: set
, increment
, decrement
, toggle
, append
, remove
Tool Actions
{
"type": "tool",
"tool": "fetchData",
"params": {"id": "{{userId}}"},
"bindTo": "userData"
}
Batch Actions
{
"type": "batch",
"parallel": true,
"actions": [
{"type": "state", "action": "set", "binding": "loading", "value": true},
{"type": "tool", "tool": "fetchData", "bindTo": "data"}
]
}
Conditional Actions
{
"type": "conditional",
"condition": "{{count > 0}}",
"then": {"type": "state", "action": "set", "binding": "message", "value": "Has data"},
"else": {"type": "state", "action": "set", "binding": "message", "value": "No data"}
}
Customization
Custom Widgets
class MyCustomWidget extends WidgetFactory {
@override
Widget build(Map<String, dynamic> definition, RenderContext context) {
// Your custom widget implementation
return Container();
}
}
// Register custom widget
MCPUIRenderer.instance.registerWidget('myWidget', MyCustomWidget());
Custom Transforms
MCPUIRenderer.instance.registerTransform('reverse', (value) {
return value.toString().split('').reversed.join('');
});
Examples
Counter App
{
"layout": {
"type": "linear",
"direction": "vertical",
"properties": {"mainAxisAlignment": "center"},
"children": [
{
"type": "label",
"properties": {
"content": "Count: {{count}}",
"style": {"fontSize": 24}
}
},
{
"type": "linear",
"direction": "horizontal",
"properties": {"mainAxisAlignment": "center"},
"children": [
{
"type": "button",
"properties": {
"label": "-",
"click": {"type": "state", "action": "decrement", "binding": "count"}
}
},
{
"type": "button",
"properties": {
"label": "+",
"click": {"type": "state", "action": "increment", "binding": "count"}
}
}
]
}
]
}
}
Form Example
{
"layout": {
"type": "linear",
"direction": "vertical",
"children": [
{
"type": "label",
"properties": {"content": "Name: {{form.name}}"}
},
{
"type": "button",
"properties": {
"label": "Update Name",
"click": {
"type": "state",
"action": "set",
"binding": "form.name",
"value": "John Doe"
}
}
}
]
}
}
API Reference
MCPUIRenderer
Main class for rendering UI definitions.
class MCPUIRenderer {
// Singleton instance
static MCPUIRenderer get instance;
// Create instance for specific server
factory MCPUIRenderer.forServer(String serverId);
// Main render method
Widget render(
Map<String, dynamic> uiDefinition, {
Map<String, dynamic>? initialState,
Map<String, Function>? toolExecutors,
ErrorWidgetBuilder? errorBuilder,
});
// Register custom widget
void registerWidget(String type, WidgetFactory factory);
// Register custom transform
void registerTransform(String name, Function transform);
// State management
T? getState<T>(String path);
void setState(String path, dynamic value);
Stream<T> watchState<T>(String path);
}
State Management
// Get state value
T? value = MCPUIRenderer.instance.getState<T>('path');
// Set state value
MCPUIRenderer.instance.setState('path', value);
// Watch state changes
Stream<T> stream = MCPUIRenderer.instance.watchState<T>('path');
Architecture
The package follows a clean architecture with these core components:
- Renderer: Converts JSON to Flutter widgets
- StateManager: Manages application state
- BindingEngine: Handles data binding and expressions
- ActionHandler: Executes user actions
- WidgetRegistry: Manages widget factories
Documentation
- MCP UI DSL v1.0 Specification - Complete specification for Model Context Protocol UI Definition Language
- API Reference - Detailed API documentation
- Architecture Overview - System architecture and design
- Getting Started Guide - Quick start guide
- Advanced Topics - Advanced usage and patterns
- Custom Widgets Guide - How to create custom widgets
- Examples - Sample implementations
- Widget Reference - Complete widget property reference
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Made with ❤️ for the Flutter and MCP communities.