@smartbear/mcp 0.25.1 → 0.26.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 +12 -3
- package/dist/bearq/client.js +2 -2
- package/dist/bugsnag/client.js +2 -2
- package/dist/collaborator/client.js +2 -1
- package/dist/common/info.js +5 -1
- package/dist/common/transport-stdio.js +2 -2
- package/dist/package.json.js +1 -1
- package/dist/pactflow/client.js +4 -4
- package/dist/qmetry/client/api/client-api.js +2 -2
- package/dist/qmetry/client/automation.js +2 -2
- package/dist/qtm4j/http/auth-service.js +2 -2
- package/dist/reflect/client.js +4 -2
- package/dist/reflect/tool/tests/get-test-detail.js +37 -0
- package/dist/swagger/client/functional-testing-api.js +36 -0
- package/dist/swagger/client/functional-testing-tools.js +11 -0
- package/dist/swagger/client/tools.js +3 -1
- package/dist/swagger/client.js +50 -14
- package/dist/zephyr/common/auth-service.js +2 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -35,6 +35,7 @@ See individual guides for suggested prompts and supported tools and resources:
|
|
|
35
35
|
- [Portal](https://developer.smartbear.com/smartbear-mcp/docs/swagger-portal-integration) - Portal and product management capabilities
|
|
36
36
|
- [Studio](https://developer.smartbear.com/smartbear-mcp/docs/swagger-studio-integration) - API and Domain management capabilities, including AI-powered API generation from prompts and automatic standardization
|
|
37
37
|
- [Contract Testing (PactFlow)](https://developer.smartbear.com/pactflow/default/getting-started) - Contract testing capabilities
|
|
38
|
+
- [Functional Testing](https://developer.smartbear.com/smartbear-mcp/docs/functional-testing-integration) - API test discovery capabilities
|
|
38
39
|
- [QMetry](https://developer.smartbear.com/smartbear-mcp/docs/qmetry-integration) - QMetry Test Management capabilities
|
|
39
40
|
- [Zephyr](https://developer.smartbear.com/smartbear-mcp/docs/zephyr-integration) - Zephyr Test Management capabilities
|
|
40
41
|
- [Collaborator](https://developer.smartbear.com/smartbear-mcp/docs/collaborator-integration) - Review and Remote System Configuration management capabilities
|
|
@@ -52,7 +53,7 @@ For BugSnag, Swagger, and Zephyr, SmartBear hosts Remote MCP Servers that you ca
|
|
|
52
53
|
|
|
53
54
|
See the [Remote MCP Servers guide](https://developer.smartbear.com/smartbear-mcp/docs/remote-mcp-servers) for per-client setup instructions. You can connect to multiple remote servers at the same time.
|
|
54
55
|
|
|
55
|
-
> **Need BearQ, Reflect, QMetry, QTM4J, PactFlow, or
|
|
56
|
+
> **Need BearQ, Reflect, QMetry, QTM4J, PactFlow, Collaborator, or Functional Testing?** These products are only available via the local npm package below, which bundles all products into a single MCP server.
|
|
56
57
|
|
|
57
58
|
## Prerequisites
|
|
58
59
|
|
|
@@ -108,7 +109,8 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
|
|
|
108
109
|
"COLLABORATOR_LOGIN_TICKET": "${input:collab_login_ticket}",
|
|
109
110
|
"QTM4J_API_KEY": "${input:qtm4j_api_key}",
|
|
110
111
|
"QTM4J_BASE_URL": "${input:qtm4j_base_url}",
|
|
111
|
-
"QTM4J_AUTOMATION_API_KEY": "${input:qtm4j_automation_api_key}"
|
|
112
|
+
"QTM4J_AUTOMATION_API_KEY": "${input:qtm4j_automation_api_key}",
|
|
113
|
+
"SWAGGER_FUNCTIONAL_TESTING_API_TOKEN": "${input:swagger_functional_testing_api_token}"
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
116
|
},
|
|
@@ -250,6 +252,12 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
|
|
|
250
252
|
"type": "promptString",
|
|
251
253
|
"description": "QTM4J Automation API Key - required for automation tools, leave blank to disable them",
|
|
252
254
|
"password": true
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"id": "swagger_functional_testing_api_token",
|
|
258
|
+
"type": "promptString",
|
|
259
|
+
"description": "Swagger Functional Testing API Token - leave blank to disable Functional Testing tools",
|
|
260
|
+
"password": true
|
|
253
261
|
}
|
|
254
262
|
]
|
|
255
263
|
}
|
|
@@ -291,7 +299,8 @@ Add the following configuration to your `claude_desktop_config.json` to launch t
|
|
|
291
299
|
"COLLABORATOR_LOGIN_TICKET": "your collab login ticket",
|
|
292
300
|
"QTM4J_API_KEY": "your_qtm4j_key",
|
|
293
301
|
"QTM4J_BASE_URL": "https://qtmcloud.qmetry.com",
|
|
294
|
-
"QTM4J_AUTOMATION_API_KEY": "your_qtm4j_automation_api_key"
|
|
302
|
+
"QTM4J_AUTOMATION_API_KEY": "your_qtm4j_automation_api_key",
|
|
303
|
+
"SWAGGER_FUNCTIONAL_TESTING_API_TOKEN": "your_swagger_functional_testing_api_token"
|
|
295
304
|
}
|
|
296
305
|
}
|
|
297
306
|
}
|
package/dist/bearq/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { USER_AGENT } from "../common/info.js";
|
|
3
3
|
import { getRequestHeader } from "../common/request-context.js";
|
|
4
4
|
import { ToolError } from "../common/tools.js";
|
|
5
5
|
import { DEFAULT_API_BASE_URL, AUTHORIZATION_HEADER } from "./config/constants.js";
|
|
@@ -53,7 +53,7 @@ class BearQClient {
|
|
|
53
53
|
return {
|
|
54
54
|
Authorization: `Bearer ${token}`,
|
|
55
55
|
"Content-Type": "application/json",
|
|
56
|
-
"User-Agent":
|
|
56
|
+
"User-Agent": USER_AGENT
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
async registerTools(register, _getInput) {
|
package/dist/bugsnag/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { USER_AGENT } from "../common/info.js";
|
|
3
3
|
import { getRequestHeader } from "../common/request-context.js";
|
|
4
4
|
import { ToolError } from "../common/tools.js";
|
|
5
5
|
import { CurrentUserAPI } from "./client/api/CurrentUser.js";
|
|
@@ -123,7 +123,7 @@ class BugsnagClient {
|
|
|
123
123
|
);
|
|
124
124
|
},
|
|
125
125
|
headers: {
|
|
126
|
-
"User-Agent":
|
|
126
|
+
"User-Agent": USER_AGENT,
|
|
127
127
|
"Content-Type": "application/json",
|
|
128
128
|
"X-Bugsnag-API": "true",
|
|
129
129
|
"X-Version": "2"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { USER_AGENT } from "../common/info.js";
|
|
2
3
|
import { getRequestHeader } from "../common/request-context.js";
|
|
3
4
|
const ConfigurationSchema = z.object({
|
|
4
5
|
base_url: z.url().describe("Collaborator server base URL"),
|
|
@@ -47,7 +48,7 @@ class CollaboratorClient {
|
|
|
47
48
|
];
|
|
48
49
|
const response = await fetch(url, {
|
|
49
50
|
method: "POST",
|
|
50
|
-
headers: { "Content-Type": "application/json" },
|
|
51
|
+
headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
|
|
51
52
|
body: JSON.stringify(body)
|
|
52
53
|
});
|
|
53
54
|
if (!response.ok) {
|
package/dist/common/info.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import packageJson from "../package.json.js";
|
|
2
2
|
const MCP_SERVER_NAME = packageJson.config.mcpServerName;
|
|
3
3
|
const MCP_SERVER_VERSION = packageJson.version;
|
|
4
|
+
const MCP_TRANSPORT = process.env.MCP_TRANSPORT?.toLowerCase().trim() || "stdio";
|
|
5
|
+
const USER_AGENT = `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION} ${MCP_TRANSPORT}`;
|
|
4
6
|
export {
|
|
5
7
|
MCP_SERVER_NAME,
|
|
6
|
-
MCP_SERVER_VERSION
|
|
8
|
+
MCP_SERVER_VERSION,
|
|
9
|
+
MCP_TRANSPORT,
|
|
10
|
+
USER_AGENT
|
|
7
11
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { enableCompileCache } from "node:module";
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { clientRegistry } from "./client-registry.js";
|
|
4
|
-
import {
|
|
4
|
+
import { USER_AGENT } from "./info.js";
|
|
5
5
|
import { SmartBearMcpServer } from "./server.js";
|
|
6
6
|
import { registerShutdownHandler } from "./shutdown.js";
|
|
7
7
|
import { isOptionalType, getTypeDescription } from "./zod-utils.js";
|
|
@@ -21,7 +21,7 @@ function getNoConfigMessage() {
|
|
|
21
21
|
}
|
|
22
22
|
async function runStdioMode() {
|
|
23
23
|
if (process.argv.includes("--version")) {
|
|
24
|
-
console.log(
|
|
24
|
+
console.log(`User-Agent: ${USER_AGENT}`);
|
|
25
25
|
process.exit(0);
|
|
26
26
|
} else if (process.argv.includes("--help")) {
|
|
27
27
|
console.log(
|
package/dist/package.json.js
CHANGED
package/dist/pactflow/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import zod__default from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { USER_AGENT } from "../common/info.js";
|
|
3
3
|
import { isSamplingPolyfillResult } from "../common/pollyfills.js";
|
|
4
4
|
import { getRequestHeader } from "../common/request-context.js";
|
|
5
5
|
import { ToolError } from "../common/tools.js";
|
|
@@ -178,7 +178,7 @@ class PactflowClient {
|
|
|
178
178
|
return {
|
|
179
179
|
Authorization: authHeader,
|
|
180
180
|
"Content-Type": "application/json",
|
|
181
|
-
"User-Agent":
|
|
181
|
+
"User-Agent": USER_AGENT
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
if (this.token) {
|
|
@@ -189,14 +189,14 @@ class PactflowClient {
|
|
|
189
189
|
return {
|
|
190
190
|
Authorization: authHeader,
|
|
191
191
|
"Content-Type": "application/json",
|
|
192
|
-
"User-Agent":
|
|
192
|
+
"User-Agent": USER_AGENT
|
|
193
193
|
};
|
|
194
194
|
} else if (this.username && this.password) {
|
|
195
195
|
const authString = `${this.username}:${this.password}`;
|
|
196
196
|
return {
|
|
197
197
|
Authorization: `Basic ${Buffer.from(authString).toString("base64")}`,
|
|
198
198
|
"Content-Type": "application/json",
|
|
199
|
-
"User-Agent":
|
|
199
|
+
"User-Agent": USER_AGENT
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
202
|
return void 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { USER_AGENT } from "../../../common/info.js";
|
|
2
2
|
import { QMETRY_DEFAULTS } from "../../config/constants.js";
|
|
3
3
|
import { handleQMetryFetchError, handleQMetryApiError } from "./error-handler.js";
|
|
4
4
|
async function qmetryRequest({
|
|
@@ -13,7 +13,7 @@ async function qmetryRequest({
|
|
|
13
13
|
const headers = {
|
|
14
14
|
apikey: token,
|
|
15
15
|
project: project || QMETRY_DEFAULTS.PROJECT_KEY,
|
|
16
|
-
"User-Agent":
|
|
16
|
+
"User-Agent": USER_AGENT,
|
|
17
17
|
"qmetry-source": "smartbear-mcp"
|
|
18
18
|
};
|
|
19
19
|
if (body) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { USER_AGENT } from "../../common/info.js";
|
|
2
2
|
import { QMETRY_DEFAULTS } from "../config/constants.js";
|
|
3
3
|
import { QMETRY_PATHS } from "../config/rest-endpoints.js";
|
|
4
4
|
import { DEFAULT_IMPORT_AUTOMATION_PAYLOAD } from "../types/automation.js";
|
|
@@ -91,7 +91,7 @@ async function importAutomationResults(token, baseUrl, project, payload) {
|
|
|
91
91
|
const headers = {
|
|
92
92
|
apikey: token,
|
|
93
93
|
project: finalPayload.projectID || project || QMETRY_DEFAULTS.PROJECT_KEY,
|
|
94
|
-
"User-Agent":
|
|
94
|
+
"User-Agent": USER_AGENT,
|
|
95
95
|
"qmetry-source": "smartbear-mcp"
|
|
96
96
|
// Note: Content-Type will be set automatically by fetch for FormData
|
|
97
97
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { USER_AGENT } from "../../common/info.js";
|
|
2
2
|
import { CONTENT_TYPES, HTTP_HEADERS } from "../config/constants.js";
|
|
3
3
|
class AuthService {
|
|
4
4
|
apiKey;
|
|
@@ -13,7 +13,7 @@ class AuthService {
|
|
|
13
13
|
return {
|
|
14
14
|
[HTTP_HEADERS.API_KEY]: this.apiKey,
|
|
15
15
|
[HTTP_HEADERS.CONTENT_TYPE]: CONTENT_TYPES.JSON,
|
|
16
|
-
[HTTP_HEADERS.USER_AGENT]:
|
|
16
|
+
[HTTP_HEADERS.USER_AGENT]: USER_AGENT,
|
|
17
17
|
[HTTP_HEADERS.ACCEPT]: CONTENT_TYPES.JSON
|
|
18
18
|
};
|
|
19
19
|
}
|
package/dist/reflect/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { USER_AGENT } from "../common/info.js";
|
|
3
3
|
import { getRequestHeader } from "../common/request-context.js";
|
|
4
4
|
import { ToolError } from "../common/tools.js";
|
|
5
5
|
import { API_KEY_HEADER, REFLECT_API_TOKEN_HEADER, AUTHORIZATION_HEADER } from "./config/constants.js";
|
|
@@ -14,6 +14,7 @@ import { ExecuteSuite } from "./tool/suites/execute-suite.js";
|
|
|
14
14
|
import { GetSuiteExecutionStatus } from "./tool/suites/get-suite-execution-status.js";
|
|
15
15
|
import { ListSuiteExecutions } from "./tool/suites/list-suite-executions.js";
|
|
16
16
|
import { ListSuites } from "./tool/suites/list-suites.js";
|
|
17
|
+
import { GetTestDetail } from "./tool/tests/get-test-detail.js";
|
|
17
18
|
import { GetTestStatus } from "./tool/tests/get-test-status.js";
|
|
18
19
|
import { ListSegments } from "./tool/tests/list-segments.js";
|
|
19
20
|
import { ListTests } from "./tool/tests/list-tests.js";
|
|
@@ -72,7 +73,7 @@ class ReflectClient {
|
|
|
72
73
|
return {
|
|
73
74
|
...this.getAuthHeader(),
|
|
74
75
|
"Content-Type": "application/json",
|
|
75
|
-
"User-Agent":
|
|
76
|
+
"User-Agent": USER_AGENT
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
getSessionState(sessionId) {
|
|
@@ -120,6 +121,7 @@ class ReflectClient {
|
|
|
120
121
|
new ExecuteSuite(this),
|
|
121
122
|
new CancelSuiteExecution(this),
|
|
122
123
|
new ListTests(this),
|
|
124
|
+
new GetTestDetail(this),
|
|
123
125
|
new RunTest(this),
|
|
124
126
|
new GetTestStatus(this)
|
|
125
127
|
];
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Tool, ToolError } from "../../../common/tools.js";
|
|
3
|
+
import { API_HOSTNAME } from "../../config/constants.js";
|
|
4
|
+
class GetTestDetail extends Tool {
|
|
5
|
+
specification = {
|
|
6
|
+
title: "Get Test Detail",
|
|
7
|
+
toolset: "Tests",
|
|
8
|
+
summary: "Get the full detail of a reflect test, including its name, description, and all recorded steps",
|
|
9
|
+
inputSchema: z.object({
|
|
10
|
+
testId: z.string().describe("ID of the reflect test to retrieve details for")
|
|
11
|
+
})
|
|
12
|
+
};
|
|
13
|
+
handle = async (args) => {
|
|
14
|
+
const { testId } = args;
|
|
15
|
+
if (!testId || !testId.trim())
|
|
16
|
+
throw new ToolError("testId argument is required");
|
|
17
|
+
const response = await fetch(
|
|
18
|
+
`https://${API_HOSTNAME}/v1/tests/${encodeURIComponent(testId)}`,
|
|
19
|
+
{
|
|
20
|
+
method: "GET",
|
|
21
|
+
headers: this.client.getHeaders()
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
throw new ToolError(
|
|
26
|
+
`Failed to get test detail: ${response.status} ${response.statusText}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
return {
|
|
31
|
+
content: [{ type: "text", text: JSON.stringify(data) }]
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
GetTestDetail
|
|
37
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ToolError } from "../../common/tools.js";
|
|
2
|
+
const API_HOSTNAME = "api.reflect.run";
|
|
3
|
+
const FUNCTIONAL_TESTING_API_KEY_HEADER = "X-API-KEY";
|
|
4
|
+
class FunctionalTestingAPI {
|
|
5
|
+
constructor(getToken, userAgent) {
|
|
6
|
+
this.getToken = getToken;
|
|
7
|
+
this.userAgent = userAgent;
|
|
8
|
+
}
|
|
9
|
+
getFtHeaders() {
|
|
10
|
+
const token = this.getToken();
|
|
11
|
+
if (!token) {
|
|
12
|
+
throw new ToolError("Swagger Functional Testing API token not found");
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
[FUNCTIONAL_TESTING_API_KEY_HEADER]: token,
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
"User-Agent": this.userAgent
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
async listTests() {
|
|
21
|
+
const response = await fetch(`https://${API_HOSTNAME}/v1/tests`, {
|
|
22
|
+
method: "GET",
|
|
23
|
+
headers: this.getFtHeaders()
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new ToolError(
|
|
27
|
+
`Failed to list Functional Testing tests: ${response.status} ${response.statusText}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return response.json();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
FUNCTIONAL_TESTING_API_KEY_HEADER,
|
|
35
|
+
FunctionalTestingAPI
|
|
36
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const FUNCTIONAL_TESTING_TOOLS = [
|
|
2
|
+
{
|
|
3
|
+
title: "List Tests",
|
|
4
|
+
toolset: "Functional Testing",
|
|
5
|
+
summary: "Lists all API tests available in your Swagger Functional Testing account. Use this tool when you need to discover available tests before running them or checking their status. Do not use this tool to retrieve test execution results or history.",
|
|
6
|
+
handler: "listFunctionalTestingTests"
|
|
7
|
+
}
|
|
8
|
+
];
|
|
9
|
+
export {
|
|
10
|
+
FUNCTIONAL_TESTING_TOOLS
|
|
11
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FUNCTIONAL_TESTING_TOOLS } from "./functional-testing-tools.js";
|
|
1
2
|
import { CreatePortalArgsSchema, PortalArgsSchema, UpdatePortalArgsSchema, CreateProductArgsSchema, ProductArgsSchema, UpdateProductArgsSchema, PublishProductArgsSchema, GetProductSectionsArgsSchema, CreateTableOfContentsArgsSchema, GetTableOfContentsArgsSchema, DeleteTableOfContentsArgsSchema, GetDocumentArgsSchema, UpdateDocumentArgsSchema } from "./portal-types.js";
|
|
2
3
|
import { ApiSearchParamsSchema, ApiDefinitionParamsSchema, CreateApiParamsSchema, ScanStandardizationParamsSchema, CreateApiFromPromptParamsSchema, StandardizeApiParamsSchema } from "./registry-types.js";
|
|
3
4
|
import { OrganizationsQuerySchema } from "./user-management-types.js";
|
|
@@ -165,7 +166,8 @@ const TOOLS = [
|
|
|
165
166
|
summary: "Standardize and fix an API definition using AI to ensure compliance with governance policies. Scans the API definition for standardization errors and automatically fixes them using SmartBear AI. Optionally provide 'newVersion' (e.g. patch bump '1.0.0' → '1.0.1') to save the fixed definition as a new version — omitting it will overwrite the current version. Returns the number of errors found and the fixed definition if successful. Use this tool when users ask to standardize, fix, govern, or ensure governance compliance of APIs.",
|
|
166
167
|
inputSchema: StandardizeApiParamsSchema,
|
|
167
168
|
handler: "standardizeApi"
|
|
168
|
-
}
|
|
169
|
+
},
|
|
170
|
+
...FUNCTIONAL_TESTING_TOOLS
|
|
169
171
|
];
|
|
170
172
|
export {
|
|
171
173
|
TOOLS
|
package/dist/swagger/client.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { USER_AGENT } from "../common/info.js";
|
|
3
3
|
import { getRequestHeader } from "../common/request-context.js";
|
|
4
|
+
import { ToolError } from "../common/tools.js";
|
|
4
5
|
import "./config-utils.js";
|
|
6
|
+
import { FunctionalTestingAPI, FUNCTIONAL_TESTING_API_KEY_HEADER } from "./client/functional-testing-api.js";
|
|
5
7
|
import { SwaggerAPI } from "./client/api.js";
|
|
6
8
|
import { SwaggerConfiguration } from "./client/configuration.js";
|
|
7
9
|
import "./client/portal-types.js";
|
|
@@ -9,29 +11,43 @@ import "./client/registry-types.js";
|
|
|
9
11
|
import { TOOLS } from "./client/tools.js";
|
|
10
12
|
import "./client/user-management-types.js";
|
|
11
13
|
const ConfigurationSchema = z.object({
|
|
12
|
-
api_key: z.string().describe("Swagger API key for authentication"),
|
|
14
|
+
api_key: z.string().optional().describe("Swagger API key for authentication"),
|
|
13
15
|
portal_base_path: z.string().optional().describe("Base path for Portal API requests (optional)"),
|
|
14
16
|
registry_base_path: z.string().optional().describe("Base path for Registry API requests (optional)"),
|
|
15
|
-
ui_base_path: z.string().optional().describe("Base URL for the SwaggerHub UI (optional)")
|
|
17
|
+
ui_base_path: z.string().optional().describe("Base URL for the SwaggerHub UI (optional)"),
|
|
18
|
+
functional_testing_api_token: z.string().optional().describe(
|
|
19
|
+
"Swagger Functional Testing API token. Leave empty to disable Functional Testing tools."
|
|
20
|
+
)
|
|
16
21
|
});
|
|
17
22
|
class SwaggerClient {
|
|
18
23
|
api;
|
|
19
24
|
_apiKey;
|
|
25
|
+
ftApi;
|
|
26
|
+
_ftApiToken;
|
|
20
27
|
name = "Swagger";
|
|
21
28
|
capabilityPrefix = "swagger";
|
|
22
29
|
configPrefix = "Swagger";
|
|
23
30
|
config = ConfigurationSchema;
|
|
24
31
|
async configure(_server, config, _cache) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
new
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
if (config.api_key) {
|
|
33
|
+
this._apiKey = config.api_key;
|
|
34
|
+
this.api = new SwaggerAPI(
|
|
35
|
+
new SwaggerConfiguration({
|
|
36
|
+
token: () => this.getAuthToken(),
|
|
37
|
+
portalBasePath: config.portal_base_path,
|
|
38
|
+
registryBasePath: config.registry_base_path,
|
|
39
|
+
uiBasePath: config.ui_base_path
|
|
40
|
+
}),
|
|
41
|
+
USER_AGENT
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (config.functional_testing_api_token) {
|
|
45
|
+
this._ftApiToken = config.functional_testing_api_token;
|
|
46
|
+
this.ftApi = new FunctionalTestingAPI(
|
|
47
|
+
() => this.getFtAuthToken(),
|
|
48
|
+
USER_AGENT
|
|
49
|
+
);
|
|
50
|
+
}
|
|
35
51
|
}
|
|
36
52
|
getAuthToken() {
|
|
37
53
|
const contextHeader = getRequestHeader("Swagger-Api-Key") || getRequestHeader("Authorization");
|
|
@@ -44,8 +60,16 @@ class SwaggerClient {
|
|
|
44
60
|
}
|
|
45
61
|
return this._apiKey || null;
|
|
46
62
|
}
|
|
63
|
+
getFtAuthToken() {
|
|
64
|
+
if (!this.ftApi) return null;
|
|
65
|
+
const contextHeader = getRequestHeader(FUNCTIONAL_TESTING_API_KEY_HEADER);
|
|
66
|
+
if (contextHeader) {
|
|
67
|
+
return Array.isArray(contextHeader) ? contextHeader[0] : contextHeader;
|
|
68
|
+
}
|
|
69
|
+
return this._ftApiToken || null;
|
|
70
|
+
}
|
|
47
71
|
isConfigured() {
|
|
48
|
-
return this.api !== void 0;
|
|
72
|
+
return this.api !== void 0 || this.ftApi !== void 0;
|
|
49
73
|
}
|
|
50
74
|
getApi() {
|
|
51
75
|
if (!this.api) throw new Error("Client not configured");
|
|
@@ -129,8 +153,20 @@ class SwaggerClient {
|
|
|
129
153
|
async standardizeApi(args) {
|
|
130
154
|
return this.getApi().standardizeApi(args);
|
|
131
155
|
}
|
|
156
|
+
async listFunctionalTestingTests() {
|
|
157
|
+
if (!this.ftApi) {
|
|
158
|
+
throw new ToolError("Functional Testing API not configured");
|
|
159
|
+
}
|
|
160
|
+
return this.ftApi.listTests();
|
|
161
|
+
}
|
|
132
162
|
async registerTools(register, _getInput) {
|
|
133
163
|
TOOLS.forEach((tool) => {
|
|
164
|
+
if (tool.toolset === "Functional Testing" && !this.ftApi) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (tool.toolset !== "Functional Testing" && !this.api && this.isConfigured()) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
134
170
|
const { handler, formatResponse, ...toolParams } = tool;
|
|
135
171
|
register(toolParams, async (args, _extra) => {
|
|
136
172
|
try {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { USER_AGENT } from "../../common/info.js";
|
|
2
2
|
class AuthService {
|
|
3
3
|
bearerToken;
|
|
4
4
|
constructor(accessToken) {
|
|
@@ -8,7 +8,7 @@ class AuthService {
|
|
|
8
8
|
return {
|
|
9
9
|
Authorization: `Bearer ${this.bearerToken}`,
|
|
10
10
|
"Content-Type": "application/json",
|
|
11
|
-
"User-Agent":
|
|
11
|
+
"User-Agent": USER_AGENT,
|
|
12
12
|
"zscale-source": "smartbear-mcp"
|
|
13
13
|
};
|
|
14
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartbear/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "MCP server for interacting SmartBear Products",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"smartbear",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@bugsnag/js": "^8.8.1",
|
|
53
53
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
54
|
+
"js-yaml": "^4.2.0",
|
|
54
55
|
"node-cache": "^5.1.2",
|
|
55
56
|
"swagger-client": "^3.37.1",
|
|
56
57
|
"vite": "^7.3.1",
|