mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
test: bind MCP validation and cleanup faults to selected inputs
This commit is contained in:
1 parent
fef76a02fb
commit
99062feaa7
7 files changed
+53
-26
No files matched your search
@@ -0,0 +1,11 @@
|
||||
import type {
|
||||
Client,
|
||||
CallToolRequestOptions,
|
||||
} from "@modelcontextprotocol/client";
|
||||
|
||||
/** Call with the server's advertised schema; callers cannot replace it. */
|
||||
export function artifactMcpCall(
|
||||
client: Client,
|
||||
parameters: Parameters<Client["callTool"]>[0],
|
||||
options?: Omit<CallToolRequestOptions, "toolDefinition">,
|
||||
): ReturnType<Client["callTool"]>;
|
||||
@@ -1,3 +1,4 @@
|
||||
import { artifactMcpCall } from "../../scripts/lib/artifact-e2e.mjs";
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
@@ -105,7 +106,7 @@ test("preserves Harmony archive formats through the public CLI/MCP lifecycle", a
|
||||
root_format: format,
|
||||
root_sha256: sha256,
|
||||
});
|
||||
const opened = await client.callTool({
|
||||
const opened = await artifactMcpCall(client, {
|
||||
name: "open_binary",
|
||||
arguments: { path },
|
||||
});
|
||||
@@ -113,7 +114,7 @@ test("preserves Harmony archive formats through the public CLI/MCP lifecycle", a
|
||||
expect(opened.structuredContent).toMatchObject({
|
||||
result: { kind: "archive", format, sha256 },
|
||||
});
|
||||
const status = await client.callTool({
|
||||
const status = await artifactMcpCall(client, {
|
||||
name: "binary_session",
|
||||
arguments: {},
|
||||
});
|
||||
@@ -121,7 +122,7 @@ test("preserves Harmony archive formats through the public CLI/MCP lifecycle", a
|
||||
expect(status.structuredContent).toMatchObject({
|
||||
result: { open: true, kind: "archive", format, sha256 },
|
||||
});
|
||||
const inspected = await client.callTool({
|
||||
const inspected = await artifactMcpCall(client, {
|
||||
name: "inspect_artifact",
|
||||
arguments: {},
|
||||
});
|
||||
@@ -133,7 +134,7 @@ test("preserves Harmony archive formats through the public CLI/MCP lifecycle", a
|
||||
),
|
||||
).toEqual(cliInventory);
|
||||
|
||||
const projected = await client.callTool({
|
||||
const projected = await artifactMcpCall(client, {
|
||||
name: "project_harmony_application_graph",
|
||||
arguments: { inventory_evidence: [inventoryEvidence] },
|
||||
});
|
||||
@@ -175,12 +176,12 @@ test("preserves Harmony archive formats through the public CLI/MCP lifecycle", a
|
||||
mcp: inventoryEvidence.evidence_id,
|
||||
cli: cliEvidence.evidence_id,
|
||||
});
|
||||
const closed = await client.callTool({
|
||||
const closed = await artifactMcpCall(client, {
|
||||
name: "close_binary",
|
||||
arguments: {},
|
||||
});
|
||||
expect(closed.isError, JSON.stringify(closed)).not.toBe(true);
|
||||
const empty = await client.callTool({
|
||||
const empty = await artifactMcpCall(client, {
|
||||
name: "binary_session",
|
||||
arguments: {},
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { artifactMcpCall } from "../../scripts/lib/artifact-e2e.mjs";
|
||||
import { createHash } from "node:crypto";
|
||||
import { unlink, writeFile } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
@@ -63,7 +64,7 @@ cliTest(
|
||||
});
|
||||
expect(output.exitCode, output.stderr).toBe(0);
|
||||
const cliEvidence = parseEvidence(output.json);
|
||||
const response = await client.callTool({
|
||||
const response = await artifactMcpCall(client, {
|
||||
name: "inspect_managed_members",
|
||||
arguments: { path },
|
||||
});
|
||||
@@ -96,7 +97,7 @@ cliTest(
|
||||
],
|
||||
});
|
||||
expect(selectedCli.exitCode, selectedCli.stderr).toBe(0);
|
||||
const selected = await client.callTool({
|
||||
const selected = await artifactMcpCall(client, {
|
||||
name: "inspect_managed_members",
|
||||
arguments: { path, type_names: [empty!.full_name] },
|
||||
});
|
||||
@@ -109,7 +110,7 @@ cliTest(
|
||||
coverage: { state: "complete", issues: [] },
|
||||
});
|
||||
|
||||
const summaryReply = await client.callTool({
|
||||
const summaryReply = await artifactMcpCall(client, {
|
||||
name: "inspect_managed_members",
|
||||
arguments: { path, detail: "summary" },
|
||||
});
|
||||
@@ -128,7 +129,7 @@ cliTest(
|
||||
});
|
||||
await unlink(path);
|
||||
for (const collection of ["types", "methods"] as const) {
|
||||
const reply = await client.callTool({
|
||||
const reply = await artifactMcpCall(client, {
|
||||
name: "inspect_analysis_view",
|
||||
arguments: {
|
||||
source: {
|
||||
@@ -149,7 +150,7 @@ cliTest(
|
||||
collection === "types" ? report.types : [],
|
||||
);
|
||||
}
|
||||
const unknown = await client.callTool({
|
||||
const unknown = await artifactMcpCall(client, {
|
||||
name: "inspect_analysis_view",
|
||||
arguments: {
|
||||
source: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { artifactMcpCall } from "../../../scripts/lib/artifact-e2e.mjs";
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { Client } from "@modelcontextprotocol/client";
|
||||
@@ -272,7 +273,7 @@ async function verifyGeneratedLauncher(
|
||||
expect((await client.listTools()).tools.map(({ name }) => name)).toContain(
|
||||
"binary_session",
|
||||
);
|
||||
const session = await client.callTool({
|
||||
const session = await artifactMcpCall(client, {
|
||||
name: "binary_session",
|
||||
arguments: {},
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { artifactMcpCall } from "../../../scripts/lib/artifact-e2e.mjs";
|
||||
import { mkdir, readFile, symlink, writeFile } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
|
||||
@@ -113,7 +114,7 @@ cliTest.skipIf(process.platform === "win32")(
|
||||
expect(
|
||||
(await client.listTools()).tools.map(({ name }) => name),
|
||||
).toContain("binary_session");
|
||||
const session = await client.callTool({
|
||||
const session = await artifactMcpCall(client, {
|
||||
name: "binary_session",
|
||||
arguments: {},
|
||||
});
|
||||
|
||||
@@ -103,7 +103,10 @@ cliTest(
|
||||
const ajv = new Ajv2020({ strict: false, validateFormats: false });
|
||||
expect(ajv.validate(tool.inputSchema, input)).toBe(true);
|
||||
expect(ajv.validate(tool.inputSchema, { left, right })).toBe(false);
|
||||
const mcp = await client.callTool({ name: tool.name, arguments: input });
|
||||
const mcp = await client.callTool(
|
||||
{ name: tool.name, arguments: input },
|
||||
{ toolDefinition: tool },
|
||||
);
|
||||
expect(mcp.isError, JSON.stringify(mcp)).not.toBe(true);
|
||||
expect(
|
||||
ajv.validate(outputSchema, mcp.structuredContent),
|
||||
@@ -116,22 +119,31 @@ cliTest(
|
||||
left.evidence_id,
|
||||
right.evidence_id,
|
||||
]);
|
||||
const retained = await client.callTool({
|
||||
name: tool.name,
|
||||
arguments: {
|
||||
scope: "both",
|
||||
left: { kind: "retained-evidence", evidence_id: left.evidence_id },
|
||||
right: { kind: "retained-evidence", evidence_id: right.evidence_id },
|
||||
const retained = await client.callTool(
|
||||
{
|
||||
name: tool.name,
|
||||
arguments: {
|
||||
scope: "both",
|
||||
left: { kind: "retained-evidence", evidence_id: left.evidence_id },
|
||||
right: {
|
||||
kind: "retained-evidence",
|
||||
evidence_id: right.evidence_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
{ toolDefinition: tool },
|
||||
);
|
||||
expect(retained.isError).not.toBe(true);
|
||||
expect(parseEvidence(retained.structuredContent).evidence_id).toBe(
|
||||
mcpEvidence.evidence_id,
|
||||
);
|
||||
const invalid = await client.callTool({
|
||||
name: tool.name,
|
||||
arguments: { ...input, scope: "all" },
|
||||
});
|
||||
const invalid = await client.callTool(
|
||||
{
|
||||
name: tool.name,
|
||||
arguments: { ...input, scope: "all" },
|
||||
},
|
||||
{ toolDefinition: tool },
|
||||
);
|
||||
expect(invalid.isError).toBe(true);
|
||||
} finally {
|
||||
await client.close();
|
||||
|
||||
@@ -860,7 +860,7 @@ it.skipIf(process.platform === "win32").each(
|
||||
};
|
||||
const client = consumer === "health" ? fixture.open() : undefined;
|
||||
injected.fingerprintReads = 0;
|
||||
injected.installationPath = fixture.kuna;
|
||||
injected.installationPath = command;
|
||||
injected.abortOnClose = { stage, abort: () => controller.abort(reason) };
|
||||
injected.failCloseReadStage = closeRefusal ? stage : undefined;
|
||||
let failure: AnalysisError | undefined;
|
||||
|
||||
Reference in new issue
Block a user