cloudaxe-opencode/packages/opencode/test/tool/mcp-resource.test.ts
2026-06-11 23:44:58 -05:00

107 lines
3.2 KiB
TypeScript

import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { Agent } from "@/agent/agent"
import { MCP } from "@/mcp"
import { MessageID, SessionID } from "@/session/schema"
import { ListMcpResourcesTool, ReadMcpResourceTool } from "@/tool/mcp-resource"
import { Tool } from "@/tool/tool"
import { Truncate } from "@/tool/truncate"
import { testEffect } from "../lib/effect"
const mcp = Layer.mock(MCP.Service, {
resources: () =>
Effect.succeed({
"zeta:guide": {
client: "zeta",
name: "guide",
uri: "fixture://guide",
description: "Guide",
mimeType: "text/plain",
},
"alpha:picture": {
client: "alpha",
name: "picture",
uri: "fixture://picture",
mimeType: "image/png",
},
}),
readResource: (clientName, uri) =>
Effect.succeed(
clientName === "alpha" && uri === "fixture://picture"
? {
contents: [
{ uri, mimeType: "text/plain", text: "caption" },
{ uri, mimeType: "image/png", blob: "aGVsbG8=" },
],
}
: undefined,
),
})
const it = testEffect(Layer.mergeAll(mcp, Truncate.defaultLayer, Agent.defaultLayer))
const baseCtx: Omit<Tool.Context, "ask"> = {
sessionID: SessionID.make("ses_test"),
messageID: MessageID.make("msg_test"),
agent: "build",
abort: AbortSignal.any([]),
messages: [],
metadata: () => Effect.void,
}
describe("tool.mcp-resource", () => {
it.instance("lists resources in a deterministic order", () =>
Effect.gen(function* () {
const info = yield* ListMcpResourcesTool
const tool = yield* info.init()
const result = yield* tool.execute({}, { ...baseCtx, ask: () => Effect.void })
expect(JSON.parse(result.output)).toEqual({
resources: [
{ clientName: "alpha", name: "picture", uri: "fixture://picture", mimeType: "image/png" },
{
clientName: "zeta",
name: "guide",
uri: "fixture://guide",
description: "Guide",
mimeType: "text/plain",
},
],
})
}),
)
it.instance("returns text and image content from a resource", () =>
Effect.gen(function* () {
const requests: Array<Omit<PermissionV1.Request, "id" | "sessionID" | "tool">> = []
const info = yield* ReadMcpResourceTool
const tool = yield* info.init()
const result = yield* tool.execute(
{ clientName: "alpha", uri: "fixture://picture" },
{
...baseCtx,
ask: (request) =>
Effect.sync(() => {
requests.push(request)
}),
},
)
expect(result.output).toBe("caption")
expect(result.attachments).toEqual([
{
type: "file",
mime: "image/png",
filename: "fixture://picture",
url: "data:image/png;base64,aGVsbG8=",
},
])
expect(requests[0]).toMatchObject({
permission: "read_mcp_resource",
patterns: ["alpha:fixture://picture"],
always: ["alpha:fixture://picture"],
})
}),
)
})