From 30e1242bc59916912c3b9835cc4207acebe61b19 Mon Sep 17 00:00:00 2001 From: Prasanna A P <106952318+Prasanna721@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:00:16 -0700 Subject: [PATCH] rename mcp internals to space --- apps/mcp/README.md | 2 +- ...pace-scope.test.ts => space-scope.test.ts} | 0 apps/mcp/src/server/index.ts | 4 +- apps/mcp/src/server/prompts/context.ts | 38 ++++++++--------- .../src/server/resources/container-tags.ts | 18 ++++---- apps/mcp/src/server/resources/profile.ts | 20 ++++----- apps/mcp/src/server/server.ts | 16 ++++---- ...ion.test.ts => space-presentation.test.ts} | 10 ++--- ...-presentation.ts => space-presentation.ts} | 41 +++++++++---------- .../{workspace-state.ts => space-state.ts} | 2 +- .../{workspace.test.ts => space.test.ts} | 8 ++-- .../mcp/src/server/{workspace.ts => space.ts} | 4 +- apps/mcp/src/server/types.ts | 4 +- .../{WorkspaceCard.tsx => SpaceCard.tsx} | 19 ++++----- .../{WorkspaceChip.tsx => SpaceChip.tsx} | 5 +-- apps/mcp/src/widget/design/globals.css | 28 ++++++------- .../{WorkspaceSelect.tsx => SpaceSelect.tsx} | 12 +++--- apps/mcp/src/widget/design/ui/index.ts | 2 +- apps/mcp/src/widget/studio/Studio.tsx | 12 +++--- apps/mcp/src/widget/views/Confirmation.tsx | 4 +- apps/mcp/src/widget/views/Picker.tsx | 8 ++-- apps/mcp/src/widget/views/Save.tsx | 4 +- apps/mcp/src/widget/views/Success.tsx | 4 +- apps/mcp/src/widget/views/Upload.tsx | 4 +- apps/mcp/wrangler.jsonc | 6 +-- 25 files changed, 132 insertions(+), 143 deletions(-) rename apps/mcp/e2e/{workspace-scope.test.ts => space-scope.test.ts} (100%) rename apps/mcp/src/server/{workspace-presentation.test.ts => space-presentation.test.ts} (91%) rename apps/mcp/src/server/{workspace-presentation.ts => space-presentation.ts} (68%) rename apps/mcp/src/server/{workspace-state.ts => space-state.ts} (90%) rename apps/mcp/src/server/{workspace.test.ts => space.test.ts} (88%) rename apps/mcp/src/server/{workspace.ts => space.ts} (75%) rename apps/mcp/src/widget/components/{WorkspaceCard.tsx => SpaceCard.tsx} (72%) rename apps/mcp/src/widget/components/{WorkspaceChip.tsx => SpaceChip.tsx} (58%) rename apps/mcp/src/widget/design/ui/{WorkspaceSelect.tsx => SpaceSelect.tsx} (94%) diff --git a/apps/mcp/README.md b/apps/mcp/README.md index a252d46e..0bf5d374 100644 --- a/apps/mcp/README.md +++ b/apps/mcp/README.md @@ -136,7 +136,7 @@ discovery and rejection tests still run. ## Storage And Rollout -`WorkspaceState` stores only the active space's container tag. It never stores bearer +`SpaceState` stores only the active space's container tag. It never stores bearer tokens, MCP client identity, or protocol messages. The old `SupermemoryMCP` class and binding remain inert for one rollout. This diff --git a/apps/mcp/e2e/workspace-scope.test.ts b/apps/mcp/e2e/space-scope.test.ts similarity index 100% rename from apps/mcp/e2e/workspace-scope.test.ts rename to apps/mcp/e2e/space-scope.test.ts diff --git a/apps/mcp/src/server/index.ts b/apps/mcp/src/server/index.ts index 69ac6870..f392ddbd 100644 --- a/apps/mcp/src/server/index.ts +++ b/apps/mcp/src/server/index.ts @@ -7,7 +7,7 @@ import { validateOAuthToken, type AuthUser } from "./auth" import { SupermemoryMCP } from "./legacy-protocol-state" import { createSupermemoryServer } from "./server" import type { ActorContext, ServerEnv } from "./types" -import { WorkspaceState } from "./workspace-state" +import { SpaceState } from "./space-state" type Bindings = ServerEnv @@ -205,7 +205,7 @@ app.all("/", (c) => handleMcpRequest(c, "/mcp")) app.all("/mcp", (c) => handleMcpRequest(c)) app.all("/mcp/", (c) => handleMcpRequest(c, "/mcp")) -export { SupermemoryMCP, WorkspaceState } +export { SpaceState, SupermemoryMCP } export type { ActorContext, ServerEnv } export default app diff --git a/apps/mcp/src/server/prompts/context.ts b/apps/mcp/src/server/prompts/context.ts index ba3f0a3b..900bce5c 100644 --- a/apps/mcp/src/server/prompts/context.ts +++ b/apps/mcp/src/server/prompts/context.ts @@ -3,14 +3,14 @@ import { DEFAULT_PROJECT_ID, type SupermemoryClient } from "../client" import { compactDescription, formatFactSection, - formatWorkspaceRow, - sortWorkspaces, - workspaceDisplayName, - workspaceMetadata, -} from "../workspace-presentation" + formatSpaceRow, + sortSpaces, + spaceDisplayName, + spaceMetadata, +} from "../space-presentation" const CONTEXT_FACT_LIMIT = 8 -const RECENT_WORKSPACE_LIMIT = 3 +const RECENT_SPACE_LIMIT = 3 export function registerContextPrompt( server: McpServer, @@ -26,24 +26,24 @@ export function registerContextPrompt( try { const selectedTag = await resolveContainerTag() const activeKey = selectedTag ?? DEFAULT_PROJECT_ID - const [profileResult, workspaces] = await Promise.all([ + const [profileResult, spaces] = await Promise.all([ getClient(activeKey).getProfile(), getClient().listContainerTags(), ]) - const activeWorkspace = workspaces.find( - (workspace) => workspace.containerTag === activeKey, + const activeSpace = spaces.find( + (space) => space.containerTag === activeKey, ) - const activeLabel = workspaceDisplayName(activeWorkspace, activeKey) + const activeLabel = spaceDisplayName(activeSpace, activeKey) const fallback = selectedTag ? "" : " (default)" const parts: string[] = [ "# Supermemory Context", `Active space: ${activeLabel} [${activeKey}]${fallback}`, ] - if (activeWorkspace) { - const metadata = workspaceMetadata(activeWorkspace) + if (activeSpace) { + const metadata = spaceMetadata(activeSpace) if (metadata) parts.push(metadata) - const description = compactDescription(activeWorkspace.description) + const description = compactDescription(activeSpace.description) if (description) parts.push(description) } @@ -68,15 +68,15 @@ export function registerContextPrompt( parts.push("No profile facts are available for this space yet.") } - const recentWorkspaces = sortWorkspaces(workspaces, activeKey) - .filter((workspace) => workspace.containerTag !== activeKey) - .slice(0, RECENT_WORKSPACE_LIMIT) - if (recentWorkspaces.length > 0) { + const recentSpaces = sortSpaces(spaces, activeKey) + .filter((space) => space.containerTag !== activeKey) + .slice(0, RECENT_SPACE_LIMIT) + if (recentSpaces.length > 0) { parts.push( "", "## Recently Active Spaces", - ...recentWorkspaces.map((workspace) => - formatWorkspaceRow(workspace, activeKey, 100), + ...recentSpaces.map((space) => + formatSpaceRow(space, activeKey, 100), ), ) } diff --git a/apps/mcp/src/server/resources/container-tags.ts b/apps/mcp/src/server/resources/container-tags.ts index 615bb608..14730d7a 100644 --- a/apps/mcp/src/server/resources/container-tags.ts +++ b/apps/mcp/src/server/resources/container-tags.ts @@ -1,10 +1,10 @@ import type { McpServer } from "@modelcontextprotocol/server" import { DEFAULT_PROJECT_ID, type SupermemoryClient } from "../client" import { - formatWorkspaceRow, - sortWorkspaces, - workspaceDisplayName, -} from "../workspace-presentation" + formatSpaceRow, + sortSpaces, + spaceDisplayName, +} from "../space-presentation" export function registerContainerTagsResource( server: McpServer, @@ -18,13 +18,13 @@ export function registerContainerTagsResource( resolveContainerTag(), ]) const activeKey = selectedTag ?? DEFAULT_PROJECT_ID - const activeWorkspace = containerTags.find( - (workspace) => workspace.containerTag === activeKey, + const activeSpace = containerTags.find( + (space) => space.containerTag === activeKey, ) - const rows = sortWorkspaces(containerTags, activeKey).map((workspace) => - formatWorkspaceRow(workspace, activeKey), + const rows = sortSpaces(containerTags, activeKey).map((space) => + formatSpaceRow(space, activeKey), ) - const activeLabel = workspaceDisplayName(activeWorkspace, activeKey) + const activeLabel = spaceDisplayName(activeSpace, activeKey) const fallback = selectedTag ? "" : " (default)" const text = [ "# My Spaces", diff --git a/apps/mcp/src/server/resources/profile.ts b/apps/mcp/src/server/resources/profile.ts index 995f95dd..afcac032 100644 --- a/apps/mcp/src/server/resources/profile.ts +++ b/apps/mcp/src/server/resources/profile.ts @@ -3,9 +3,9 @@ import { DEFAULT_PROJECT_ID, type SupermemoryClient } from "../client" import { compactDescription, formatFactSection, - workspaceDisplayName, - workspaceMetadata, -} from "../workspace-presentation" + spaceDisplayName, + spaceMetadata, +} from "../space-presentation" const PROFILE_FACT_LIMIT = 12 @@ -21,24 +21,24 @@ export function registerProfileResource( async () => { const selectedTag = await resolveContainerTag() const activeKey = selectedTag ?? DEFAULT_PROJECT_ID - const [profileResult, workspaces] = await Promise.all([ + const [profileResult, spaces] = await Promise.all([ getClient(activeKey).getProfile(), getClient().listContainerTags(), ]) - const activeWorkspace = workspaces.find( - (workspace) => workspace.containerTag === activeKey, + const activeSpace = spaces.find( + (space) => space.containerTag === activeKey, ) - const activeLabel = workspaceDisplayName(activeWorkspace, activeKey) + const activeLabel = spaceDisplayName(activeSpace, activeKey) const fallback = selectedTag ? "" : " (default)" const parts: string[] = [ "# Active Space Profile", `Space: ${activeLabel} [${activeKey}]${fallback}`, ] - if (activeWorkspace) { - const metadata = workspaceMetadata(activeWorkspace) + if (activeSpace) { + const metadata = spaceMetadata(activeSpace) if (metadata) parts.push(metadata) - const description = compactDescription(activeWorkspace.description) + const description = compactDescription(activeSpace.description) if (description) parts.push(description) } diff --git a/apps/mcp/src/server/server.ts b/apps/mcp/src/server/server.ts index 93fa90e6..86eb3d54 100644 --- a/apps/mcp/src/server/server.ts +++ b/apps/mcp/src/server/server.ts @@ -18,9 +18,9 @@ import { registerAllTools } from "./tools" import { errorResult } from "./tools/types" import type { ActorContext, ServerEnv } from "./types" import { - resolveContainerTag as resolveWorkspaceContainerTag, - workspaceStateName, -} from "./workspace" + resolveContainerTag as resolveSpaceContainerTag, + spaceStateName, +} from "./space" const DEFAULT_API_URL = "https://api.supermemory.ai" @@ -53,17 +53,15 @@ export function createSupermemoryServer( version: "1.0.0", }) const apiUrl = env.API_URL || DEFAULT_API_URL - const workspaceState = env.WORKSPACE_STATE.getByName( - workspaceStateName(actor), - ) + const spaceState = env.SPACE_STATE.getByName(spaceStateName(actor)) const getClient = (containerTag?: string) => new SupermemoryClient(actor.bearerToken, containerTag, apiUrl) - const getActiveContainerTag = () => workspaceState.getActiveContainerTag() + const getActiveContainerTag = () => spaceState.getActiveContainerTag() const setActiveContainerTag = (containerTag: string) => - workspaceState.setActiveContainerTag(containerTag) + spaceState.setActiveContainerTag(containerTag) const resolveContainerTag = (explicit?: string) => - resolveWorkspaceContainerTag(explicit, getActiveContainerTag) + resolveSpaceContainerTag(explicit, getActiveContainerTag) const analytics = createPosthogAnalytics(env, actor, waitUntil) const toolServer = createTrackedToolServer( server, diff --git a/apps/mcp/src/server/workspace-presentation.test.ts b/apps/mcp/src/server/space-presentation.test.ts similarity index 91% rename from apps/mcp/src/server/workspace-presentation.test.ts rename to apps/mcp/src/server/space-presentation.test.ts index 9d4958f9..c57fe9d1 100644 --- a/apps/mcp/src/server/workspace-presentation.test.ts +++ b/apps/mcp/src/server/space-presentation.test.ts @@ -3,9 +3,9 @@ import type { ContainerTag } from "../shared/types" import { compactDescription, formatFactSection, - formatWorkspaceRow, - sortWorkspaces, -} from "./workspace-presentation" + formatSpaceRow, + sortSpaces, +} from "./space-presentation" const space = ( containerTag: string, @@ -27,7 +27,7 @@ const space = ( describe("space presentation", () => { it("keeps the active space first, then sorts by activity", () => { - const sorted = sortWorkspaces( + const sorted = sortSpaces( [ space("older", "2026-01-01T00:00:00.000Z"), space("active", "2025-01-01T00:00:00.000Z"), @@ -44,7 +44,7 @@ describe("space presentation", () => { }) it("formats compact rows without internal database IDs", () => { - const row = formatWorkspaceRow( + const row = formatSpaceRow( space("project-key", "2026-07-29T19:44:28.177Z"), "project-key", ) diff --git a/apps/mcp/src/server/workspace-presentation.ts b/apps/mcp/src/server/space-presentation.ts similarity index 68% rename from apps/mcp/src/server/workspace-presentation.ts rename to apps/mcp/src/server/space-presentation.ts index fa3a2932..630a5f3a 100644 --- a/apps/mcp/src/server/workspace-presentation.ts +++ b/apps/mcp/src/server/space-presentation.ts @@ -5,11 +5,11 @@ const DEFAULT_DESCRIPTION_LIMIT = 160 const plural = (count: number, singular: string, pluralForm: string) => `${count} ${count === 1 ? singular : pluralForm}` -export function workspaceDisplayName( - workspace: ContainerTag | undefined, +export function spaceDisplayName( + space: ContainerTag | undefined, key: string, ): string { - return workspace?.name || key + return space?.name || key } export function compactDescription( @@ -39,43 +39,40 @@ export function formatActivityDate(value: string | null): string | undefined { }).format(date) } -export function workspaceMetadata(workspace: ContainerTag): string { - const lastActivity = formatActivityDate(workspace.lastActivityAt) +export function spaceMetadata(space: ContainerTag): string { + const lastActivity = formatActivityDate(space.lastActivityAt) const fields = [ - workspace.visibility - ? `${workspace.visibility.charAt(0).toUpperCase()}${workspace.visibility.slice(1)}` + space.visibility + ? `${space.visibility.charAt(0).toUpperCase()}${space.visibility.slice(1)}` : undefined, - plural(workspace.documentCount, "document", "documents"), - plural(workspace.memoryCount, "memory", "memories"), + plural(space.documentCount, "document", "documents"), + plural(space.memoryCount, "memory", "memories"), lastActivity ? `Last active ${lastActivity}` : undefined, ] return fields.filter(Boolean).join(" · ") } -export function formatWorkspaceRow( - workspace: ContainerTag, +export function formatSpaceRow( + space: ContainerTag, activeKey: string, descriptionLimit = DEFAULT_DESCRIPTION_LIMIT, ): string { - const active = workspace.containerTag === activeKey ? " · Active" : "" - const metadata = workspaceMetadata(workspace) - const description = compactDescription( - workspace.description, - descriptionLimit, - ) + const active = space.containerTag === activeKey ? " · Active" : "" + const metadata = spaceMetadata(space) + const description = compactDescription(space.description, descriptionLimit) const firstLine = - `- ${workspaceDisplayName(workspace, workspace.containerTag)} ` + - `[${workspace.containerTag}]${active}${metadata ? ` · ${metadata}` : ""}` + `- ${spaceDisplayName(space, space.containerTag)} ` + + `[${space.containerTag}]${active}${metadata ? ` · ${metadata}` : ""}` return description ? `${firstLine}\n ${description}` : firstLine } -export function sortWorkspaces( - workspaces: ContainerTag[], +export function sortSpaces( + spaces: ContainerTag[], activeKey: string, ): ContainerTag[] { - return [...workspaces].sort((left, right) => { + return [...spaces].sort((left, right) => { if (left.containerTag === activeKey) return -1 if (right.containerTag === activeKey) return 1 diff --git a/apps/mcp/src/server/workspace-state.ts b/apps/mcp/src/server/space-state.ts similarity index 90% rename from apps/mcp/src/server/workspace-state.ts rename to apps/mcp/src/server/space-state.ts index 27344c37..138bd656 100644 --- a/apps/mcp/src/server/workspace-state.ts +++ b/apps/mcp/src/server/space-state.ts @@ -3,7 +3,7 @@ import { containerTagSchema } from "./container-tag" const ACTIVE_CONTAINER_TAG_KEY = "activeContainerTag" -export class WorkspaceState extends DurableObject { +export class SpaceState extends DurableObject { async getActiveContainerTag(): Promise { return this.ctx.storage.get(ACTIVE_CONTAINER_TAG_KEY) } diff --git a/apps/mcp/src/server/workspace.test.ts b/apps/mcp/src/server/space.test.ts similarity index 88% rename from apps/mcp/src/server/workspace.test.ts rename to apps/mcp/src/server/space.test.ts index 1464dd46..e9034b16 100644 --- a/apps/mcp/src/server/workspace.test.ts +++ b/apps/mcp/src/server/space.test.ts @@ -1,16 +1,16 @@ import { describe, expect, it, vi } from "vitest" import { optionalContainerTagSchema } from "./container-tag" -import { resolveContainerTag, workspaceStateName } from "./workspace" +import { resolveContainerTag, spaceStateName } from "./space" -describe("workspace application state", () => { +describe("space application state", () => { it("keys active state by organization and user without collisions", () => { expect( - workspaceStateName({ + spaceStateName({ organizationId: "org:one", userId: "user:two", }), ).not.toBe( - workspaceStateName({ + spaceStateName({ organizationId: "org", userId: "one:user:two", }), diff --git a/apps/mcp/src/server/workspace.ts b/apps/mcp/src/server/space.ts similarity index 75% rename from apps/mcp/src/server/workspace.ts rename to apps/mcp/src/server/space.ts index 81055cff..18f61612 100644 --- a/apps/mcp/src/server/workspace.ts +++ b/apps/mcp/src/server/space.ts @@ -1,9 +1,9 @@ import type { ActorContext } from "./types" -export function workspaceStateName( +export function spaceStateName( actor: Pick, ): string { - return `workspace:${JSON.stringify([actor.organizationId, actor.userId])}` + return `space:${JSON.stringify([actor.organizationId, actor.userId])}` } export async function resolveContainerTag( diff --git a/apps/mcp/src/server/types.ts b/apps/mcp/src/server/types.ts index f10df537..ca37aaad 100644 --- a/apps/mcp/src/server/types.ts +++ b/apps/mcp/src/server/types.ts @@ -1,4 +1,4 @@ -import type { WorkspaceState } from "./workspace-state" +import type { SpaceState } from "./space-state" export interface ActorContext { userId: string @@ -8,7 +8,7 @@ export interface ActorContext { } export interface ServerEnv { - WORKSPACE_STATE: DurableObjectNamespace + SPACE_STATE: DurableObjectNamespace API_URL?: string MCP_RESOURCE?: string ALLOWED_MCP_ORIGIN_HOSTNAMES?: string diff --git a/apps/mcp/src/widget/components/WorkspaceCard.tsx b/apps/mcp/src/widget/components/SpaceCard.tsx similarity index 72% rename from apps/mcp/src/widget/components/WorkspaceCard.tsx rename to apps/mcp/src/widget/components/SpaceCard.tsx index 18b96f9d..c5c5a3c0 100644 --- a/apps/mcp/src/widget/components/WorkspaceCard.tsx +++ b/apps/mcp/src/widget/components/SpaceCard.tsx @@ -10,12 +10,7 @@ interface Props { onClick: (containerTag: string) => void } -export function WorkspaceCard({ - containerTag, - active, - access, - onClick, -}: Props) { +export function SpaceCard({ containerTag, active, access, onClick }: Props) { const name = containerTag.name || formatTagLabel(containerTag.containerTag) const docs = containerTag.documentCount const mems = containerTag.memoryCount @@ -26,26 +21,26 @@ export function WorkspaceCard({ return (