mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
End-to-end tests that drive the deployed Supermemory MCP over streamable HTTP (no mocks): - discovery: handshake + tool/resource/prompt listing - identity: whoAmI, listProjects - memory: save -> recall round-trip, profile variants, forget, container scoping - graph/resources/prompts: memory-graph, fetch-graph-data, profile/projects, context - oauth: protected-resource discovery chain, dynamic client registration, token-endpoint negatives, and a real refresh -> access token round-trip - auth: GET / info, 401 on missing/invalid token - root-scope: x-sm-project scoping behavior Tests skip without SUPERMEMORY_API_KEY (OAuth tier-D skips without its token env vars) so CI is safe without secrets. Adds vitest + a test:e2e script and documents running + the OAuth flow in apps/mcp/README.md.
52 lines
1.5 KiB
TypeScript
52 lines
1.5 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it } from "vitest"
|
|
import { API_KEY, callTool, connect, textOf, type Session } from "./helpers"
|
|
|
|
const EXPECTED_TOOLS = [
|
|
"memory",
|
|
"recall",
|
|
"listProjects",
|
|
"whoAmI",
|
|
"memory-graph",
|
|
]
|
|
|
|
describe.skipIf(!API_KEY)("MCP — discovery & identity", () => {
|
|
let s: Session
|
|
|
|
beforeAll(async () => {
|
|
s = await connect()
|
|
})
|
|
afterAll(async () => {
|
|
await s?.close()
|
|
})
|
|
|
|
it("handshakes and lists the expected tools", async () => {
|
|
const { tools } = await s.client.listTools()
|
|
const names = tools.map((t) => t.name)
|
|
for (const t of EXPECTED_TOOLS) expect(names).toContain(t)
|
|
})
|
|
|
|
it("lists profile & projects resources", async () => {
|
|
const { resources } = await s.client.listResources()
|
|
const uris = resources.map((r) => r.uri)
|
|
expect(uris).toContain("supermemory://profile")
|
|
expect(uris).toContain("supermemory://projects")
|
|
})
|
|
|
|
it("lists the context prompt", async () => {
|
|
const { prompts } = await s.client.listPrompts()
|
|
expect(prompts.map((p) => p.name)).toContain("context")
|
|
})
|
|
|
|
it("whoAmI resolves to the authenticated account", async () => {
|
|
const res = await callTool(s.client, "whoAmI")
|
|
expect(res.isError).toBeFalsy()
|
|
const parsed = JSON.parse(textOf(res))
|
|
expect(parsed.userId).toBeTruthy()
|
|
})
|
|
|
|
it("listProjects returns content", async () => {
|
|
const res = await callTool(s.client, "listProjects", { refresh: true })
|
|
expect(res.isError).toBeFalsy()
|
|
expect(textOf(res).length).toBeGreaterThan(0)
|
|
})
|
|
})
|