@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// The tools this app opts in to, listed by the real mount over the real registry through the official
|
||||
// SDK client. The transport's own rules are `@conusai-kit/host/http`'s tests.
|
||||
|
||||
import { buildRegistry } from "@conusai-kit/core"
|
||||
import { createMcpHandler } from "@conusai-kit/host/http"
|
||||
import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client"
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
import { appModules } from "../modules/index.js"
|
||||
|
||||
const registry = buildRegistry([...appModules])
|
||||
|
||||
describe("this app's MCP tools", () => {
|
||||
it("are the procedures that opted in, and a tool call goes through the scoped caller", async () => {
|
||||
const output = { notes: [], hasMore: false }
|
||||
const callByName = vi.fn(async () => output)
|
||||
const handle = createMcpHandler({
|
||||
registry,
|
||||
contextFor: async () => ({
|
||||
principal: { method: "bearer", actor: { userId: "user-a" } },
|
||||
caller: { callByName } as never,
|
||||
}),
|
||||
checkCsrf: () => undefined,
|
||||
})
|
||||
const transport = new StreamableHTTPClientTransport(new URL("https://app.example.test/api/mcp"), {
|
||||
fetch: (url, init) => handle(new Request(url, init), "sdk-request"),
|
||||
})
|
||||
const client = new Client({ name: "app-template-test", version: "1.0.0" }, { versionNegotiation: { mode: "auto" } })
|
||||
try {
|
||||
await client.connect(transport)
|
||||
const listed = await client.listTools()
|
||||
// The Agent's workspace reads are tools too: what an MCP client of a workspace can list and open.
|
||||
expect(listed.tools.map((tool) => tool.name)).toEqual([
|
||||
"agent.run.status", // kit:agent
|
||||
"assistant.workspace.openProject", // kit:agent
|
||||
"assistant.workspace.projects", // kit:agent
|
||||
"knowledge.search", // kit:knowledge
|
||||
"notes.note.list",
|
||||
])
|
||||
expect(listed.tools.find((tool) => tool.name === "notes.note.list")?.inputSchema.required).toEqual([
|
||||
"org",
|
||||
"workspace",
|
||||
"project",
|
||||
])
|
||||
const result = await client.callTool({
|
||||
name: "notes.note.list",
|
||||
arguments: { org: "org-a", workspace: "ws-a", project: "project-a" },
|
||||
})
|
||||
expect(result.structuredContent).toEqual(output)
|
||||
} finally {
|
||||
await client.close()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// This journey requires explicit optional-module admission.
|
||||
vi.mock("../modules/inclusion.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../modules/inclusion.js")>()),
|
||||
...(await import("./support/native-readiness.js")).selectedModules(["agent", "knowledge"]),
|
||||
}))
|
||||
Reference in New Issue
Block a user