flutter_mcp_ui_runtime 0.2.4 copy "flutter_mcp_ui_runtime: ^0.2.4" to clipboard
flutter_mcp_ui_runtime: ^0.2.4 copied to clipboard

Runtime for building dynamic Flutter UIs from JSON with lifecycle management, state handling, and MCP protocol support.

Flutter MCP UI Runtime #

🙌 Support This Project #

If you find this package useful, consider supporting ongoing development on PayPal.

Donate
Support makemind via PayPal


🔗 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.4

Important: Building with Dynamic Icons #

If your app uses dynamic icons from JSON (e.g., "icon": "folder"), you must build with the --no-tree-shake-icons flag:

flutter build apk --no-tree-shake-icons
flutter build ios --no-tree-shake-icons
flutter build macos --no-tree-shake-icons

This is necessary because the runtime creates icons dynamically from strings, which the compiler cannot detect at build time. Without this flag, Material Icons will be removed by tree shaking and your icons won't appear.

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 binding
  • gridview - Grid layout with fixed/max cross axis extent
  • listtile - Material design list item
  • appbar, bottomnavigationbar, drawer
  • tabbar, navigationrail
  • floatingactionbutton, popupmenubutton

Scroll Widgets (2) #

  • singlechildscrollview - Scrollable single child
  • pageview - Swipeable pages

Animation Widgets (1) #

  • animatedcontainer - Animated property transitions

Interactive Widgets (2) #

  • gesturedetector - Gesture detection
  • inkwell - Material ripple effect

Dialog Widgets (3) #

  • alertdialog - Alert dialog
  • snackbar - Temporary message bar
  • bottomsheet - Bottom sheet modal

For complete widget reference with properties and examples, see the Widget Reference.

Expression Binding #

The renderer supports dynamic data binding using double curly braces:

{
  "type": "text",
  "content": "{{user.name}}",
  "style": {
    "fontSize": 16,
    "color": "{{theme.colors.textOnBackground}}"
  }
}

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 #

Contributing #

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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.

0
likes
140
points
51
downloads

Publisher

unverified uploader

Weekly Downloads

Runtime for building dynamic Flutter UIs from JSON with lifecycle management, state handling, and MCP protocol support.

Homepage
Repository (GitHub)

Topics

#ui #json #mcp #flutter #runtime

Documentation

API reference

License

unknown (license)

Dependencies

collection, crypto, flutter, flutter_mcp_ui_core, http, provider, shared_preferences

More

Packages that depend on flutter_mcp_ui_runtime