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 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
+ [![CI](https://github.com/major/pcp-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/major/pcp-mcp/actions/workflows/ci.yml)
39
+ [![codecov](https://codecov.io/gh/major/pcp-mcp/branch/main/graph/badge.svg)](https://codecov.io/gh/major/pcp-mcp)
40
+ [![PyPI version](https://badge.fury.io/py/pcp-mcp.svg)](https://pypi.org/project/pcp-mcp/)
41
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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 -->
@@ -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
+ [![CI](https://github.com/major/pcp-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/major/pcp-mcp/actions/workflows/ci.yml)
10
+ [![codecov](https://codecov.io/gh/major/pcp-mcp/branch/main/graph/badge.svg)](https://codecov.io/gh/major/pcp-mcp)
11
+ [![PyPI version](https://badge.fury.io/py/pcp-mcp.svg)](https://pypi.org/project/pcp-mcp/)
12
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
13
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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