Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,17 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

- name: Check Zod v4 migration
run: |
bun run check:zod
bun test packages/validation/api.test.ts
bunx vitest run packages/tools/src/tools-shared.test.ts packages/tools/src/tool-operations.test.ts

- name: Run TypeScript type checking
run: bunx turbo run check-types --filter='@supermemory/ai-sdk' --filter='@supermemory/memory-graph'

- name: Check MCP server
run: cd apps/mcp && bun run check

- name: Run Biome CI (format & lint on changed files)
run: bunx biome ci --changed --since=origin/main --no-errors-on-unmatched
7 changes: 5 additions & 2 deletions apps/mcp/.dev.vars.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
API_URL=
MCP_URL=

#(optional)
POSTHOG_API_KEY=
# Optional comma-separated browser Origin hostnames beyond the built-in list.
ALLOWED_MCP_ORIGIN_HOSTNAMES=

# Optional
POSTHOG_API_KEY=
37 changes: 24 additions & 13 deletions apps/mcp/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Supermemory MCP Server 4.0

A standalone MCP (Model Context Protocol) server for Supermemory that gives AI assistants persistent memory across conversations. Built on Cloudflare Workers with Durable Objects for scalable, persistent connections.
A standalone MCP (Model Context Protocol) server for Supermemory that gives AI assistants persistent memory across conversations. Built on Cloudflare Workers with the Cloudflare Agents SDK stateless handler and MCP TypeScript SDK v2.

## Features

Expand Down Expand Up @@ -132,7 +132,7 @@ Get the current logged-in user's information.
{}
```

Returns: `{ userId, email, name, client, sessionId }`
Returns: `{ userId, email, name, client, sessionId }`. `sessionId` is `null` on the stateless HTTP transport.

## Resources

Expand Down Expand Up @@ -166,13 +166,16 @@ Create a `.dev.vars` file:

```env
API_URL=http://localhost:8787
or
API_URL=https://api.supermemory.ai
MCP_URL=http://localhost:8788
ALLOWED_MCP_ORIGIN_HOSTNAMES=custom-client.example
```

| Variable | Description | Default |
|----------|-------------|---------|
| `API_URL` | Main Supermemory API URL for OAuth validation | `https://api.supermemory.ai` |
| `MCP_URL` | Public MCP base URL used in OAuth metadata | Incoming request host |
| `ALLOWED_MCP_ORIGIN_HOSTNAMES` | Optional comma-separated browser Origin hostnames added to the built-in Supermemory/ChatGPT/Claude/Gemini/Grok/T3/local allowlist | Empty |
| `POSTHOG_API_KEY` | Optional PostHog project key | Empty |

### Run Locally

Expand All @@ -184,7 +187,13 @@ The server will start at `http://localhost:8788`.

**Note:** For local development, you also need the main Supermemory API running at the `API_URL` for OAuth token validation.

### End-to-End Tests
### Tests

Run the local unit and protocol-wire suite:

```bash
bun run test
```

The `e2e/` suite drives a real MCP server over streamable HTTP (no mocks) and asserts the
core journey: handshake → tool/resource/prompt discovery → `whoAmI` → `listProjects` →
Expand All @@ -205,7 +214,7 @@ bun run test:e2e
| `e2e/discovery.test.ts` | handshake, tools/resources/prompts listing, `whoAmI`, `listProjects` |
| `e2e/memory.test.ts` | save→recall round-trip, profile variants, `forget`, container scoping, bad args |
| `e2e/list-memories.test.ts` | `listMemories` discovery, save→list round-trip, pagination, arg validation |
| `e2e/root-scope.test.ts` | `x-sm-project` header strips the `containerTag` param and scopes the whole connection |
| `e2e/root-scope.test.ts` | `x-sm-project` header strips the `containerTag` param and scopes the whole client transport |
| `e2e/graph.test.ts` | `memory-graph`, `fetch-graph-data`, resource reads, `context` prompt |

#### OAuth flow tests
Expand Down Expand Up @@ -251,22 +260,24 @@ bun run deploy
▼ │
┌─────────────────────────────────────────────────────┐
│ Supermemory MCP Server │
│ (mcp.supermemory.ai/mcp) │
│ (mcp.supermemory.ai/mcp)
│ ┌─────────────────────────────────────────────┐ │
│ │ Cloudflare Durable Object │ │
│ │ • Session state │ │
│ │ • Client info persistence │ │
│ │ • MCP protocol handling │ │
│ │ Agents SDK stateless MCP v2 handler │ │
│ │ • Fresh request-local server instances │ │
│ │ • 2026-07-28 + stateless 2025 protocols │ │
│ │ • MCP protocol validation and dispatch │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```

## Tech Stack

- **Runtime:** Cloudflare Workers
- **State:** Durable Objects with SQLite
- **State:** Stateless MCP transport; memories live in the Supermemory API
- **Framework:** Hono
- **MCP SDK:** @modelcontextprotocol/sdk + agents
- **MCP HTTP handler:** `agents/mcp/server` from Cloudflare Agents SDK `0.20`
- **MCP protocol SDK:** @modelcontextprotocol/server v2 (currently `2.0.0-beta.5`)
- **MCP App UI:** @modelcontextprotocol/ext-apps `1.7.5`; its published browser package still peers on SDK v1, but that build-only dependency is not bundled into the Worker runtime
- **API Client:** supermemory SDK
- **Analytics:** PostHog

6 changes: 4 additions & 2 deletions apps/mcp/e2e/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
import {
Client,
StreamableHTTPClientTransport,
} from "@modelcontextprotocol/client"

export const MCP_URL =
process.env.SUPERMEMORY_MCP_URL ?? "https://mcp.supermemory.ai/mcp"
Expand Down
16 changes: 10 additions & 6 deletions apps/mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@
"dev:app": "vite build && wrangler dev --port ${PORT:-8788}",
"deploy": "vite build && wrangler deploy --minify",
"cf-typegen": "wrangler types --env-interface CloudflareBindings",
"test:e2e": "vitest run"
"check-types": "tsc --noEmit",
"test": "vite build && vitest run src",
"test:e2e": "vite build && vitest run",
"check": "bun run check-types && bun run test"
},
"dependencies": {
"@cloudflare/workers-oauth-provider": "^0.2.2",
"@modelcontextprotocol/ext-apps": "^1.0.0",
"@modelcontextprotocol/sdk": "^1.25.2",
"agents": "^0.3.5",
"@modelcontextprotocol/server": "2.0.0-beta.5",
"agents": "^0.20.0",
"hono": "^4.11.1",
"posthog-node": "^5.18.0",
"supermemory": "^4.0.0",
"zod": "^3.25.76"
"zod": "^4.4.3"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250620.0",
"@modelcontextprotocol/client": "2.0.0-beta.5",
"@modelcontextprotocol/ext-apps": "1.7.5",
"@modelcontextprotocol/sdk": "1.29.0",
"d3-force-3d": "^3.0.5",
"force-graph": "^1.49.0",
"typescript": "^5.8.3",
Expand Down
Loading