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.
Files changed (132) hide show
  1. linux_mcp_server-1.3.2/.github/workflows/build-publish.yml +178 -0
  2. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.gitignore +1 -0
  3. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/pipeline-build-multiarch.yaml +6 -6
  4. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/push.yaml +0 -1
  5. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/Makefile +10 -1
  6. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/PKG-INFO +1 -1
  7. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/install.md +25 -7
  8. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/pyproject.toml +2 -0
  9. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/connection/ssh.py +0 -1
  10. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/formatters.py +0 -56
  11. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/models.py +14 -0
  12. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/logs.py +20 -14
  13. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_formatters.py +0 -55
  14. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_logs.py +71 -69
  15. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/uv.lock +34 -0
  16. linux_mcp_server-1.3.1/.github/workflows/build-publish.yml +0 -94
  17. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.codecov.yml +0 -0
  18. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.coderabbit.yaml +0 -0
  19. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.devcontainer/Containerfile +0 -0
  20. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.devcontainer/devcontainer.json +0 -0
  21. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/ci.yml +0 -0
  22. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/ci_installation.yaml +0 -0
  23. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/docs.yml +0 -0
  24. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.github/workflows/functional-tests.yml +0 -0
  25. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/pull_request.yaml +0 -0
  26. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/.tekton/task-get-version.yaml +0 -0
  27. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/AGENTS.md +0 -0
  28. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/Containerfile +0 -0
  29. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/LICENSE +0 -0
  30. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/README.md +0 -0
  31. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/audit.md +0 -0
  32. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/commands.md +0 -0
  33. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/config.md +0 -0
  34. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/connection.md +0 -0
  35. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/formatters.md +0 -0
  36. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/index.md +0 -0
  37. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/parsers.md +0 -0
  38. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/server.md +0 -0
  39. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/logs.md +0 -0
  40. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/network.md +0 -0
  41. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/processes.md +0 -0
  42. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/services.md +0 -0
  43. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/storage.md +0 -0
  44. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/api/tools/system_info.md +0 -0
  45. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/architecture.md +0 -0
  46. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/cheatsheet.md +0 -0
  47. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/clients.md +0 -0
  48. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/contributing.md +0 -0
  49. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/debugging.md +0 -0
  50. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/examples/claude_desktop_config.example.json +0 -0
  51. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/examples/example_config.sh +0 -0
  52. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/getting-started.md +0 -0
  53. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/index.md +0 -0
  54. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/troubleshooting.md +0 -0
  55. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/docs/usage.md +0 -0
  56. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/licenses/GPL-3.0.txt +0 -0
  57. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/mkdocs.yml +0 -0
  58. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/renovate.json +0 -0
  59. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/scripts/publish_mcp_registry.py +0 -0
  60. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/scripts/verify_installation.sh +0 -0
  61. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/server.json +0 -0
  62. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/__init__.py +0 -0
  63. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/__main__.py +0 -0
  64. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/_vendor/__init__.py +0 -0
  65. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/audit.py +0 -0
  66. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/commands.py +0 -0
  67. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/config.py +0 -0
  68. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/connection/__init__.py +0 -0
  69. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/logging_config.py +0 -0
  70. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/parsers.py +0 -0
  71. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/server.py +0 -0
  72. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/__init__.py +0 -0
  73. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/network.py +0 -0
  74. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/processes.py +0 -0
  75. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/services.py +0 -0
  76. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/storage.py +0 -0
  77. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/tools/system_info.py +0 -0
  78. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/__init__.py +0 -0
  79. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/decorators.py +0 -0
  80. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/enum.py +0 -0
  81. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/format.py +0 -0
  82. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/types.py +0 -0
  83. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/src/linux_mcp_server/utils/validation.py +0 -0
  84. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/__init__.py +0 -0
  85. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/_vendor/__init__.py +0 -0
  86. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/_vendor/test_vendor.py +0 -0
  87. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/cli/__init__.py +0 -0
  88. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/cli/test_cli.py +0 -0
  89. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/conftest.py +0 -0
  90. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/__init__.py +0 -0
  91. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/__init__.py +0 -0
  92. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_connection_manager.py +0 -0
  93. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_discover_ssh_key.py +0 -0
  94. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_execute_command.py +0 -0
  95. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_get_bin_path.py +0 -0
  96. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_host_key_verification.py +0 -0
  97. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/connection/ssh/test_timeout.py +0 -0
  98. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/__init__.py +0 -0
  99. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_cpu_info.py +0 -0
  100. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_free_output.py +0 -0
  101. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_ip_brief.py +0 -0
  102. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_listing.py +0 -0
  103. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_os_release.py +0 -0
  104. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_proc.py +0 -0
  105. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_ps_output.py +0 -0
  106. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_service_count.py +0 -0
  107. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_ss.py +0 -0
  108. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/parsers/test_parse_system_info.py +0 -0
  109. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test__main__.py +0 -0
  110. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_audit.py +0 -0
  111. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_commands.py +0 -0
  112. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_config.py +0 -0
  113. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_logging_config.py +0 -0
  114. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_server.py +0 -0
  115. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/test_tool_schemas.py +0 -0
  116. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/__init__.py +0 -0
  117. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/__init__.py +0 -0
  118. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/conftest.py +0 -0
  119. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_list_block_devices.py +0 -0
  120. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_list_directories.py +0 -0
  121. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_list_files.py +0 -0
  122. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_path_validation.py +0 -0
  123. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/storage/test_read_file.py +0 -0
  124. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_network.py +0 -0
  125. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_processes.py +0 -0
  126. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_services.py +0 -0
  127. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/tools/test_system_info.py +0 -0
  128. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/__init__.py +0 -0
  129. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/test_decorators.py +0 -0
  130. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/test_enum.py +0 -0
  131. {linux_mcp_server-1.3.1 → linux_mcp_server-1.3.2}/tests/utils/test_format.py +0 -0
  132. {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 }}
