newrelic-mcp 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +430 -0
- package/dist/client/newrelic-client.d.ts +40 -0
- package/dist/client/newrelic-client.d.ts.map +1 -0
- package/dist/client/newrelic-client.js +173 -0
- package/dist/client/newrelic-client.js.map +1 -0
- package/dist/server.d.ts +24 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +204 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/alert.d.ts +14 -0
- package/dist/tools/alert.d.ts.map +1 -0
- package/dist/tools/alert.js +183 -0
- package/dist/tools/alert.js.map +1 -0
- package/dist/tools/apm.d.ts +9 -0
- package/dist/tools/apm.d.ts.map +1 -0
- package/dist/tools/apm.js +33 -0
- package/dist/tools/apm.js.map +1 -0
- package/dist/tools/entity.d.ts +11 -0
- package/dist/tools/entity.d.ts.map +1 -0
- package/dist/tools/entity.js +140 -0
- package/dist/tools/entity.js.map +1 -0
- package/dist/tools/nerdgraph.d.ts +9 -0
- package/dist/tools/nerdgraph.d.ts.map +1 -0
- package/dist/tools/nerdgraph.js +33 -0
- package/dist/tools/nerdgraph.js.map +1 -0
- package/dist/tools/nrql.d.ts +25 -0
- package/dist/tools/nrql.d.ts.map +1 -0
- package/dist/tools/nrql.js +58 -0
- package/dist/tools/nrql.js.map +1 -0
- package/dist/tools/synthetics.d.ts +12 -0
- package/dist/tools/synthetics.d.ts.map +1 -0
- package/dist/tools/synthetics.js +149 -0
- package/dist/tools/synthetics.js.map +1 -0
- package/package.json +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 @cloudbring
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# New Relic MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that provides seamless integration with New Relic's observability platform. Query metrics, manage alerts, monitor applications, and interact with your entire observability stack through a simple, unified interface.
|
|
4
|
+
|
|
5
|
+
> **Disclaimer**: This is an unofficial community project and is not affiliated with, endorsed by, or supported by New Relic, Inc. All trademarks are the property of their respective owners.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 📊 **NRQL Queries** - Execute powerful queries to analyze your data
|
|
10
|
+
- 🚀 **APM Integration** - Monitor application performance and health
|
|
11
|
+
- 🔔 **Alert Management** - View and acknowledge alerts and incidents
|
|
12
|
+
- 🔍 **Entity Search** - Discover and inspect entities across your infrastructure
|
|
13
|
+
- 📈 **Synthetics Monitoring** - Manage synthetic monitors and checks
|
|
14
|
+
- 🔧 **NerdGraph API** - Direct access to New Relic's GraphQL API
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Quick Install with Smithery
|
|
19
|
+
|
|
20
|
+
To install New Relic MCP for Claude Desktop automatically via [Smithery](https://smithery.ai/mcp/newrelic-mcp):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @smithery/cli install newrelic-mcp --client claude
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Manual Installation
|
|
27
|
+
|
|
28
|
+
<details>
|
|
29
|
+
<summary>Claude Desktop</summary>
|
|
30
|
+
|
|
31
|
+
Add to your Claude Desktop configuration file:
|
|
32
|
+
|
|
33
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
34
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"newrelic": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": [
|
|
42
|
+
"-y",
|
|
43
|
+
"newrelic-mcp"
|
|
44
|
+
],
|
|
45
|
+
"env": {
|
|
46
|
+
"NEW_RELIC_API_KEY": "your-api-key-here",
|
|
47
|
+
"NEW_RELIC_ACCOUNT_ID": "your-account-id"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
</details>
|
|
54
|
+
|
|
55
|
+
<details>
|
|
56
|
+
<summary>Cline (VS Code)</summary>
|
|
57
|
+
|
|
58
|
+
Add to your Cline settings in VS Code:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"cline.mcpServers": [
|
|
63
|
+
{
|
|
64
|
+
"name": "newrelic",
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "newrelic-mcp"],
|
|
67
|
+
"env": {
|
|
68
|
+
"NEW_RELIC_API_KEY": "your-api-key-here",
|
|
69
|
+
"NEW_RELIC_ACCOUNT_ID": "your-account-id"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
</details>
|
|
76
|
+
|
|
77
|
+
<details>
|
|
78
|
+
<summary>Zed Editor</summary>
|
|
79
|
+
|
|
80
|
+
Add to your Zed configuration file at `~/.config/zed/settings.json`:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"language_models": {
|
|
85
|
+
"mcp": {
|
|
86
|
+
"servers": {
|
|
87
|
+
"newrelic": {
|
|
88
|
+
"command": "npx",
|
|
89
|
+
"args": ["-y", "newrelic-mcp"],
|
|
90
|
+
"env": {
|
|
91
|
+
"NEW_RELIC_API_KEY": "your-api-key-here",
|
|
92
|
+
"NEW_RELIC_ACCOUNT_ID": "your-account-id"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
</details>
|
|
101
|
+
|
|
102
|
+
<details>
|
|
103
|
+
<summary>Windsurf Editor</summary>
|
|
104
|
+
|
|
105
|
+
Add to your Windsurf Cascade configuration:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"newrelic": {
|
|
111
|
+
"command": "npx",
|
|
112
|
+
"args": ["-y", "newrelic-mcp"],
|
|
113
|
+
"env": {
|
|
114
|
+
"NEW_RELIC_API_KEY": "your-api-key-here",
|
|
115
|
+
"NEW_RELIC_ACCOUNT_ID": "your-account-id"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
</details>
|
|
122
|
+
|
|
123
|
+
<details>
|
|
124
|
+
<summary>Local Development</summary>
|
|
125
|
+
|
|
126
|
+
1. Clone the repository:
|
|
127
|
+
```bash
|
|
128
|
+
git clone https://github.com/cloudbring/newrelic-mcp.git
|
|
129
|
+
cd newrelic-mcp
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
2. Install dependencies and build:
|
|
133
|
+
```bash
|
|
134
|
+
npm install
|
|
135
|
+
npm run build
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
3. Add to your MCP client configuration:
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"mcpServers": {
|
|
142
|
+
"newrelic": {
|
|
143
|
+
"command": "node",
|
|
144
|
+
"args": ["/path/to/newrelic-mcp/dist/server.js"],
|
|
145
|
+
"env": {
|
|
146
|
+
"NEW_RELIC_API_KEY": "your-api-key-here",
|
|
147
|
+
"NEW_RELIC_ACCOUNT_ID": "your-account-id"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
</details>
|
|
154
|
+
|
|
155
|
+
## Configuration
|
|
156
|
+
|
|
157
|
+
### Required Environment Variables
|
|
158
|
+
|
|
159
|
+
- `NEW_RELIC_API_KEY` - Your New Relic User API Key (required)
|
|
160
|
+
- `NEW_RELIC_ACCOUNT_ID` - Your New Relic Account ID (optional, can be provided per tool call)
|
|
161
|
+
|
|
162
|
+
### Getting Your New Relic Credentials
|
|
163
|
+
|
|
164
|
+
1. **API Key**:
|
|
165
|
+
- Log in to [New Relic](https://one.newrelic.com)
|
|
166
|
+
- Navigate to **API Keys** in the left sidebar
|
|
167
|
+
- Create a new User API Key with appropriate permissions
|
|
168
|
+
|
|
169
|
+
2. **Account ID**:
|
|
170
|
+
- Find your Account ID in the URL when logged into New Relic
|
|
171
|
+
- Or navigate to **Administration** → **Access management** → **Accounts**
|
|
172
|
+
|
|
173
|
+
For detailed setup instructions, see [docs/new-relic-setup.md](docs/new-relic-setup.md).
|
|
174
|
+
|
|
175
|
+
## Usage Examples
|
|
176
|
+
|
|
177
|
+
Once configured, you can interact with New Relic through your MCP client:
|
|
178
|
+
|
|
179
|
+
### Query Your Data
|
|
180
|
+
```
|
|
181
|
+
"Show me the average response time for my web application over the last hour"
|
|
182
|
+
"What are the top 10 slowest database queries today?"
|
|
183
|
+
"Display error rate trends for the production environment"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Monitor Applications
|
|
187
|
+
```
|
|
188
|
+
"List all my APM applications and their current status"
|
|
189
|
+
"Show me the health of my Node.js services"
|
|
190
|
+
"Which applications have active alerts?"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Manage Alerts
|
|
194
|
+
```
|
|
195
|
+
"Show me all open incidents"
|
|
196
|
+
"What critical alerts fired in the last 24 hours?"
|
|
197
|
+
"Acknowledge incident #12345"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Search Infrastructure
|
|
201
|
+
```
|
|
202
|
+
"Find all Redis databases in production"
|
|
203
|
+
"Show me entities with high CPU usage"
|
|
204
|
+
"List all synthetic monitors and their success rates"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Available Tools
|
|
208
|
+
|
|
209
|
+
| Tool | Description |
|
|
210
|
+
|------|-------------|
|
|
211
|
+
| `run_nrql_query` | Execute NRQL queries to analyze your data |
|
|
212
|
+
| `list_apm_applications` | List all APM applications in your account |
|
|
213
|
+
| `search_entities` | Search for entities by name, type, or tags |
|
|
214
|
+
| `get_entity_details` | Get detailed information about a specific entity |
|
|
215
|
+
| `run_nerdgraph_query` | Execute custom NerdGraph GraphQL queries |
|
|
216
|
+
| `list_alert_policies` | List all alert policies in your account |
|
|
217
|
+
| `list_open_incidents` | List all open incidents with priority filtering |
|
|
218
|
+
| `acknowledge_incident` | Acknowledge an open incident |
|
|
219
|
+
| `list_synthetics_monitors` | List all Synthetics monitors |
|
|
220
|
+
| `create_browser_monitor` | Create a new browser-based Synthetics monitor |
|
|
221
|
+
| `get_account_details` | Get New Relic account details |
|
|
222
|
+
|
|
223
|
+
## Troubleshooting
|
|
224
|
+
|
|
225
|
+
<details>
|
|
226
|
+
<summary>Connection Issues</summary>
|
|
227
|
+
|
|
228
|
+
If you're having trouble connecting:
|
|
229
|
+
|
|
230
|
+
1. Verify your API key is valid:
|
|
231
|
+
```bash
|
|
232
|
+
curl -X POST https://api.newrelic.com/graphql \
|
|
233
|
+
-H 'Content-Type: application/json' \
|
|
234
|
+
-H 'API-Key: YOUR_API_KEY' \
|
|
235
|
+
-d '{"query":"{ actor { user { email } } }"}'
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
2. Check that your Account ID is correct
|
|
239
|
+
3. Ensure your API key has the necessary permissions
|
|
240
|
+
4. Check the MCP client logs for detailed error messages
|
|
241
|
+
</details>
|
|
242
|
+
|
|
243
|
+
<details>
|
|
244
|
+
<summary>Permission Errors</summary>
|
|
245
|
+
|
|
246
|
+
If you receive permission errors:
|
|
247
|
+
|
|
248
|
+
1. Verify your API key has the required permissions:
|
|
249
|
+
- For NRQL queries: `NRQL query` permission
|
|
250
|
+
- For APM data: `APM` read permissions
|
|
251
|
+
- For alerts: `Alerts` read/write permissions
|
|
252
|
+
|
|
253
|
+
2. Create a new API key with broader permissions if needed
|
|
254
|
+
</details>
|
|
255
|
+
|
|
256
|
+
## Development
|
|
257
|
+
|
|
258
|
+
### Project Structure
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
src/
|
|
262
|
+
├── server.ts # Main MCP server implementation
|
|
263
|
+
├── client/
|
|
264
|
+
│ └── newrelic-client.ts # New Relic API client
|
|
265
|
+
└── tools/
|
|
266
|
+
├── nrql.ts # NRQL query tool
|
|
267
|
+
├── apm.ts # APM applications tool
|
|
268
|
+
├── entity.ts # Entity management tools
|
|
269
|
+
├── alert.ts # Alert and incident tools
|
|
270
|
+
├── synthetics.ts # Synthetics monitoring tools
|
|
271
|
+
└── nerdgraph.ts # NerdGraph query tool
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Setup Development Environment
|
|
275
|
+
|
|
276
|
+
1. Clone the repository:
|
|
277
|
+
```bash
|
|
278
|
+
git clone https://github.com/cloudbring/newrelic-mcp.git
|
|
279
|
+
cd newrelic-mcp
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
2. Install dependencies:
|
|
283
|
+
```bash
|
|
284
|
+
npm install
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
3. Create a `.env` file:
|
|
288
|
+
```bash
|
|
289
|
+
NEW_RELIC_API_KEY=your-api-key-here
|
|
290
|
+
NEW_RELIC_ACCOUNT_ID=your-account-id
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
4. Build the project:
|
|
294
|
+
```bash
|
|
295
|
+
npm run build
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Development Commands
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# Start development server with hot reload
|
|
302
|
+
npm run dev
|
|
303
|
+
|
|
304
|
+
# Build for production
|
|
305
|
+
npm run build
|
|
306
|
+
|
|
307
|
+
# Run tests
|
|
308
|
+
npm test
|
|
309
|
+
|
|
310
|
+
# Run tests with coverage
|
|
311
|
+
npm run test:coverage
|
|
312
|
+
|
|
313
|
+
# Run linting
|
|
314
|
+
npm run lint
|
|
315
|
+
|
|
316
|
+
# Format code
|
|
317
|
+
npm run format
|
|
318
|
+
|
|
319
|
+
# Test server startup
|
|
320
|
+
npm run test:server
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Testing
|
|
324
|
+
|
|
325
|
+
The project uses Test-Driven Development (TDD) with:
|
|
326
|
+
- **Vitest** for unit testing
|
|
327
|
+
- **Gherkin** for BDD testing
|
|
328
|
+
- **Evalite** for LLM response validation
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Run all tests
|
|
332
|
+
npm test
|
|
333
|
+
|
|
334
|
+
# Run with coverage
|
|
335
|
+
npm run test:coverage
|
|
336
|
+
|
|
337
|
+
# Run BDD tests only
|
|
338
|
+
npm run test:bdd
|
|
339
|
+
|
|
340
|
+
# Run integration tests with real API
|
|
341
|
+
USE_REAL_ENV=true npm test
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Debugging
|
|
345
|
+
|
|
346
|
+
Use the MCP Inspector to test and debug the server:
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
# Run with MCP Inspector
|
|
350
|
+
npm run inspect
|
|
351
|
+
|
|
352
|
+
# Run with development server
|
|
353
|
+
npm run inspect:dev
|
|
354
|
+
|
|
355
|
+
# Run with environment variables
|
|
356
|
+
npm run inspect:env
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
See [docs/mcp-inspector-setup.md](docs/mcp-inspector-setup.md) for detailed instructions.
|
|
360
|
+
|
|
361
|
+
### Architecture
|
|
362
|
+
|
|
363
|
+
The server follows a modular architecture with:
|
|
364
|
+
- **Client Layer**: Handles New Relic API communication
|
|
365
|
+
- **Tools Layer**: Implements MCP tool specifications
|
|
366
|
+
- **Server Layer**: Manages MCP protocol and tool routing
|
|
367
|
+
|
|
368
|
+
Each tool:
|
|
369
|
+
- Has a single, focused purpose
|
|
370
|
+
- Validates inputs using Zod schemas
|
|
371
|
+
- Returns structured, typed responses
|
|
372
|
+
- Includes comprehensive error handling
|
|
373
|
+
|
|
374
|
+
## Contributing
|
|
375
|
+
|
|
376
|
+
We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details.
|
|
377
|
+
|
|
378
|
+
### Development Workflow
|
|
379
|
+
|
|
380
|
+
1. Fork the repository
|
|
381
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
382
|
+
3. Write tests first (TDD approach)
|
|
383
|
+
4. Implement your feature
|
|
384
|
+
5. Ensure all tests pass (`npm test`)
|
|
385
|
+
6. Maintain >90% code coverage
|
|
386
|
+
7. Run linting (`npm run lint`)
|
|
387
|
+
8. Commit your changes (commits will be auto-formatted)
|
|
388
|
+
9. Push to your branch
|
|
389
|
+
10. Open a Pull Request
|
|
390
|
+
|
|
391
|
+
### Code Style
|
|
392
|
+
|
|
393
|
+
This project uses:
|
|
394
|
+
- **Biome** for linting and formatting
|
|
395
|
+
- **TypeScript** with strict mode
|
|
396
|
+
- **2 spaces** for indentation
|
|
397
|
+
- **Single quotes** for strings
|
|
398
|
+
- **Semicolons** always
|
|
399
|
+
|
|
400
|
+
## Documentation
|
|
401
|
+
|
|
402
|
+
- [New Relic Setup Guide](docs/new-relic-setup.md) - Detailed credential setup
|
|
403
|
+
- [MCP Inspector Setup](docs/mcp-inspector-setup.md) - Testing and debugging
|
|
404
|
+
- [Logging & Telemetry](docs/logging-telemetry.md) - Test monitoring
|
|
405
|
+
- [Implementation Details](docs/implementation.md) - Architecture deep dive
|
|
406
|
+
|
|
407
|
+
## Support
|
|
408
|
+
|
|
409
|
+
- 🐛 [Report bugs](https://github.com/cloudbring/newrelic-mcp/issues)
|
|
410
|
+
- 💡 [Request features](https://github.com/cloudbring/newrelic-mcp/issues)
|
|
411
|
+
- 💬 [Join discussions](https://github.com/cloudbring/newrelic-mcp/discussions)
|
|
412
|
+
- 📖 [Read the docs](https://github.com/cloudbring/newrelic-mcp/tree/main/docs)
|
|
413
|
+
|
|
414
|
+
## License
|
|
415
|
+
|
|
416
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
417
|
+
|
|
418
|
+
## Disclaimer
|
|
419
|
+
|
|
420
|
+
This project is not affiliated with, endorsed by, or supported by New Relic, Inc. It is an independent open-source project that uses New Relic's public APIs.
|
|
421
|
+
|
|
422
|
+
## Acknowledgments
|
|
423
|
+
|
|
424
|
+
- Built on the [Model Context Protocol](https://modelcontextprotocol.io) specification
|
|
425
|
+
- Integrates with [New Relic's](https://newrelic.com) observability platform APIs
|
|
426
|
+
- Inspired by the broader MCP ecosystem
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
Made with ❤️ by [@cloudbring](https://github.com/cloudbring) using Cursor and Claude Code
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface NrqlQueryResult {
|
|
2
|
+
results: any[];
|
|
3
|
+
metadata: {
|
|
4
|
+
eventTypes?: string[];
|
|
5
|
+
timeWindow?: {
|
|
6
|
+
begin: number;
|
|
7
|
+
end: number;
|
|
8
|
+
};
|
|
9
|
+
facets?: string[];
|
|
10
|
+
timeSeries?: boolean;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface AccountDetails {
|
|
14
|
+
accountId: string;
|
|
15
|
+
name: string;
|
|
16
|
+
region?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ApmApplication {
|
|
19
|
+
guid: string;
|
|
20
|
+
name: string;
|
|
21
|
+
language: string;
|
|
22
|
+
reporting: boolean;
|
|
23
|
+
alertSeverity?: string;
|
|
24
|
+
tags?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
export declare class NewRelicClient {
|
|
27
|
+
private apiKey;
|
|
28
|
+
private defaultAccountId?;
|
|
29
|
+
constructor(apiKey?: string, defaultAccountId?: string);
|
|
30
|
+
validateCredentials(): Promise<boolean>;
|
|
31
|
+
getAccountDetails(accountId?: string): Promise<AccountDetails>;
|
|
32
|
+
runNrqlQuery(params: {
|
|
33
|
+
nrql: string;
|
|
34
|
+
accountId: string;
|
|
35
|
+
}): Promise<NrqlQueryResult>;
|
|
36
|
+
listApmApplications(accountId?: string): Promise<ApmApplication[]>;
|
|
37
|
+
private parseTags;
|
|
38
|
+
executeNerdGraphQuery(query: string, variables?: any): Promise<any>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=newrelic-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"newrelic-client.d.ts","sourceRoot":"","sources":["../../src/client/newrelic-client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,GAAG,EAAE,CAAC;IACf,QAAQ,EAAE;QACR,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,UAAU,CAAC,EAAE;YACX,KAAK,EAAE,MAAM,CAAC;YACd,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;QACF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAC,CAAS;gBAEtB,MAAM,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM;IAKhD,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAkBvC,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA2B9D,YAAY,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IA2DnF,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAyCxE,OAAO,CAAC,SAAS;IAYX,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;CAwB1E"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NewRelicClient = void 0;
|
|
4
|
+
const NERDGRAPH_URL = 'https://api.newrelic.com/graphql';
|
|
5
|
+
class NewRelicClient {
|
|
6
|
+
apiKey;
|
|
7
|
+
defaultAccountId;
|
|
8
|
+
constructor(apiKey, defaultAccountId) {
|
|
9
|
+
this.apiKey = apiKey || process.env.NEW_RELIC_API_KEY || '';
|
|
10
|
+
this.defaultAccountId = defaultAccountId || process.env.NEW_RELIC_ACCOUNT_ID;
|
|
11
|
+
}
|
|
12
|
+
async validateCredentials() {
|
|
13
|
+
try {
|
|
14
|
+
const query = `{
|
|
15
|
+
actor {
|
|
16
|
+
user {
|
|
17
|
+
id
|
|
18
|
+
email
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}`;
|
|
22
|
+
const response = await this.executeNerdGraphQuery(query);
|
|
23
|
+
return !!response.data?.actor?.user;
|
|
24
|
+
}
|
|
25
|
+
catch (_error) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async getAccountDetails(accountId) {
|
|
30
|
+
const id = accountId || this.defaultAccountId;
|
|
31
|
+
if (!id) {
|
|
32
|
+
throw new Error('Account ID must be provided');
|
|
33
|
+
}
|
|
34
|
+
const query = `{
|
|
35
|
+
actor {
|
|
36
|
+
account(id: ${id}) {
|
|
37
|
+
id
|
|
38
|
+
name
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}`;
|
|
42
|
+
const response = await this.executeNerdGraphQuery(query);
|
|
43
|
+
if (!response.data?.actor?.account) {
|
|
44
|
+
throw new Error(`Account ${id} not found`);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
accountId: response.data.actor.account.id,
|
|
48
|
+
name: response.data.actor.account.name,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async runNrqlQuery(params) {
|
|
52
|
+
if (!params.nrql || typeof params.nrql !== 'string') {
|
|
53
|
+
throw new Error('Invalid or empty NRQL query provided');
|
|
54
|
+
}
|
|
55
|
+
if (!params.accountId || !/^\d+$/.test(params.accountId)) {
|
|
56
|
+
throw new Error('Invalid account ID format');
|
|
57
|
+
}
|
|
58
|
+
const query = `{
|
|
59
|
+
actor {
|
|
60
|
+
account(id: ${params.accountId}) {
|
|
61
|
+
nrql(query: "${params.nrql.replace(/"/g, '\\"')}") {
|
|
62
|
+
results
|
|
63
|
+
metadata {
|
|
64
|
+
eventTypes
|
|
65
|
+
timeWindow {
|
|
66
|
+
begin
|
|
67
|
+
end
|
|
68
|
+
}
|
|
69
|
+
facets
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}`;
|
|
75
|
+
try {
|
|
76
|
+
const response = await this.executeNerdGraphQuery(query);
|
|
77
|
+
if (response.errors) {
|
|
78
|
+
const errorMessage = response.errors[0]?.message || 'NRQL query failed';
|
|
79
|
+
throw new Error(errorMessage);
|
|
80
|
+
}
|
|
81
|
+
const nrqlResult = response.data?.actor?.account?.nrql;
|
|
82
|
+
if (!nrqlResult) {
|
|
83
|
+
throw new Error('No results returned from NRQL query');
|
|
84
|
+
}
|
|
85
|
+
// Detect if it's a time series query
|
|
86
|
+
const isTimeSeries = params.nrql.toLowerCase().includes('timeseries');
|
|
87
|
+
return {
|
|
88
|
+
results: nrqlResult.results || [],
|
|
89
|
+
metadata: {
|
|
90
|
+
...nrqlResult.metadata,
|
|
91
|
+
timeSeries: isTimeSeries,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (error.message.includes('Syntax error')) {
|
|
97
|
+
throw new Error(`NRQL Syntax error: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async listApmApplications(accountId) {
|
|
103
|
+
const id = accountId || this.defaultAccountId;
|
|
104
|
+
if (!id) {
|
|
105
|
+
throw new Error('Account ID must be provided');
|
|
106
|
+
}
|
|
107
|
+
const query = `{
|
|
108
|
+
actor {
|
|
109
|
+
entitySearch(query: "domain = 'APM' AND type = 'APPLICATION' AND accountId = '${id}'") {
|
|
110
|
+
results {
|
|
111
|
+
entities {
|
|
112
|
+
guid
|
|
113
|
+
name
|
|
114
|
+
... on ApmApplicationEntityOutline {
|
|
115
|
+
language
|
|
116
|
+
reporting
|
|
117
|
+
alertSeverity
|
|
118
|
+
tags {
|
|
119
|
+
key
|
|
120
|
+
values
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}`;
|
|
128
|
+
const response = await this.executeNerdGraphQuery(query);
|
|
129
|
+
const entities = response.data?.actor?.entitySearch?.results?.entities || [];
|
|
130
|
+
return entities.map((entity) => ({
|
|
131
|
+
guid: entity.guid,
|
|
132
|
+
name: entity.name,
|
|
133
|
+
language: entity.language || 'unknown',
|
|
134
|
+
reporting: entity.reporting || false,
|
|
135
|
+
alertSeverity: entity.alertSeverity,
|
|
136
|
+
tags: this.parseTags(entity.tags),
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
parseTags(tags) {
|
|
140
|
+
if (!tags)
|
|
141
|
+
return {};
|
|
142
|
+
const result = {};
|
|
143
|
+
tags.forEach((tag) => {
|
|
144
|
+
if (tag.key && tag.values?.length > 0) {
|
|
145
|
+
result[tag.key] = tag.values[0];
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
async executeNerdGraphQuery(query, variables) {
|
|
151
|
+
// Check if API key is missing or empty
|
|
152
|
+
if (!this.apiKey || this.apiKey === '' || this.apiKey.length === 0) {
|
|
153
|
+
throw new Error('NEW_RELIC_API_KEY environment variable is not set');
|
|
154
|
+
}
|
|
155
|
+
const response = await fetch(NERDGRAPH_URL, {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
headers: {
|
|
158
|
+
'Content-Type': 'application/json',
|
|
159
|
+
'API-Key': this.apiKey,
|
|
160
|
+
},
|
|
161
|
+
body: JSON.stringify({ query, variables }),
|
|
162
|
+
});
|
|
163
|
+
if (!response.ok) {
|
|
164
|
+
if (response.status === 401) {
|
|
165
|
+
throw new Error('Unauthorized: Invalid API key');
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`NerdGraph API error: ${response.status} ${response.statusText}`);
|
|
168
|
+
}
|
|
169
|
+
return await response.json();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.NewRelicClient = NewRelicClient;
|
|
173
|
+
//# sourceMappingURL=newrelic-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"newrelic-client.js","sourceRoot":"","sources":["../../src/client/newrelic-client.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { NewRelicClient } from './client/newrelic-client';
|
|
4
|
+
export declare class NewRelicMCPServer {
|
|
5
|
+
private server;
|
|
6
|
+
private client;
|
|
7
|
+
private tools;
|
|
8
|
+
private defaultAccountId?;
|
|
9
|
+
constructor(client?: NewRelicClient);
|
|
10
|
+
private registerTools;
|
|
11
|
+
private setupHandlers;
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
executeTool(name: string, args: any): Promise<any>;
|
|
14
|
+
private requiresAccountId;
|
|
15
|
+
getMetadata(): {
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
description: string;
|
|
19
|
+
};
|
|
20
|
+
getRegisteredTools(): string[];
|
|
21
|
+
getTool(name: string): Tool | undefined;
|
|
22
|
+
getDefaultAccountId(): string | undefined;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=server.d.ts.map
|