@smartbear/mcp 0.2.1 → 0.3.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/README.md CHANGED
@@ -1,24 +1,58 @@
1
1
  <div align="center">
2
2
  <a href="https://www.smartbear.com">
3
3
  <picture>
4
- <source media="(prefers-color-scheme: dark)" srcset="assets/smartbear-logo-light.svg">
5
- <img alt="SmartBear logo" src="assets/smartbear-logo-dark.svg">
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://assets.smartbear.com/m/79b99a7ff9c81a9a/original/SmartBear-Logo_Dark-Mode.svg">
5
+ <img alt="SmartBear logo" src="https://assets.smartbear.com/m/105001cc5db1e0bf/original/SmartBear-Logo_Light-Mode.svg">
6
6
  </picture>
7
7
  </a>
8
8
  <h1>SmartBear MCP server</h1>
9
+
10
+ <!-- Badges -->
11
+ <div>
12
+ <a href="https://github.com/SmartBear/smartbear-mcp/actions/workflows/test.yml"><img src="https://github.com/SmartBear/smartbear-mcp/workflows/Test%20Suite/badge.svg" alt="Test Status"></a>
13
+ <a href="https://smartbear.github.io/smartbear-mcp/"><img src="https://img.shields.io/badge/coverage-dynamic-brightgreen" alt="Coverage"></a>
14
+ <a href="https://www.npmjs.com/package/@smartbear/mcp"><img src="https://img.shields.io/npm/v/@smartbear/mcp" alt="npm version"></a>
15
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Compatible-blue" alt="MCP Compatible"></a>
16
+ <a href="https://developer.smartbear.com/smartbear-mcp"><img src="https://img.shields.io/badge/documentation-latest-blue.svg" alt="Documentation"></a>
17
+ </div>
9
18
  </div>
