mcp-interactive-ui-server 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .env
10
+ .venv/
11
+ venv/
12
+ .mypy_cache/
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ *.so
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AiAgentKarl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-interactive-ui-server
3
+ Version: 0.1.0
4
+ Summary: MCP Apps UI toolkit — forms, dashboards, charts, tables for AI agents to render interactive UIs
5
+ Project-URL: Homepage, https://github.com/AiAgentKarl/mcp-interactive-ui-server
6
+ Project-URL: Repository, https://github.com/AiAgentKarl/mcp-interactive-ui-server
7
+ Project-URL: Issues, https://github.com/AiAgentKarl/mcp-interactive-ui-server/issues
8
+ Author: AiAgentKarl
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-agents,charts,dashboard,forms,interactive,mcp,mcp-apps,model-context-protocol,ui
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: Software Development :: User Interfaces
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: mcp[cli]>=1.0.0
24
+ Description-Content-Type: text/markdown
25
+
26
+ # mcp-interactive-ui-server
27
+
28
+ <!-- mcp-name: mcp-interactive-ui-server -->
29
+
30
+ [![PyPI version](https://badge.fury.io/py/mcp-interactive-ui-server.svg)](https://pypi.org/project/mcp-interactive-ui-server/)
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+
33
+ **MCP Apps UI toolkit** — forms, dashboards, charts, tables for AI agents to render interactive UIs.
34
+
35
+ ## What Are MCP Apps?
36
+
37
+ MCP Apps is a 2026 extension to the Model Context Protocol that enables AI agents to go beyond text responses and render **interactive user interfaces** directly within MCP-compatible clients.
38
+
39
+ Instead of returning plain text or markdown, agents can generate structured UI schemas that clients render as native components — forms, dashboards, charts, tables, and multi-step wizards. This bridges the gap between conversational AI and application-level interactivity.
40
+
41
+ ### Why This Matters
42
+
43
+ - **Agents become app builders**: Instead of describing data, agents can present it visually with charts, dashboards, and tables
44
+ - **Structured data collection**: Forms and wizards let agents gather complex user input with validation
45
+ - **Richer interactions**: Toggles, buttons, accordions, and tabs embedded directly in responses
46
+ - **Client-agnostic**: The JSON schema approach works across any MCP client that supports UI rendering
47
+
48
+ ## Tools (6)
49
+
50
+ | Tool | Description |
51
+ |------|------------|
52
+ | `create_form` | Generate interactive forms with text, number, select, checkbox, date fields and validation |
53
+ | `create_dashboard` | Build grid-based dashboards with stat cards, charts, tables, progress bars |
54
+ | `create_chart` | Define charts (bar, line, pie, scatter, area, donut, heatmap) with data and styling |
55
+ | `create_table` | Create sortable, filterable, paginated tables from headers and row data |
56
+ | `create_wizard` | Multi-step form wizards with per-step validation and progress tracking |
57
+ | `render_markdown` | Enhanced markdown with embedded interactive elements (buttons, toggles, inputs, tabs) |
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ pip install mcp-interactive-ui-server
63
+ ```
64
+
65
+ ## Quick Start
66
+
67
+ ### Claude Desktop
68
+
69
+ Add to `claude_desktop_config.json`:
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "interactive-ui": {
75
+ "command": "interactive-ui-server"
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### Cursor / Windsurf
82
+
83
+ Add to your MCP settings:
84
+
85
+ ```json
86
+ {
87
+ "mcpServers": {
88
+ "interactive-ui": {
89
+ "command": "interactive-ui-server"
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ### With uvx (no install needed)
96
+
97
+ ```json
98
+ {
99
+ "mcpServers": {
100
+ "interactive-ui": {
101
+ "command": "uvx",
102
+ "args": ["mcp-interactive-ui-server"]
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## Usage Examples
109
+
110
+ ### Create a Contact Form
111
+
112
+ ```
113
+ Agent: create_form("Contact Us", [
114
+ {"label": "Name", "type": "text", "required": true},
115
+ {"label": "Email", "type": "email", "required": true},
116
+ {"label": "Subject", "type": "select", "options": ["General", "Support", "Sales"]},
117
+ {"label": "Message", "type": "textarea", "rows": 6}
118
+ ])
119
+ ```
120
+
121
+ ### Build a Sales Dashboard
122
+
123
+ ```
124
+ Agent: create_dashboard("Q1 Sales", [
125
+ {"type": "stat_card", "title": "Revenue", "value": "$142K", "trend": "up", "change": "+12%"},
126
+ {"type": "stat_card", "title": "Orders", "value": "1,247", "trend": "up", "change": "+8%"},
127
+ {"type": "chart", "title": "Monthly Sales", "chart_type": "bar",
128
+ "data": {"labels": ["Jan","Feb","Mar"], "datasets": [{"label": "Sales", "values": [42,51,49]}]}},
129
+ {"type": "progress_bar", "title": "Quarterly Target", "value": 72, "max": 100}
130
+ ])
131
+ ```
132
+
133
+ ### Generate a Chart
134
+
135
+ ```
136
+ Agent: create_chart("pie",
137
+ {"labels": ["Chrome", "Firefox", "Safari", "Edge"], "values": [65, 15, 12, 8]},
138
+ title="Browser Market Share"
139
+ )
140
+ ```
141
+
142
+ ### Interactive Markdown Report
143
+
144
+ ```
145
+ Agent: render_markdown(
146
+ "# Status Report\n\nSystem health: {{status_badge}}\n\n{{details}}\n\n{{action_btn}}",
147
+ [
148
+ {"type": "badge", "id": "status_badge", "text": "Healthy", "color": "green"},
149
+ {"type": "accordion", "id": "details", "title": "View Details", "content": "All 12 services operational."},
150
+ {"type": "button", "id": "action_btn", "label": "Run Diagnostics", "action": "diagnose"}
151
+ ]
152
+ )
153
+ ```
154
+
155
+ ## UI Schema
156
+
157
+ All tools return structured JSON following the `mcp-ui` schema specification:
158
+
159
+ ```json
160
+ {
161
+ "$schema": "mcp-ui/<component>/v1",
162
+ "type": "<component_type>",
163
+ "title": "...",
164
+ "...": "component-specific properties",
165
+ "metadata": {
166
+ "created_at": "ISO timestamp",
167
+ "version": "1.0"
168
+ }
169
+ }
170
+ ```
171
+
172
+ Schema types: `form`, `dashboard`, `chart`, `table`, `wizard`, `enhanced_markdown`
173
+
174
+ ## Requirements
175
+
176
+ - Python 3.10+
177
+ - MCP SDK (`mcp[cli]>=1.0.0`)
178
+
179
+ ## License
180
+
181
+ MIT
@@ -0,0 +1,156 @@
1
+ # mcp-interactive-ui-server
2
+
3
+ <!-- mcp-name: mcp-interactive-ui-server -->
4
+
5
+ [![PyPI version](https://badge.fury.io/py/mcp-interactive-ui-server.svg)](https://pypi.org/project/mcp-interactive-ui-server/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ **MCP Apps UI toolkit** — forms, dashboards, charts, tables for AI agents to render interactive UIs.
9
+
10
+ ## What Are MCP Apps?
11
+
12
+ MCP Apps is a 2026 extension to the Model Context Protocol that enables AI agents to go beyond text responses and render **interactive user interfaces** directly within MCP-compatible clients.
13
+
14
+ Instead of returning plain text or markdown, agents can generate structured UI schemas that clients render as native components — forms, dashboards, charts, tables, and multi-step wizards. This bridges the gap between conversational AI and application-level interactivity.
15
+
16
+ ### Why This Matters
17
+
18
+ - **Agents become app builders**: Instead of describing data, agents can present it visually with charts, dashboards, and tables
19
+ - **Structured data collection**: Forms and wizards let agents gather complex user input with validation
20
+ - **Richer interactions**: Toggles, buttons, accordions, and tabs embedded directly in responses
21
+ - **Client-agnostic**: The JSON schema approach works across any MCP client that supports UI rendering
22
+
23
+ ## Tools (6)
24
+
25
+ | Tool | Description |
26
+ |------|------------|
27
+ | `create_form` | Generate interactive forms with text, number, select, checkbox, date fields and validation |
28
+ | `create_dashboard` | Build grid-based dashboards with stat cards, charts, tables, progress bars |
29
+ | `create_chart` | Define charts (bar, line, pie, scatter, area, donut, heatmap) with data and styling |
30
+ | `create_table` | Create sortable, filterable, paginated tables from headers and row data |
31
+ | `create_wizard` | Multi-step form wizards with per-step validation and progress tracking |
32
+ | `render_markdown` | Enhanced markdown with embedded interactive elements (buttons, toggles, inputs, tabs) |
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install mcp-interactive-ui-server
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### Claude Desktop
43
+
44
+ Add to `claude_desktop_config.json`:
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "interactive-ui": {
50
+ "command": "interactive-ui-server"
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Cursor / Windsurf
57
+
58
+ Add to your MCP settings:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "interactive-ui": {
64
+ "command": "interactive-ui-server"
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### With uvx (no install needed)
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "interactive-ui": {
76
+ "command": "uvx",
77
+ "args": ["mcp-interactive-ui-server"]
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ ## Usage Examples
84
+
85
+ ### Create a Contact Form
86
+
87
+ ```
88
+ Agent: create_form("Contact Us", [
89
+ {"label": "Name", "type": "text", "required": true},
90
+ {"label": "Email", "type": "email", "required": true},
91
+ {"label": "Subject", "type": "select", "options": ["General", "Support", "Sales"]},
92
+ {"label": "Message", "type": "textarea", "rows": 6}
93
+ ])
94
+ ```
95
+
96
+ ### Build a Sales Dashboard
97
+
98
+ ```
99
+ Agent: create_dashboard("Q1 Sales", [
100
+ {"type": "stat_card", "title": "Revenue", "value": "$142K", "trend": "up", "change": "+12%"},
101
+ {"type": "stat_card", "title": "Orders", "value": "1,247", "trend": "up", "change": "+8%"},
102
+ {"type": "chart", "title": "Monthly Sales", "chart_type": "bar",
103
+ "data": {"labels": ["Jan","Feb","Mar"], "datasets": [{"label": "Sales", "values": [42,51,49]}]}},
104
+ {"type": "progress_bar", "title": "Quarterly Target", "value": 72, "max": 100}
105
+ ])
106
+ ```
107
+
108
+ ### Generate a Chart
109
+
110
+ ```
111
+ Agent: create_chart("pie",
112
+ {"labels": ["Chrome", "Firefox", "Safari", "Edge"], "values": [65, 15, 12, 8]},
113
+ title="Browser Market Share"
114
+ )
115
+ ```
116
+
117
+ ### Interactive Markdown Report
118
+
119
+ ```
120
+ Agent: render_markdown(
121
+ "# Status Report\n\nSystem health: {{status_badge}}\n\n{{details}}\n\n{{action_btn}}",
122
+ [
123
+ {"type": "badge", "id": "status_badge", "text": "Healthy", "color": "green"},
124
+ {"type": "accordion", "id": "details", "title": "View Details", "content": "All 12 services operational."},
125
+ {"type": "button", "id": "action_btn", "label": "Run Diagnostics", "action": "diagnose"}
126
+ ]
127
+ )
128
+ ```
129
+
130
+ ## UI Schema
131
+
132
+ All tools return structured JSON following the `mcp-ui` schema specification:
133
+
134
+ ```json
135
+ {
136
+ "$schema": "mcp-ui/<component>/v1",
137
+ "type": "<component_type>",
138
+ "title": "...",
139
+ "...": "component-specific properties",
140
+ "metadata": {
141
+ "created_at": "ISO timestamp",
142
+ "version": "1.0"
143
+ }
144
+ }
145
+ ```
146
+
147
+ Schema types: `form`, `dashboard`, `chart`, `table`, `wizard`, `enhanced_markdown`
148
+
149
+ ## Requirements
150
+
151
+ - Python 3.10+
152
+ - MCP SDK (`mcp[cli]>=1.0.0`)
153
+
154
+ ## License
155
+
156
+ MIT
@@ -0,0 +1,44 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "mcp-interactive-ui-server"
7
+ version = "0.1.0"
8
+ description = "MCP Apps UI toolkit — forms, dashboards, charts, tables for AI agents to render interactive UIs"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "AiAgentKarl"}
14
+ ]
15
+ keywords = [
16
+ "mcp", "model-context-protocol", "ui", "forms", "dashboard",
17
+ "charts", "interactive", "ai-agents", "mcp-apps"
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 3 - Alpha",
21
+ "Intended Audience :: Developers",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Software Development :: Libraries",
29
+ "Topic :: Software Development :: User Interfaces",
30
+ ]
31
+ dependencies = [
32
+ "mcp[cli]>=1.0.0",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/AiAgentKarl/mcp-interactive-ui-server"
37
+ Repository = "https://github.com/AiAgentKarl/mcp-interactive-ui-server"
38
+ Issues = "https://github.com/AiAgentKarl/mcp-interactive-ui-server/issues"
39
+
40
+ [project.scripts]
41
+ interactive-ui-server = "src.server:main"
42
+
43
+ [tool.hatch.build.targets.wheel]
44
+ packages = ["src"]
@@ -0,0 +1 @@
1
+ # MCP Interactive UI Server
@@ -0,0 +1,33 @@
1
+ """
2
+ MCP Interactive UI Server — Hauptserver-Datei.
3
+
4
+ Gibt AI-Agents die Möglichkeit, interaktive UIs zu generieren:
5
+ Formulare, Dashboards, Charts, Tabellen, Wizards und Enhanced Markdown.
6
+ """
7
+
8
+ from mcp.server.fastmcp import FastMCP
9
+ from .tools.ui import register_tools
10
+
11
+
12
+ # Server-Instanz erstellen
13
+ mcp = FastMCP(
14
+ "Interactive UI Server",
15
+ instructions=(
16
+ "MCP Apps UI toolkit for AI agents. "
17
+ "Generate interactive forms, dashboards, charts, tables, wizards, "
18
+ "and enhanced markdown that MCP clients can render as native UIs. "
19
+ "All tools return structured JSON schemas following the mcp-ui specification."
20
+ ),
21
+ )
22
+
23
+ # UI-Tools registrieren
24
+ register_tools(mcp)
25
+
26
+
27
+ def main():
28
+ """Startet den MCP-Server über stdio-Transport."""
29
+ mcp.run()
30
+
31
+
32
+ if __name__ == "__main__":
33
+ main()
@@ -0,0 +1,4 @@
1
+ # UI-Tool-Definitionen
2
+ from .ui import register_tools
3
+
4
+ __all__ = ["register_tools"]
@@ -0,0 +1,538 @@
1
+ """
2
+ MCP Interactive UI Tools — Generiert strukturierte UI-Definitionen,
3
+ die MCP-Clients als interaktive Oberflächen rendern können.
4
+ """
5
+
6
+ import json
7
+ from datetime import datetime
8
+ from typing import Any
9
+
10
+
11
+ # ─── UI Schema-Definitionen ───────────────────────────────────────────
12
+
13
+ # Gültige Feld-Typen für Formulare
14
+ FIELD_TYPES = ["text", "number", "select", "checkbox", "date", "email", "password", "textarea", "radio", "range"]
15
+
16
+ # Gültige Widget-Typen für Dashboards
17
+ WIDGET_TYPES = ["chart", "stat_card", "table", "progress_bar", "metric", "list", "markdown"]
18
+
19
+ # Gültige Chart-Typen
20
+ CHART_TYPES = ["bar", "line", "pie", "scatter", "area", "donut", "heatmap"]
21
+
22
+
23
+ def _build_field(field: dict) -> dict:
24
+ """Baut eine einzelne Feld-Definition für Formulare."""
25
+ field_type = field.get("type", "text")
26
+ if field_type not in FIELD_TYPES:
27
+ field_type = "text"
28
+
29
+ result = {
30
+ "id": field.get("id", field.get("label", "field").lower().replace(" ", "_")),
31
+ "type": field_type,
32
+ "label": field.get("label", "Unnamed Field"),
33
+ "required": field.get("required", False),
34
+ "placeholder": field.get("placeholder", ""),
35
+ }
36
+
37
+ # Typ-spezifische Eigenschaften
38
+ if field_type == "select" and "options" in field:
39
+ result["options"] = field["options"]
40
+ if field_type == "number":
41
+ if "min" in field:
42
+ result["min"] = field["min"]
43
+ if "max" in field:
44
+ result["max"] = field["max"]
45
+ if "step" in field:
46
+ result["step"] = field["step"]
47
+ if field_type == "range":
48
+ result["min"] = field.get("min", 0)
49
+ result["max"] = field.get("max", 100)
50
+ result["step"] = field.get("step", 1)
51
+ if field_type == "textarea":
52
+ result["rows"] = field.get("rows", 4)
53
+ if field_type == "radio" and "options" in field:
54
+ result["options"] = field["options"]
55
+ if "default" in field:
56
+ result["default"] = field["default"]
57
+ if "validation" in field:
58
+ result["validation"] = field["validation"]
59
+
60
+ return result
61
+
62
+
63
+ def _build_widget(widget: dict) -> dict:
64
+ """Baut eine einzelne Widget-Definition für Dashboards."""
65
+ widget_type = widget.get("type", "stat_card")
66
+ if widget_type not in WIDGET_TYPES:
67
+ widget_type = "stat_card"
68
+
69
+ result = {
70
+ "id": widget.get("id", widget.get("title", "widget").lower().replace(" ", "_")),
71
+ "type": widget_type,
72
+ "title": widget.get("title", "Widget"),
73
+ }
74
+
75
+ # Typ-spezifische Eigenschaften
76
+ if widget_type == "stat_card":
77
+ result["value"] = widget.get("value", "0")
78
+ result["unit"] = widget.get("unit", "")
79
+ result["change"] = widget.get("change", None)
80
+ result["trend"] = widget.get("trend", "neutral") # up, down, neutral
81
+ elif widget_type == "chart":
82
+ result["chart_type"] = widget.get("chart_type", "bar")
83
+ result["data"] = widget.get("data", {})
84
+ elif widget_type == "table":
85
+ result["headers"] = widget.get("headers", [])
86
+ result["rows"] = widget.get("rows", [])
87
+ result["sortable"] = widget.get("sortable", True)
88
+ elif widget_type == "progress_bar":
89
+ result["value"] = widget.get("value", 0)
90
+ result["max"] = widget.get("max", 100)
91
+ result["color"] = widget.get("color", "blue")
92
+ result["label"] = widget.get("label", "")
93
+ elif widget_type == "metric":
94
+ result["value"] = widget.get("value", "0")
95
+ result["prefix"] = widget.get("prefix", "")
96
+ result["suffix"] = widget.get("suffix", "")
97
+ result["sparkline"] = widget.get("sparkline", [])
98
+ elif widget_type == "list":
99
+ result["items"] = widget.get("items", [])
100
+ result["ordered"] = widget.get("ordered", False)
101
+ elif widget_type == "markdown":
102
+ result["content"] = widget.get("content", "")
103
+
104
+ # Layout-Optionen (Grid-Positionierung)
105
+ if "width" in widget:
106
+ result["width"] = widget["width"] # 1-4 (Grid-Spalten)
107
+ if "height" in widget:
108
+ result["height"] = widget["height"] # 1-4 (Grid-Zeilen)
109
+
110
+ return result
111
+
112
+
113
+ def register_tools(mcp):
114
+ """Registriert alle UI-Tools beim MCP-Server."""
115
+
116
+ @mcp.tool()
117
+ async def create_form(
118
+ title: str,
119
+ fields: list[dict[str, Any]],
120
+ description: str = "",
121
+ submit_label: str = "Submit",
122
+ layout: str = "vertical"
123
+ ) -> str:
124
+ """Generiert eine JSON-Formular-Definition mit verschiedenen Feld-Typen.
125
+
126
+ Erstellt ein strukturiertes Formular-Schema, das MCP-Clients
127
+ als interaktives UI rendern können.
128
+
129
+ Unterstützte Feld-Typen: text, number, select, checkbox, date,
130
+ email, password, textarea, radio, range.
131
+
132
+ Jedes Feld braucht mindestens: {"label": "Name", "type": "text"}
133
+ Optional: id, required, placeholder, default, validation, options (für select/radio),
134
+ min/max/step (für number/range), rows (für textarea).
135
+
136
+ Args:
137
+ title: Formular-Titel
138
+ fields: Liste von Feld-Definitionen (dicts mit type, label, etc.)
139
+ description: Optionale Beschreibung über dem Formular
140
+ submit_label: Text des Submit-Buttons
141
+ layout: "vertical" oder "horizontal" Feld-Anordnung
142
+
143
+ Returns:
144
+ JSON-String mit dem Formular-Schema
145
+ """
146
+ form_schema = {
147
+ "$schema": "mcp-ui/form/v1",
148
+ "type": "form",
149
+ "title": title,
150
+ "description": description,
151
+ "layout": layout if layout in ("vertical", "horizontal") else "vertical",
152
+ "fields": [_build_field(f) for f in fields],
153
+ "actions": {
154
+ "submit": {
155
+ "label": submit_label,
156
+ "type": "primary"
157
+ },
158
+ "cancel": {
159
+ "label": "Cancel",
160
+ "type": "secondary"
161
+ }
162
+ },
163
+ "metadata": {
164
+ "created_at": datetime.now().isoformat(),
165
+ "field_count": len(fields),
166
+ "version": "1.0"
167
+ }
168
+ }
169
+
170
+ return json.dumps(form_schema, indent=2)
171
+
172
+ @mcp.tool()
173
+ async def create_dashboard(
174
+ title: str,
175
+ widgets: list[dict[str, Any]],
176
+ description: str = "",
177
+ columns: int = 3,
178
+ refresh_interval: int = 0
179
+ ) -> str:
180
+ """Generiert ein Dashboard-Layout mit verschiedenen Widget-Typen.
181
+
182
+ Erstellt eine strukturierte Dashboard-Definition mit konfigurierbarem
183
+ Grid-Layout, die MCP-Clients als interaktives Dashboard rendern können.
184
+
185
+ Unterstützte Widget-Typen: chart, stat_card, table, progress_bar,
186
+ metric, list, markdown.
187
+
188
+ Jedes Widget braucht mindestens: {"type": "stat_card", "title": "Users", "value": "1234"}
189
+
190
+ Args:
191
+ title: Dashboard-Titel
192
+ widgets: Liste von Widget-Definitionen (dicts mit type, title, etc.)
193
+ description: Optionale Dashboard-Beschreibung
194
+ columns: Anzahl Grid-Spalten (1-6)
195
+ refresh_interval: Auto-Refresh in Sekunden (0 = kein Refresh)
196
+
197
+ Returns:
198
+ JSON-String mit dem Dashboard-Schema
199
+ """
200
+ columns = max(1, min(6, columns))
201
+
202
+ dashboard_schema = {
203
+ "$schema": "mcp-ui/dashboard/v1",
204
+ "type": "dashboard",
205
+ "title": title,
206
+ "description": description,
207
+ "layout": {
208
+ "type": "grid",
209
+ "columns": columns,
210
+ "gap": "16px",
211
+ "padding": "24px"
212
+ },
213
+ "widgets": [_build_widget(w) for w in widgets],
214
+ "settings": {
215
+ "refresh_interval": refresh_interval,
216
+ "theme": "auto",
217
+ "responsive": True
218
+ },
219
+ "metadata": {
220
+ "created_at": datetime.now().isoformat(),
221
+ "widget_count": len(widgets),
222
+ "version": "1.0"
223
+ }
224
+ }
225
+
226
+ return json.dumps(dashboard_schema, indent=2)
227
+
228
+ @mcp.tool()
229
+ async def create_chart(
230
+ chart_type: str,
231
+ data: dict[str, Any],
232
+ title: str = "Chart",
233
+ x_label: str = "",
234
+ y_label: str = "",
235
+ colors: list[str] | None = None,
236
+ stacked: bool = False
237
+ ) -> str:
238
+ """Generiert eine Chart-Definition (Bar, Line, Pie, Scatter, etc.).
239
+
240
+ Erstellt ein Chart-Schema mit Daten und Konfiguration,
241
+ das MCP-Clients als interaktives Diagramm rendern können.
242
+
243
+ Unterstützte Chart-Typen: bar, line, pie, scatter, area, donut, heatmap.
244
+
245
+ Daten-Format:
246
+ - Für bar/line/area: {"labels": ["Jan","Feb"], "datasets": [{"label": "Sales", "values": [10,20]}]}
247
+ - Für pie/donut: {"labels": ["A","B","C"], "values": [30, 50, 20]}
248
+ - Für scatter: {"datasets": [{"label": "Set 1", "points": [{"x": 1, "y": 2}]}]}
249
+ - Für heatmap: {"x_labels": [...], "y_labels": [...], "values": [[...]]}
250
+
251
+ Args:
252
+ chart_type: Art des Charts (bar, line, pie, scatter, area, donut, heatmap)
253
+ data: Chart-Daten als Dictionary
254
+ title: Chart-Titel
255
+ x_label: Beschriftung X-Achse
256
+ y_label: Beschriftung Y-Achse
257
+ colors: Optionale Farbliste (hex oder CSS-Farbnamen)
258
+ stacked: Gestapelte Darstellung (nur bar/area)
259
+
260
+ Returns:
261
+ JSON-String mit dem Chart-Schema
262
+ """
263
+ if chart_type not in CHART_TYPES:
264
+ chart_type = "bar"
265
+
266
+ # Standard-Farbpalette
267
+ default_colors = [
268
+ "#3B82F6", "#10B981", "#F59E0B", "#EF4444",
269
+ "#8B5CF6", "#EC4899", "#06B6D4", "#84CC16"
270
+ ]
271
+
272
+ chart_schema = {
273
+ "$schema": "mcp-ui/chart/v1",
274
+ "type": "chart",
275
+ "chart_type": chart_type,
276
+ "title": title,
277
+ "data": data,
278
+ "config": {
279
+ "x_label": x_label,
280
+ "y_label": y_label,
281
+ "colors": colors if colors else default_colors,
282
+ "stacked": stacked and chart_type in ("bar", "area"),
283
+ "legend": True,
284
+ "animation": True,
285
+ "tooltip": True,
286
+ "responsive": True
287
+ },
288
+ "metadata": {
289
+ "created_at": datetime.now().isoformat(),
290
+ "version": "1.0"
291
+ }
292
+ }
293
+
294
+ return json.dumps(chart_schema, indent=2)
295
+
296
+ @mcp.tool()
297
+ async def create_table(
298
+ headers: list[str],
299
+ rows: list[list[Any]],
300
+ sortable: bool = True,
301
+ filterable: bool = True,
302
+ page_size: int = 10,
303
+ title: str = ""
304
+ ) -> str:
305
+ """Generiert eine interaktive Tabellen-Definition mit Sortierung und Filterung.
306
+
307
+ Erstellt ein Tabellen-Schema mit Spalten-Definitionen und Daten,
308
+ das MCP-Clients als interaktive Tabelle rendern können.
309
+
310
+ Args:
311
+ headers: Liste von Spalten-Überschriften
312
+ rows: Liste von Zeilen (jede Zeile ist eine Liste von Werten)
313
+ sortable: Spalten sortierbar machen
314
+ filterable: Suchfilter anzeigen
315
+ page_size: Zeilen pro Seite (Pagination)
316
+ title: Optionaler Tabellen-Titel
317
+
318
+ Returns:
319
+ JSON-String mit dem Tabellen-Schema
320
+ """
321
+ # Spalten-Definitionen aus Headers bauen
322
+ columns = []
323
+ for i, header in enumerate(headers):
324
+ col = {
325
+ "id": header.lower().replace(" ", "_"),
326
+ "label": header,
327
+ "sortable": sortable,
328
+ "type": "string" # Standard-Typ
329
+ }
330
+
331
+ # Typ-Erkennung aus den Daten
332
+ if rows:
333
+ sample = rows[0][i] if i < len(rows[0]) else None
334
+ if isinstance(sample, (int, float)):
335
+ col["type"] = "number"
336
+ col["align"] = "right"
337
+ elif isinstance(sample, bool):
338
+ col["type"] = "boolean"
339
+
340
+ columns.append(col)
341
+
342
+ table_schema = {
343
+ "$schema": "mcp-ui/table/v1",
344
+ "type": "table",
345
+ "title": title,
346
+ "columns": columns,
347
+ "rows": [
348
+ {
349
+ columns[j]["id"]: cell
350
+ for j, cell in enumerate(row)
351
+ if j < len(columns)
352
+ }
353
+ for row in rows
354
+ ],
355
+ "features": {
356
+ "sortable": sortable,
357
+ "filterable": filterable,
358
+ "pagination": {
359
+ "enabled": len(rows) > page_size,
360
+ "page_size": page_size,
361
+ "total_rows": len(rows)
362
+ },
363
+ "selectable": False,
364
+ "exportable": True
365
+ },
366
+ "metadata": {
367
+ "created_at": datetime.now().isoformat(),
368
+ "row_count": len(rows),
369
+ "column_count": len(headers),
370
+ "version": "1.0"
371
+ }
372
+ }
373
+
374
+ return json.dumps(table_schema, indent=2)
375
+
376
+ @mcp.tool()
377
+ async def create_wizard(
378
+ steps: list[dict[str, Any]],
379
+ title: str = "Wizard",
380
+ allow_skip: bool = False,
381
+ show_progress: bool = True
382
+ ) -> str:
383
+ """Generiert einen Multi-Step-Formular-Wizard mit Validierung.
384
+
385
+ Erstellt eine Wizard-Definition mit mehreren Schritten,
386
+ die MCP-Clients als geführten Prozess rendern können.
387
+ Jeder Schritt hat eigene Felder und Validierungsregeln.
388
+
389
+ Jeder Step braucht: {"title": "Schritt 1", "fields": [...]}
390
+ Optional: description, validation (dict mit Regeln).
391
+
392
+ Validierungsregeln pro Step:
393
+ - {"required_fields": ["name", "email"]}
394
+ - {"custom": {"field_id": {"min_length": 3}}}
395
+
396
+ Args:
397
+ steps: Liste von Step-Definitionen (dicts mit title, fields, etc.)
398
+ title: Wizard-Gesamttitel
399
+ allow_skip: Schritte überspringbar machen
400
+ show_progress: Fortschrittsanzeige einblenden
401
+
402
+ Returns:
403
+ JSON-String mit dem Wizard-Schema
404
+ """
405
+ wizard_steps = []
406
+ for i, step in enumerate(steps):
407
+ wizard_step = {
408
+ "id": f"step_{i + 1}",
409
+ "title": step.get("title", f"Step {i + 1}"),
410
+ "description": step.get("description", ""),
411
+ "fields": [_build_field(f) for f in step.get("fields", [])],
412
+ "validation": step.get("validation", {}),
413
+ "skippable": allow_skip and not step.get("required", True)
414
+ }
415
+ wizard_steps.append(wizard_step)
416
+
417
+ wizard_schema = {
418
+ "$schema": "mcp-ui/wizard/v1",
419
+ "type": "wizard",
420
+ "title": title,
421
+ "steps": wizard_steps,
422
+ "navigation": {
423
+ "show_progress": show_progress,
424
+ "allow_back": True,
425
+ "allow_skip": allow_skip,
426
+ "confirm_cancel": True
427
+ },
428
+ "actions": {
429
+ "next": {"label": "Next", "type": "primary"},
430
+ "back": {"label": "Back", "type": "secondary"},
431
+ "finish": {"label": "Finish", "type": "primary"},
432
+ "cancel": {"label": "Cancel", "type": "ghost"}
433
+ },
434
+ "metadata": {
435
+ "created_at": datetime.now().isoformat(),
436
+ "step_count": len(steps),
437
+ "total_fields": sum(len(s.get("fields", [])) for s in steps),
438
+ "version": "1.0"
439
+ }
440
+ }
441
+
442
+ return json.dumps(wizard_schema, indent=2)
443
+
444
+ @mcp.tool()
445
+ async def render_markdown(
446
+ content: str,
447
+ interactive_elements: list[dict[str, Any]] | None = None,
448
+ theme: str = "auto"
449
+ ) -> str:
450
+ """Erweitertes Markdown mit eingebetteten interaktiven Elementen.
451
+
452
+ Kombiniert Standard-Markdown mit interaktiven UI-Komponenten
453
+ wie Buttons, Toggles, Inputs und Accordions, die MCP-Clients
454
+ inline rendern können.
455
+
456
+ Interaktive Elemente werden via Platzhalter {{element_id}} im
457
+ Markdown eingebettet.
458
+
459
+ Unterstützte Element-Typen:
460
+ - button: {"type": "button", "id": "btn1", "label": "Click", "action": "submit"}
461
+ - toggle: {"type": "toggle", "id": "tog1", "label": "Dark Mode", "default": false}
462
+ - input: {"type": "input", "id": "inp1", "placeholder": "Enter value..."}
463
+ - accordion: {"type": "accordion", "id": "acc1", "title": "Details", "content": "..."}
464
+ - alert: {"type": "alert", "id": "alt1", "severity": "info", "message": "Hinweis..."}
465
+ - badge: {"type": "badge", "id": "bdg1", "text": "New", "color": "green"}
466
+ - tabs: {"type": "tabs", "id": "tab1", "items": [{"label": "Tab 1", "content": "..."}]}
467
+
468
+ Args:
469
+ content: Markdown-Inhalt (mit optionalen {{element_id}} Platzhaltern)
470
+ interactive_elements: Liste interaktiver Element-Definitionen
471
+ theme: "auto", "light" oder "dark"
472
+
473
+ Returns:
474
+ JSON-String mit dem Enhanced-Markdown-Schema
475
+ """
476
+ ELEMENT_TYPES = ["button", "toggle", "input", "accordion", "alert", "badge", "tabs"]
477
+
478
+ elements = {}
479
+ if interactive_elements:
480
+ for elem in interactive_elements:
481
+ elem_type = elem.get("type", "button")
482
+ if elem_type not in ELEMENT_TYPES:
483
+ continue
484
+
485
+ elem_id = elem.get("id", f"elem_{len(elements)}")
486
+ element_def = {
487
+ "type": elem_type,
488
+ "id": elem_id,
489
+ }
490
+
491
+ # Typ-spezifische Eigenschaften
492
+ if elem_type == "button":
493
+ element_def["label"] = elem.get("label", "Button")
494
+ element_def["action"] = elem.get("action", "click")
495
+ element_def["variant"] = elem.get("variant", "primary")
496
+ element_def["icon"] = elem.get("icon", None)
497
+ elif elem_type == "toggle":
498
+ element_def["label"] = elem.get("label", "Toggle")
499
+ element_def["default"] = elem.get("default", False)
500
+ elif elem_type == "input":
501
+ element_def["placeholder"] = elem.get("placeholder", "")
502
+ element_def["input_type"] = elem.get("input_type", "text")
503
+ elif elem_type == "accordion":
504
+ element_def["title"] = elem.get("title", "Details")
505
+ element_def["content"] = elem.get("content", "")
506
+ element_def["open"] = elem.get("open", False)
507
+ elif elem_type == "alert":
508
+ element_def["severity"] = elem.get("severity", "info")
509
+ element_def["message"] = elem.get("message", "")
510
+ elif elem_type == "badge":
511
+ element_def["text"] = elem.get("text", "")
512
+ element_def["color"] = elem.get("color", "blue")
513
+ elif elem_type == "tabs":
514
+ element_def["items"] = elem.get("items", [])
515
+ element_def["default_tab"] = elem.get("default_tab", 0)
516
+
517
+ elements[elem_id] = element_def
518
+
519
+ markdown_schema = {
520
+ "$schema": "mcp-ui/markdown/v1",
521
+ "type": "enhanced_markdown",
522
+ "content": content,
523
+ "interactive_elements": elements,
524
+ "config": {
525
+ "theme": theme if theme in ("auto", "light", "dark") else "auto",
526
+ "syntax_highlighting": True,
527
+ "math_rendering": True,
528
+ "mermaid_diagrams": True
529
+ },
530
+ "metadata": {
531
+ "created_at": datetime.now().isoformat(),
532
+ "element_count": len(elements),
533
+ "content_length": len(content),
534
+ "version": "1.0"
535
+ }
536
+ }
537
+
538
+ return json.dumps(markdown_schema, indent=2)