pcp-mcp 1.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.
- pcp_mcp-1.1.0/PKG-INFO +259 -0
- pcp_mcp-1.1.0/README.md +230 -0
- pcp_mcp-1.1.0/pyproject.toml +116 -0
- pcp_mcp-1.1.0/src/pcp_mcp/AGENTS.md +70 -0
- pcp_mcp-1.1.0/src/pcp_mcp/__init__.py +63 -0
- pcp_mcp-1.1.0/src/pcp_mcp/client.py +274 -0
- pcp_mcp-1.1.0/src/pcp_mcp/config.py +107 -0
- pcp_mcp-1.1.0/src/pcp_mcp/context.py +104 -0
- pcp_mcp-1.1.0/src/pcp_mcp/errors.py +47 -0
- pcp_mcp-1.1.0/src/pcp_mcp/icons.py +31 -0
- pcp_mcp-1.1.0/src/pcp_mcp/middleware.py +75 -0
- pcp_mcp-1.1.0/src/pcp_mcp/models.py +164 -0
- pcp_mcp-1.1.0/src/pcp_mcp/prompts/__init__.py +308 -0
- pcp_mcp-1.1.0/src/pcp_mcp/py.typed +0 -0
- pcp_mcp-1.1.0/src/pcp_mcp/resources/__init__.py +21 -0
- pcp_mcp-1.1.0/src/pcp_mcp/resources/catalog.py +307 -0
- pcp_mcp-1.1.0/src/pcp_mcp/resources/health.py +117 -0
- pcp_mcp-1.1.0/src/pcp_mcp/server.py +144 -0
- pcp_mcp-1.1.0/src/pcp_mcp/tools/AGENTS.md +61 -0
- pcp_mcp-1.1.0/src/pcp_mcp/tools/__init__.py +21 -0
- pcp_mcp-1.1.0/src/pcp_mcp/tools/metrics.py +189 -0
- pcp_mcp-1.1.0/src/pcp_mcp/tools/system.py +479 -0
- pcp_mcp-1.1.0/src/pcp_mcp/utils/__init__.py +38 -0
- pcp_mcp-1.1.0/src/pcp_mcp/utils/builders.py +290 -0
- pcp_mcp-1.1.0/src/pcp_mcp/utils/extractors.py +78 -0
pcp_mcp-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pcp-mcp
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: MCP server for Performance Co-Pilot
|
|
5
|
+
Keywords: mcp,pcp,performance-co-pilot,monitoring,model-context-protocol
|
|
6
|
+
Author: Major Hayden
|
|
7
|
+
Author-email: Major Hayden <major@mhtx.net>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: System Administrators
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: System :: Monitoring
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Dist: cachetools>=5.0
|
|
21
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
22
|
+
Requires-Dist: httpx>=0.27
|
|
23
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
24
|
+
Requires-Dist: typing-extensions>=4.0 ; python_full_version < '3.11'
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Project-URL: Homepage, https://github.com/major/pcp-mcp
|
|
27
|
+
Project-URL: Repository, https://github.com/major/pcp-mcp
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# pcp-mcp
|
|
31
|
+
|
|
32
|
+
MCP server for [Performance Co-Pilot (PCP)](https://pcp.io/) metrics.
|
|
33
|
+
|
|
34
|
+
Query system performance metrics via the Model Context Protocol - CPU, memory, disk I/O, network, processes, and more.
|
|
35
|
+
|
|
36
|
+
📖 **[Full Documentation](https://major.github.io/pcp-mcp)** | 🚀 **[Getting Started](https://major.github.io/pcp-mcp/getting-started/)**
|
|
37
|
+
|
|
38
|
+
[](https://github.com/major/pcp-mcp/actions/workflows/ci.yml)
|
|
39
|
+
[](https://codecov.io/gh/major/pcp-mcp)
|
|
40
|
+
[](https://pypi.org/project/pcp-mcp/)
|
|
41
|
+
[](https://www.python.org/downloads/)
|
|
42
|
+
[](https://opensource.org/licenses/MIT)
|
|
43
|
+
|
|
44
|
+
## 🚀 Quick Start (No Install)
|
|
45
|
+
|
|
46
|
+
Run immediately with [uvx](https://docs.astral.sh/uv/) — no installation required:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uvx pcp-mcp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or install as a persistent global tool:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uvx tool install pcp-mcp
|
|
56
|
+
pcp-mcp
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 📦 Installation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install pcp-mcp
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv add pcp-mcp
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 📋 Requirements
|
|
72
|
+
|
|
73
|
+
- **Python**: 3.10+
|
|
74
|
+
- **PCP**: Performance Co-Pilot with `pmcd` and `pmproxy` running
|
|
75
|
+
```bash
|
|
76
|
+
# Fedora/RHEL/CentOS
|
|
77
|
+
sudo dnf install pcp
|
|
78
|
+
sudo systemctl enable --now pmcd pmproxy
|
|
79
|
+
|
|
80
|
+
# Ubuntu/Debian
|
|
81
|
+
sudo apt install pcp
|
|
82
|
+
sudo systemctl enable --now pmcd pmproxy
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## ⚙️ Configuration
|
|
86
|
+
|
|
87
|
+
Configure via environment variables:
|
|
88
|
+
|
|
89
|
+
| Variable | Description | Default |
|
|
90
|
+
|----------|-------------|---------|
|
|
91
|
+
| `PCP_HOST` | pmproxy host | `localhost` |
|
|
92
|
+
| `PCP_PORT` | pmproxy port | `44322` |
|
|
93
|
+
| `PCP_TARGET_HOST` | Target pmcd host to monitor | `localhost` |
|
|
94
|
+
| `PCP_USE_TLS` | Use HTTPS for pmproxy | `false` |
|
|
95
|
+
| `PCP_TLS_VERIFY` | Verify TLS certificates | `true` |
|
|
96
|
+
| `PCP_TLS_CA_BUNDLE` | Path to custom CA bundle | (optional) |
|
|
97
|
+
| `PCP_TIMEOUT` | Request timeout (seconds) | `30` |
|
|
98
|
+
| `PCP_USERNAME` | HTTP basic auth user | (optional) |
|
|
99
|
+
| `PCP_PASSWORD` | HTTP basic auth password | (optional) |
|
|
100
|
+
| `PCP_ALLOWED_HOSTS` | Hostspecs allowed via host param | (optional) |
|
|
101
|
+
|
|
102
|
+
## 🎯 Usage
|
|
103
|
+
|
|
104
|
+
### Monitor localhost (default)
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pcp-mcp
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Monitor a remote host
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
PCP_TARGET_HOST=webserver1.example.com pcp-mcp
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Or use the CLI flag:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pcp-mcp --target-host webserver1.example.com
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Connect to remote pmproxy
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
PCP_HOST=metrics.example.com pcp-mcp
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Use SSE transport
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
pcp-mcp --transport sse
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## 🔌 MCP Client Configuration
|
|
135
|
+
|
|
136
|
+
### Claude Desktop
|
|
137
|
+
|
|
138
|
+
Add to `~/.config/claude/claude_desktop_config.json`:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"mcpServers": {
|
|
143
|
+
"pcp": {
|
|
144
|
+
"command": "uvx",
|
|
145
|
+
"args": ["pcp-mcp"]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
For remote monitoring:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"mcpServers": {
|
|
156
|
+
"pcp": {
|
|
157
|
+
"command": "uvx",
|
|
158
|
+
"args": ["pcp-mcp", "--target-host", "webserver1.example.com"]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
> 💡 Using `uvx` means you don't need pcp-mcp installed — it runs directly from PyPI.
|
|
165
|
+
|
|
166
|
+
## 🛠️ Available Tools
|
|
167
|
+
|
|
168
|
+
### System Monitoring
|
|
169
|
+
|
|
170
|
+
- **`get_system_snapshot`** - Point-in-time system overview (CPU, memory, disk, network, load)
|
|
171
|
+
- **`get_process_top`** - Top processes by CPU, memory, or I/O usage
|
|
172
|
+
- **`query_metrics`** - Fetch current values for specific PCP metrics
|
|
173
|
+
- **`search_metrics`** - Discover available metrics by name pattern
|
|
174
|
+
- **`describe_metric`** - Get detailed metadata about a metric
|
|
175
|
+
|
|
176
|
+
### Example Queries
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
"What's the current CPU usage?"
|
|
180
|
+
→ Uses get_system_snapshot
|
|
181
|
+
|
|
182
|
+
"Show me the top 10 processes by memory usage"
|
|
183
|
+
→ Uses get_process_top(sort_by="memory", limit=10)
|
|
184
|
+
|
|
185
|
+
"What metrics are available for network traffic?"
|
|
186
|
+
→ Uses search_metrics(pattern="network")
|
|
187
|
+
|
|
188
|
+
"Get detailed info about kernel.all.load"
|
|
189
|
+
→ Uses describe_metric(name="kernel.all.load")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 📚 Resources
|
|
193
|
+
|
|
194
|
+
Browse metrics via MCP resources:
|
|
195
|
+
|
|
196
|
+
- `pcp://health` - Quick system health summary
|
|
197
|
+
- `pcp://metrics/common` - Catalog of commonly used metrics
|
|
198
|
+
- `pcp://namespaces` - Live-discovered metric namespaces
|
|
199
|
+
|
|
200
|
+
## 💡 Use Cases
|
|
201
|
+
|
|
202
|
+
### Performance Troubleshooting
|
|
203
|
+
|
|
204
|
+
Ask Claude to:
|
|
205
|
+
- "Analyze current system performance and identify bottlenecks"
|
|
206
|
+
- "Why is my disk I/O so high?"
|
|
207
|
+
- "Which processes are consuming the most CPU?"
|
|
208
|
+
|
|
209
|
+
### System Monitoring
|
|
210
|
+
|
|
211
|
+
- "Give me a health check of the production server"
|
|
212
|
+
- "Compare CPU usage over the last minute"
|
|
213
|
+
- "Monitor network traffic on eth0"
|
|
214
|
+
|
|
215
|
+
### Capacity Planning
|
|
216
|
+
|
|
217
|
+
- "What's the memory utilization trend?"
|
|
218
|
+
- "Show me disk usage across all filesystems"
|
|
219
|
+
- "Analyze process resource consumption patterns"
|
|
220
|
+
|
|
221
|
+
## 🏗️ Architecture
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
225
|
+
│ LLM │ ◄─MCP─► │ pcp-mcp │ ◄─HTTP─► │ pmproxy │ ◄─────► │ pmcd │
|
|
226
|
+
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
|
227
|
+
(REST API) (metrics)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
- **pcp-mcp**: FastMCP server exposing PCP metrics via MCP tools
|
|
231
|
+
- **pmproxy**: PCP's REST API server (runs on port 44322 by default)
|
|
232
|
+
- **pmcd**: PCP metrics collector daemon
|
|
233
|
+
- **Remote monitoring**: Set `PCP_TARGET_HOST` to query a different pmcd instance via pmproxy
|
|
234
|
+
|
|
235
|
+
## 🔧 Development
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Install dependencies
|
|
239
|
+
uv sync --dev
|
|
240
|
+
|
|
241
|
+
# Run all checks
|
|
242
|
+
make check
|
|
243
|
+
|
|
244
|
+
# Individual commands
|
|
245
|
+
make lint # ruff check
|
|
246
|
+
make format # ruff format
|
|
247
|
+
make typecheck # ty check
|
|
248
|
+
make test # pytest with coverage
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## 📖 Documentation
|
|
252
|
+
|
|
253
|
+
Full documentation at [https://major.github.io/pcp-mcp](https://major.github.io/pcp-mcp)
|
|
254
|
+
|
|
255
|
+
## 📄 License
|
|
256
|
+
|
|
257
|
+
MIT
|
|
258
|
+
|
|
259
|
+
<!-- mcp-name: io.github.major/pcp -->
|
pcp_mcp-1.1.0/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# pcp-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [Performance Co-Pilot (PCP)](https://pcp.io/) metrics.
|
|
4
|
+
|
|
5
|
+
Query system performance metrics via the Model Context Protocol - CPU, memory, disk I/O, network, processes, and more.
|
|
6
|
+
|
|
7
|
+
📖 **[Full Documentation](https://major.github.io/pcp-mcp)** | 🚀 **[Getting Started](https://major.github.io/pcp-mcp/getting-started/)**
|
|
8
|
+
|
|
9
|
+
[](https://github.com/major/pcp-mcp/actions/workflows/ci.yml)
|
|
10
|
+
[](https://codecov.io/gh/major/pcp-mcp)
|
|
11
|
+
[](https://pypi.org/project/pcp-mcp/)
|
|
12
|
+
[](https://www.python.org/downloads/)
|
|
13
|
+
[](https://opensource.org/licenses/MIT)
|
|
14
|
+
|
|
15
|
+
## 🚀 Quick Start (No Install)
|
|
16
|
+
|
|
17
|
+
Run immediately with [uvx](https://docs.astral.sh/uv/) — no installation required:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uvx pcp-mcp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or install as a persistent global tool:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uvx tool install pcp-mcp
|
|
27
|
+
pcp-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 📦 Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install pcp-mcp
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv add pcp-mcp
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 📋 Requirements
|
|
43
|
+
|
|
44
|
+
- **Python**: 3.10+
|
|
45
|
+
- **PCP**: Performance Co-Pilot with `pmcd` and `pmproxy` running
|
|
46
|
+
```bash
|
|
47
|
+
# Fedora/RHEL/CentOS
|
|
48
|
+
sudo dnf install pcp
|
|
49
|
+
sudo systemctl enable --now pmcd pmproxy
|
|
50
|
+
|
|
51
|
+
# Ubuntu/Debian
|
|
52
|
+
sudo apt install pcp
|
|
53
|
+
sudo systemctl enable --now pmcd pmproxy
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## ⚙️ Configuration
|
|
57
|
+
|
|
58
|
+
Configure via environment variables:
|
|
59
|
+
|
|
60
|
+
| Variable | Description | Default |
|
|
61
|
+
|----------|-------------|---------|
|
|
62
|
+
| `PCP_HOST` | pmproxy host | `localhost` |
|
|
63
|
+
| `PCP_PORT` | pmproxy port | `44322` |
|
|
64
|
+
| `PCP_TARGET_HOST` | Target pmcd host to monitor | `localhost` |
|
|
65
|
+
| `PCP_USE_TLS` | Use HTTPS for pmproxy | `false` |
|
|
66
|
+
| `PCP_TLS_VERIFY` | Verify TLS certificates | `true` |
|
|
67
|
+
| `PCP_TLS_CA_BUNDLE` | Path to custom CA bundle | (optional) |
|
|
68
|
+
| `PCP_TIMEOUT` | Request timeout (seconds) | `30` |
|
|
69
|
+
| `PCP_USERNAME` | HTTP basic auth user | (optional) |
|
|
70
|
+
| `PCP_PASSWORD` | HTTP basic auth password | (optional) |
|
|
71
|
+
| `PCP_ALLOWED_HOSTS` | Hostspecs allowed via host param | (optional) |
|
|
72
|
+
|
|
73
|
+
## 🎯 Usage
|
|
74
|
+
|
|
75
|
+
### Monitor localhost (default)
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pcp-mcp
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Monitor a remote host
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
PCP_TARGET_HOST=webserver1.example.com pcp-mcp
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or use the CLI flag:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pcp-mcp --target-host webserver1.example.com
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Connect to remote pmproxy
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
PCP_HOST=metrics.example.com pcp-mcp
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Use SSE transport
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pcp-mcp --transport sse
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 🔌 MCP Client Configuration
|
|
106
|
+
|
|
107
|
+
### Claude Desktop
|
|
108
|
+
|
|
109
|
+
Add to `~/.config/claude/claude_desktop_config.json`:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"pcp": {
|
|
115
|
+
"command": "uvx",
|
|
116
|
+
"args": ["pcp-mcp"]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For remote monitoring:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"mcpServers": {
|
|
127
|
+
"pcp": {
|
|
128
|
+
"command": "uvx",
|
|
129
|
+
"args": ["pcp-mcp", "--target-host", "webserver1.example.com"]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
> 💡 Using `uvx` means you don't need pcp-mcp installed — it runs directly from PyPI.
|
|
136
|
+
|
|
137
|
+
## 🛠️ Available Tools
|
|
138
|
+
|
|
139
|
+
### System Monitoring
|
|
140
|
+
|
|
141
|
+
- **`get_system_snapshot`** - Point-in-time system overview (CPU, memory, disk, network, load)
|
|
142
|
+
- **`get_process_top`** - Top processes by CPU, memory, or I/O usage
|
|
143
|
+
- **`query_metrics`** - Fetch current values for specific PCP metrics
|
|
144
|
+
- **`search_metrics`** - Discover available metrics by name pattern
|
|
145
|
+
- **`describe_metric`** - Get detailed metadata about a metric
|
|
146
|
+
|
|
147
|
+
### Example Queries
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
"What's the current CPU usage?"
|
|
151
|
+
→ Uses get_system_snapshot
|
|
152
|
+
|
|
153
|
+
"Show me the top 10 processes by memory usage"
|
|
154
|
+
→ Uses get_process_top(sort_by="memory", limit=10)
|
|
155
|
+
|
|
156
|
+
"What metrics are available for network traffic?"
|
|
157
|
+
→ Uses search_metrics(pattern="network")
|
|
158
|
+
|
|
159
|
+
"Get detailed info about kernel.all.load"
|
|
160
|
+
→ Uses describe_metric(name="kernel.all.load")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## 📚 Resources
|
|
164
|
+
|
|
165
|
+
Browse metrics via MCP resources:
|
|
166
|
+
|
|
167
|
+
- `pcp://health` - Quick system health summary
|
|
168
|
+
- `pcp://metrics/common` - Catalog of commonly used metrics
|
|
169
|
+
- `pcp://namespaces` - Live-discovered metric namespaces
|
|
170
|
+
|
|
171
|
+
## 💡 Use Cases
|
|
172
|
+
|
|
173
|
+
### Performance Troubleshooting
|
|
174
|
+
|
|
175
|
+
Ask Claude to:
|
|
176
|
+
- "Analyze current system performance and identify bottlenecks"
|
|
177
|
+
- "Why is my disk I/O so high?"
|
|
178
|
+
- "Which processes are consuming the most CPU?"
|
|
179
|
+
|
|
180
|
+
### System Monitoring
|
|
181
|
+
|
|
182
|
+
- "Give me a health check of the production server"
|
|
183
|
+
- "Compare CPU usage over the last minute"
|
|
184
|
+
- "Monitor network traffic on eth0"
|
|
185
|
+
|
|
186
|
+
### Capacity Planning
|
|
187
|
+
|
|
188
|
+
- "What's the memory utilization trend?"
|
|
189
|
+
- "Show me disk usage across all filesystems"
|
|
190
|
+
- "Analyze process resource consumption patterns"
|
|
191
|
+
|
|
192
|
+
## 🏗️ Architecture
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
196
|
+
│ LLM │ ◄─MCP─► │ pcp-mcp │ ◄─HTTP─► │ pmproxy │ ◄─────► │ pmcd │
|
|
197
|
+
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
|
198
|
+
(REST API) (metrics)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
- **pcp-mcp**: FastMCP server exposing PCP metrics via MCP tools
|
|
202
|
+
- **pmproxy**: PCP's REST API server (runs on port 44322 by default)
|
|
203
|
+
- **pmcd**: PCP metrics collector daemon
|
|
204
|
+
- **Remote monitoring**: Set `PCP_TARGET_HOST` to query a different pmcd instance via pmproxy
|
|
205
|
+
|
|
206
|
+
## 🔧 Development
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Install dependencies
|
|
210
|
+
uv sync --dev
|
|
211
|
+
|
|
212
|
+
# Run all checks
|
|
213
|
+
make check
|
|
214
|
+
|
|
215
|
+
# Individual commands
|
|
216
|
+
make lint # ruff check
|
|
217
|
+
make format # ruff format
|
|
218
|
+
make typecheck # ty check
|
|
219
|
+
make test # pytest with coverage
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 📖 Documentation
|
|
223
|
+
|
|
224
|
+
Full documentation at [https://major.github.io/pcp-mcp](https://major.github.io/pcp-mcp)
|
|
225
|
+
|
|
226
|
+
## 📄 License
|
|
227
|
+
|
|
228
|
+
MIT
|
|
229
|
+
|
|
230
|
+
<!-- mcp-name: io.github.major/pcp -->
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pcp-mcp"
|
|
3
|
+
version = "1.1.0"
|
|
4
|
+
description = "MCP server for Performance Co-Pilot"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [{ name = "Major Hayden", email = "major@mhtx.net" }]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
keywords = ["mcp", "pcp", "performance-co-pilot", "monitoring", "model-context-protocol"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 5 - Production/Stable",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Intended Audience :: System Administrators",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Topic :: System :: Monitoring",
|
|
21
|
+
"Typing :: Typed",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"cachetools>=5.0",
|
|
25
|
+
"fastmcp>=2.0.0",
|
|
26
|
+
"httpx>=0.27",
|
|
27
|
+
"pydantic-settings>=2.0.0",
|
|
28
|
+
"typing_extensions>=4.0; python_version < '3.11'",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/major/pcp-mcp"
|
|
33
|
+
Repository = "https://github.com/major/pcp-mcp"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
pcp-mcp = "pcp_mcp:main"
|
|
37
|
+
|
|
38
|
+
[build-system]
|
|
39
|
+
requires = ["uv_build>=0.9.18"]
|
|
40
|
+
build-backend = "uv_build"
|
|
41
|
+
|
|
42
|
+
[dependency-groups]
|
|
43
|
+
dev = [
|
|
44
|
+
"pytest>=8",
|
|
45
|
+
"pytest-cov>=6",
|
|
46
|
+
"pytest-asyncio>=0.25",
|
|
47
|
+
"respx>=0.22",
|
|
48
|
+
"ty>=0.0.12",
|
|
49
|
+
"ruff>=0.9",
|
|
50
|
+
"radon>=6",
|
|
51
|
+
"pytest-randomly>=4.0.1",
|
|
52
|
+
"mkdocs-material>=9.5",
|
|
53
|
+
"mkdocstrings[python]>=0.27",
|
|
54
|
+
"commitizen>=4.0",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[tool.uv.build-backend]
|
|
58
|
+
module-name = "pcp_mcp"
|
|
59
|
+
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
target-version = "py310"
|
|
62
|
+
line-length = 100
|
|
63
|
+
|
|
64
|
+
[tool.ruff.lint]
|
|
65
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "ASYNC", "D"]
|
|
66
|
+
ignore = [
|
|
67
|
+
"D100", # Missing docstring in public module
|
|
68
|
+
"D104", # Missing docstring in public package
|
|
69
|
+
"D105", # Missing docstring in magic method
|
|
70
|
+
"D107", # Missing docstring in __init__
|
|
71
|
+
"UP045", # Optional[X] vs X | None - Pydantic needs Optional in Annotated params
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[tool.ruff.lint.per-file-ignores]
|
|
75
|
+
"tests/**/*.py" = ["D"]
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint.pydocstyle]
|
|
78
|
+
convention = "google"
|
|
79
|
+
|
|
80
|
+
[tool.pytest.ini_options]
|
|
81
|
+
asyncio_mode = "auto"
|
|
82
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
83
|
+
testpaths = ["tests"]
|
|
84
|
+
addopts = "--cov=pcp_mcp --cov-report=term-missing"
|
|
85
|
+
|
|
86
|
+
[tool.coverage.run]
|
|
87
|
+
source = ["src/pcp_mcp"]
|
|
88
|
+
branch = true
|
|
89
|
+
|
|
90
|
+
[tool.coverage.report]
|
|
91
|
+
exclude_lines = [
|
|
92
|
+
"pragma: no cover",
|
|
93
|
+
"if TYPE_CHECKING:",
|
|
94
|
+
"raise NotImplementedError",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
[tool.ty.environment]
|
|
98
|
+
python-version = "3.14"
|
|
99
|
+
python-platform = "linux"
|
|
100
|
+
extra-paths = ["src"]
|
|
101
|
+
|
|
102
|
+
[tool.pyright]
|
|
103
|
+
pythonVersion = "3.10"
|
|
104
|
+
pythonPlatform = "Linux"
|
|
105
|
+
venvPath = "."
|
|
106
|
+
venv = ".venv"
|
|
107
|
+
typeCheckingMode = "standard"
|
|
108
|
+
|
|
109
|
+
[tool.commitizen]
|
|
110
|
+
name = "cz_conventional_commits"
|
|
111
|
+
version_provider = "pep621"
|
|
112
|
+
tag_format = "v$version"
|
|
113
|
+
update_changelog_on_bump = true
|
|
114
|
+
changelog_file = "CHANGELOG.md"
|
|
115
|
+
changelog_incremental = true
|
|
116
|
+
bump_message = "bump: version $current_version → $new_version"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# pcp_mcp Core Package
|
|
2
|
+
|
|
3
|
+
## OVERVIEW
|
|
4
|
+
|
|
5
|
+
Core MCP server package. Entry point, HTTP client, configuration, models, error handling.
|
|
6
|
+
|
|
7
|
+
## STRUCTURE
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
pcp_mcp/
|
|
11
|
+
├── __init__.py # CLI entry (main() with argparse)
|
|
12
|
+
├── server.py # FastMCP setup, lifespan context
|
|
13
|
+
├── client.py # PCPClient async httpx wrapper
|
|
14
|
+
├── config.py # PCPMCPSettings (Pydantic)
|
|
15
|
+
├── models.py # Response models (SystemSnapshot, ProcessInfo, etc.)
|
|
16
|
+
├── errors.py # Exception → ToolError mapping
|
|
17
|
+
├── context.py # get_client(), get_settings() helpers
|
|
18
|
+
├── middleware.py # Request caching middleware
|
|
19
|
+
├── icons.py # System assessment icons (emoji mappings)
|
|
20
|
+
├── tools/ # MCP tools (see tools/AGENTS.md)
|
|
21
|
+
├── resources/ # MCP resources (health.py, catalog.py)
|
|
22
|
+
├── utils/ # Extractors, builders
|
|
23
|
+
└── prompts/ # LLM system prompts
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## KEY PATTERNS
|
|
27
|
+
|
|
28
|
+
### Server Lifespan
|
|
29
|
+
```python
|
|
30
|
+
@asynccontextmanager
|
|
31
|
+
async def lifespan(mcp: FastMCP) -> AsyncIterator[dict]:
|
|
32
|
+
async with PCPClient(...) as client:
|
|
33
|
+
yield {"client": client, "settings": settings}
|
|
34
|
+
```
|
|
35
|
+
Tools access via `ctx.request_context.lifespan_context["client"]`.
|
|
36
|
+
|
|
37
|
+
### Client Rate Calculation
|
|
38
|
+
`fetch_with_rates()` takes two samples, calculates per-second rates for counters.
|
|
39
|
+
Handles counter wrap-around (reset to 0) gracefully.
|
|
40
|
+
|
|
41
|
+
### Error Mapping
|
|
42
|
+
```python
|
|
43
|
+
try:
|
|
44
|
+
result = await client.fetch(names)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
raise handle_pcp_error(e, "fetching metrics") from e
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Configuration
|
|
50
|
+
Pydantic settings with `env_prefix="PCP_"`. Computed properties: `base_url`, `auth`.
|
|
51
|
+
|
|
52
|
+
## WHERE TO LOOK
|
|
53
|
+
|
|
54
|
+
| Task | File | Notes |
|
|
55
|
+
|------|------|-------|
|
|
56
|
+
| Add CLI flag | `__init__.py` | argparse in `main()` |
|
|
57
|
+
| Change transport | `__init__.py` | `server.run(transport=...)` |
|
|
58
|
+
| Add env var | `config.py` | Add field with `Field(default=...)` |
|
|
59
|
+
| New response type | `models.py` | Inherit `BaseModel` |
|
|
60
|
+
| Map new exception | `errors.py` | Add case to `handle_pcp_error()` |
|
|
61
|
+
| Access client in tool | `context.py` | Use `get_client(ctx)` |
|
|
62
|
+
| Add caching | `middleware.py` | Request caching layer |
|
|
63
|
+
| System icons | `icons.py` | Assessment emoji mappings |
|
|
64
|
+
|
|
65
|
+
## ANTI-PATTERNS
|
|
66
|
+
|
|
67
|
+
- **NEVER** call `client.fetch()` for counter metrics expecting rates
|
|
68
|
+
- **NEVER** use client outside `async with` context
|
|
69
|
+
- **NEVER** log credentials from settings
|
|
70
|
+
- **ALWAYS** use `handle_pcp_error()` for exception wrapping
|