feat(mcp): add credential and all-runs tools; replace deprecated z.string().uuid()
- add list_scenario_credentials, add_scenario_credential, remove_scenario_credential tools - add list_all_runs tool (global across all scenarios) - replace all deprecated z.string().uuid() with z.uuid() throughout mcp.service
This commit is contained in:
+156
-25
@@ -86,7 +86,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Delete a session by numeric ID (closes it first if open)",
|
description: "Delete a session by numeric ID (closes it first if open)",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Session ID to delete"),
|
id: z.uuid().describe("Session ID to delete"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ id }) => {
|
async ({ id }) => {
|
||||||
@@ -151,7 +151,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Get an environment record by ID",
|
description: "Get an environment record by ID",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Environment ID"),
|
id: z.uuid().describe("Environment ID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ id }) => {
|
async ({ id }) => {
|
||||||
@@ -207,7 +207,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Update an existing environment (name and/or data)",
|
description: "Update an existing environment (name and/or data)",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Environment ID to update"),
|
id: z.uuid().describe("Environment ID to update"),
|
||||||
name: z.string().optional().describe("New name"),
|
name: z.string().optional().describe("New name"),
|
||||||
data: z
|
data: z
|
||||||
.record(z.string(), z.string())
|
.record(z.string(), z.string())
|
||||||
@@ -238,7 +238,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Delete an environment by ID",
|
description: "Delete an environment by ID",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Environment ID to delete"),
|
id: z.uuid().describe("Environment ID to delete"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ id }) => {
|
async ({ id }) => {
|
||||||
@@ -392,7 +392,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Get a scenario with its steps by ID",
|
description: "Get a scenario with its steps by ID",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Scenario ID"),
|
id: z.uuid().describe("Scenario ID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ id }) => {
|
async ({ id }) => {
|
||||||
@@ -442,7 +442,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Update a scenario name",
|
description: "Update a scenario name",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Scenario ID"),
|
id: z.uuid().describe("Scenario ID"),
|
||||||
name: z.string().optional().describe("New name"),
|
name: z.string().optional().describe("New name"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -468,7 +468,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Delete a scenario by ID",
|
description: "Delete a scenario by ID",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Scenario ID"),
|
id: z.uuid().describe("Scenario ID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ id }) => {
|
async ({ id }) => {
|
||||||
@@ -493,7 +493,7 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Add a step to a scenario",
|
description: "Add a step to a scenario",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
scenarioId: z.string().uuid().describe("Parent scenario ID"),
|
scenarioId: z.uuid().describe("Parent scenario ID"),
|
||||||
order: z
|
order: z
|
||||||
.number()
|
.number()
|
||||||
.int()
|
.int()
|
||||||
@@ -527,8 +527,8 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Get a single step of a scenario",
|
description: "Get a single step of a scenario",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
scenarioId: z.string().uuid().describe("Scenario ID"),
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
stepId: z.string().uuid().describe("Step ID"),
|
stepId: z.uuid().describe("Step ID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ scenarioId, stepId }) => {
|
async ({ scenarioId, stepId }) => {
|
||||||
@@ -551,8 +551,8 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Update a step within a scenario",
|
description: "Update a step within a scenario",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
scenarioId: z.string().uuid().describe("Scenario ID"),
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
stepId: z.string().uuid().describe("Step ID"),
|
stepId: z.uuid().describe("Step ID"),
|
||||||
order: z
|
order: z
|
||||||
.number()
|
.number()
|
||||||
.int()
|
.int()
|
||||||
@@ -591,8 +591,8 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Delete a step from a scenario",
|
description: "Delete a step from a scenario",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
scenarioId: z.string().uuid().describe("Scenario ID"),
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
stepId: z.string().uuid().describe("Step ID"),
|
stepId: z.uuid().describe("Step ID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ scenarioId, stepId }) => {
|
async ({ scenarioId, stepId }) => {
|
||||||
@@ -621,7 +621,7 @@ export class McpService {
|
|||||||
description:
|
description:
|
||||||
"List runs for a scenario (paginated, optionally filtered by status)",
|
"List runs for a scenario (paginated, optionally filtered by status)",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
scenarioId: z.string().uuid().describe("Scenario ID"),
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
status: z
|
status: z
|
||||||
.enum(["pending", "in_progress", "pass", "fail"])
|
.enum(["pending", "in_progress", "pass", "fail"])
|
||||||
.optional()
|
.optional()
|
||||||
@@ -664,11 +664,8 @@ export class McpService {
|
|||||||
{
|
{
|
||||||
description: "Trigger an immediate run of a scenario by ID",
|
description: "Trigger an immediate run of a scenario by ID",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Scenario ID to run"),
|
id: z.uuid().describe("Scenario ID to run"),
|
||||||
environmentId: z
|
environmentId: z.uuid().describe("Environment ID to run the scenario in"),
|
||||||
.string()
|
|
||||||
.uuid()
|
|
||||||
.describe("Environment ID to run the scenario in"),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ id, environmentId }) => {
|
async ({ id, environmentId }) => {
|
||||||
@@ -692,8 +689,8 @@ export class McpService {
|
|||||||
description:
|
description:
|
||||||
"Get a specific scenario run with all step runs and their outputs",
|
"Get a specific scenario run with all step runs and their outputs",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
scenarioId: z.string().uuid().describe("Scenario ID"),
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
runId: z.string().uuid().describe("Run ID"),
|
runId: z.uuid().describe("Run ID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ scenarioId, runId }) => {
|
async ({ scenarioId, runId }) => {
|
||||||
@@ -717,8 +714,8 @@ export class McpService {
|
|||||||
description:
|
description:
|
||||||
"Block until a scenario run reaches pass or fail (max 5 min), then return the full run with step outputs",
|
"Block until a scenario run reaches pass or fail (max 5 min), then return the full run with step outputs",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
scenarioId: z.string().uuid().describe("Scenario ID"),
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
runId: z.string().uuid().describe("Run ID"),
|
runId: z.uuid().describe("Run ID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ scenarioId, runId }) => {
|
async ({ scenarioId, runId }) => {
|
||||||
@@ -736,13 +733,147 @@ export class McpService {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
server.registerTool(
|
||||||
|
"list_scenario_credentials",
|
||||||
|
{
|
||||||
|
description: "List credentials assigned to a scenario",
|
||||||
|
inputSchema: {
|
||||||
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async ({ scenarioId }) => {
|
||||||
|
try {
|
||||||
|
const creds =
|
||||||
|
await this.scenarioService.findScenarioCredentials(scenarioId);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text" as const, text: JSON.stringify(creds) }],
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
isError: true,
|
||||||
|
content: [{ type: "text" as const, text: (err as Error).message }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
server.registerTool(
|
||||||
|
"add_scenario_credential",
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
"Add a credential to a scenario with an alias (used in snippets)",
|
||||||
|
inputSchema: {
|
||||||
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
|
credentialId: z.uuid().describe("Credential ID to associate"),
|
||||||
|
alias: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Alias used to reference this credential in step code, e.g. pkcs_key",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async ({ scenarioId, credentialId, alias }) => {
|
||||||
|
try {
|
||||||
|
const result = await this.scenarioService.addScenarioCredential(
|
||||||
|
scenarioId,
|
||||||
|
{ credentialId, alias },
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{ type: "text" as const, text: JSON.stringify(result) },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
isError: true,
|
||||||
|
content: [{ type: "text" as const, text: (err as Error).message }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
server.registerTool(
|
||||||
|
"remove_scenario_credential",
|
||||||
|
{
|
||||||
|
description: "Remove a credential assignment from a scenario",
|
||||||
|
inputSchema: {
|
||||||
|
scenarioId: z.uuid().describe("Scenario ID"),
|
||||||
|
scenarioCredentialId: z.uuid().describe("Scenario-credential assignment ID (not the credential ID)"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async ({ scenarioId, scenarioCredentialId }) => {
|
||||||
|
try {
|
||||||
|
await this.scenarioService.removeScenarioCredential(
|
||||||
|
scenarioId,
|
||||||
|
scenarioCredentialId,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text" as const,
|
||||||
|
text: `Credential assignment ${scenarioCredentialId} removed from scenario ${scenarioId}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
isError: true,
|
||||||
|
content: [{ type: "text" as const, text: (err as Error).message }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
server.registerTool(
|
||||||
|
"list_all_runs",
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
"List runs across all scenarios (paginated, filterable by status)",
|
||||||
|
inputSchema: {
|
||||||
|
status: z
|
||||||
|
.enum(["pending", "in_progress", "pass", "fail"])
|
||||||
|
.optional()
|
||||||
|
.describe("Filter by run status"),
|
||||||
|
page: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(1)
|
||||||
|
.optional()
|
||||||
|
.describe("Page number (default 1)"),
|
||||||
|
limit: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(1)
|
||||||
|
.optional()
|
||||||
|
.describe("Items per page (default 20)"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async ({ status, page, limit }) => {
|
||||||
|
try {
|
||||||
|
const result = await this.scenarioService.findAllRuns({
|
||||||
|
status,
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
content: [{ type: "text" as const, text: JSON.stringify(result) }],
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
isError: true,
|
||||||
|
content: [{ type: "text" as const, text: (err as Error).message }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
server.registerTool(
|
server.registerTool(
|
||||||
"export_scenario",
|
"export_scenario",
|
||||||
{
|
{
|
||||||
description:
|
description:
|
||||||
"Export a scenario as a portable JSON payload (name + steps)",
|
"Export a scenario as a portable JSON payload (name + steps)",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.string().uuid().describe("Scenario ID to export"),
|
id: z.uuid().describe("Scenario ID to export"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async ({ id }) => {
|
async ({ id }) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user