19
+ <br />
20
+
21
+ A Model Context Protocol (MCP) server which provides AI assistants with seamless access to SmartBear's suite of testing and monitoring tools, including [Insight Hub](https://www.smartbear.com/insight-hub), [Reflect](https://reflect.run), and [API Hub](https://www.smartbear.com/api-hub).
22
+
23
+ ## What is MCP?
24
+
25
+ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open standard that enables AI assistants to securely connect to external data sources and tools. This server exposes SmartBear's APIs through natural language interfaces, allowing you to query your testing data, analyze performance metrics, and manage test automation directly from your AI workflow.
26
+
27
+ ## Supported Tools
28
+
29
+ See individual guides for suggested prompts and supported tools and resources:
30
+
31
+ - [Insight Hub](https://developer.smartbear.com/smartbear-mcp/docs/insight-hub-integration) - Comprehensive error monitoring and debugging capabilities
32
+ - [Test Hub](https://developer.smartbear.com/smartbear-mcp/docs/test-hub-integration) - Test management and execution capabilities
33
+ - [API Hub](https://developer.smartbear.com/smartbear-mcp/docs/api-hub-integration) - Portal management capabilities
34
+
35
+
36
+ ## Prerequisites
37
+
38
+ - Node.js 20+ and npm
39
+ - Access to SmartBear products (Insight Hub, Reflect, or API Hub)
40
+ - Valid API tokens for the products you want to integrate
41
+
42
+ ## Installation
10
43
 
11
- An [MCP](https://modelcontextprotocol.io) server for SmartBear's API Hub, Test Hub and Insight Hub.
44
+ The MCP server is distributed as an npm package [`@smartbear/mcp`](https://www.npmjs.com/package/@smartbear/mcp), making it easy to integrate into your development workflow.
12
45
 
13
- ## Usage
46
+ The server is started with the API key or auth token that you use with your SmartBear product(s). They are optional and can be removed from your configuration if you aren't using the product. For Insight Hub, if you provide a project API key it will narrow down all searches to a single project in your Insight Hub dashboard. Leave this field blank if you wish to interact across multiple projects at a time.
14
47
 
15
- The server is started with the API key or auth token that you use with your product(s). They are optional and can be removed from your configuration if you aren't using the product.
48
+ ### VS Code with Copilot
16
49
 
17
- ### VS Code
50
+ For the quickest setup, use the "MCP: Add server…" command in the Command Palette to add the `@smartbear/mcp` npm package.
18
51
 
19
- Add the [`@smartbear/mcp`](https://www.npmjs.com/package/@smartbear/mcp) package to your project via NPM or via the "MCP: Add server…" command in VS Code.
52
+ <details>
53
+ <summary><strong>📋 Manual installation</strong></summary>
20
54
 
21
- If setting up manually, add the following configuration to `.vscode/mcp.json`:
55
+ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` package to run the server and add the following to your `.vscode/mcp.json` file:
22
56
 
23
57
  ```json
24
58
  {
@@ -66,76 +100,128 @@ If setting up manually, add the following configuration to `.vscode/mcp.json`:
66
100
  ]
67
101
  }
68
102
  ```
103
+ </details>
69
104
 
70
- ### MCP Inspector
105
+ ### Claude Desktop
71
106
 
72
- To test the MCP server using the npm package, run:
107
+ Add the following configuration to your `claude_desktop_config.json` to launch the MCP server via `npx`:
73
108
 
74
- ```bash
75
- REFLECT_API_TOKEN=your_reflect_token INSIGHT_HUB_AUTH_TOKEN=your_insight_hub_token API_HUB_API_KEY=your_api_hub_api_key npx @smartbear/mcp
109
+ ```json
110
+ {
111
+ "mcpServers": {
112
+ "smartbear": {
113
+ "command": "npx",
114
+ "args": [
115
+ "-y",
116
+ "@smartbear/mcp@latest"
117
+ ],
118
+ "env": {
119
+ "INSIGHT_HUB_AUTH_TOKEN": "your_personal_auth_token",
120
+ "INSIGHT_HUB_PROJECT_API_KEY": "your_project_api_key",
121
+ "REFLECT_API_TOKEN": "your_reflect_token",
122
+ "API_HUB_API_KEY": "your_api_hub_key"
123
+ }
124
+ }
125
+ }
126
+ }
76
127
  ```
77
128
 
78
- This will open an inspector window in your browser, where you can test the tools.
79
-
80
- ## Supported Tools
81
-
82
- See individual guides for suggested prompts and supported tools and resources:
83
-
84
- - [Insight Hub](./insight-hub/README.md)\
85
- Get your top events and invite your LLM to help you fix them.
86
- - [Reflect](./reflect/README.md)
87
- - [API Hub](./api-hub/README.md)
129
+ ## Documentation
88
130
 
89
- ## Environment Variables
90
-
91
- - `INSIGHT_HUB_AUTH_TOKEN`: Required for Insight Hub tools. The Auth Token for Insight Hub.
92
- - `REFLECT_API_TOKEN`: Required for Reflect tools. The Reflect Account API Key for Reflect-based tools.
93
- - `API_HUB_API_KEY`: Required for API Hub tools. The API Key for API Hub tools.
94
- - `MCP_SERVER_INSIGHT_HUB_API_KEY`: Optional. If set, enables error reporting of the _MCP_server_ code via the BugSnag SDK. This is useful for debugging and monitoring of the MCP server itself and shouldn't be set to the same API key as your app.
95
-
96
- See individual guides for product-specific configuration via environment variables.
131
+ For detailed introduction, examples, and advanced configuration visit our 📖 [Full Documentation](https://developer.smartbear.com/smartbear-mcp)
97
132
 
98
133
  ## Local Development
99
134
 
100
- If you want to build and run the MCP server from source (for development or contribution):
101
-
102
- ### Build
135
+ For developers who want to contribute to the SmartBear MCP server, customize its functionality, or work with the latest development features, you can build and run the server directly from source code. This approach gives you full control over the implementation and allows you to make modifications as needed.
136
+
137
+ 1. **Clone the repository:**
138
+ ```bash
139
+ git clone https://github.com/SmartBear/smartbear-mcp.git
140
+ cd smartbear-mcp
141
+ ```
142
+
143
+ 2. **Install dependencies:**
144
+ ```bash
145
+ npm install
146
+ ```
147
+
148
+ 3. **Build the server:**
149
+ ```bash
150
+ npm run build
151
+ ```
152
+
153
+ 4. **Add the server to your IDE** configuration updating `.vscode/mcp.json` (or equivalent) to point to your local build
154
+
155
+ <details>
156
+ <summary><strong>📋 VSCode (mcp.json)</strong></summary>
157
+
158
+ ```json
159
+ {
160
+ "servers": {
161
+ "smartbear": {
162
+ "type": "stdio",
163
+ "command": "node",
164
+ "dev": { // <-- To allow debugging in VS Code
165
+ "watch": "dist/**/*.js",
166
+ "debug": {
167
+ "type": "node"
168
+ },
169
+ },
170
+ "args": ["<PATH_TO_SMARTBEAR_MCP_REPO>/dist/index.js"],
171
+ "env": {
172
+ "INSIGHT_HUB_AUTH_TOKEN": "${input:insight_hub_auth_token}",
173
+ "INSIGHT_HUB_PROJECT_API_KEY": "${input:insight_hub_project_api_key}",
174
+ "REFLECT_API_TOKEN": "${input:reflect_api_token}",
175
+ "API_HUB_API_KEY": "${input:api_hub_api_key}"
176
+ }
177
+ }
178
+ },
179
+ "inputs": [
180
+ {
181
+ "id": "insight_hub_auth_token",
182
+ "type": "promptString",
183
+ "description": "Insight Hub Auth Token - leave blank to disable Insight Hub tools",
184
+ "password": true
185
+ },
186
+ {
187
+ "id": "insight_hub_project_api_key",
188
+ "type": "promptString",
189
+ "description": "Insight Hub Project API Key - for single project interactions",
190
+ "password": false
191
+ },
192
+ {
193
+ "id": "reflect_api_token",
194
+ "type": "promptString",
195
+ "description": "Reflect API Token - leave blank to disable Reflect tools",
196
+ "password": true
197
+ },
198
+ {
199
+ "id": "api_hub_api_key",
200
+ "type": "promptString",
201
+ "description": "API Hub API Key - leave blank to disable API Hub tools",
202
+ "password": true
203
+ }
204
+ ]
205
+ }
206
+ ```
207
+ </details>
103
208
 
104
- Clone this repository and run:
209
+ 5. **Local testing** using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) web interface:
105
210
 
106
- ```bash
107
- npm install
108
- npm run build
109
- ```
211
+ ```bash
212
+ INSIGHT_HUB_AUTH_TOKEN="your_token" REFLECT_API_TOKEN="your_reflect_token" API_HUB_API_KEY="your_api_hub_key" npx @modelcontextprotocol/inspector npx @smartbear/mcp@latest
213
+ ```
110
214
 
111
- ### Usage (Local Build)
215
+ ## License
112
216
 
113
- Update your `.vscode/mcp.json` to point to your local build:
217
+ This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the [LICENSE](LICENSE.txt) file in the project repository.
114
218
 
115
- ```json
116
- {
117
- "servers": {
118
- "smartbear": {
119
- "type": "stdio",
120
- "command": "node",
121
- "args": ["<PATH_TO_SMARTBEAR_MCP>/dist/index.js"],
122
- "env": {
123
- // ...same as above...
124
- }
125
- }
126
- },
127
- "inputs": [
128
- // ...same as above...
129
- ]
130
- }
131
- ```
219
+ ## Support
132
220
 
133
- Or run the server directly:
221
+ * [Search open and closed issues](https://github.com/SmartBear/smartbear-mcp/issues?utf8=✓&q=is%3Aissue) for similar problems
222
+ * [Report a bug or request a feature](https://github.com/SmartBear/smartbear-mcp/issues/new)
134
223
 
135
- ```bash
136
- REFLECT_API_TOKEN=your_reflect_token INSIGHT_HUB_AUTH_TOKEN=your_insight_hub_token API_HUB_API_KEY=your_api_hub_api_key node dist/index.js
137
- ```
138
224
 
139
- ## License
225
+ ---
140
226
 
141
- This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
227
+ **SmartBear MCP Server** - Bringing the power of SmartBear's testing and monitoring ecosystem to your AI-powered development workflow.
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
2
3
  // Tool definitions for API Hub API client
3
4
  export class ApiHubClient {
4
5
  headers;
@@ -6,6 +7,7 @@ export class ApiHubClient {
6
7
  this.headers = {
7
8
  "Authorization": `Bearer ${token}`,
8
9
  "Content-Type": "application/json",
10
+ "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
9
11
  };
10
12
  }
11
13
  async getPortals() {
@@ -1,10 +1,13 @@
1
1
  export function toolDescriptionTemplate(params) {
2
- const { summary, useCases, examples, parameters, hints } = params;
2
+ const { summary, useCases, examples, parameters, hints, outputFormat } = params;
3
3
  let description = summary;
4
4
  // Parameters (essential)
5
5
  if (parameters.length > 0) {
6
6
  description += `\n\n**Parameters:** ${parameters.map(p => `${p.name} (${p.type})${p.required ? ' *required*' : ''}`).join(', ')}`;
7
7
  }
8
+ if (outputFormat) {
9
+ description += `\n\n**Output Format:** ${outputFormat}`;
10
+ }
8
11
  // Use Cases
9
12
  if (useCases.length > 0) {
10
13
  description += `\n\n**Use Cases:** ${useCases.map((uc, i) => `${i + 1}. ${uc}`).join(' ')}`;
@@ -1,7 +1,7 @@
1
1
  import { BaseAPI, pickFieldsFromArray } from './base.js';
2
2
  // --- API Class ---
3
3
  export class CurrentUserAPI extends BaseAPI {
4
- static organizationFields = ['id', 'name'];
4
+ static organizationFields = ['id', 'name', 'slug'];
5
5
  static projectFields = ['id', 'name', 'slug', 'api_key'];
6
6
  constructor(configuration) {
7
7
  super(configuration);
@@ -25,7 +25,10 @@ export class CurrentUserAPI extends BaseAPI {
25
25
  url,
26
26
  }, paginate);
27
27
  // Only return allowed fields
28
- return pickFieldsFromArray(data, CurrentUserAPI.organizationFields);
28
+ return {
29
+ ...data,
30
+ body: pickFieldsFromArray(data.body || [], CurrentUserAPI.organizationFields)
31
+ };
29
32
  }
30
33
  /**
31
34
  * List projects for a given organization
@@ -49,6 +52,9 @@ export class CurrentUserAPI extends BaseAPI {
49
52
  url,
50
53
  }, paginate);
51
54
  // Only return allowed fields
52
- return pickFieldsFromArray(data, CurrentUserAPI.projectFields);
55
+ return {
56
+ ...data,
57
+ body: pickFieldsFromArray(data.body || [], CurrentUserAPI.projectFields)
58
+ };
53
59
  }
54
60
  }
@@ -1,5 +1,25 @@
1
1
  import { BaseAPI } from './base.js';
2
2
  import { toQueryString } from './filters.js';
3
+ export const ErrorOperations = [
4
+ 'override_severity',
5
+ 'assign',
6
+ 'create_issue',
7
+ 'link_issue',
8
+ 'unlink_issue',
9
+ 'open',
10
+ 'snooze',
11
+ 'fix',
12
+ 'ignore',
13
+ 'delete',
14
+ 'discard',
15
+ 'undiscard'
16
+ ];
17
+ export const ReopenConditions = [
18
+ 'occurs_after',
19
+ 'n_occurrences_in_m_hours',
20
+ 'n_additional_occurrences',
21
+ 'n_additional_users'
22
+ ];
3
23
  // --- API Class ---
4
24
  export class ErrorAPI extends BaseAPI {
5
25
  constructor(configuration) {
@@ -41,6 +61,17 @@ export class ErrorAPI extends BaseAPI {
41
61
  url,
42
62
  }));
43
63
  }
64
+ /**
65
+ * List the Events on a Project
66
+ * GET /projects/{project_id}/events
67
+ */
68
+ async listEventsOnProject(projectId, queryString = '') {
69
+ const url = `/projects/${projectId}/events${queryString}`;
70
+ return await this.request({
71
+ method: 'GET',
72
+ url,
73
+ });
74
+ }
44
75
  /**
45
76
  * View an Event by ID
46
77
  * GET /projects/{project_id}/events/{event_id}
@@ -72,4 +103,54 @@ export class ErrorAPI extends BaseAPI {
72
103
  url,
73
104
  }));
74
105
  }
106
+ /**
107
+ * Update an Error on a Project
108
+ * PATCH /projects/{project_id}/errors/{error_id}
109
+ */
110
+ async updateErrorOnProject(projectId, errorId, data, options = {}) {
111
+ const params = new URLSearchParams();
112
+ for (const [key, value] of Object.entries(options)) {
113
+ if (value !== undefined)
114
+ params.append(key, String(value));
115
+ }
116
+ const url = params.toString()
117
+ ? `/projects/${projectId}/errors/${errorId}?${params}`
118
+ : `/projects/${projectId}/errors/${errorId}`;
119
+ return (await this.request({
120
+ method: 'PATCH',
121
+ url,
122
+ body: data,
123
+ }));
124
+ }
125
+ /**
126
+ * List Pivots on an Error
127
+ * GET /projects/{project_id}/errors/{error_id}/pivots
128
+ */
129
+ async listErrorPivots(projectId, errorId, options = {}) {
130
+ const params = new URLSearchParams();
131
+ if (options.filters) {
132
+ const filterParams = new URLSearchParams(toQueryString(options.filters));
133
+ filterParams.forEach((value, key) => {
134
+ params.append(key, value);
135
+ });
136
+ }
137
+ if (options.summary_size !== undefined) {
138
+ params.append('summary_size', options.summary_size.toString());
139
+ }
140
+ if (options.pivots && options.pivots.length > 0) {
141
+ options.pivots.forEach(pivot => {
142
+ params.append('pivots[]', pivot);
143
+ });
144
+ }
145
+ if (options.per_page !== undefined) {
146
+ params.append('per_page', options.per_page.toString());
147
+ }
148
+ const url = params.toString()
149
+ ? `/projects/${projectId}/errors/${errorId}/pivots?${params}`
150
+ : `/projects/${projectId}/errors/${errorId}/pivots`;
151
+ return await this.request({
152
+ method: 'GET',
153
+ url,
154
+ });
155
+ }
75
156
  }
@@ -23,6 +23,24 @@ export class ProjectAPI extends BaseAPI {
23
23
  url,
24
24
  });
25
25
  // Only return allowed fields
26
- return pickFieldsFromArray(data, ProjectAPI.eventFieldFields);
26
+ return {
27
+ ...data,
28
+ body: pickFieldsFromArray(data.body || [], ProjectAPI.eventFieldFields)
29
+ };
30
+ }
31
+ /**
32
+ * Create a Project in an Organization
33
+ * POST /organizations/{organization_id}/projects
34
+ * @param organizationId The organization ID
35
+ * @param data The project creation request body
36
+ * @returns A promise that resolves to the created project
37
+ */
38
+ async createProject(organizationId, data) {
39
+ const url = `/organizations/${organizationId}/projects`;
40
+ return await this.request({
41
+ method: 'POST',
42
+ url,
43
+ body: data,
44
+ });
27
45
  }
28
46
  }
@@ -31,12 +31,17 @@ export class BaseAPI {
31
31
  const url = options.url.startsWith('http') ? options.url : `${this.configuration.basePath || ''}${options.url}`;
32
32
  let results = [];
33
33
  let nextUrl = url;
34
+ let apiResponse;
34
35
  do {
35
36
  const response = await fetch(nextUrl, fetchOptions);
36
37
  if (!response.ok) {
37
38
  const errorText = await response.text();
38
39
  throw new Error(`Request failed with status ${response.status}: ${errorText}`);
39
40
  }
41
+ apiResponse = {
42
+ status: response.status,
43
+ headers: response.headers
44
+ };
40
45
  const data = await response.json();
41
46
  if (paginate) {
42
47
  results = results.concat(data);
@@ -50,9 +55,12 @@ export class BaseAPI {
50
55
  }
51
56
  }
52
57
  else {
53
- return data;
58
+ apiResponse.body = data;
54
59
  }
55
60
  } while (paginate && nextUrl);
56
- return results;
61
+ if (paginate) {
62
+ apiResponse.body = results;
63
+ }
64
+ return apiResponse;
57
65
  }
58
66
  }