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.
- mcp_interactive_ui_server-0.1.0/.gitignore +15 -0
- mcp_interactive_ui_server-0.1.0/LICENSE +21 -0
- mcp_interactive_ui_server-0.1.0/PKG-INFO +181 -0
- mcp_interactive_ui_server-0.1.0/README.md +156 -0
- mcp_interactive_ui_server-0.1.0/pyproject.toml +44 -0
- mcp_interactive_ui_server-0.1.0/src/__init__.py +1 -0
- mcp_interactive_ui_server-0.1.0/src/server.py +33 -0
- mcp_interactive_ui_server-0.1.0/src/tools/__init__.py +4 -0
- mcp_interactive_ui_server-0.1.0/src/tools/ui.py +538 -0
|
@@ -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
|
+
[](https://pypi.org/project/mcp-interactive-ui-server/)
|
|
31
|
+
[](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
|
+
[](https://pypi.org/project/mcp-interactive-ui-server/)
|
|
6
|
+
[](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,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)
|