flet-mcp-server 0.1.0__py3-none-any.whl

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/__init__.py ADDED
File without changes
flet_mcp/main.py ADDED
@@ -0,0 +1,12 @@
1
+ from flet_mcp.server import mcp
2
+
3
+ def run_server():
4
+ """
5
+ Entry point for the uv script execution.
6
+ Runs the MCP server over standard input/output (stdio),
7
+ which is the communication protocol required by desktop AI agents.
8
+ """
9
+ mcp.run(transport='stdio')
10
+
11
+ if __name__ == "__main__":
12
+ run_server()
flet_mcp/server.py ADDED
@@ -0,0 +1,72 @@
1
+ from mcp.server.fastmcp import FastMCP
2
+ from flet_mcp.services.github_docs import FletDocsFetcher
3
+ from flet_mcp.services.packages import FletPackageFetcher
4
+
5
+ # Initialize the FastMCP server
6
+ mcp = FastMCP("Flet MCP Server")
7
+ docs_fetcher = FletDocsFetcher()
8
+ pkg_fetcher = FletPackageFetcher()
9
+
10
+ # --- DOCUMENTATION TOOLS ---
11
+
12
+ @mcp.tool()
13
+ async def search_flet_docs(query: str) -> list[str]:
14
+ """
15
+ Search the official Flet documentation index for a specific topic or control.
16
+ Always use this first to find the correct file path before calling get_flet_doc.
17
+
18
+ Args:
19
+ query: The keyword to search for (e.g., 'dropdown', 'navigation', 'layout').
20
+ """
21
+ return await docs_fetcher.search_docs(query)
22
+
23
+ @mcp.tool()
24
+ async def get_flet_doc(doc_path: str) -> str:
25
+ """
26
+ Fetch the full Markdown documentation for a specific Flet control or topic.
27
+
28
+ Args:
29
+ doc_path: The exact path to the doc file, usually obtained from search_flet_docs
30
+ (e.g., 'website/docs/controls/dropdown/index.md').
31
+ """
32
+ return await docs_fetcher.get_doc_content(doc_path)
33
+
34
+ @mcp.tool()
35
+ async def list_flet_controls() -> list[str]:
36
+ """
37
+ Get a complete list of all available Flet UI controls.
38
+ Use this to discover what UI elements can be built in Flet.
39
+ """
40
+ return await docs_fetcher.list_flet_controls()
41
+
42
+ # --- ECOSYSTEM & PACKAGE TOOLS ---
43
+
44
+ @mcp.tool()
45
+ async def list_official_packages() -> list[str]:
46
+ """
47
+ Get a list of all official Flet extension packages (e.g. flet-audio, flet-video).
48
+ Use this to see what official extra capabilities Flet supports outside the core library.
49
+ """
50
+ return await pkg_fetcher.list_official_packages()
51
+
52
+ @mcp.tool()
53
+ async def search_flet_ecosystem(query: str) -> list[dict]:
54
+ """
55
+ Search the open-source community for third-party Flet packages and components.
56
+ Use this when the user wants to add a feature (e.g., 'calendar', 'table', 'auth')
57
+ that might not be in the core Flet library.
58
+
59
+ Args:
60
+ query: The keyword to search for (e.g., 'calendar').
61
+ """
62
+ return await pkg_fetcher.search_flet_ecosystem(query)
63
+
64
+ @mcp.tool()
65
+ async def get_package_details(package_name: str) -> str:
66
+ """
67
+ Fetch PyPI details, current version, and installation instructions for a specific Flet package.
68
+
69
+ Args:
70
+ package_name: The exact name of the package on PyPI (e.g., 'flet-audio').
71
+ """
72
+ return await pkg_fetcher.get_package_details(package_name)
File without changes
@@ -0,0 +1,98 @@
1
+ import os
2
+ import httpx
3
+ import diskcache
4
+
5
+ # Set up a persistent local cache in the user's home directory
6
+ # This prevents us from getting rate-limited by GitHub when the AI asks multiple questions
7
+ CACHE_DIR = os.path.expanduser("~/.cache/flet-mcp")
8
+ cache = diskcache.Cache(CACHE_DIR)
9
+
10
+ class FletDocsFetcher:
11
+ """Fetches and caches Flet documentation from the official GitHub repo."""
12
+
13
+ def __init__(self):
14
+ self.client = httpx.AsyncClient(timeout=10.0)
15
+ self.headers = {
16
+ "Accept": "application/vnd.github.v3+json",
17
+ "User-Agent": "Flet-MCP-Server/0.1.0"
18
+ }
19
+ # If the user has a GITHUB_TOKEN, use it to vastly expand API limits
20
+ if token := os.getenv("GITHUB_TOKEN"):
21
+ self.headers["Authorization"] = f"Bearer {token}"
22
+
23
+ async def _fetch_json(self, url: str) -> dict | list | None:
24
+ """Helper to fetch and cache JSON responses (24-hour TTL)."""
25
+ if url in cache:
26
+ return cache[url]
27
+
28
+ response = await self.client.get(url, headers=self.headers)
29
+ if response.status_code == 200:
30
+ data = response.json()
31
+ cache.set(url, data, expire=86400) # 86400 seconds = 24 hours
32
+ return data
33
+ return None
34
+
35
+ async def _fetch_text(self, url: str) -> str | None:
36
+ """Helper to fetch and cache raw Markdown text (24-hour TTL)."""
37
+ if url in cache:
38
+ return cache[url]
39
+
40
+ response = await self.client.get(url)
41
+ if response.status_code == 200:
42
+ text = response.text
43
+ cache.set(url, text, expire=86400)
44
+ return text
45
+ return None
46
+
47
+ async def get_docs_tree(self) -> list[str]:
48
+ """Gets a flat list of all Markdown documentation paths in the Flet repo."""
49
+ # The Tree API is the most efficient way to get all files in a repo at once
50
+ repo_api_url = "https://api.github.com/repos/flet-dev/flet/git/trees/main?recursive=1"
51
+ data = await self._fetch_json(repo_api_url)
52
+
53
+ if not data or "tree" not in data:
54
+ return []
55
+
56
+ # Filter out everything except markdown files in the docs folder
57
+ doc_paths = [
58
+ item["path"] for item in data["tree"]
59
+ if item["path"].startswith("website/docs/") and item["path"].endswith(".md")
60
+ ]
61
+ return doc_paths
62
+
63
+ async def get_doc_content(self, file_path: str) -> str:
64
+ """Fetches the raw Markdown content for a specific Flet doc file."""
65
+ # Use raw.githubusercontent for fast, quota-free raw file fetching
66
+ raw_url = f"https://raw.githubusercontent.com/flet-dev/flet/main/{file_path}"
67
+ content = await self._fetch_text(raw_url)
68
+
69
+ if content:
70
+ return content
71
+ return f"Error: Could not fetch documentation for {file_path}. Ensure the path is correct."
72
+
73
+ async def search_docs(self, query: str) -> list[str]:
74
+ """A keyword search over the available document paths."""
75
+ all_docs = await self.get_docs_tree()
76
+ query_lower = query.lower()
77
+
78
+ # Filter paths that contain the query string
79
+ # e.g., querying "dropdown" will match "docs/docs/controls/dropdown.md"
80
+ matches = [path for path in all_docs if query_lower in path.lower()]
81
+ return matches
82
+
83
+ async def list_flet_controls(self) -> list[str]:
84
+ """Returns a list of all available Flet UI controls."""
85
+ all_docs = await self.get_docs_tree()
86
+
87
+ # Filter only the files that live in the controls directory
88
+ controls = []
89
+ for path in all_docs:
90
+ if "website/docs/controls/" in path:
91
+ # Extract just the control name from the path (e.g., 'dropdown/index.md' -> 'dropdown')
92
+ parts = path.split("website/docs/controls/")
93
+ if len(parts) > 1:
94
+ clean_name = parts[1].split("/")[0].replace(".md", "")
95
+ if clean_name not in controls:
96
+ controls.append(clean_name)
97
+
98
+ return sorted(controls)
@@ -0,0 +1,131 @@
1
+ import os
2
+ import httpx
3
+ import diskcache
4
+
5
+ CACHE_DIR = os.path.expanduser("~/.cache/flet-mcp")
6
+ cache = diskcache.Cache(CACHE_DIR)
7
+
8
+ class FletPackageFetcher:
9
+ def __init__(self):
10
+ self.client = httpx.AsyncClient(timeout=15.0)
11
+ self.github_headers = {
12
+ "Accept": "application/vnd.github.v3+json",
13
+ "User-Agent": "Flet-MCP-Server/0.1.0"
14
+ }
15
+ if token := os.getenv("GITHUB_TOKEN"):
16
+ self.github_headers["Authorization"] = f"Bearer {token}"
17
+
18
+ _FALLBACK_OFFICIAL = [
19
+ "flet-ads", "flet-audio", "flet-audio-recorder", "flet-camera",
20
+ "flet-charts", "flet-code-editor", "flet-color-pickers", "flet-datatable2",
21
+ "flet-flashlight", "flet-geolocator", "flet-lottie", "flet-map",
22
+ "flet-permission-handler", "flet-rive", "flet-secure-storage",
23
+ "flet-video", "flet-webview"
24
+ ]
25
+
26
+ async def _fetch_json(self, url: str, headers: dict | None = None) -> dict | None:
27
+ if url in cache:
28
+ return cache[url]
29
+ try:
30
+ response = await self.client.get(url, headers=headers)
31
+ if response.status_code == 200:
32
+ data = response.json()
33
+ cache.set(url, data, expire=86400)
34
+ return data
35
+ except Exception:
36
+ pass
37
+ return None
38
+
39
+ async def list_official_packages(self) -> list[str]:
40
+ """Scrapes the Flet monorepo to find all official extensions."""
41
+ url = "https://api.github.com/repos/flet-dev/flet/git/trees/main?recursive=1"
42
+ data = await self._fetch_json(url, headers=self.github_headers)
43
+
44
+ if not data or "tree" not in data:
45
+ return self._FALLBACK_OFFICIAL
46
+
47
+ packages = []
48
+ for item in data["tree"]:
49
+ path = item["path"]
50
+ if path.startswith("sdk/python/packages/") and item["type"] == "tree":
51
+ parts = path.split("/")
52
+ if len(parts) == 4:
53
+ packages.append(parts[3])
54
+
55
+ return sorted(list(set(packages))) if packages else self._FALLBACK_OFFICIAL
56
+
57
+ async def _is_true_flet_package(self, package_name: str) -> bool:
58
+ """Verifies PyPI metadata to ensure the package actually depends on flet."""
59
+ url = f"https://pypi.org/pypi/{package_name}/json"
60
+ data = await self._fetch_json(url)
61
+
62
+ if not data or "info" not in data:
63
+ return False
64
+
65
+ requires_dist = data["info"].get("requires_dist")
66
+ if not requires_dist:
67
+ # Some packages might be Flet related but not strictly depend on 'flet' in metadata
68
+ # but for a 'strict' check we require it.
69
+ return False
70
+
71
+ for req in requires_dist:
72
+ # Clean up requirement string (e.g. 'flet (>=0.1.0) ; extra == "all"')
73
+ dep_name = req.split(";")[0].split(" ")[0].split(">")[0].split("=")[0].split("<")[0]
74
+ base_name = dep_name.split("[")[0].strip().lower()
75
+ if base_name == "flet":
76
+ return True
77
+ return False
78
+
79
+ async def search_flet_ecosystem(self, query: str) -> list[dict]:
80
+ """Searches GitHub for third-party Flet packages and verifies them."""
81
+ search_query = f"flet {query} language:python"
82
+ url = f"https://api.github.com/search/repositories?q={search_query}&sort=stars&order=desc&per_page=15"
83
+
84
+ data = await self._fetch_json(url, headers=self.github_headers)
85
+ if not data or "items" not in data:
86
+ return []
87
+
88
+ results = []
89
+ for item in data["items"]:
90
+ # Check if this GitHub repo is actually a published PyPI package depending on flet
91
+ repo_name = item["name"]
92
+ is_verified = await self._is_true_flet_package(repo_name)
93
+
94
+ results.append({
95
+ "name": repo_name,
96
+ "full_name": item["full_name"],
97
+ "description": item["description"],
98
+ "stars": item["stargazers_count"],
99
+ "url": item["html_url"],
100
+ "is_verified_flet_package": is_verified
101
+ })
102
+ return results
103
+
104
+ async def get_package_details(self, package_name: str) -> str:
105
+ """Fetches detailed package info and installation instructions from PyPI."""
106
+ url = f"https://pypi.org/pypi/{package_name}/json"
107
+ data = await self._fetch_json(url)
108
+
109
+ if not data or "info" not in data:
110
+ return f"Package '{package_name}' not found on PyPI."
111
+
112
+ info = data["info"]
113
+ version = info.get("version", "Unknown")
114
+ summary = info.get("summary", "No summary available.")
115
+
116
+ # Smart Classification
117
+ pkg_type = "Python Package"
118
+ summary_lower = summary.lower()
119
+ if "control" in summary_lower or "widget" in summary_lower or "ui" in summary_lower:
120
+ pkg_type = "UI Control"
121
+ elif "service" in summary_lower or "auth" in summary_lower or "database" in summary_lower:
122
+ pkg_type = "Service Integration"
123
+
124
+ details = (
125
+ f"Package: {package_name} (v{version})\n"
126
+ f"Type: {pkg_type}\n"
127
+ f"Summary: {summary}\n\n"
128
+ f"Installation:\n```bash\n"
129
+ f"uv add {package_name}\n```\n"
130
+ )
131
+ return details
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: flet-mcp-server
3
+ Version: 0.1.0
4
+ Summary: Auto-updating MCP server for Flet documentation and packages
5
+ Project-URL: Homepage, https://github.com/Nwokike/flet-mcp-server
6
+ Project-URL: Repository, https://github.com/Nwokike/flet-mcp-server
7
+ Project-URL: Issues, https://github.com/Nwokike/flet-mcp-server/issues
8
+ Author-email: Onyeka Nwokike <nwokikeonyeka@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,ai,documentation,flet,github-api,mcp
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: diskcache>=5.6.3
22
+ Requires-Dist: httpx>=0.28.1
23
+ Requires-Dist: mcp>=1.27.0
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest-asyncio>=1.3.0; extra == 'test'
26
+ Requires-Dist: pytest-cov>=7.1.0; extra == 'test'
27
+ Requires-Dist: pytest>=9.0.3; extra == 'test'
28
+ Requires-Dist: ruff>=0.15.12; extra == 'test'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # Flet MCP Server
32
+
33
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
34
+ [![Python: 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
35
+
36
+ An auto-updating Model Context Protocol (MCP) server that dynamically fetches, caches, and serves the official Flet documentation and ecosystem packages directly from GitHub and PyPI.
37
+
38
+ ## Features
39
+
40
+ * **GitHub Tree Sync**: Maps documentation in real-time.
41
+ * **Intelligent Caching**: Uses `diskcache` for fast responses.
42
+ * **Ecosystem Discovery**: Finds and verifies official and community Flet packages.
43
+ * **AI-Optimized**: Tool definitions designed for LLM understanding.
44
+
45
+ ## Tools Included
46
+
47
+ ### 1. `list_flet_controls`
48
+ List all available Flet UI controls.
49
+
50
+ ### 2. `search_flet_docs(query)`
51
+ Search the documentation index.
52
+
53
+ ### 3. `get_flet_doc(doc_path)`
54
+ Get raw Markdown for a specific doc.
55
+
56
+ ### 4. `list_official_packages()`
57
+ List official Flet extension packages.
58
+
59
+ ### 5. `search_flet_ecosystem(query)`
60
+ Search for verified community Flet components.
61
+
62
+ ### 6. `get_package_details(package_name)`
63
+ Fetch version and installation info from PyPI.
64
+
65
+ ## Client Configuration Examples
66
+
67
+ ### 🌌 Antigravity / Cascade
68
+ Add this to your `mcp_config.json`:
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "flet-mcp-server": {
74
+ "command": "uvx",
75
+ "args": ["flet-mcp-server"]
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### 🤖 Claude Desktop
82
+ Add this to your `claude_desktop_config.json`:
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "flet-mcp-server": {
88
+ "command": "uvx",
89
+ "args": ["flet-mcp-server"]
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ### 💻 Cursor / Windsurf
96
+ In your IDE's MCP settings, add a new server:
97
+ - **Name**: Flet MCP
98
+ - **Type**: Command
99
+ - **Command**: `uvx flet-mcp-server`
100
+
101
+ ## Development
102
+
103
+ ### Install
104
+ ```bash
105
+ git clone https://github.com/Nwokike/flet-mcp-server.git
106
+ cd flet-mcp-server
107
+ uv sync
108
+ ```
109
+
110
+ ### Test
111
+ ```bash
112
+ uv run pytest
113
+ ```
114
+
115
+ ## License
116
+ MIT
@@ -0,0 +1,11 @@
1
+ flet_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ flet_mcp/main.py,sha256=DyPZy9vB9RMrl0_ft8W2b2u9kexli_aOwQmG86l3QL4,320
3
+ flet_mcp/server.py,sha256=YqvocNPUm3jMnBf7H_IP8yv7bKOMdqbnWnBlpF3Oea0,2485
4
+ flet_mcp/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ flet_mcp/services/github_docs.py,sha256=XfhssrS7HWL-w13uPK2L69TiqKxUeFufrYrtrB5p9qI,4043
6
+ flet_mcp/services/packages.py,sha256=jS3uXzJ6-Tjrh8ZKH5-e6Wn-g_qa9VWPGBF1DAkELNI,5338
7
+ flet_mcp_server-0.1.0.dist-info/METADATA,sha256=L9Fda4GoB6j3-aZqI_L2cFAdRF40LxfKtui9uFhOOC4,3203
8
+ flet_mcp_server-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
9
+ flet_mcp_server-0.1.0.dist-info/entry_points.txt,sha256=GvbVY1sP95qcsikhGlsXfEKcnJbqm0BNJLgjdeYUoHE,61
10
+ flet_mcp_server-0.1.0.dist-info/licenses/LICENSE,sha256=0nUZjabbuM34H2XHsAfhYFnhNF4baiGt9ufHQWfIvP4,1071
11
+ flet_mcp_server-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ flet-mcp-server = flet_mcp.main:run_server
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Onyeka Nwokike
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.