mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-18 21:14:06 +00:00
Fixes cross-host graph rendering and moves widget uploads off the JSON/base64 tool transport. - render graph data from the launcher result without a second tool call - stream multipart uploads through one-time, short-lived upload sessions - remove temporary widget diagnostics and redundant unit tests Tested with Biome, TypeScript, 17 unit tests, a Wrangler deployment dry-run, and live graph rendering in ChatGPT and Claude. Authenticated E2E setup is currently blocked by the saved OAuth refresh session returning `invalid_grant: session not found`.
83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it } from "vitest"
|
|
import { graphViewSchema } from "../src/shared/types"
|
|
import {
|
|
OAUTH_CREDENTIALS_AVAILABLE,
|
|
callTool,
|
|
connect,
|
|
type Session,
|
|
textOf,
|
|
} from "./helpers"
|
|
const describeWithAuth = describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)
|
|
|
|
describeWithAuth("MCP — graph, resources & prompts", () => {
|
|
let s: Session
|
|
|
|
beforeAll(async () => {
|
|
s = await connect()
|
|
})
|
|
afterAll(async () => {
|
|
await s?.close()
|
|
})
|
|
|
|
it("memory-graph returns a rendered graph widget", async () => {
|
|
const res = await callTool(s.client, "memory-graph")
|
|
expect(res.isError).toBeFalsy()
|
|
expect(textOf(res)).toMatch(/Rendered the interactive Memory Graph MCP App/)
|
|
const result = graphViewSchema.safeParse(res.structuredContent)
|
|
expect(result.success).toBe(true)
|
|
if (!result.success) throw result.error
|
|
expect(result.data.view).toBe("graph")
|
|
expect(result.data.rendered).toBe(true)
|
|
expect(result.data.documentCount).toBe(result.data.documents.length)
|
|
})
|
|
|
|
it("fetch-graph-data returns paginated documents", async () => {
|
|
const res = await callTool(s.client, "fetch-graph-data", {
|
|
page: 1,
|
|
limit: 5,
|
|
})
|
|
expect(res.isError).toBeFalsy()
|
|
const sc = res.structuredContent as {
|
|
documents?: unknown[]
|
|
pagination?: { limit?: number }
|
|
}
|
|
expect(Array.isArray(sc?.documents)).toBe(true)
|
|
expect(sc?.pagination?.limit).toBe(5)
|
|
})
|
|
|
|
it("reads the profile resource", async () => {
|
|
const res = await s.client.readResource({ uri: "supermemory://profile" })
|
|
expect(res.contents.length).toBeGreaterThan(0)
|
|
expect(res.contents[0].mimeType).toBe("text/plain")
|
|
expect(res.contents[0].text).toMatch(/# Active Space Profile/)
|
|
expect(res.contents[0].text).toMatch(/Space:/)
|
|
expect(res.contents[0].text).toMatch(
|
|
/Use `listSpaces` to find the relevant space key/,
|
|
)
|
|
})
|
|
|
|
it("reads all spaces in a compact human-readable format", async () => {
|
|
const res = await s.client.readResource({
|
|
uri: "supermemory://spaces",
|
|
})
|
|
const text = res.contents[0].text as string
|
|
expect(res.contents[0].mimeType).toBe("text/plain")
|
|
expect(text).toMatch(/# My Spaces/)
|
|
expect(text).toMatch(/Active:/)
|
|
expect(text).not.toMatch(/"containerTags":/)
|
|
})
|
|
|
|
it("gets compact active-space context without prompt arguments", async () => {
|
|
const prompts = await s.client.listPrompts()
|
|
const contextPrompt = prompts.prompts.find(
|
|
(prompt) => prompt.name === "context",
|
|
)
|
|
expect(contextPrompt?.arguments ?? []).toHaveLength(0)
|
|
|
|
const res = await s.client.getPrompt({ name: "context", arguments: {} })
|
|
expect(res.messages.length).toBeGreaterThan(0)
|
|
const text = res.messages[0].content.text as string
|
|
expect(text).toMatch(/# Supermemory Context/)
|
|
expect(text).toMatch(/Active space:/)
|
|
})
|
|
})
|