@smartbear/mcp 0.5.0 → 0.6.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 +2 -108
- package/dist/bugsnag/client/api/CurrentUser.js +2 -3
- package/dist/bugsnag/client/api/Project.js +122 -6
- package/dist/bugsnag/client/api/base.js +21 -10
- package/dist/bugsnag/client.js +431 -17
- package/dist/common/server.js +9 -0
- package/dist/index.js +2 -2
- package/dist/pactflow/client/ai.js +33 -2
- package/dist/pactflow/client/base.js +16 -3
- package/dist/pactflow/client/prompt-utils.js +89 -0
- package/dist/pactflow/client/prompts.js +133 -0
- package/dist/pactflow/client/tools.js +35 -3
- package/dist/pactflow/client.js +137 -6
- package/package.json +4 -2
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { EndpointMatcherSchema, MatcherRecommendationInputSchema, } from "./ai.js";
|
|
2
|
+
import { OADMatcherPrompt } from "./prompts.js";
|
|
3
|
+
/**
|
|
4
|
+
* Get OpenAPI matcher recommendations using sampling.
|
|
5
|
+
*
|
|
6
|
+
* @param openAPI The OpenAPI document to analyze.
|
|
7
|
+
* @param server The SmartBear MCP server instance.
|
|
8
|
+
* @returns A promise that resolves to the matcher recommendations.
|
|
9
|
+
* @throws Error if unable to parse recommendations.
|
|
10
|
+
*/
|
|
11
|
+
export async function getOADMatcherRecommendations(openAPI, server) {
|
|
12
|
+
const matcherResponse = await server.createMessage({
|
|
13
|
+
messages: [
|
|
14
|
+
{
|
|
15
|
+
role: "user",
|
|
16
|
+
content: {
|
|
17
|
+
type: "text",
|
|
18
|
+
text: OADMatcherPrompt.replace("{0}", JSON.stringify(openAPI)),
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
maxTokens: 1000,
|
|
23
|
+
});
|
|
24
|
+
const regex = /```json[c5]?([\s\S]*?)```/i;
|
|
25
|
+
const match = regex.exec(matcherResponse.content.text);
|
|
26
|
+
if (match) {
|
|
27
|
+
const jsonText = match[1].trim();
|
|
28
|
+
const parsed = JSON.parse(jsonText);
|
|
29
|
+
const matcherRecommendations = MatcherRecommendationInputSchema.parse(parsed);
|
|
30
|
+
return matcherRecommendations;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
throw new Error("Unable to parse recommendations please provide OpenAPI matchers manually.");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get user selection for matcher recommendations.
|
|
38
|
+
*
|
|
39
|
+
* @param recommendations The list of matcher recommendations.
|
|
40
|
+
* @param getInput The function to get user input.
|
|
41
|
+
* @returns The selected endpoint matcher.
|
|
42
|
+
*/
|
|
43
|
+
export async function getUserMatcherSelection(recommendations, getInput) {
|
|
44
|
+
const recommendationsMap = new Map();
|
|
45
|
+
recommendations.forEach((rec, index) => {
|
|
46
|
+
recommendationsMap.set(`Recommendation ${index + 1}`, JSON.stringify(rec));
|
|
47
|
+
});
|
|
48
|
+
const result = await getInput({
|
|
49
|
+
message: `Select one of the generated matchers you would want to use \n\n ${recommendations
|
|
50
|
+
.map((rec, index) => `\n\nRecommendation ${index + 1}: \n\n\n ${JSON.stringify(rec)}`)
|
|
51
|
+
.join("\n\n")}`,
|
|
52
|
+
requestedSchema: {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
generatedMatchers: {
|
|
56
|
+
type: "string",
|
|
57
|
+
title: "Generated Matchers",
|
|
58
|
+
description: "Use the matchers generated for the OpenAPI document",
|
|
59
|
+
enum: recommendations.map((_, index) => `Recommendation ${index + 1}`),
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
required: ["generatedMatchers"],
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
if (result.action === "accept") {
|
|
66
|
+
return EndpointMatcherSchema.parse(JSON.parse(recommendationsMap.get(result.content?.generatedMatchers) ||
|
|
67
|
+
""));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const result = await getInput({
|
|
71
|
+
message: "Enter the matchers you would want to use for the OpenAPI document",
|
|
72
|
+
requestedSchema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
enteredMatchers: {
|
|
76
|
+
type: "string",
|
|
77
|
+
title: "Enter the matchers you would want to use for the OpenAPI document",
|
|
78
|
+
description: "Enter the matchers you would want to use for the OpenAPI document",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ["enteredMatchers"],
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
if (result.action === "accept") {
|
|
85
|
+
return EndpointMatcherSchema.parse(JSON.parse(result.content?.enteredMatchers));
|
|
86
|
+
}
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
3
|
+
import { EndpointMatcherSchema } from "./ai.js";
|
|
4
|
+
const OADMatcherPromptOpenAPIDocExample = {
|
|
5
|
+
openapi: "3.1.0",
|
|
6
|
+
info: {
|
|
7
|
+
title: "My API",
|
|
8
|
+
version: "1.0.0",
|
|
9
|
+
description: "A sample API for demonstration purposes.",
|
|
10
|
+
},
|
|
11
|
+
paths: {
|
|
12
|
+
"/users": {
|
|
13
|
+
get: {
|
|
14
|
+
summary: "Get all users",
|
|
15
|
+
responses: {
|
|
16
|
+
"200": {
|
|
17
|
+
description: "A list of users",
|
|
18
|
+
content: {
|
|
19
|
+
"application/json": {
|
|
20
|
+
schema: {
|
|
21
|
+
type: "array",
|
|
22
|
+
items: {
|
|
23
|
+
$ref: "#/components/schemas/User",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
components: {
|
|
34
|
+
schemas: {
|
|
35
|
+
User: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
id: {
|
|
39
|
+
type: "integer",
|
|
40
|
+
format: "int64",
|
|
41
|
+
},
|
|
42
|
+
name: {
|
|
43
|
+
type: "string",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const OADMatcherPromptRecommendationExample = [
|
|
51
|
+
{
|
|
52
|
+
path: "/users",
|
|
53
|
+
methods: ["GET"],
|
|
54
|
+
statusCodes: [200, "2XX"],
|
|
55
|
+
operationId: "get*",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
path: "/users/*",
|
|
59
|
+
methods: ["GET"],
|
|
60
|
+
statusCodes: ["2XX"],
|
|
61
|
+
operationId: "*User*",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
path: "/users",
|
|
65
|
+
methods: ["GET"],
|
|
66
|
+
statusCodes: [200],
|
|
67
|
+
operationId: "getAllUsers",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
path: "/users/**",
|
|
71
|
+
methods: ["GET"],
|
|
72
|
+
statusCodes: ["2XX", 404],
|
|
73
|
+
operationId: "get*",
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
export const OADMatcherPrompt = `
|
|
77
|
+
|
|
78
|
+
Generate a list of recommendations(maximum of 5) in JSON to use with an OpenAPI matcher.
|
|
79
|
+
Zod Schema for the matcher to be generated is provided below in the markdown block of javascript use this to generate the recommendations for the matcher. Recommendations should contain all the fields from the schema and only output the JSON in a markdown formatted block.
|
|
80
|
+
|
|
81
|
+
\`\`\`javascript
|
|
82
|
+
const EndpointMatcherSchema = ${JSON.stringify(zodToJsonSchema(EndpointMatcherSchema))};
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
Example OpenAPI document:-
|
|
86
|
+
|
|
87
|
+
if OpenAPI document provided is:-
|
|
88
|
+
|
|
89
|
+
\`\`\`json
|
|
90
|
+
${JSON.stringify(OADMatcherPromptOpenAPIDocExample, null, 2)}
|
|
91
|
+
\`\`\`
|
|
92
|
+
|
|
93
|
+
Generated recommendations are:-
|
|
94
|
+
|
|
95
|
+
\`\`\`json
|
|
96
|
+
${JSON.stringify(OADMatcherPromptRecommendationExample, null, 2)}
|
|
97
|
+
\`\`\`
|
|
98
|
+
|
|
99
|
+
Actual OpenAPI document:-
|
|
100
|
+
|
|
101
|
+
Now provided the below OpenAPI document:-
|
|
102
|
+
|
|
103
|
+
\`\`\`json
|
|
104
|
+
{0}
|
|
105
|
+
\`\`\`
|
|
106
|
+
|
|
107
|
+
Give JSON recommendations only provide the JSON block in markdown don't include any additional text.
|
|
108
|
+
`;
|
|
109
|
+
export const PROMPTS = [
|
|
110
|
+
{
|
|
111
|
+
name: "OpenAPI Matcher recommendations",
|
|
112
|
+
params: {
|
|
113
|
+
description: "Get OpenAPI matcher recommendations using sampling",
|
|
114
|
+
title: "OpenAPI Matcher recommendations",
|
|
115
|
+
argsSchema: {
|
|
116
|
+
openAPI: z.string(),
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
callback: function ({ openAPI }) {
|
|
120
|
+
return {
|
|
121
|
+
messages: [
|
|
122
|
+
{
|
|
123
|
+
role: "user",
|
|
124
|
+
content: {
|
|
125
|
+
type: "text",
|
|
126
|
+
text: OADMatcherPrompt.replace("{0}", openAPI),
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
];
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* and registered with their corresponding handler.
|
|
11
11
|
*/
|
|
12
12
|
import { z } from "zod";
|
|
13
|
-
import { GenerationInputSchema, RefineInputSchema } from "./ai.js";
|
|
14
|
-
import { CanIDeploySchema } from "./base.js";
|
|
13
|
+
import { GenerationInputSchema, RefineInputSchema, } from "./ai.js";
|
|
14
|
+
import { CanIDeploySchema, MatrixSchema } from "./base.js";
|
|
15
15
|
export const TOOLS = [
|
|
16
16
|
{
|
|
17
17
|
title: "Generate Pact Tests",
|
|
@@ -20,6 +20,7 @@ export const TOOLS = [
|
|
|
20
20
|
zodSchema: GenerationInputSchema,
|
|
21
21
|
handler: "generate",
|
|
22
22
|
clients: ["pactflow"], // ONLY pactflow
|
|
23
|
+
enableElicitation: true,
|
|
23
24
|
},
|
|
24
25
|
{
|
|
25
26
|
title: "Review Pact Tests",
|
|
@@ -27,7 +28,8 @@ export const TOOLS = [
|
|
|
27
28
|
purpose: "Review Pact tests for API interactions",
|
|
28
29
|
zodSchema: RefineInputSchema,
|
|
29
30
|
handler: "review",
|
|
30
|
-
clients: ["pactflow"]
|
|
31
|
+
clients: ["pactflow"],
|
|
32
|
+
enableElicitation: true,
|
|
31
33
|
},
|
|
32
34
|
{
|
|
33
35
|
title: "Get Provider States",
|
|
@@ -51,5 +53,35 @@ export const TOOLS = [
|
|
|
51
53
|
zodSchema: CanIDeploySchema,
|
|
52
54
|
handler: "canIDeploy",
|
|
53
55
|
clients: ["pactflow", "pact_broker"]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
title: "Matrix",
|
|
59
|
+
summary: "Retrieve the comprehensive contract verification matrix that shows the relationship between consumer and provider versions, their associated pact files, and verification results stored in the Pact Broker or Pactflow. The matrix provides detailed visibility into which consumer and provider versions have been successfully verified against each other, and highlights failures with detailed information about the cause.",
|
|
60
|
+
purpose: "The Matrix serves as a powerful tool for teams to understand the state of their contract testing ecosystem. It enables tracking of all interactions between consumer and provider versions over time, with detailed insights into verification successes and failures. This helps teams rapidly identify compatibility issues, understand why specific verifications failed, and make informed decisions about deployments. Matrix offers a more intuitive and consolidated view of the verification status, making it easier to spot trends or problematic versions. Additionally, the Matrix supports complex queries using selectors, and can answer specific 'can-i-deploy' questions, ensuring that only compatible versions are deployed to production environments.",
|
|
61
|
+
useCases: [
|
|
62
|
+
"Quickly identify which consumer and provider version combinations have passed or failed verification.",
|
|
63
|
+
"Diagnose and investigate why a particular consumer-provider verification failed.",
|
|
64
|
+
"Visualize the overall contract compatibility across two pacticipants / services.",
|
|
65
|
+
"Perform advanced queries using selectors to understand compatibility within specific branches, environments, or version ranges.",
|
|
66
|
+
"Support informed deployment decisions by answering 'can I deploy version X of this service to production?'",
|
|
67
|
+
"Expose contract verification details to non-frequent API users in a more accessible format."
|
|
68
|
+
],
|
|
69
|
+
zodSchema: MatrixSchema,
|
|
70
|
+
handler: "getMatrix",
|
|
71
|
+
clients: ["pactflow", "pact_broker"]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
title: "PactFlow AI Status",
|
|
75
|
+
summary: "Check PactFlow AI usage status, remaining credits, and eligibility",
|
|
76
|
+
purpose: "Retrieve the AI feature status for the PactFlow account, including whether AI is enabled, the number of remaining and consumed AI credits, and entitlement or permission issues preventing usage.",
|
|
77
|
+
useCases: [
|
|
78
|
+
"Verify if AI functionality is enabled for the account before attempting to use AI-powered features",
|
|
79
|
+
"Monitor remaining and consumed AI credits to manage usage and avoid unexpected disruptions",
|
|
80
|
+
"Detect entitlement or permission issues when a user tries to access AI features and guide corrective actions",
|
|
81
|
+
"Integrate into deployment pipelines to ensure the environment is correctly configured with necessary entitlements and sufficient credits before executing AI-driven tasks",
|
|
82
|
+
"Fetches usage and entitlement reports for auditing, budgeting, and compliance purposes"
|
|
83
|
+
],
|
|
84
|
+
handler: "getAIStatus",
|
|
85
|
+
clients: ["pactflow"]
|
|
54
86
|
}
|
|
55
87
|
];
|
package/dist/pactflow/client.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
|
|
2
2
|
import { TOOLS } from "./client/tools.js";
|
|
3
|
+
import { getOADMatcherRecommendations, getUserMatcherSelection } from "./client/prompt-utils.js";
|
|
4
|
+
import { PROMPTS } from "./client/prompts.js";
|
|
3
5
|
// Tool definitions for PactFlow AI API client
|
|
4
6
|
export class PactflowClient {
|
|
5
7
|
name = "Contract Testing";
|
|
@@ -8,7 +10,16 @@ export class PactflowClient {
|
|
|
8
10
|
aiBaseUrl;
|
|
9
11
|
baseUrl;
|
|
10
12
|
clientType;
|
|
11
|
-
|
|
13
|
+
server;
|
|
14
|
+
/**
|
|
15
|
+
* Creates an instance of the PactflowClient.
|
|
16
|
+
*
|
|
17
|
+
* @param auth The authentication token or credentials.
|
|
18
|
+
* @param baseUrl The base URL for the API.
|
|
19
|
+
* @param clientType The type of client (e.g., PactFlow, Pact Broker).
|
|
20
|
+
* @param server The SmartBear MCP server instance.
|
|
21
|
+
*/
|
|
22
|
+
constructor(auth, baseUrl, clientType, server) {
|
|
12
23
|
// Set headers based on the type of auth provided
|
|
13
24
|
if (typeof auth === "string") {
|
|
14
25
|
this.headers = {
|
|
@@ -28,16 +39,23 @@ export class PactflowClient {
|
|
|
28
39
|
this.baseUrl = baseUrl;
|
|
29
40
|
this.aiBaseUrl = `${this.baseUrl}/api/ai`;
|
|
30
41
|
this.clientType = clientType;
|
|
42
|
+
this.server = server;
|
|
31
43
|
}
|
|
32
44
|
// PactFlow AI client methods
|
|
33
45
|
/**
|
|
34
46
|
* Generate new Pact tests based on the provided input.
|
|
35
47
|
*
|
|
36
48
|
* @param toolInput The input data for the generation process.
|
|
49
|
+
* @param getInput Function to get additional input from the user if needed.
|
|
37
50
|
* @returns The result of the generation process.
|
|
38
51
|
* @throws Error if the HTTP request fails or the operation times out.
|
|
39
52
|
*/
|
|
40
|
-
async generate(toolInput) {
|
|
53
|
+
async generate(toolInput, getInput) {
|
|
54
|
+
if (toolInput.openapi?.document && (!toolInput.openapi?.matcher || Object.keys(toolInput.openapi.matcher).length === 0)) {
|
|
55
|
+
const matcherResponse = await getOADMatcherRecommendations(toolInput.openapi.document, this.server);
|
|
56
|
+
const userSelection = await getUserMatcherSelection(matcherResponse, getInput);
|
|
57
|
+
toolInput.openapi.matcher = userSelection;
|
|
58
|
+
}
|
|
41
59
|
// Submit the generation request
|
|
42
60
|
const response = await fetch(`${this.aiBaseUrl}/generate`, {
|
|
43
61
|
method: "POST",
|
|
@@ -54,10 +72,16 @@ export class PactflowClient {
|
|
|
54
72
|
* Review the provided Pact tests and suggest improvements.
|
|
55
73
|
*
|
|
56
74
|
* @param toolInput The input data for the review process.
|
|
75
|
+
* @param getInput Function to get additional input from the user if needed.
|
|
57
76
|
* @returns The result of the review process.
|
|
58
77
|
* @throws Error if the HTTP request fails or the operation times out.
|
|
59
78
|
*/
|
|
60
|
-
async review(toolInput) {
|
|
79
|
+
async review(toolInput, getInput) {
|
|
80
|
+
if (toolInput.openapi?.document && (!toolInput.openapi?.matcher || Object.keys(toolInput.openapi.matcher).length === 0)) {
|
|
81
|
+
const matcherResponse = await getOADMatcherRecommendations(toolInput.openapi.document, this.server);
|
|
82
|
+
const userSelection = await getUserMatcherSelection(matcherResponse, getInput);
|
|
83
|
+
toolInput.openapi.matcher = userSelection;
|
|
84
|
+
}
|
|
61
85
|
// Submit review request
|
|
62
86
|
const response = await fetch(`${this.aiBaseUrl}/review`, {
|
|
63
87
|
method: "POST",
|
|
@@ -70,6 +94,32 @@ export class PactflowClient {
|
|
|
70
94
|
const status_response = await response.json();
|
|
71
95
|
return await this.pollForCompletion(status_response, "Review Pacts");
|
|
72
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Retrieves AI status information for the current user
|
|
99
|
+
* and organization.
|
|
100
|
+
*
|
|
101
|
+
* @returns Entitlement containing AI status information, organization
|
|
102
|
+
* entitlements, and user entitlements.
|
|
103
|
+
* @throws Error if the request fails or returns a non-OK response.
|
|
104
|
+
*/
|
|
105
|
+
async getAIStatus() {
|
|
106
|
+
const url = `${this.aiBaseUrl}/entitlement`;
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(url, {
|
|
109
|
+
method: "GET",
|
|
110
|
+
headers: this.headers,
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
const errorText = await response.text().catch(() => "");
|
|
114
|
+
throw new Error(`PactFlow AI Status Request Failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
|
|
115
|
+
}
|
|
116
|
+
return (await response.json());
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
process.stderr.write(`[GetAICredits] Unexpected error: ${error}\n`);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
73
123
|
async getStatus(statusUrl) {
|
|
74
124
|
const response = await fetch(statusUrl, {
|
|
75
125
|
method: "HEAD",
|
|
@@ -153,11 +203,76 @@ export class PactflowClient {
|
|
|
153
203
|
return (await response.json());
|
|
154
204
|
}
|
|
155
205
|
catch (error) {
|
|
156
|
-
console.error(
|
|
206
|
+
console.error(`[CanIDeploy] Unexpected error: ${error}\n`);
|
|
157
207
|
throw error;
|
|
158
208
|
}
|
|
159
209
|
}
|
|
160
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Retrieves the matrix of pact verification results for the specified pacticipants.
|
|
212
|
+
* This allows you to see which consumer/provider combinations have been verified
|
|
213
|
+
* and make deployment decisions based on contract test results.
|
|
214
|
+
*
|
|
215
|
+
* @param body - Matrix query parameters including pacticipants, versions, environments, etc.
|
|
216
|
+
* @returns MatrixResponse containing the verification matrix, notices, and summary
|
|
217
|
+
* @throws Error if the request fails or returns a non-OK response
|
|
218
|
+
*/
|
|
219
|
+
async getMatrix(body) {
|
|
220
|
+
const { q, latestby, limit } = body;
|
|
221
|
+
// Build query parameters manually to avoid URL encoding of square brackets
|
|
222
|
+
const queryParts = [];
|
|
223
|
+
// Add optional parameters
|
|
224
|
+
if (latestby) {
|
|
225
|
+
queryParts.push(`latestby=${encodeURIComponent(latestby)}`);
|
|
226
|
+
}
|
|
227
|
+
if (limit !== undefined) {
|
|
228
|
+
queryParts.push(`limit=${limit}`);
|
|
229
|
+
}
|
|
230
|
+
// Add the q parameters (pacticipant selectors)
|
|
231
|
+
q.forEach((selector) => {
|
|
232
|
+
queryParts.push(`q[]pacticipant=${encodeURIComponent(selector.pacticipant)}`);
|
|
233
|
+
if (selector.version) {
|
|
234
|
+
queryParts.push(`q[]version=${encodeURIComponent(selector.version)}`);
|
|
235
|
+
}
|
|
236
|
+
if (selector.branch) {
|
|
237
|
+
queryParts.push(`q[]branch=${encodeURIComponent(selector.branch)}`);
|
|
238
|
+
}
|
|
239
|
+
if (selector.environment) {
|
|
240
|
+
queryParts.push(`q[]environment=${encodeURIComponent(selector.environment)}`);
|
|
241
|
+
}
|
|
242
|
+
if (selector.latest !== undefined) {
|
|
243
|
+
queryParts.push(`q[]latest=${selector.latest}`);
|
|
244
|
+
}
|
|
245
|
+
if (selector.tag) {
|
|
246
|
+
queryParts.push(`q[]tag=${encodeURIComponent(selector.tag)}`);
|
|
247
|
+
}
|
|
248
|
+
if (selector.mainBranch !== undefined) {
|
|
249
|
+
queryParts.push(`q[]mainBranch=${selector.mainBranch}`);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
const url = `${this.baseUrl}/matrix?${queryParts.join('&')}`;
|
|
253
|
+
try {
|
|
254
|
+
const response = await fetch(url, {
|
|
255
|
+
method: "GET",
|
|
256
|
+
headers: this.headers,
|
|
257
|
+
});
|
|
258
|
+
if (!response.ok) {
|
|
259
|
+
const errorText = await response.text().catch(() => "");
|
|
260
|
+
throw new Error(`Matrix Request Failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
|
|
261
|
+
}
|
|
262
|
+
return (await response.json());
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
console.error("[GetMatrix] Unexpected error:", error);
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Registers tools with the provided register function.
|
|
271
|
+
*
|
|
272
|
+
* @param register - The function used to register tools.
|
|
273
|
+
* @param getInput - The function used to get input for tools.
|
|
274
|
+
*/
|
|
275
|
+
registerTools(register, getInput) {
|
|
161
276
|
for (const tool of TOOLS.filter(t => t.clients.includes(this.clientType))) {
|
|
162
277
|
const { handler, clients: _, formatResponse, ...toolparams } = tool; // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
163
278
|
register(toolparams, async (args, _extra) => {
|
|
@@ -165,7 +280,13 @@ export class PactflowClient {
|
|
|
165
280
|
if (typeof handler_fn !== "function") {
|
|
166
281
|
throw new Error(`Handler '${handler}' not found on PactClient`);
|
|
167
282
|
}
|
|
168
|
-
|
|
283
|
+
let result;
|
|
284
|
+
if (tool.enableElicitation) {
|
|
285
|
+
result = await handler_fn.call(this, args, getInput);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
result = await handler_fn.call(this, args);
|
|
289
|
+
}
|
|
169
290
|
// Use custom response formatter if provided
|
|
170
291
|
if (formatResponse) {
|
|
171
292
|
return formatResponse(result);
|
|
@@ -177,4 +298,14 @@ export class PactflowClient {
|
|
|
177
298
|
});
|
|
178
299
|
}
|
|
179
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Registers prompts with the provided register function.
|
|
303
|
+
*
|
|
304
|
+
* @param register - The function used to register prompts.
|
|
305
|
+
*/
|
|
306
|
+
registerPrompts(register) {
|
|
307
|
+
PROMPTS.forEach(prompt => {
|
|
308
|
+
register(prompt.name, prompt.params, prompt.callback);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
180
311
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartbear/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "MCP server for interacting SmartBear Products",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"smartbear",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"pactflow"
|
|
12
12
|
],
|
|
13
13
|
"homepage": "https://developer.smartbear.com/smartbear-mcp",
|
|
14
|
+
"mcpName": "com.smartbear/smartbear-mcp",
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
16
17
|
"url": "git@github.com:SmartBear/smartbear-mcp.git"
|
|
@@ -45,7 +46,8 @@
|
|
|
45
46
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
46
47
|
"node-cache": "^5.1.2",
|
|
47
48
|
"swagger-client": "^3.35.6",
|
|
48
|
-
"zod": "^3"
|
|
49
|
+
"zod": "^3",
|
|
50
|
+
"zod-to-json-schema": "^3.24.6"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
53
|
"@eslint/js": "^9.29.0",
|