arch-ops-server 3.0.1__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.
@@ -0,0 +1,245 @@
1
+ # SPDX-License-Identifier: GPL-3.0-only OR MIT
2
+ """
3
+ Arch Wiki interface module.
4
+ Provides search and page retrieval via MediaWiki API with BeautifulSoup fallback.
5
+ """
6
+
7
+ import logging
8
+ from typing import List, Dict, Any, Optional
9
+ import httpx
10
+ from bs4 import BeautifulSoup
11
+ from markdownify import markdownify as md
12
+
13
+ from .utils import create_error_response
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Arch Wiki API endpoint
18
+ WIKI_API_URL = "https://wiki.archlinux.org/api.php"
19
+ WIKI_BASE_URL = "https://wiki.archlinux.org"
20
+
21
+ # HTTP client settings
22
+ DEFAULT_TIMEOUT = 10.0
23
+
24
+
25
+ async def search_wiki(query: str, limit: int = 10) -> Dict[str, Any]:
26
+ """
27
+ Search the Arch Wiki using MediaWiki API.
28
+
29
+ Uses the opensearch action which returns suggestions.
30
+
31
+ Args:
32
+ query: Search term
33
+ limit: Maximum number of results (default: 10)
34
+
35
+ Returns:
36
+ Dict containing search results with titles, snippets, and URLs
37
+ """
38
+ logger.info(f"Searching Arch Wiki for: {query}")
39
+
40
+ params = {
41
+ "action": "opensearch",
42
+ "search": query,
43
+ "limit": limit,
44
+ "namespace": "0", # Main namespace only
45
+ "format": "json"
46
+ }
47
+
48
+ try:
49
+ async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
50
+ response = await client.get(WIKI_API_URL, params=params)
51
+ response.raise_for_status()
52
+
53
+ data = response.json()
54
+
55
+ # OpenSearch returns: [query, [titles], [descriptions], [urls]]
56
+ if len(data) >= 4:
57
+ titles = data[1]
58
+ descriptions = data[2]
59
+ urls = data[3]
60
+
61
+ results = [
62
+ {
63
+ "title": title,
64
+ "snippet": desc,
65
+ "url": url
66
+ }
67
+ for title, desc, url in zip(titles, descriptions, urls)
68
+ ]
69
+
70
+ logger.info(f"Found {len(results)} results for '{query}'")
71
+
72
+ return {
73
+ "query": query,
74
+ "count": len(results),
75
+ "results": results
76
+ }
77
+ else:
78
+ return {
79
+ "query": query,
80
+ "count": 0,
81
+ "results": []
82
+ }
83
+
84
+ except httpx.TimeoutException:
85
+ logger.error(f"Wiki search timed out for query: {query}")
86
+ return create_error_response(
87
+ "TimeoutError",
88
+ f"Arch Wiki search timed out for query: {query}",
89
+ "The Wiki server did not respond in time. Try again later."
90
+ )
91
+ except httpx.HTTPStatusError as e:
92
+ logger.error(f"Wiki search HTTP error: {e}")
93
+ return create_error_response(
94
+ "HTTPError",
95
+ f"Wiki search failed with status {e.response.status_code}",
96
+ str(e)
97
+ )
98
+ except Exception as e:
99
+ logger.error(f"Wiki search failed: {e}")
100
+ return create_error_response(
101
+ "SearchError",
102
+ f"Failed to search Arch Wiki: {str(e)}"
103
+ )
104
+
105
+
106
+ async def get_wiki_page(title: str, as_markdown: bool = True) -> str:
107
+ """
108
+ Fetch a Wiki page using MediaWiki API, with scraping fallback.
109
+
110
+ Args:
111
+ title: Page title (e.g., "Installation_guide")
112
+ as_markdown: Convert HTML to Markdown (default: True)
113
+
114
+ Returns:
115
+ Page content as Markdown or HTML string
116
+ """
117
+ logger.info(f"Fetching Wiki page: {title}")
118
+
119
+ # Try MediaWiki API first
120
+ content = await _fetch_via_api(title)
121
+
122
+ # Fallback to scraping if API fails
123
+ if content is None:
124
+ logger.warning(f"API fetch failed for {title}, falling back to scraping")
125
+ content = await _fetch_via_scraping(title)
126
+
127
+ if content is None:
128
+ error_msg = f"Page '{title}' not found or could not be retrieved"
129
+ logger.error(error_msg)
130
+ raise ValueError(error_msg)
131
+
132
+ # Convert to Markdown if requested
133
+ if as_markdown and content:
134
+ try:
135
+ content = md(content, heading_style="ATX", strip=['script', 'style'])
136
+ except Exception as e:
137
+ logger.warning(f"Markdown conversion failed: {e}, returning HTML")
138
+
139
+ return content
140
+
141
+
142
+ async def _fetch_via_api(title: str) -> Optional[str]:
143
+ """
144
+ Fetch page content via MediaWiki API.
145
+
146
+ Args:
147
+ title: Page title
148
+
149
+ Returns:
150
+ HTML content or None if failed
151
+ """
152
+ params = {
153
+ "action": "parse",
154
+ "page": title,
155
+ "format": "json",
156
+ "prop": "text",
157
+ "disableeditsection": "1",
158
+ "disabletoc": "1"
159
+ }
160
+
161
+ try:
162
+ async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
163
+ response = await client.get(WIKI_API_URL, params=params)
164
+ response.raise_for_status()
165
+
166
+ data = response.json()
167
+
168
+ # Check for errors in response
169
+ if "error" in data:
170
+ logger.warning(f"API error: {data['error'].get('info', 'Unknown error')}")
171
+ return None
172
+
173
+ # Extract HTML content
174
+ if "parse" in data and "text" in data["parse"]:
175
+ html_content = data["parse"]["text"]["*"]
176
+ logger.info(f"Successfully fetched {title} via API")
177
+ return html_content
178
+
179
+ return None
180
+
181
+ except Exception as e:
182
+ logger.warning(f"API fetch failed for {title}: {e}")
183
+ return None
184
+
185
+
186
+ async def _fetch_via_scraping(title: str) -> Optional[str]:
187
+ """
188
+ Fetch page content via direct HTTP scraping (fallback).
189
+
190
+ Args:
191
+ title: Page title
192
+
193
+ Returns:
194
+ HTML content or None if failed
195
+ """
196
+ # Construct URL
197
+ url = f"{WIKI_BASE_URL}/title/{title}"
198
+
199
+ try:
200
+ async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
201
+ response = await client.get(url, follow_redirects=True)
202
+ response.raise_for_status()
203
+
204
+ # Parse HTML
205
+ soup = BeautifulSoup(response.text, 'lxml')
206
+
207
+ # Find main content div
208
+ content_div = soup.find('div', {'id': 'bodyContent'})
209
+
210
+ if content_div:
211
+ # Remove unnecessary elements
212
+ for element in content_div.find_all(['script', 'style', 'nav']):
213
+ element.decompose()
214
+
215
+ logger.info(f"Successfully scraped {title}")
216
+ return str(content_div)
217
+
218
+ return None
219
+
220
+ except httpx.HTTPStatusError as e:
221
+ if e.response.status_code == 404:
222
+ logger.error(f"Page not found: {title}")
223
+ else:
224
+ logger.error(f"HTTP error scraping {title}: {e}")
225
+ return None
226
+ except Exception as e:
227
+ logger.error(f"Scraping failed for {title}: {e}")
228
+ return None
229
+
230
+
231
+ async def get_wiki_page_as_text(title: str) -> str:
232
+ """
233
+ Convenience wrapper to get Wiki page as clean Markdown text.
234
+
235
+ Args:
236
+ title: Page title
237
+
238
+ Returns:
239
+ Markdown content
240
+
241
+ Raises:
242
+ ValueError: If page cannot be retrieved
243
+ """
244
+ return await get_wiki_page(title, as_markdown=True)
245
+
@@ -0,0 +1,253 @@
1
+ Metadata-Version: 2.3
2
+ Name: arch-ops-server
3
+ Version: 3.0.1
4
+ Summary: MCP server bridging AI assistants with Arch Linux ecosystem (Wiki, AUR, official repos)
5
+ Keywords: arch-linux,mcp,model-context-protocol,aur,pacman,wiki,ai-assistant
6
+ Author: Nihal
7
+ Author-email: Nihal <2tv8xupqg@mozmail.com>
8
+ License: GPL-3.0-only OR MIT
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: System :: Archiving :: Packaging
19
+ Classifier: Topic :: System :: Systems Administration
20
+ Requires-Dist: mcp>=1.0.0
21
+ Requires-Dist: httpx>=0.27.0
22
+ Requires-Dist: beautifulsoup4>=4.12.0
23
+ Requires-Dist: lxml>=5.0.0
24
+ Requires-Dist: markdownify>=0.12.0
25
+ Requires-Dist: pytest>=8.0.0 ; extra == 'dev'
26
+ Requires-Dist: pytest-asyncio>=0.23.0 ; extra == 'dev'
27
+ Requires-Dist: pytest-cov>=4.1.0 ; extra == 'dev'
28
+ Requires-Dist: pytest-mock>=3.12.0 ; extra == 'dev'
29
+ Requires-Dist: httpx>=0.27.0 ; extra == 'dev'
30
+ Requires-Dist: starlette>=0.27.0 ; extra == 'http'
31
+ Requires-Dist: uvicorn[standard]>=0.23.0 ; extra == 'http'
32
+ Requires-Python: >=3.11
33
+ Provides-Extra: dev
34
+ Provides-Extra: http
35
+ Description-Content-Type: text/markdown
36
+
37
+ # Arch Linux MCP Server
38
+
39
+ <a href="https://glama.ai/mcp/servers/@nihalxkumar/arch-mcp">
40
+ <img width="380" height="200" src="https://glama.ai/mcp/servers/@nihalxkumar/arch-mcp/badge" />
41
+ </a>
42
+
43
+ **Disclaimer:** Unofficial community project, not affiliated with Arch Linux.
44
+
45
+ A [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that bridges AI assistants with the Arch Linux ecosystem. Enables intelligent, safe, and efficient access to the Arch Wiki, AUR, and official repositories for AI-assisted Arch Linux usage on Arch and non-Arch systems.
46
+
47
+ Leverage AI to get output for digestible, structured results that are ready for follow up questions and actions.
48
+
49
+ 📖 [Complete Documentation with Comfy Guides](https://nxk.mintlify.app/arch-mcp)
50
+
51
+ ## Sneak Peak into what's available
52
+
53
+ <details open>
54
+ <summary>Claude Desktop (no terminal)</summary>
55
+
56
+ ![Claude Desktop Demo](assets/claudedesktop_signalcli.gif)
57
+
58
+ </details>
59
+
60
+ <details>
61
+ <summary>VS Code (with terminal)</summary>
62
+
63
+ ![VS Code Demo](assets/vscode_notesnook.gif)
64
+
65
+ </details>
66
+
67
+ ### Resources (URI-based Access)
68
+
69
+ Direct access to Arch ecosystem data via custom URI schemes:
70
+
71
+ #### Documentation & Search
72
+ | URI Scheme | Example | Returns |
73
+ |------------|---------|---------|
74
+ | `archwiki://` | `archwiki://Installation_guide` | Markdown-formatted Wiki page |
75
+
76
+ #### Package Information
77
+ | URI Scheme | Example | Returns |
78
+ |------------|---------|---------|
79
+ | `archrepo://` | `archrepo://vim` | Official repository package details |
80
+ | `aur://*/info` | `aur://yay/info` | AUR package metadata (votes, maintainer, dates) |
81
+ | `aur://*/pkgbuild` | `aur://yay/pkgbuild` | Raw PKGBUILD with safety analysis |
82
+
83
+ #### System Packages (Arch only)
84
+ | URI Scheme | Example | Returns |
85
+ |------------|---------|---------|
86
+ | `pacman://installed` | `pacman://installed` | System installed packages list |
87
+ | `pacman://orphans` | `pacman://orphans` | Orphaned packages |
88
+ | `pacman://explicit` | `pacman://explicit` | Explicitly installed packages |
89
+ | `pacman://groups` | `pacman://groups` | All package groups |
90
+ | `pacman://group/*` | `pacman://group/base-devel` | Packages in specific group |
91
+ | `pacman://database/freshness` | `pacman://database/freshness` | Package database sync status |
92
+
93
+ #### System Monitoring & Logs
94
+ | URI Scheme | Example | Returns |
95
+ |------------|---------|---------|
96
+ | `system://info` | `system://info` | System information (kernel, memory, uptime) |
97
+ | `system://disk` | `system://disk` | Disk space usage statistics |
98
+ | `system://services/failed` | `system://services/failed` | Failed systemd services |
99
+ | `system://logs/boot` | `system://logs/boot` | Recent boot logs |
100
+ | `pacman://log/recent` | `pacman://log/recent` | Recent package transactions |
101
+ | `pacman://log/failed` | `pacman://log/failed` | Failed package transactions |
102
+
103
+ #### News & Updates
104
+ | URI Scheme | Example | Returns |
105
+ |------------|---------|---------|
106
+ | `archnews://latest` | `archnews://latest` | Latest Arch Linux news |
107
+ | `archnews://critical` | `archnews://critical` | Critical news requiring manual intervention |
108
+ | `archnews://since-update` | `archnews://since-update` | News since last system update |
109
+
110
+ #### Configuration
111
+ | URI Scheme | Example | Returns |
112
+ |------------|---------|---------|
113
+ | `config://pacman` | `config://pacman` | Parsed pacman.conf configuration |
114
+ | `config://makepkg` | `config://makepkg` | Parsed makepkg.conf configuration |
115
+ | `mirrors://active` | `mirrors://active` | Currently configured mirrors |
116
+ | `mirrors://health` | `mirrors://health` | Mirror configuration health status |
117
+
118
+ ### Tools (Executable Functions)
119
+
120
+ #### Package Search & Information
121
+ | Tool | Description | Platform |
122
+ |------|-------------|----------|
123
+ | `search_archwiki` | Query Arch Wiki with ranked results | Any |
124
+ | `search_aur` | Search AUR (relevance/votes/popularity/modified) | Any |
125
+ | `get_official_package_info` | Get official package details (hybrid local/remote) | Any |
126
+
127
+ #### Package Lifecycle Management
128
+ | Tool | Description | Platform |
129
+ |------|-------------|----------|
130
+ | `check_updates_dry_run` | Check for available updates | Arch only |
131
+ | `install_package_secure` | Install with security checks (blocks malicious packages) | Arch only |
132
+ | `remove_package` | Remove single package (with deps, forced) | Arch only |
133
+ | `remove_packages_batch` | Remove multiple packages efficiently | Arch only |
134
+
135
+ #### Package Analysis & Maintenance
136
+ | Tool | Description | Platform |
137
+ |------|-------------|----------|
138
+ | `list_orphan_packages` | Find orphaned packages | Arch only |
139
+ | `remove_orphans` | Clean orphans (dry-run, exclusions) | Arch only |
140
+ | `verify_package_integrity` | Check file integrity (modified/missing files) | Arch only |
141
+ | `list_explicit_packages` | List user-installed packages | Arch only |
142
+ | `mark_as_explicit` | Prevent package from being orphaned | Arch only |
143
+ | `mark_as_dependency` | Allow package to be orphaned | Arch only |
144
+
145
+ #### Package Organization
146
+ | Tool | Description | Platform |
147
+ |------|-------------|----------|
148
+ | `find_package_owner` | Find which package owns a file | Arch only |
149
+ | `list_package_files` | List files in package (regex filtering) | Arch only |
150
+ | `search_package_files` | Search files across packages | Arch only |
151
+ | `list_package_groups` | List all groups (base, base-devel, etc.) | Arch only |
152
+ | `list_group_packages` | Show packages in specific group | Arch only |
153
+
154
+ #### System Monitoring & Diagnostics
155
+ | Tool | Description | Platform |
156
+ |------|-------------|----------|
157
+ | `get_system_info` | System info (kernel, memory, uptime) | Any |
158
+ | `check_disk_space` | Disk usage with warnings | Any |
159
+ | `get_pacman_cache_stats` | Package cache size and age | Arch only |
160
+ | `check_failed_services` | Find failed systemd services | systemd |
161
+ | `get_boot_logs` | Retrieve journalctl boot logs | systemd |
162
+ | `check_database_freshness` | Check package database sync status | Arch only |
163
+
164
+ #### Transaction History & Logs
165
+ | Tool | Description | Platform |
166
+ |------|-------------|----------|
167
+ | `get_transaction_history` | Recent package transactions (install/upgrade/remove) | Arch only |
168
+ | `find_when_installed` | Package installation history | Arch only |
169
+ | `find_failed_transactions` | Failed package operations | Arch only |
170
+ | `get_database_sync_history` | Database sync events | Arch only |
171
+
172
+ #### News & Safety Checks
173
+ | Tool | Description | Platform |
174
+ |------|-------------|----------|
175
+ | `get_latest_news` | Fetch Arch Linux news from RSS | Any |
176
+ | `check_critical_news` | Find critical news (manual intervention required) | Any |
177
+ | `get_news_since_last_update` | News posted since last system update | Arch only |
178
+
179
+ #### Mirror Management
180
+ | Tool | Description | Platform |
181
+ |------|-------------|----------|
182
+ | `list_active_mirrors` | Show configured mirrors | Arch only |
183
+ | `test_mirror_speed` | Test mirror latency | Arch only |
184
+ | `suggest_fastest_mirrors` | Recommend optimal mirrors by location | Any |
185
+ | `check_mirrorlist_health` | Verify mirror configuration | Arch only |
186
+
187
+ #### Configuration Management
188
+ | Tool | Description | Platform |
189
+ |------|-------------|----------|
190
+ | `analyze_pacman_conf` | Parse pacman.conf settings | Arch only |
191
+ | `analyze_makepkg_conf` | Parse makepkg.conf settings | Arch only |
192
+ | `check_ignored_packages` | List ignored packages (warns on critical) | Arch only |
193
+ | `get_parallel_downloads_setting` | Get parallel download config | Arch only |
194
+
195
+ #### Security Analysis
196
+ | Tool | Description | Platform |
197
+ |------|-------------|----------|
198
+ | `analyze_pkgbuild_safety` | Comprehensive PKGBUILD analysis (50+ red flags) | Any |
199
+ | `analyze_package_metadata_risk` | Package trust scoring (votes, maintainer, age) | Any |
200
+
201
+ ### Prompts (Guided Workflows)
202
+
203
+ | Prompt | Purpose | Workflow |
204
+ |--------|---------|----------|
205
+ | `troubleshoot_issue` | Diagnose system errors | Extract keywords → Search Wiki → Context-aware suggestions |
206
+ | `audit_aur_package` | Pre-installation safety audit | Fetch metadata → Analyze PKGBUILD → Security recommendations |
207
+ | `analyze_dependencies` | Installation planning | Check repos → Map dependencies → Suggest install order |
208
+ | `safe_system_update` | Safe update workflow | Check critical news → Verify disk space → List updates → Check services → Recommendations |
209
+
210
+ ---
211
+
212
+ ## Installation
213
+
214
+ ### Prerequisites
215
+ - Python 3.11+
216
+ - [uv](https://github.com/astral-sh/uv) (recommended) or pip
217
+
218
+ ### Quick Install with `uvx`
219
+
220
+ ```bash
221
+ uvx arch-ops-server
222
+ ```
223
+ ---
224
+
225
+ ## Configuration
226
+
227
+ Claude / Cursor / Any MCP client that supports STDIO transport
228
+
229
+ ```json
230
+ {
231
+ "mcpServers": {
232
+ "arch-ops": {
233
+ "command": "uvx",
234
+ "args": ["arch-ops-server"]
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ ## Contributing
241
+
242
+ Contributions are greatly appreciated. Please feel free to submit a pull request or open an issue and help make things better for everyone.
243
+
244
+ [Contributing Guide](https://nxk.mintlify.app/arch-mcp/contributing)
245
+
246
+ ## License
247
+
248
+ This project is dual-licensed under your choice of:
249
+
250
+ - **[GPL-3.0-only](https://www.gnu.org/licenses/gpl-3.0.en.html)** - See [LICENSE-GPL](LICENSE-GPL)
251
+ - **[MIT License](https://opensource.org/licenses/MIT)** - See [LICENSE-MIT](LICENSE-MIT)
252
+
253
+ You may use this software under the terms of either license. See [LICENSE](LICENSE) for more details.
@@ -0,0 +1,17 @@
1
+ arch_ops_server/__init__.py,sha256=Dn-V4Ig5xLC7BlgFeqb28mLFciBzrga3b5CYoXyYNyU,4255
2
+ arch_ops_server/aur.py,sha256=poYbh2DW7I1tZfCeNp_7e10fh9ZZx8HTnYZnKKZtflQ,49808
3
+ arch_ops_server/config.py,sha256=4mtpS28vXSMeEVGrTWTMwZEzgIyfl0oCAYEzF7SKxE8,11076
4
+ arch_ops_server/http_server.py,sha256=wZ3hY6o6EftbN1OZiTUau7861LB9ihKWap6gevev_No,31810
5
+ arch_ops_server/logs.py,sha256=qWExDvluHmQvbZHu87veQxMnuMK8BNLBYBppZJlemEc,10558
6
+ arch_ops_server/mirrors.py,sha256=Evt-g20cMOTZQl9FbbkbklFd0gKWz-I7vVNrmyQO19U,13403
7
+ arch_ops_server/news.py,sha256=E97eASR24tq_EaVDYuamIoBl4a7QtBkpscOaUPuU0W4,9359
8
+ arch_ops_server/pacman.py,sha256=S1Gc53CA6o4--YavA03EkxL0dGCZNhoFFZjawlW_p20,38354
9
+ arch_ops_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ arch_ops_server/server.py,sha256=9t8KMZmy6MtQQXk7BwTz6oQNj3xwOGbINmDdxS2R-1M,72661
11
+ arch_ops_server/system.py,sha256=JfBUB3KD0veulQ-IIK8IOC8Jn6lqtLMCtlnryiL1n7w,9221
12
+ arch_ops_server/utils.py,sha256=po7MVqCx-hsdx-lOgs7uGicjoUVMf6HvuNNYl2qyFH0,10112
13
+ arch_ops_server/wiki.py,sha256=XB_emMGXYF3Vn5likRICkGOa72YDZvOhtZBgp_d1gg8,7350
14
+ arch_ops_server-3.0.1.dist-info/WHEEL,sha256=DpNsHFUm_gffZe1FgzmqwuqiuPC6Y-uBCzibcJcdupM,78
15
+ arch_ops_server-3.0.1.dist-info/entry_points.txt,sha256=ZS2crFEqE9TteC4j2HmYS1wKvoBOCCXT2FJXJW5C4-E,117
16
+ arch_ops_server-3.0.1.dist-info/METADATA,sha256=fJURCaEYIOf7UlridiAeEkz8HRd31LrkNMnu3hM7XLg,10712
17
+ arch_ops_server-3.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.8
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ arch-ops-server = arch_ops_server:main_sync
3
+ arch-ops-server-http = arch_ops_server:main_http_sync
4
+