linux-mcp-server 1.3.1__tar.gz → 1.3.2__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.
- linux_mcp_server-1.3.2/.github/workflows/build-publish.yml +178 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.gitignore +1 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/pipeline-build-multiarch.yaml +6 -6
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/push.yaml +0 -1
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/Makefile +10 -1
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/PKG-INFO +1 -1
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/install.md +25 -7
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/pyproject.toml +2 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/connection/ssh.py +0 -1
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/formatters.py +0 -56
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/models.py +14 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/logs.py +20 -14
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_formatters.py +0 -55
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_logs.py +71 -69
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/uv.lock +34 -0
- linux_mcp_server-1.3.1/.github/workflows/build-publish.yml +0 -94
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.codecov.yml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.coderabbit.yaml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.devcontainer/Containerfile +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.devcontainer/devcontainer.json +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/ci.yml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/ci_installation.yaml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/docs.yml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/functional-tests.yml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/pull_request.yaml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/task-get-version.yaml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/AGENTS.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/Containerfile +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/LICENSE +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/README.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/audit.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/commands.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/config.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/connection.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/formatters.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/index.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/parsers.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/server.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/logs.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/network.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/processes.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/services.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/storage.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/system_info.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/architecture.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/cheatsheet.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/clients.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/contributing.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/debugging.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/examples/claude_desktop_config.example.json +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/examples/example_config.sh +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/getting-started.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/index.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/troubleshooting.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/usage.md +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/licenses/GPL-3.0.txt +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/mkdocs.yml +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/renovate.json +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/scripts/publish_mcp_registry.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/scripts/verify_installation.sh +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/server.json +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/__main__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/_vendor/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/audit.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/commands.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/config.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/connection/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/logging_config.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/parsers.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/server.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/network.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/processes.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/services.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/storage.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/system_info.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/decorators.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/enum.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/format.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/types.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/validation.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/_vendor/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/_vendor/test_vendor.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/cli/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/cli/test_cli.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/conftest.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_connection_manager.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_discover_ssh_key.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_execute_command.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_get_bin_path.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_host_key_verification.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_timeout.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_cpu_info.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_free_output.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_ip_brief.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_listing.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_os_release.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_proc.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_ps_output.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_service_count.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_ss.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_system_info.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test__main__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_audit.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_commands.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_config.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_logging_config.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_server.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_tool_schemas.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/conftest.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_list_block_devices.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_list_directories.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_list_files.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_path_validation.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_read_file.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_network.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_processes.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_services.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_system_info.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/__init__.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/test_decorators.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/test_enum.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/test_format.py +0 -0
- {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/test_validation.py +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
name: Build and publish
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- '*'
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: Build sdist and wheel
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@v6.0.2
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
|
|
21
|
+
- name: Show environment
|
|
22
|
+
run: |
|
|
23
|
+
set -x
|
|
24
|
+
python -VV
|
|
25
|
+
python -m site
|
|
26
|
+
ls -ld $(python -c "import site; print(site.getsitepackages()[0])")
|
|
27
|
+
git tag --list --sort=-refname --format='%(refname:short) %(objectname:short)'
|
|
28
|
+
whoami
|
|
29
|
+
|
|
30
|
+
- name: Install build tools
|
|
31
|
+
run: |
|
|
32
|
+
python -m pip install --upgrade pip
|
|
33
|
+
python -m pip install build
|
|
34
|
+
|
|
35
|
+
- name: Build
|
|
36
|
+
run: python -m build --sdist --wheel
|
|
37
|
+
|
|
38
|
+
- name: Upload artifacts
|
|
39
|
+
uses: actions/upload-artifact@v6.0.0
|
|
40
|
+
with:
|
|
41
|
+
name: artifacts
|
|
42
|
+
path: dist
|
|
43
|
+
if-no-files-found: error
|
|
44
|
+
|
|
45
|
+
publish-pypi:
|
|
46
|
+
name: Publish to PyPI
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
needs:
|
|
49
|
+
- build
|
|
50
|
+
|
|
51
|
+
environment:
|
|
52
|
+
name: pypi
|
|
53
|
+
url: https://pypi.org/p/linux-mcp-server
|
|
54
|
+
|
|
55
|
+
permissions:
|
|
56
|
+
id-token: write
|
|
57
|
+
|
|
58
|
+
steps:
|
|
59
|
+
- name: Download artifacts
|
|
60
|
+
uses: actions/download-artifact@v7.0.0
|
|
61
|
+
with:
|
|
62
|
+
name: artifacts
|
|
63
|
+
path: dist
|
|
64
|
+
|
|
65
|
+
- name: Show environment
|
|
66
|
+
run: |
|
|
67
|
+
set -x
|
|
68
|
+
python -VV
|
|
69
|
+
python -m site
|
|
70
|
+
ls -ld $(python -c "import site; print(site.getsitepackages()[0])")
|
|
71
|
+
ls -l dist/
|
|
72
|
+
whoami
|
|
73
|
+
|
|
74
|
+
- name: Publish to PyPI
|
|
75
|
+
uses: pypa/gh-action-pypi-publish@v1.13.0
|
|
76
|
+
|
|
77
|
+
publish-mcp:
|
|
78
|
+
name: Publish to MCP registry
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
needs:
|
|
81
|
+
- publish-pypi
|
|
82
|
+
|
|
83
|
+
environment:
|
|
84
|
+
name: mcp
|
|
85
|
+
|
|
86
|
+
permissions:
|
|
87
|
+
id-token: write
|
|
88
|
+
|
|
89
|
+
steps:
|
|
90
|
+
- name: Checkout
|
|
91
|
+
uses: actions/checkout@v6.0.2
|
|
92
|
+
|
|
93
|
+
- name: Publish to MCP Registry
|
|
94
|
+
run: ./scripts/publish_mcp_registry.py
|
|
95
|
+
|
|
96
|
+
create-release:
|
|
97
|
+
name: Create GitHub Release
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
|
|
100
|
+
permissions:
|
|
101
|
+
contents: write
|
|
102
|
+
|
|
103
|
+
steps:
|
|
104
|
+
- name: Create GitHub Release
|
|
105
|
+
uses: softprops/action-gh-release@v2.5.0
|
|
106
|
+
with:
|
|
107
|
+
tag_name: ${{ github.ref_name }}
|
|
108
|
+
generate_release_notes: true
|
|
109
|
+
|
|
110
|
+
zipapp:
|
|
111
|
+
name: Zipapp - ${{ matrix.python-version }} ${{ matrix.image.family }} ${{ matrix.image.arch }}
|
|
112
|
+
runs-on: ${{ matrix.image.name }}
|
|
113
|
+
needs:
|
|
114
|
+
- create-release
|
|
115
|
+
|
|
116
|
+
strategy:
|
|
117
|
+
fail-fast: false
|
|
118
|
+
matrix:
|
|
119
|
+
python-version:
|
|
120
|
+
- "3.10"
|
|
121
|
+
- "3.11"
|
|
122
|
+
- "3.12"
|
|
123
|
+
- "3.13"
|
|
124
|
+
- "3.14"
|
|
125
|
+
- "3.14t"
|
|
126
|
+
|
|
127
|
+
image:
|
|
128
|
+
- name: ubuntu-24.04
|
|
129
|
+
family: linux
|
|
130
|
+
arch: amd64
|
|
131
|
+
|
|
132
|
+
- name: ubuntu-24.04-arm
|
|
133
|
+
family: linux
|
|
134
|
+
arch: arm64
|
|
135
|
+
|
|
136
|
+
- name: macos-15-intel
|
|
137
|
+
family: macos
|
|
138
|
+
arch: amd64
|
|
139
|
+
|
|
140
|
+
- name: macos-26
|
|
141
|
+
family: macos
|
|
142
|
+
arch: arm64
|
|
143
|
+
|
|
144
|
+
- name: windows-2025
|
|
145
|
+
family: windows
|
|
146
|
+
arch: amd64
|
|
147
|
+
|
|
148
|
+
exclude:
|
|
149
|
+
- python-version: "3.14t"
|
|
150
|
+
image:
|
|
151
|
+
name: windows-2025
|
|
152
|
+
|
|
153
|
+
permissions:
|
|
154
|
+
contents: write
|
|
155
|
+
|
|
156
|
+
steps:
|
|
157
|
+
- name: Checkout
|
|
158
|
+
uses: actions/checkout@v6.0.2
|
|
159
|
+
with:
|
|
160
|
+
ref: ${{ github.ref_name }}
|
|
161
|
+
fetch-depth: 0
|
|
162
|
+
|
|
163
|
+
- name: Install Python
|
|
164
|
+
uses: actions/setup-python@v6.2.0
|
|
165
|
+
with:
|
|
166
|
+
python-version: ${{ matrix.python-version }}
|
|
167
|
+
|
|
168
|
+
- name: Install uv
|
|
169
|
+
uses: astral-sh/setup-uv@v7.3.0
|
|
170
|
+
|
|
171
|
+
- name: Build zipapp
|
|
172
|
+
run: make zipapp ZIPAPP_OUTPUT=linux-mcp-server-py${{ matrix.python-version }}-${{ matrix.image.family }}-${{ matrix.image.arch }}.pyz
|
|
173
|
+
|
|
174
|
+
- name: Upload to GitHub Release
|
|
175
|
+
uses: softprops/action-gh-release@v2.5.0
|
|
176
|
+
with:
|
|
177
|
+
files: linux-mcp-server-py${{ matrix.python-version }}-${{ matrix.image.family }}-${{ matrix.image.arch }}.pyz
|
|
178
|
+
tag_name: ${{ github.ref_name }}
|
|
@@ -187,7 +187,7 @@ spec:
|
|
|
187
187
|
value: prefetch-dependencies-oci-ta
|
|
188
188
|
|
|
189
189
|
- name: bundle
|
|
190
|
-
value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.2@sha256:
|
|
190
|
+
value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.2@sha256:c07551efbd7fc414ae1245ddd93579b00317fee0734980f539fd8aea3cfcb945
|
|
191
191
|
|
|
192
192
|
- name: kind
|
|
193
193
|
value: task
|
|
@@ -275,7 +275,7 @@ spec:
|
|
|
275
275
|
value: buildah-remote-oci-ta
|
|
276
276
|
|
|
277
277
|
- name: bundle
|
|
278
|
-
value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.8@sha256:
|
|
278
|
+
value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.8@sha256:4c6e3e4c3fe8a289161dfbc38a162d28a0289eb4d51f835e847f8c3677a211f3
|
|
279
279
|
|
|
280
280
|
- name: kind
|
|
281
281
|
value: task
|
|
@@ -313,7 +313,7 @@ spec:
|
|
|
313
313
|
value: build-image-index
|
|
314
314
|
|
|
315
315
|
- name: bundle
|
|
316
|
-
value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.2@sha256:
|
|
316
|
+
value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.2@sha256:30989fa1f475bb8f6bda811b26bd4ddf7187288ed5815ce634ba399341852c75
|
|
317
317
|
|
|
318
318
|
- name: kind
|
|
319
319
|
value: task
|
|
@@ -390,7 +390,7 @@ spec:
|
|
|
390
390
|
value: ecosystem-cert-preflight-checks
|
|
391
391
|
|
|
392
392
|
- name: bundle
|
|
393
|
-
value: quay.io/konflux-ci/tekton-catalog/task-ecosystem-cert-preflight-checks:0.2@sha256:
|
|
393
|
+
value: quay.io/konflux-ci/tekton-catalog/task-ecosystem-cert-preflight-checks:0.2@sha256:40bc4bcc1c52c114139daee60ec2ddeb59921ecef8a68f241d5593c79b2a21d6
|
|
394
394
|
|
|
395
395
|
- name: kind
|
|
396
396
|
value: task
|
|
@@ -683,7 +683,7 @@ spec:
|
|
|
683
683
|
value: push-dockerfile-oci-ta
|
|
684
684
|
|
|
685
685
|
- name: bundle
|
|
686
|
-
value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.1@sha256:
|
|
686
|
+
value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.1@sha256:2623be4a9bad87ade614b4b24a8f98a4e100042a845e8f162b8237168697294c
|
|
687
687
|
|
|
688
688
|
- name: kind
|
|
689
689
|
value: task
|
|
@@ -706,7 +706,7 @@ spec:
|
|
|
706
706
|
value: rpms-signature-scan
|
|
707
707
|
|
|
708
708
|
- name: bundle
|
|
709
|
-
value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2@sha256:
|
|
709
|
+
value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2@sha256:23f133f47d13e6fd35ad6a65138f5b48bd2e6c4e66a2512991ff9f7d90cd7e0e
|
|
710
710
|
|
|
711
711
|
- name: kind
|
|
712
712
|
value: task
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.PHONY: help sync lint format types test ci verify fix clean docs docs-serve
|
|
1
|
+
.PHONY: help sync lint format types test ci verify fix clean docs docs-serve zipapp
|
|
2
2
|
|
|
3
3
|
# Default target
|
|
4
4
|
help:
|
|
@@ -15,6 +15,9 @@ help:
|
|
|
15
15
|
@echo " make fix - Auto-fix lint and format issues"
|
|
16
16
|
@echo " make clean - Remove build artifacts and caches"
|
|
17
17
|
@echo ""
|
|
18
|
+
@echo "📦 Build Targets:"
|
|
19
|
+
@echo " make zipapp - Build a zipapp using shiv"
|
|
20
|
+
@echo ""
|
|
18
21
|
@echo "📚 Documentation Targets:"
|
|
19
22
|
@echo " make docs - Build documentation"
|
|
20
23
|
@echo " make docs-serve - Serve docs locally with live reload"
|
|
@@ -47,8 +50,14 @@ fix:
|
|
|
47
50
|
clean:
|
|
48
51
|
rm -rf .pytest_cache .ruff_cache .pyright coverage dist build site
|
|
49
52
|
rm -rf src/*.egg-info
|
|
53
|
+
rm -f *.pyz
|
|
50
54
|
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
51
55
|
|
|
56
|
+
ZIPAPP_OUTPUT ?= linux-mcp-server.pyz
|
|
57
|
+
|
|
58
|
+
zipapp:
|
|
59
|
+
uv run --locked shiv . -c linux-mcp-server -o $(ZIPAPP_OUTPUT) -p "/usr/bin/env python3"
|
|
60
|
+
|
|
52
61
|
docs:
|
|
53
62
|
uv run --locked --group docs mkdocs build
|
|
54
63
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linux-mcp-server
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: MCP server for read-only Linux system administration, diagnostics, and troubleshooting
|
|
5
5
|
Project-URL: Source code, https://github.com/rhel-lightspeed/linux-mcp-server
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/rhel-lightspeed/linux-mcp-server/issues
|
|
@@ -253,6 +253,17 @@ sudo pacman -S python python-pip
|
|
|
253
253
|
|
|
254
254
|
#### Installing Python
|
|
255
255
|
|
|
256
|
+
Installing Python is not needed if you are using uv (recommended) -
|
|
257
|
+
it will automatically install Python versions as needed.
|
|
258
|
+
|
|
259
|
+
To check your installed version of Python:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
python3 --version
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
linux-mcp-server requires Python 3.10 or newer.
|
|
266
|
+
|
|
256
267
|
=== "Official Python Installer (Recommended)"
|
|
257
268
|
|
|
258
269
|
Download from [python.org/downloads/macos](https://www.python.org/downloads/macos/) and run the installer.
|
|
@@ -272,13 +283,7 @@ sudo pacman -S python python-pip
|
|
|
272
283
|
|
|
273
284
|
#### Installing linux-mcp-server
|
|
274
285
|
|
|
275
|
-
=== "
|
|
276
|
-
|
|
277
|
-
```bash
|
|
278
|
-
pip3 install --user linux-mcp-server
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
=== "uv"
|
|
286
|
+
=== "uv (Recommended)"
|
|
282
287
|
|
|
283
288
|
Install [uv](https://docs.astral.sh/uv/#installation).
|
|
284
289
|
|
|
@@ -288,6 +293,12 @@ sudo pacman -S python python-pip
|
|
|
288
293
|
uv tool install linux-mcp-server
|
|
289
294
|
```
|
|
290
295
|
|
|
296
|
+
=== "pip"
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
pip3 install --user linux-mcp-server
|
|
300
|
+
```
|
|
301
|
+
|
|
291
302
|
??? failure "Command not found after installation?"
|
|
292
303
|
|
|
293
304
|
On macOS (which uses `zsh` by default), add the install location to your `PATH`:
|
|
@@ -302,6 +313,13 @@ sudo pacman -S python python-pip
|
|
|
302
313
|
uv tool update-shell
|
|
303
314
|
```
|
|
304
315
|
|
|
316
|
+
??? failure "No matching distribution found for linux-mcp-server"
|
|
317
|
+
|
|
318
|
+
If pip3 claims to be unable to find linux-mcp-server,
|
|
319
|
+
that probably means you have a too-old version
|
|
320
|
+
of Python. Check your python version
|
|
321
|
+
with `python3 --version` - it should be 3.10 or newer.
|
|
322
|
+
|
|
305
323
|
#### SSH Setup on macOS
|
|
306
324
|
|
|
307
325
|
macOS includes OpenSSH by default. To set up key-based authentication:
|
|
@@ -52,6 +52,7 @@ linux-mcp-server = "linux_mcp_server.__main__:cli"
|
|
|
52
52
|
dev = [
|
|
53
53
|
"ipdb",
|
|
54
54
|
"ipython",
|
|
55
|
+
"shiv",
|
|
55
56
|
{include-group = "lint"},
|
|
56
57
|
{include-group = "test"},
|
|
57
58
|
]
|
|
@@ -142,6 +143,7 @@ tag-only = [
|
|
|
142
143
|
"astral-sh/setup-uv",
|
|
143
144
|
"codecov/codecov-action",
|
|
144
145
|
"pypa/gh-action-pypi-publish",
|
|
146
|
+
"softprops/action-gh-release",
|
|
145
147
|
]
|
|
146
148
|
|
|
147
149
|
[tool.pyright]
|
|
@@ -4,8 +4,6 @@ This module provides functions to format parsed data into
|
|
|
4
4
|
human-readable strings for tool output.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
7
|
from linux_mcp_server.models import ListeningPort
|
|
10
8
|
from linux_mcp_server.models import NetworkConnection
|
|
11
9
|
from linux_mcp_server.models import NetworkInterface
|
|
@@ -222,60 +220,6 @@ def format_service_logs(stdout: str, service_name: str, lines_count: int) -> str
|
|
|
222
220
|
return "\n".join(lines)
|
|
223
221
|
|
|
224
222
|
|
|
225
|
-
def format_journal_logs(
|
|
226
|
-
stdout: str,
|
|
227
|
-
lines_count: int,
|
|
228
|
-
unit: str | None = None,
|
|
229
|
-
priority: str | None = None,
|
|
230
|
-
since: str | None = None,
|
|
231
|
-
transport: str | None = None,
|
|
232
|
-
) -> str:
|
|
233
|
-
"""Format journal logs output.
|
|
234
|
-
|
|
235
|
-
Args:
|
|
236
|
-
stdout: Raw output from journalctl.
|
|
237
|
-
lines_count: Number of log lines.
|
|
238
|
-
unit: Optional unit filter.
|
|
239
|
-
priority: Optional priority filter.
|
|
240
|
-
since: Optional time filter.
|
|
241
|
-
transport: Optional transport filter (e.g., 'audit', 'kernel').
|
|
242
|
-
|
|
243
|
-
Returns:
|
|
244
|
-
Formatted string representation.
|
|
245
|
-
"""
|
|
246
|
-
filters = []
|
|
247
|
-
if unit:
|
|
248
|
-
filters.append(f"unit={unit}")
|
|
249
|
-
if priority:
|
|
250
|
-
filters.append(f"priority={priority}")
|
|
251
|
-
if since:
|
|
252
|
-
filters.append(f"since={since}")
|
|
253
|
-
|
|
254
|
-
log_type = f"{transport.title()} Logs" if transport else "Journal Logs"
|
|
255
|
-
filter_str = f", {', '.join(filters)}" if filters else (", no filters" if not transport else "")
|
|
256
|
-
header = f"=== {log_type} (last {lines_count} entries{filter_str}) ===\n"
|
|
257
|
-
|
|
258
|
-
lines = [header]
|
|
259
|
-
lines.append(stdout)
|
|
260
|
-
return "\n".join(lines)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
def format_log_file(stdout: str, log_path: Path, lines_count: int) -> str:
|
|
264
|
-
"""Format log file output.
|
|
265
|
-
|
|
266
|
-
Args:
|
|
267
|
-
stdout: Raw content from log file.
|
|
268
|
-
log_path: Path to the log file.
|
|
269
|
-
lines_count: Number of lines read.
|
|
270
|
-
|
|
271
|
-
Returns:
|
|
272
|
-
Formatted string representation.
|
|
273
|
-
"""
|
|
274
|
-
lines = [f"=== Log File: {log_path} (last {lines_count} lines) ===\n"]
|
|
275
|
-
lines.append(stdout)
|
|
276
|
-
return "\n".join(lines)
|
|
277
|
-
|
|
278
|
-
|
|
279
223
|
def format_disk_usage(stdout: str, disk_io: str | None = None) -> str:
|
|
280
224
|
"""Format disk usage output.
|
|
281
225
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import typing as t
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel
|
|
6
7
|
from pydantic import Field
|
|
8
|
+
from pydantic import field_serializer
|
|
7
9
|
from pydantic import model_validator
|
|
8
10
|
|
|
9
11
|
from linux_mcp_server.utils.format import format_bytes
|
|
@@ -184,3 +186,15 @@ class NodeEntry(BaseModel):
|
|
|
184
186
|
class StorageNodes(BaseModel):
|
|
185
187
|
nodes: list[NodeEntry]
|
|
186
188
|
total: int = Field(default_factory=field_length("nodes"))
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
### Log models ###
|
|
192
|
+
class LogEntries(BaseModel):
|
|
193
|
+
entries: list[str]
|
|
194
|
+
unit: str = ""
|
|
195
|
+
path: Path | None = None
|
|
196
|
+
lines_count: int = Field(default_factory=field_length("entries"))
|
|
197
|
+
|
|
198
|
+
@field_serializer("unit", "path")
|
|
199
|
+
def serialize_empty_as_null(self, value: str | Path | None) -> str | Path | None:
|
|
200
|
+
return value or None
|
|
@@ -12,8 +12,7 @@ from pydantic.functional_validators import BeforeValidator
|
|
|
12
12
|
from linux_mcp_server.audit import log_tool_call
|
|
13
13
|
from linux_mcp_server.commands import get_command
|
|
14
14
|
from linux_mcp_server.config import CONFIG
|
|
15
|
-
from linux_mcp_server.
|
|
16
|
-
from linux_mcp_server.formatters import format_log_file
|
|
15
|
+
from linux_mcp_server.models import LogEntries
|
|
17
16
|
from linux_mcp_server.server import mcp
|
|
18
17
|
from linux_mcp_server.utils import StrEnum
|
|
19
18
|
from linux_mcp_server.utils.decorators import disallow_local_execution_in_containers
|
|
@@ -89,33 +88,33 @@ async def _get_journal_logs(
|
|
|
89
88
|
@disallow_local_execution_in_containers
|
|
90
89
|
async def get_journal_logs(
|
|
91
90
|
unit: t.Annotated[
|
|
92
|
-
str
|
|
91
|
+
str,
|
|
93
92
|
Field(
|
|
94
93
|
description="Filter by systemd unit name or pattern",
|
|
95
94
|
examples=["sshd.service", "nginx", "httpd", "systemd-*", "audit*"],
|
|
96
95
|
),
|
|
97
|
-
] =
|
|
96
|
+
] = "",
|
|
98
97
|
priority: t.Annotated[
|
|
99
|
-
str
|
|
98
|
+
str,
|
|
100
99
|
Field(
|
|
101
100
|
description="Filter by syslog priority level (0-7), name, or range",
|
|
102
101
|
examples=["err", "warning", "info", "debug", "3", "err..warning"],
|
|
103
102
|
),
|
|
104
|
-
] =
|
|
103
|
+
] = "",
|
|
105
104
|
since: t.Annotated[
|
|
106
|
-
str
|
|
105
|
+
str,
|
|
107
106
|
Field(
|
|
108
107
|
description="Filter entries since specified time (absolute or relative)",
|
|
109
108
|
examples=["today", "yesterday", "-1h", "-30m", "-7d", "2025-01-15 10:00:00"],
|
|
110
109
|
),
|
|
111
|
-
] =
|
|
110
|
+
] = "",
|
|
112
111
|
transport: t.Annotated[
|
|
113
112
|
Transport | None,
|
|
114
113
|
"Filter by journal transport (e.g., 'audit' for audit logs, 'kernel' for kernel messages, 'syslog' for syslog messages)",
|
|
115
114
|
] = None,
|
|
116
115
|
lines: t.Annotated[int, Field(description="Number of log lines to retrieve. Default: 100", ge=1, le=10_000)] = 100,
|
|
117
116
|
host: Host = None,
|
|
118
|
-
) ->
|
|
117
|
+
) -> LogEntries:
|
|
119
118
|
"""Get systemd journal logs.
|
|
120
119
|
|
|
121
120
|
Retrieves entries from the systemd journal with optional filtering by unit,
|
|
@@ -128,12 +127,17 @@ async def get_journal_logs(
|
|
|
128
127
|
)
|
|
129
128
|
|
|
130
129
|
if returncode != 0:
|
|
131
|
-
|
|
130
|
+
raise ToolError(f"Error reading journal logs: {stderr}")
|
|
132
131
|
|
|
133
132
|
if is_empty_output(stdout):
|
|
134
|
-
|
|
133
|
+
raise ToolError("No journal entries found matching the criteria.")
|
|
135
134
|
|
|
136
|
-
|
|
135
|
+
entries = [line for line in stdout.strip().splitlines() if line]
|
|
136
|
+
|
|
137
|
+
return LogEntries(
|
|
138
|
+
entries=entries,
|
|
139
|
+
unit=unit,
|
|
140
|
+
)
|
|
137
141
|
|
|
138
142
|
|
|
139
143
|
@mcp.tool(
|
|
@@ -155,7 +159,7 @@ async def read_log_file(
|
|
|
155
159
|
],
|
|
156
160
|
lines: t.Annotated[int, Field(description="Number of lines to retrieve from the end.", ge=1, le=10_000)] = 100,
|
|
157
161
|
host: Host = None,
|
|
158
|
-
) ->
|
|
162
|
+
) -> LogEntries:
|
|
159
163
|
"""Read a specific log file.
|
|
160
164
|
|
|
161
165
|
Retrieves the last N lines from a log file. The file path must be in the
|
|
@@ -212,4 +216,6 @@ async def read_log_file(
|
|
|
212
216
|
if is_empty_output(stdout):
|
|
213
217
|
raise ToolError(f"Log file is empty: {log_path}")
|
|
214
218
|
|
|
215
|
-
|
|
219
|
+
entries = [line for line in stdout.strip().splitlines() if line]
|
|
220
|
+
|
|
221
|
+
return LogEntries(entries=entries, path=log_path)
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
"""Tests for formatters module."""
|
|
2
2
|
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
3
|
from linux_mcp_server.formatters import format_disk_usage
|
|
6
4
|
from linux_mcp_server.formatters import format_hardware_info
|
|
7
|
-
from linux_mcp_server.formatters import format_journal_logs
|
|
8
5
|
from linux_mcp_server.formatters import format_listening_ports
|
|
9
|
-
from linux_mcp_server.formatters import format_log_file
|
|
10
6
|
from linux_mcp_server.formatters import format_network_connections
|
|
11
7
|
from linux_mcp_server.formatters import format_network_interfaces
|
|
12
8
|
from linux_mcp_server.formatters import format_process_detail
|
|
@@ -247,57 +243,6 @@ class TestFormatServiceLogs:
|
|
|
247
243
|
assert "Accepted publickey" in result
|
|
248
244
|
|
|
249
245
|
|
|
250
|
-
class TestFormatJournalLogs:
|
|
251
|
-
"""Tests for format_journal_logs function."""
|
|
252
|
-
|
|
253
|
-
def test_format_no_filters(self):
|
|
254
|
-
"""Test formatting without filters."""
|
|
255
|
-
stdout = "Dec 12 10:00:00 host kernel: Log message"
|
|
256
|
-
result = format_journal_logs(stdout, 100)
|
|
257
|
-
assert "=== Journal Logs (last 100 entries, no filters) ===" in result
|
|
258
|
-
|
|
259
|
-
def test_format_with_filters(self):
|
|
260
|
-
"""Test formatting with filters."""
|
|
261
|
-
stdout = "Dec 12 10:00:00 host sshd[1234]: Message"
|
|
262
|
-
result = format_journal_logs(stdout, 50, unit="ssh.service", priority="err", since="today")
|
|
263
|
-
assert "unit=ssh.service" in result
|
|
264
|
-
assert "priority=err" in result
|
|
265
|
-
assert "since=today" in result
|
|
266
|
-
|
|
267
|
-
def test_format_with_transport_audit(self):
|
|
268
|
-
"""Test formatting with transport=audit uses Audit Logs header."""
|
|
269
|
-
stdout = "Dec 12 10:00:00 host audit[1234]: SYSCALL"
|
|
270
|
-
result = format_journal_logs(stdout, 100, transport="audit")
|
|
271
|
-
assert "=== Audit Logs (last 100 entries" in result
|
|
272
|
-
assert "SYSCALL" in result
|
|
273
|
-
|
|
274
|
-
def test_format_with_transport_audit_and_other_filters(self):
|
|
275
|
-
"""Test formatting with transport=audit combined with other filters includes all filters."""
|
|
276
|
-
stdout = "Dec 12 10:00:00 host audit[1234]: Error message"
|
|
277
|
-
result = format_journal_logs(stdout, 50, transport="audit", priority="err", since="today")
|
|
278
|
-
assert "=== Audit Logs (last 50 entries" in result
|
|
279
|
-
assert "priority=err" in result
|
|
280
|
-
assert "since=today" in result
|
|
281
|
-
|
|
282
|
-
def test_format_with_transport_kernel(self):
|
|
283
|
-
"""Test formatting with transport=kernel uses Kernel Logs header."""
|
|
284
|
-
stdout = "Dec 12 10:00:00 host kernel: Kernel message"
|
|
285
|
-
result = format_journal_logs(stdout, 100, transport="kernel")
|
|
286
|
-
assert "=== Kernel Logs (last 100 entries)" in result
|
|
287
|
-
assert "Kernel message" in result
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
class TestFormatLogFile:
|
|
291
|
-
"""Tests for format_log_file function."""
|
|
292
|
-
|
|
293
|
-
def test_format_log_file(self):
|
|
294
|
-
"""Test formatting log file."""
|
|
295
|
-
stdout = "2024-01-01 10:00:00 INFO Application started"
|
|
296
|
-
result = format_log_file(stdout, Path("/var/log/app.log"), 100)
|
|
297
|
-
assert "=== Log File: /var/log/app.log (last 100 lines) ===" in result
|
|
298
|
-
assert "Application started" in result
|
|
299
|
-
|
|
300
|
-
|
|
301
246
|
class TestFormatDiskUsage:
|
|
302
247
|
"""Tests for format_disk_usage function."""
|
|
303
248
|
|