flet-mcp 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.
- flet_mcp-0.1.0/PKG-INFO +114 -0
- flet_mcp-0.1.0/README.md +95 -0
- flet_mcp-0.1.0/pyproject.toml +32 -0
- flet_mcp-0.1.0/setup.cfg +4 -0
- flet_mcp-0.1.0/src/flet_mcp/__init__.py +3 -0
- flet_mcp-0.1.0/src/flet_mcp/api_store.py +147 -0
- flet_mcp-0.1.0/src/flet_mcp/build/__init__.py +0 -0
- flet_mcp-0.1.0/src/flet_mcp/build/api.py +520 -0
- flet_mcp-0.1.0/src/flet_mcp/build/docs.py +136 -0
- flet_mcp-0.1.0/src/flet_mcp/build/examples.py +170 -0
- flet_mcp-0.1.0/src/flet_mcp/build/indexer.py +105 -0
- flet_mcp-0.1.0/src/flet_mcp/data/api.json +79156 -0
- flet_mcp-0.1.0/src/flet_mcp/data/icons.yml +2096 -0
- flet_mcp-0.1.0/src/flet_mcp/data/mcp.db +0 -0
- flet_mcp-0.1.0/src/flet_mcp/db.py +42 -0
- flet_mcp-0.1.0/src/flet_mcp/icons_store.py +138 -0
- flet_mcp-0.1.0/src/flet_mcp/server.py +364 -0
- flet_mcp-0.1.0/src/flet_mcp.egg-info/PKG-INFO +114 -0
- flet_mcp-0.1.0/src/flet_mcp.egg-info/SOURCES.txt +20 -0
- flet_mcp-0.1.0/src/flet_mcp.egg-info/dependency_links.txt +1 -0
- flet_mcp-0.1.0/src/flet_mcp.egg-info/requires.txt +8 -0
- flet_mcp-0.1.0/src/flet_mcp.egg-info/top_level.txt +1 -0
flet_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flet-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Flet MCP server for LLM agents
|
|
5
|
+
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://flet.dev
|
|
8
|
+
Project-URL: Repository, https://github.com/flet-dev/flet
|
|
9
|
+
Project-URL: Documentation, https://flet.dev/docs
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
13
|
+
Requires-Dist: pyyaml>=6.0
|
|
14
|
+
Provides-Extra: build
|
|
15
|
+
Requires-Dist: markdownify>=0.14.1; extra == "build"
|
|
16
|
+
Requires-Dist: griffe>=1.6.2; extra == "build"
|
|
17
|
+
Requires-Dist: flet; extra == "build"
|
|
18
|
+
Requires-Dist: flet-cli; extra == "build"
|
|
19
|
+
|
|
20
|
+
# flet-mcp
|
|
21
|
+
|
|
22
|
+
MCP (Model Context Protocol) server that gives LLM agents access to Flet examples, documentation, and API reference.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install flet-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Start the MCP server
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# stdio transport (default, for use with Claude Desktop, Cursor, etc.)
|
|
36
|
+
flet mcp
|
|
37
|
+
|
|
38
|
+
# HTTP transport
|
|
39
|
+
flet mcp --transport streamable-http --port 8000
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Configure in Claude Desktop
|
|
43
|
+
|
|
44
|
+
Add to your `claude_desktop_config.json`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"flet": {
|
|
50
|
+
"command": "flet",
|
|
51
|
+
"args": ["mcp"]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### List available tools
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
fastmcp list packages/flet-mcp/src/flet_mcp/server.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Call tools from the command line
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Search examples
|
|
67
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_examples '{"query": "dropdown"}'
|
|
68
|
+
|
|
69
|
+
# Get full example code
|
|
70
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_example '{"example_id": "controls_dropdown_styled"}'
|
|
71
|
+
|
|
72
|
+
# Search documentation
|
|
73
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_docs '{"query": "TextField validation"}'
|
|
74
|
+
|
|
75
|
+
# Get control API reference
|
|
76
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_control_api '{"name": "TextField"}'
|
|
77
|
+
|
|
78
|
+
# Find an icon
|
|
79
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py find_icon '{"query": "settings"}'
|
|
80
|
+
|
|
81
|
+
# Search large enums
|
|
82
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_enum_members '{"name": "Icons", "query": "arrow"}'
|
|
83
|
+
|
|
84
|
+
# Get CLI help
|
|
85
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_cli_help '{"command": "run"}'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Use with Pydantic AI
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from pydantic_ai import Agent
|
|
92
|
+
from pydantic_ai.toolsets import MCPToolset
|
|
93
|
+
from flet_mcp import mcp
|
|
94
|
+
|
|
95
|
+
agent = Agent("claude-sonnet-4-20250514", toolsets=[MCPToolset(mcp)])
|
|
96
|
+
result = agent.run_sync("Create a Flet app with a login form")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Tools
|
|
100
|
+
|
|
101
|
+
| Tool | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `search_examples` | Search example projects by keyword |
|
|
104
|
+
| `get_example` | Get full source code for an example |
|
|
105
|
+
| `search_docs` | Search documentation by keyword |
|
|
106
|
+
| `get_doc` | Get full content of a doc section |
|
|
107
|
+
| `list_controls` | List controls and services, with optional filtering |
|
|
108
|
+
| `get_control_api` | Get properties, events, and methods for a control |
|
|
109
|
+
| `get_type_api` | Get fields and methods for a type (ButtonStyle, Padding, etc.) |
|
|
110
|
+
| `get_enum` | Get enum members |
|
|
111
|
+
| `search_enum_members` | Search large enums (Icons, CupertinoIcons) |
|
|
112
|
+
| `enum_has_member` | Check if an enum value exists |
|
|
113
|
+
| `find_icon` | Search Material and Cupertino icons by keyword |
|
|
114
|
+
| `get_cli_help` | Get structured CLI command options |
|
flet_mcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# flet-mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server that gives LLM agents access to Flet examples, documentation, and API reference.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install flet-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Start the MCP server
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# stdio transport (default, for use with Claude Desktop, Cursor, etc.)
|
|
17
|
+
flet mcp
|
|
18
|
+
|
|
19
|
+
# HTTP transport
|
|
20
|
+
flet mcp --transport streamable-http --port 8000
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Configure in Claude Desktop
|
|
24
|
+
|
|
25
|
+
Add to your `claude_desktop_config.json`:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"flet": {
|
|
31
|
+
"command": "flet",
|
|
32
|
+
"args": ["mcp"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### List available tools
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
fastmcp list packages/flet-mcp/src/flet_mcp/server.py
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Call tools from the command line
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Search examples
|
|
48
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_examples '{"query": "dropdown"}'
|
|
49
|
+
|
|
50
|
+
# Get full example code
|
|
51
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_example '{"example_id": "controls_dropdown_styled"}'
|
|
52
|
+
|
|
53
|
+
# Search documentation
|
|
54
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_docs '{"query": "TextField validation"}'
|
|
55
|
+
|
|
56
|
+
# Get control API reference
|
|
57
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_control_api '{"name": "TextField"}'
|
|
58
|
+
|
|
59
|
+
# Find an icon
|
|
60
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py find_icon '{"query": "settings"}'
|
|
61
|
+
|
|
62
|
+
# Search large enums
|
|
63
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_enum_members '{"name": "Icons", "query": "arrow"}'
|
|
64
|
+
|
|
65
|
+
# Get CLI help
|
|
66
|
+
fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_cli_help '{"command": "run"}'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Use with Pydantic AI
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from pydantic_ai import Agent
|
|
73
|
+
from pydantic_ai.toolsets import MCPToolset
|
|
74
|
+
from flet_mcp import mcp
|
|
75
|
+
|
|
76
|
+
agent = Agent("claude-sonnet-4-20250514", toolsets=[MCPToolset(mcp)])
|
|
77
|
+
result = agent.run_sync("Create a Flet app with a login form")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Tools
|
|
81
|
+
|
|
82
|
+
| Tool | Description |
|
|
83
|
+
|------|-------------|
|
|
84
|
+
| `search_examples` | Search example projects by keyword |
|
|
85
|
+
| `get_example` | Get full source code for an example |
|
|
86
|
+
| `search_docs` | Search documentation by keyword |
|
|
87
|
+
| `get_doc` | Get full content of a doc section |
|
|
88
|
+
| `list_controls` | List controls and services, with optional filtering |
|
|
89
|
+
| `get_control_api` | Get properties, events, and methods for a control |
|
|
90
|
+
| `get_type_api` | Get fields and methods for a type (ButtonStyle, Padding, etc.) |
|
|
91
|
+
| `get_enum` | Get enum members |
|
|
92
|
+
| `search_enum_members` | Search large enums (Icons, CupertinoIcons) |
|
|
93
|
+
| `enum_has_member` | Check if an enum value exists |
|
|
94
|
+
| `find_icon` | Search Material and Cupertino icons by keyword |
|
|
95
|
+
| `get_cli_help` | Get structured CLI command options |
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "flet-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Flet MCP server for LLM agents"
|
|
5
|
+
authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }]
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"fastmcp >=2.0.0",
|
|
11
|
+
"pyyaml >=6.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.optional-dependencies]
|
|
15
|
+
build = [
|
|
16
|
+
"markdownify >=0.14.1",
|
|
17
|
+
"griffe >=1.6.2",
|
|
18
|
+
"flet",
|
|
19
|
+
"flet-cli",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://flet.dev"
|
|
24
|
+
Repository = "https://github.com/flet-dev/flet"
|
|
25
|
+
Documentation = "https://flet.dev/docs"
|
|
26
|
+
|
|
27
|
+
[build-system]
|
|
28
|
+
requires = ["setuptools"]
|
|
29
|
+
build-backend = "setuptools.build_meta"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.package-data]
|
|
32
|
+
flet_mcp = ["data/*"]
|
flet_mcp-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Load and query the Griffe-generated API reference (api.json)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib.resources
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ApiStore:
|
|
12
|
+
"""Lazy-loading store for the bundled api.json data.
|
|
13
|
+
|
|
14
|
+
The api.json file uses lists for controls/events/types/enums,
|
|
15
|
+
each entry having a "name" key. This store builds name-keyed dicts
|
|
16
|
+
for fast lookup.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
self._raw: dict[str, Any] | None = None
|
|
21
|
+
self._controls: dict[str, dict] | None = None
|
|
22
|
+
self._events: dict[str, dict] | None = None
|
|
23
|
+
self._types: dict[str, dict] | None = None
|
|
24
|
+
self._enums: dict[str, dict] | None = None
|
|
25
|
+
|
|
26
|
+
def _load(self) -> dict[str, Any]:
|
|
27
|
+
if self._raw is None:
|
|
28
|
+
ref = importlib.resources.files("flet_mcp").joinpath("data/api.json")
|
|
29
|
+
self._raw = json.loads(Path(str(ref)).read_text(encoding="utf-8"))
|
|
30
|
+
# Build name-keyed dicts from lists
|
|
31
|
+
self._controls = {c["name"]: c for c in self._raw.get("controls", [])}
|
|
32
|
+
self._events = {e["name"]: e for e in self._raw.get("events", [])}
|
|
33
|
+
self._types = {t["name"]: t for t in self._raw.get("types", [])}
|
|
34
|
+
self._enums = {e["name"]: e for e in self._raw.get("enums", [])}
|
|
35
|
+
return self._raw
|
|
36
|
+
|
|
37
|
+
# ------------------------------------------------------------------
|
|
38
|
+
# Controls
|
|
39
|
+
# ------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
def list_controls(
|
|
42
|
+
self,
|
|
43
|
+
category: str | None = None,
|
|
44
|
+
kind: str | None = None,
|
|
45
|
+
limit: int = 50,
|
|
46
|
+
) -> list[dict[str, Any]]:
|
|
47
|
+
"""List controls, optionally filtered by category or kind."""
|
|
48
|
+
self._load()
|
|
49
|
+
results: list[dict[str, Any]] = []
|
|
50
|
+
for name, ctrl in self._controls.items():
|
|
51
|
+
if kind and ctrl.get("kind") != kind:
|
|
52
|
+
continue
|
|
53
|
+
if category and category not in ctrl.get("categories", []):
|
|
54
|
+
continue
|
|
55
|
+
results.append(
|
|
56
|
+
{
|
|
57
|
+
"name": name,
|
|
58
|
+
"kind": ctrl.get("kind"),
|
|
59
|
+
"summary": ctrl.get("summary", ""),
|
|
60
|
+
"categories": ctrl.get("categories", []),
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
if len(results) >= limit:
|
|
64
|
+
break
|
|
65
|
+
return results
|
|
66
|
+
|
|
67
|
+
def get_control(self, name: str) -> dict[str, Any] | None:
|
|
68
|
+
"""Return full control dict by name, or None."""
|
|
69
|
+
self._load()
|
|
70
|
+
return self._controls.get(name)
|
|
71
|
+
|
|
72
|
+
# ------------------------------------------------------------------
|
|
73
|
+
# Types & Events
|
|
74
|
+
# ------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
def get_type(self, name: str) -> dict[str, Any] | None:
|
|
77
|
+
"""Return full type dict by name, or None."""
|
|
78
|
+
self._load()
|
|
79
|
+
return self._types.get(name) or self._events.get(name)
|
|
80
|
+
|
|
81
|
+
# ------------------------------------------------------------------
|
|
82
|
+
# Enums
|
|
83
|
+
# ------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
def get_enum(self, name: str) -> dict[str, Any] | None:
|
|
86
|
+
"""Return enum data. Large enums are truncated with a hint to search."""
|
|
87
|
+
self._load()
|
|
88
|
+
enum = self._enums.get(name)
|
|
89
|
+
if enum is None:
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
if enum.get("kind") == "large_enum":
|
|
93
|
+
members = enum.get("members", [])
|
|
94
|
+
return {
|
|
95
|
+
"name": name,
|
|
96
|
+
"kind": "large_enum",
|
|
97
|
+
"total_members": len(members),
|
|
98
|
+
"sample_members": members[:10],
|
|
99
|
+
"note": (
|
|
100
|
+
f"This enum has {len(members)} members. "
|
|
101
|
+
"Use search_enum_members() to find specific values."
|
|
102
|
+
),
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return enum
|
|
106
|
+
|
|
107
|
+
def search_enum_members(self, name: str, query: str, limit: int = 10) -> list[str]:
|
|
108
|
+
"""Search enum members by case-insensitive substring match."""
|
|
109
|
+
self._load()
|
|
110
|
+
enum = self._enums.get(name)
|
|
111
|
+
if enum is None:
|
|
112
|
+
return []
|
|
113
|
+
|
|
114
|
+
query_lower = query.lower()
|
|
115
|
+
results: list[str] = []
|
|
116
|
+
for member in enum.get("members", []):
|
|
117
|
+
member_name = member["name"] if isinstance(member, dict) else str(member)
|
|
118
|
+
if query_lower in member_name.lower():
|
|
119
|
+
results.append(member_name)
|
|
120
|
+
if len(results) >= limit:
|
|
121
|
+
break
|
|
122
|
+
return results
|
|
123
|
+
|
|
124
|
+
def enum_has_member(self, name: str, member: str) -> bool:
|
|
125
|
+
"""Check whether an enum contains a specific member."""
|
|
126
|
+
self._load()
|
|
127
|
+
enum = self._enums.get(name)
|
|
128
|
+
if enum is None:
|
|
129
|
+
return False
|
|
130
|
+
members = enum.get("members", [])
|
|
131
|
+
member_lower = member.lower()
|
|
132
|
+
return any(
|
|
133
|
+
(m["name"] if isinstance(m, dict) else str(m)).lower() == member_lower
|
|
134
|
+
for m in members
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# ------------------------------------------------------------------
|
|
138
|
+
# CLI
|
|
139
|
+
# ------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
def get_cli_help(self, command: str | None = None) -> Any:
|
|
142
|
+
"""Return CLI help. None -> list commands; otherwise command help text."""
|
|
143
|
+
self._load()
|
|
144
|
+
cli = self._raw.get("cli", {})
|
|
145
|
+
if command is None:
|
|
146
|
+
return list(cli.keys())
|
|
147
|
+
return cli.get(command)
|
|
File without changes
|