macos-sysinfo-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- macos_sysinfo_mcp-0.1.0/.claude/settings.local.json +9 -0
- macos_sysinfo_mcp-0.1.0/.gitignore +15 -0
- macos_sysinfo_mcp-0.1.0/CLAUDE.md +80 -0
- macos_sysinfo_mcp-0.1.0/PKG-INFO +69 -0
- macos_sysinfo_mcp-0.1.0/README.md +47 -0
- macos_sysinfo_mcp-0.1.0/get_sys_info/__init__.py +207 -0
- macos_sysinfo_mcp-0.1.0/get_sys_info/__main__.py +4 -0
- macos_sysinfo_mcp-0.1.0/pyproject.toml +39 -0
- macos_sysinfo_mcp-0.1.0/uv.lock +751 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
An MCP (Model Context Protocol) server that collects macOS system information — OS version, CPU, memory, disk, network, processes, and uptime — exposed via a single `get_os_info` tool.
|
|
8
|
+
|
|
9
|
+
## Environment
|
|
10
|
+
|
|
11
|
+
- Python 3.12.10 (managed by pyenv + uv 0.11.17)
|
|
12
|
+
- Virtual env: `.venv/` (uv-created)
|
|
13
|
+
- Dependencies managed via `pyproject.toml`
|
|
14
|
+
|
|
15
|
+
## Package Structure
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
get_sys_info/
|
|
19
|
+
├── get_sys_info/ # Python package
|
|
20
|
+
│ ├── __init__.py # MCP server — single tool: get_os_info
|
|
21
|
+
│ └── __main__.py # python -m entry point
|
|
22
|
+
├── pyproject.toml # project config / build / entry point
|
|
23
|
+
├── CLAUDE.md
|
|
24
|
+
├── .gitignore
|
|
25
|
+
└── .venv/
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
source .venv/bin/activate # activate venv
|
|
32
|
+
uv sync # install / update deps
|
|
33
|
+
uv run python -m get_sys_info # run MCP server (stdio mode)
|
|
34
|
+
uv build # build wheel + sdist
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Key Dependencies
|
|
38
|
+
|
|
39
|
+
- `mcp` — MCP Python SDK (FastMCP server)
|
|
40
|
+
- `psutil` — cross-platform system metrics
|
|
41
|
+
|
|
42
|
+
## Packaging for Other Projects
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Build the package
|
|
46
|
+
uv build
|
|
47
|
+
|
|
48
|
+
# Install in another project
|
|
49
|
+
uv pip install dist/get_sys_info-0.1.0-py3-none-any.whl
|
|
50
|
+
# or from local source
|
|
51
|
+
uv pip install -e /path/to/get_sys_info
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## MCP Config for Consumer Projects
|
|
55
|
+
|
|
56
|
+
In the consumer project's `.claude/mcp.json` or `claude_desktop_config.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"get-sys-info": {
|
|
62
|
+
"command": "python",
|
|
63
|
+
"args": ["-m", "get_sys_info"]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For uv-managed projects without a pre-installed package:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"get-sys-info": {
|
|
75
|
+
"command": "uv",
|
|
76
|
+
"args": ["run", "--with", "get-sys-info", "python", "-m", "get_sys_info"]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: macos-sysinfo-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for macOS system information
|
|
5
|
+
Project-URL: Homepage, https://github.com/QIMING/macos-sysinfo-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/QIMING/macos-sysinfo-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/QIMING/macos-sysinfo-mcp/issues
|
|
8
|
+
Author-email: QIMING <13728724090@163.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: macos,mcp,model-context-protocol,system-info
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: System :: Monitoring
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Requires-Dist: mcp[cli]>=1.0.0
|
|
20
|
+
Requires-Dist: psutil>=6.0.0
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# macOS System Info MCP
|
|
24
|
+
|
|
25
|
+
An MCP (Model Context Protocol) server that collects macOS system information — OS version, CPU, memory, disk, network, processes, and uptime — exposed via a single `get_os_info` tool.
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### In MCP Client Configuration
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"macos-sysinfo-mcp": {
|
|
35
|
+
"command": "python",
|
|
36
|
+
"args": ["-m", "get_sys_info"]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or with `uv` (no pre-install needed):
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"mcpServers": {
|
|
47
|
+
"macos-sysinfo-mcp": {
|
|
48
|
+
"command": "uv",
|
|
49
|
+
"args": [
|
|
50
|
+
"run",
|
|
51
|
+
"--with", "macos-sysinfo-mcp",
|
|
52
|
+
"python", "-m", "get_sys_info"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Tool: `get_os_info`
|
|
60
|
+
|
|
61
|
+
- **Required parameter**: `output_path` — absolute path to save the JSON result
|
|
62
|
+
|
|
63
|
+
## Development
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv sync
|
|
67
|
+
source .venv/bin/activate
|
|
68
|
+
uv run python -m get_sys_info
|
|
69
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# macOS System Info MCP
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that collects macOS system information — OS version, CPU, memory, disk, network, processes, and uptime — exposed via a single `get_os_info` tool.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
### In MCP Client Configuration
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"macos-sysinfo-mcp": {
|
|
13
|
+
"command": "python",
|
|
14
|
+
"args": ["-m", "get_sys_info"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or with `uv` (no pre-install needed):
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"macos-sysinfo-mcp": {
|
|
26
|
+
"command": "uv",
|
|
27
|
+
"args": [
|
|
28
|
+
"run",
|
|
29
|
+
"--with", "macos-sysinfo-mcp",
|
|
30
|
+
"python", "-m", "get_sys_info"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Tool: `get_os_info`
|
|
38
|
+
|
|
39
|
+
- **Required parameter**: `output_path` — absolute path to save the JSON result
|
|
40
|
+
|
|
41
|
+
## Development
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv sync
|
|
45
|
+
source .venv/bin/activate
|
|
46
|
+
uv run python -m get_sys_info
|
|
47
|
+
```
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Server — Get OS Info
|
|
3
|
+
One tool: get_os_info — returns comprehensive macOS system information.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import platform
|
|
8
|
+
import subprocess
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
import psutil
|
|
12
|
+
from mcp.server.fastmcp import FastMCP
|
|
13
|
+
|
|
14
|
+
server = FastMCP("get-sys-info")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _run_cmd(cmd: list[str]) -> str | None:
|
|
18
|
+
"""Run a shell command and return stdout, or None on failure."""
|
|
19
|
+
try:
|
|
20
|
+
return subprocess.check_output(cmd, text=True).strip()
|
|
21
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _sw_vers() -> dict[str, str | None]:
|
|
26
|
+
"""macOS version details via sw_vers."""
|
|
27
|
+
raw = _run_cmd(["sw_vers"])
|
|
28
|
+
if not raw:
|
|
29
|
+
return {}
|
|
30
|
+
result = {}
|
|
31
|
+
for line in raw.splitlines():
|
|
32
|
+
if ":" in line:
|
|
33
|
+
k, v = line.split(":", 1)
|
|
34
|
+
result[k.strip()] = v.strip()
|
|
35
|
+
return result
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _uptime_seconds() -> float | None:
|
|
39
|
+
"""System uptime in seconds from sysctl (macOS)."""
|
|
40
|
+
raw = _run_cmd(["sysctl", "-n", "kern.boottime"])
|
|
41
|
+
if not raw:
|
|
42
|
+
return None
|
|
43
|
+
try:
|
|
44
|
+
sec = int(raw.split("sec = ")[1].split(",")[0])
|
|
45
|
+
return datetime.now().timestamp() - sec
|
|
46
|
+
except (ValueError, IndexError):
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _human_time(seconds: float) -> str:
|
|
51
|
+
"""Format seconds into a human-readable string."""
|
|
52
|
+
days, rem = divmod(int(seconds), 86400)
|
|
53
|
+
hours, rem = divmod(rem, 3600)
|
|
54
|
+
minutes, secs = divmod(rem, 60)
|
|
55
|
+
parts = []
|
|
56
|
+
if days:
|
|
57
|
+
parts.append(f"{days}d")
|
|
58
|
+
if hours:
|
|
59
|
+
parts.append(f"{hours}h")
|
|
60
|
+
if minutes:
|
|
61
|
+
parts.append(f"{minutes}m")
|
|
62
|
+
parts.append(f"{secs}s")
|
|
63
|
+
return " ".join(parts)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@server.tool()
|
|
67
|
+
def get_os_info(output_path: str) -> str:
|
|
68
|
+
"""Return comprehensive macOS system information and save to a JSON file.
|
|
69
|
+
|
|
70
|
+
Collects macOS system details (OS version, CPU, memory, disk,
|
|
71
|
+
network, processes, uptime), returns them as a JSON string,
|
|
72
|
+
and saves the result to the specified file.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
output_path: Absolute path to save the JSON output file.
|
|
76
|
+
Pass your project root directory (e.g. the consumer
|
|
77
|
+
project's root) with a filename like "system_info.json".
|
|
78
|
+
"""
|
|
79
|
+
sv = _sw_vers()
|
|
80
|
+
up_secs = _uptime_seconds()
|
|
81
|
+
|
|
82
|
+
mem = psutil.virtual_memory()
|
|
83
|
+
swap = psutil.swap_memory()
|
|
84
|
+
disks = psutil.disk_partitions()
|
|
85
|
+
disk_io = psutil.disk_io_counters()
|
|
86
|
+
addrs = psutil.net_if_addrs()
|
|
87
|
+
net_io = psutil.net_io_counters()
|
|
88
|
+
load1, load5, load15 = psutil.getloadavg()
|
|
89
|
+
|
|
90
|
+
# Primary IP (first non-loopback IPv4)
|
|
91
|
+
primary_ip = None
|
|
92
|
+
for _iface, addr_list in addrs.items():
|
|
93
|
+
for addr in addr_list:
|
|
94
|
+
if addr.family == 2 and not addr.address.startswith("127."):
|
|
95
|
+
primary_ip = addr.address
|
|
96
|
+
break
|
|
97
|
+
if primary_ip:
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
# Top processes by CPU
|
|
101
|
+
proc_count = len(psutil.pids())
|
|
102
|
+
top_procs = []
|
|
103
|
+
for p in sorted(
|
|
104
|
+
psutil.process_iter(["pid", "name", "cpu_percent", "memory_percent"]),
|
|
105
|
+
key=lambda p: (p.info.get("cpu_percent") or 0),
|
|
106
|
+
reverse=True,
|
|
107
|
+
)[:10]:
|
|
108
|
+
info = p.info
|
|
109
|
+
top_procs.append({
|
|
110
|
+
"pid": info["pid"],
|
|
111
|
+
"name": info.get("name", "?"),
|
|
112
|
+
"cpu%": round(info.get("cpu_percent", 0) or 0, 1),
|
|
113
|
+
"mem%": round(info.get("memory_percent", 0) or 0, 1),
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
info: dict = {
|
|
117
|
+
"hostname": platform.node(),
|
|
118
|
+
"os": {
|
|
119
|
+
"system": platform.system(),
|
|
120
|
+
"release": platform.release(),
|
|
121
|
+
"version": platform.version(),
|
|
122
|
+
"machine": platform.machine(),
|
|
123
|
+
"macOS": sv.get("ProductName", "?"),
|
|
124
|
+
"macOS_version": sv.get("ProductVersion", "?"),
|
|
125
|
+
"macOS_build": sv.get("BuildVersion", "?"),
|
|
126
|
+
},
|
|
127
|
+
"uptime": _human_time(up_secs) if up_secs else "unknown",
|
|
128
|
+
"uptime_seconds": up_secs,
|
|
129
|
+
"boot_time": (
|
|
130
|
+
datetime.fromtimestamp(psutil.boot_time()).isoformat()
|
|
131
|
+
if psutil.boot_time() else None
|
|
132
|
+
),
|
|
133
|
+
"cpu": {
|
|
134
|
+
"model": _run_cmd(["sysctl", "-n", "machdep.cpu.brand_string"]),
|
|
135
|
+
"architecture": platform.machine(),
|
|
136
|
+
"physical_cores": psutil.cpu_count(logical=False),
|
|
137
|
+
"logical_cores": psutil.cpu_count(logical=True),
|
|
138
|
+
"usage_per_core": psutil.cpu_percent(percpu=True),
|
|
139
|
+
"usage_total": psutil.cpu_percent(interval=0.1),
|
|
140
|
+
"load_average": {
|
|
141
|
+
"1min": round(load1, 2),
|
|
142
|
+
"5min": round(load5, 2),
|
|
143
|
+
"15min": round(load15, 2),
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
"memory": {
|
|
147
|
+
"total": mem.total,
|
|
148
|
+
"available": mem.available,
|
|
149
|
+
"used": mem.used,
|
|
150
|
+
"percent": mem.percent,
|
|
151
|
+
"swap_total": swap.total,
|
|
152
|
+
"swap_used": swap.used,
|
|
153
|
+
"swap_percent": swap.percent if swap.total else 0,
|
|
154
|
+
},
|
|
155
|
+
"disks": [],
|
|
156
|
+
"network": {
|
|
157
|
+
"hostname": platform.node(),
|
|
158
|
+
"primary_ip": primary_ip,
|
|
159
|
+
"bytes_sent": net_io.bytes_sent,
|
|
160
|
+
"bytes_recv": net_io.bytes_recv,
|
|
161
|
+
"packets_sent": net_io.packets_sent,
|
|
162
|
+
"packets_recv": net_io.packets_recv,
|
|
163
|
+
},
|
|
164
|
+
"processes": {
|
|
165
|
+
"total": proc_count,
|
|
166
|
+
"top_by_cpu": top_procs,
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for d in disks:
|
|
171
|
+
try:
|
|
172
|
+
usage = psutil.disk_usage(d.mountpoint)
|
|
173
|
+
info["disks"].append({
|
|
174
|
+
"device": d.device,
|
|
175
|
+
"mount": d.mountpoint,
|
|
176
|
+
"fstype": d.fstype,
|
|
177
|
+
"total": usage.total,
|
|
178
|
+
"used": usage.used,
|
|
179
|
+
"free": usage.free,
|
|
180
|
+
"percent": usage.percent,
|
|
181
|
+
})
|
|
182
|
+
except PermissionError:
|
|
183
|
+
continue
|
|
184
|
+
|
|
185
|
+
if disk_io:
|
|
186
|
+
info["disk_io"] = {
|
|
187
|
+
"read_count": disk_io.read_count,
|
|
188
|
+
"write_count": disk_io.write_count,
|
|
189
|
+
"read_bytes": disk_io.read_bytes,
|
|
190
|
+
"write_bytes": disk_io.write_bytes,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
result = json.dumps(info, ensure_ascii=False, indent=2)
|
|
194
|
+
|
|
195
|
+
with open(output_path, "w") as f:
|
|
196
|
+
f.write(result)
|
|
197
|
+
|
|
198
|
+
return result
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def main():
|
|
202
|
+
"""Entry point — run the MCP server over stdio."""
|
|
203
|
+
server.run(transport="stdio")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
if __name__ == "__main__":
|
|
207
|
+
main()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "macos-sysinfo-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server for macOS system information"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "QIMING", email = "13728724090@163.com" },
|
|
10
|
+
]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: MacOS",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Topic :: System :: Monitoring",
|
|
19
|
+
]
|
|
20
|
+
keywords = ["mcp", "system-info", "macos", "model-context-protocol"]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"mcp[cli]>=1.0.0",
|
|
23
|
+
"psutil>=6.0.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/QIMING/macos-sysinfo-mcp"
|
|
28
|
+
Repository = "https://github.com/QIMING/macos-sysinfo-mcp"
|
|
29
|
+
Issues = "https://github.com/QIMING/macos-sysinfo-mcp/issues"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
get-sys-info = "get_sys_info:main"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["hatchling"]
|
|
36
|
+
build-backend = "hatchling.build"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["get_sys_info"]
|