@@ -19,6 +19,7 @@ wheels/
19
19
  *.egg-info/
20
20
  .installed.cfg
21
21
  *.egg
22
+ *.pyz
22
23
 
23
24
  # Vendored packages
24
25
  src/linux_mcp_server/_vendor/*
@@ -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:c664a6df6514b59c3ce53570b0994b45af66ecc89ba2a8e41834eae0622addf6
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:f579f6d72db53da9e0b3f84e89d66d0f81c360a0785576308a93c3774b73be11
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:8fd2bd1329a833cf1c3c049c0044961d6f5d5bfc954ebf188c19a56852c42600
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:33b7133c0c132c361295c30947f73bd45a3a3b62a24b83f3d8cd7c71f757828c
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:6fb61bec5ef161225a850005233db68cfdc03ad54e1a54cc49cc98d98ea3d259
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:a99d8fd4c9027356b18e5d2910cc44dbc2fcb53c384ba34696645d9e7faa9084
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
@@ -41,7 +41,6 @@ spec:
41
41
  - name: additional-tags
42
42
  value:
43
43
  - latest
44
- - '{{ target_branch }}'
45
44
 
46
45
  pipelineRef:
47
46
  name: pipeline-build-multiarch
@@ -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.1
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
- === "pip"
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]
@@ -354,7 +354,6 @@ async def execute_command(
354
354
  Raises:
355
355
  ValueError: If host is provided without username
356
356
  ConnectionError: If remote connection fails
357
- ToolError: If the command is missing
358
357
 
359
358
  Examples:
360
359
  # Local execution
@@ -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.formatters import format_journal_logs
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 | None,
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
- ] = None,
96
+ ] = "",
98
97
  priority: t.Annotated[
99
- str | None,
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
- ] = None,
103
+ ] = "",
105
104
  since: t.Annotated[
106
- str | None,
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
- ] = None,
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
- ) -> str:
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
- return f"Error reading journal logs: {stderr}"
130
+ raise ToolError(f"Error reading journal logs: {stderr}")
132
131
 
133
132
  if is_empty_output(stdout):
134
- return "No journal entries found matching the criteria."
133
+ raise ToolError("No journal entries found matching the criteria.")
135
134
 
136
- return format_journal_logs(stdout, lines, unit, priority, since, transport)
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
- ) -> str:
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
- return format_log_file(stdout, log_path, lines)
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