Skip to content

Commit 38584cf

Browse files
committed
Merge branch 'main' of https://github.com/MCPJam/inspector
2 parents c413087 + 4c20534 commit 38584cf

35 files changed

Lines changed: 2312 additions & 1485 deletions

mcpjam-inspector/client/src/App.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ import {
166166
import { getEffectiveWorkspaceClientCapabilities } from "./lib/client-config";
167167
import { buildEvalsHash } from "./lib/evals-router";
168168
import { withTestingSurface } from "./lib/testing-surface";
169-
import { useClientConfigStore } from "./stores/client-config-store";
169+
import { useWorkspaceClientConfigSyncPending } from "./hooks/use-workspace-client-config-sync-pending";
170170
import { ingestOAuthTraceLogs } from "./stores/traffic-log-store";
171171
import { clearGuestSession } from "./lib/guest-session";
172172

@@ -663,6 +663,7 @@ export default function App() {
663663
handleLeaveWorkspace,
664664
handleUpdateWorkspace,
665665
handleUpdateClientConfig,
666+
handleUpdateHostContext,
666667
handleDeleteWorkspace,
667668
handleWorkspaceShared,
668669
saveServerConfigWithoutConnecting,
@@ -852,11 +853,8 @@ export default function App() {
852853

853854
// Get the Convex workspace ID from the active workspace
854855
const activeWorkspace = workspaces[activeWorkspaceId];
855-
const isClientConfigSyncPending = useClientConfigStore(
856-
(state) =>
857-
state.isAwaitingRemoteEcho &&
858-
state.pendingWorkspaceId === activeWorkspaceId,
859-
);
856+
const isClientConfigSyncPending =
857+
useWorkspaceClientConfigSyncPending(activeWorkspaceId);
860858
const hostedClientCapabilities = getEffectiveWorkspaceClientCapabilities(
861859
activeWorkspace?.clientConfig,
862860
) as Record<string, unknown>;
@@ -1837,7 +1835,11 @@ export default function App() {
18371835
)
18381836
) : null)}
18391837
{activeTab === "views" && (
1840-
<ViewsTab selectedServer={appState.selectedServer} />
1838+
<ViewsTab
1839+
selectedServer={appState.selectedServer}
1840+
activeWorkspaceId={activeWorkspaceId}
1841+
onSaveHostContext={handleUpdateHostContext}
1842+
/>
18411843
)}
18421844
{activeTab === "conformance" && (
18431845
<ConformanceTab server={selectedServerEntry ?? null} />
@@ -1975,10 +1977,12 @@ export default function App() {
19751977
serverConfig={selectedMCPConfig}
19761978
serverName={appState.selectedServer}
19771979
servers={workspaceServers}
1980+
activeWorkspaceId={activeWorkspaceId}
19781981
isAuthenticated={isAuthenticated}
19791982
isAuthLoading={isAuthLoading}
19801983
isServerSyncing={isSelectedServerSyncing}
19811984
onConnect={handleConnect}
1985+
onSaveHostContext={handleUpdateHostContext}
19821986
ensureServersReady={ensureServersReady}
19831987
onOnboardingChange={setAppBuilderOnboarding}
19841988
playgroundServerSelectorProps={playgroundServerSelectorProps}

mcpjam-inspector/client/src/components/ServersTab.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
DialogDescription,
3030
DialogTitle,
3131
} from "@mcpjam/design-system/dialog";
32-
import type { WorkspaceClientConfig } from "@/lib/client-config";
32+
import type { WorkspaceConnectionConfigDraft } from "@/lib/client-config";
3333
import {
3434
ServerDetailModal,
3535
type ServerDetailTab,
@@ -513,7 +513,7 @@ interface ServersTabProps {
513513
onNavigateToRegistry?: () => void;
514514
onSaveClientConfig?: (
515515
workspaceId: string,
516-
clientConfig: WorkspaceClientConfig | undefined
516+
clientConfig: WorkspaceConnectionConfigDraft | undefined
517517
) => Promise<void>;
518518
}
519519

@@ -1551,8 +1551,7 @@ export function ServersTab({
15511551
<DialogContent className="flex h-[88vh] w-[min(96vw,88rem)] max-w-[88rem] flex-col gap-0 overflow-hidden p-0 sm:max-w-[88rem]">
15521552
<DialogTitle className="sr-only">Connection Settings</DialogTitle>
15531553
<DialogDescription className="sr-only">
1554-
Edit workspace connection settings, client capabilities, and host
1555-
context.
1554+
Edit workspace connection settings and client capabilities.
15561555
</DialogDescription>
15571556
<div className="min-h-0 flex-1 overflow-hidden">
15581557
<ClientConfigTab

mcpjam-inspector/client/src/components/ViewsTab.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { useSharedAppState } from "@/state/app-state-context";
2020
import { ViewsListSidebar } from "./views/ViewsListSidebar";
2121
import { ViewEditorPanel } from "./views/ViewEditorPanel";
2222
import { executeToolApi } from "@/lib/apis/mcp-tools-api";
23+
import type { WorkspaceHostContextDraft } from "@/lib/client-config";
2324
import {
2425
useCurrentDisplayContext,
2526
areDisplayContextsEqual,
@@ -32,6 +33,11 @@ import { ToolRenderOverride } from "@/components/chat-v2/thread/tool-render-over
3233
import { buildPersistedExecutionReplay } from "@/components/chat-v2/thread/persisted-execution-replay";
3334

3435
interface ViewsTabProps {
36+
activeWorkspaceId?: string | null;
37+
onSaveHostContext?: (
38+
workspaceId: string,
39+
hostContext: WorkspaceHostContextDraft,
40+
) => Promise<void>;
3541
selectedServer?: string;
3642
}
3743

@@ -49,7 +55,11 @@ function safeSerializeForCompare(value: unknown): string {
4955
}
5056
}
5157

52-
export function ViewsTab({ selectedServer }: ViewsTabProps) {
58+
export function ViewsTab({
59+
activeWorkspaceId = null,
60+
onSaveHostContext,
61+
selectedServer,
62+
}: ViewsTabProps) {
5363
const { isAuthenticated, isLoading } = useConvexAuth();
5464
const posthog = usePostHog();
5565
const appState = useSharedAppState();
@@ -1116,8 +1126,10 @@ export function ViewsTab({ selectedServer }: ViewsTabProps) {
11161126
</div>
11171127
) : (
11181128
<PlaygroundMain
1129+
activeWorkspaceId={activeWorkspaceId}
11191130
key={selectedView._id}
11201131
serverName={serversById.get(selectedView.serverId) || ""}
1132+
onSaveHostContext={onSaveHostContext}
11211133
pendingExecution={pendingExecution}
11221134
onExecutionInjected={handleExecutionInjected}
11231135
isExecuting={false}

mcpjam-inspector/client/src/components/chat-v2/thread/__tests__/chatgpt-app-renderer.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ vi.mock("@/stores/ui-playground-store", () => ({
3535
selector(mockPlaygroundStoreState),
3636
}));
3737

38-
vi.mock("@/stores/client-config-store", () => ({
39-
useClientConfigStore: (
40-
selector: (state: { draftConfig?: { hostContext?: Record<string, unknown> } }) => unknown,
41-
) => selector({ draftConfig: undefined }),
38+
vi.mock("@/stores/host-context-store", () => ({
39+
useHostContextStore: (
40+
selector: (state: { draftHostContext: Record<string, unknown> }) => unknown,
41+
) => selector({ draftHostContext: {} }),
4242
}));
4343

4444
vi.mock("@/stores/traffic-log-store", () => ({

mcpjam-inspector/client/src/components/chat-v2/thread/chatgpt-app-renderer.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {
3939
loadLocalChatGptWidget,
4040
type WidgetCspData,
4141
} from "./chatgpt-widget-loaders";
42-
import { useClientConfigStore } from "@/stores/client-config-store";
42+
import { useHostContextStore } from "@/stores/host-context-store";
4343
import {
4444
extractHostDeviceCapabilities,
4545
extractHostLocale,
@@ -626,9 +626,7 @@ export function ChatGPTAppRenderer({
626626
const rootRef = useRef<HTMLDivElement>(null);
627627
const inlineWidthRef = useRef<number | undefined>(undefined);
628628
const themeMode = usePreferencesStore((s) => s.themeMode);
629-
const draftHostContext = useClientConfigStore(
630-
(s) => s.draftConfig?.hostContext,
631-
);
629+
const draftHostContext = useHostContextStore((s) => s.draftHostContext);
632630
// Get locale and time zone from playground store, fallback to browser settings
633631
const playgroundLocale = useUIPlaygroundStore((s) => s.globals.locale);
634632
const playgroundTimeZone = useUIPlaygroundStore((s) => s.globals.timeZone);

mcpjam-inspector/client/src/components/chat-v2/thread/mcp-apps/__tests__/mcp-apps-renderer.test.tsx

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,8 @@ const {
8686
};
8787
});
8888

89-
const mockClientConfigStoreState = {
90-
draftConfig: undefined as
91-
| {
92-
version: 1;
93-
clientCapabilities: Record<string, unknown>;
94-
hostContext: Record<string, unknown>;
95-
}
96-
| undefined,
89+
const mockHostContextStoreState = {
90+
draftHostContext: {} as Record<string, unknown>,
9791
};
9892

9993
const mockPreferencesState = {
@@ -165,8 +159,8 @@ vi.mock("@/stores/ui-playground-store", () => ({
165159
selector(mockPlaygroundStoreState),
166160
}));
167161

168-
vi.mock("@/stores/client-config-store", () => ({
169-
useClientConfigStore: (selector: any) => selector(mockClientConfigStoreState),
162+
vi.mock("@/stores/host-context-store", () => ({
163+
useHostContextStore: (selector: any) => selector(mockHostContextStoreState),
170164
}));
171165

172166
vi.mock("@/stores/traffic-log-store", () => ({
@@ -230,7 +224,7 @@ const baseProps = {
230224
describe("MCPAppsRenderer tool input streaming", () => {
231225
beforeEach(() => {
232226
vi.clearAllMocks();
233-
mockClientConfigStoreState.draftConfig = undefined;
227+
mockHostContextStoreState.draftHostContext = {};
234228
Object.assign(mockPlaygroundStoreState, {
235229
isPlaygroundActive: false,
236230
mcpAppsCspMode: "permissive",
@@ -341,15 +335,11 @@ describe("MCPAppsRenderer tool input streaming", () => {
341335
});
342336

343337
it("clamps configured host display modes before sending host context", async () => {
344-
mockClientConfigStoreState.draftConfig = {
345-
version: 1,
346-
clientCapabilities: {},
347-
hostContext: {
348-
displayMode: "fullscreen",
349-
availableDisplayModes: ["inline"],
350-
locale: "fr-FR",
351-
timeZone: "Europe/Paris",
352-
},
338+
mockHostContextStoreState.draftHostContext = {
339+
displayMode: "fullscreen",
340+
availableDisplayModes: ["inline"],
341+
locale: "fr-FR",
342+
timeZone: "Europe/Paris",
353343
};
354344

355345
render(<MCPAppsRenderer {...baseProps} />);
@@ -376,16 +366,12 @@ describe("MCPAppsRenderer tool input streaming", () => {
376366
});
377367

378368
it("filters non-standard host style variables out of the initialize payload", async () => {
379-
mockClientConfigStoreState.draftConfig = {
380-
version: 1,
381-
clientCapabilities: {},
382-
hostContext: {
383-
styles: {
384-
variables: {
385-
"--font-sans": "Custom Sans",
386-
"--mcpjam-theme-preset": "soft-pop",
387-
"--totally-unknown": "ignore-me",
388-
},
369+
mockHostContextStoreState.draftHostContext = {
370+
styles: {
371+
variables: {
372+
"--font-sans": "Custom Sans",
373+
"--mcpjam-theme-preset": "soft-pop",
374+
"--totally-unknown": "ignore-me",
389375
},
390376
},
391377
};
@@ -488,16 +474,12 @@ describe("MCPAppsRenderer tool input streaming", () => {
488474
);
489475
});
490476

491-
mockClientConfigStoreState.draftConfig = {
492-
version: 1,
493-
clientCapabilities: {},
494-
hostContext: {
495-
locale: "es-ES",
496-
timeZone: "Europe/Madrid",
497-
deviceCapabilities: {
498-
hover: false,
499-
touch: true,
500-
},
477+
mockHostContextStoreState.draftHostContext = {
478+
locale: "es-ES",
479+
timeZone: "Europe/Madrid",
480+
deviceCapabilities: {
481+
hover: false,
482+
touch: true,
501483
},
502484
};
503485

mcpjam-inspector/client/src/components/chat-v2/thread/mcp-apps/mcp-apps-renderer.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ import type { CheckoutSession } from "@/shared/acp-types";
7070
import { listResources, readResource } from "@/lib/apis/mcp-resources-api";
7171
import { listPrompts } from "@/lib/apis/mcp-prompts-api";
7272
import { useChatboxHostStyle } from "@/contexts/chatbox-host-style-context";
73-
import { useClientConfigStore } from "@/stores/client-config-store";
73+
import { useHostContextStore } from "@/stores/host-context-store";
7474
import {
7575
clampDisplayModeToAvailableModes,
7676
extractHostDisplayMode,
@@ -209,9 +209,7 @@ export function MCPAppsRenderer({
209209
const themeMode = usePreferencesStore((s) => s.themeMode);
210210
const sharedHostStyle = usePreferencesStore((s) => s.hostStyle);
211211
const chatboxHostStyle = useChatboxHostStyle();
212-
const draftHostContext = useClientConfigStore(
213-
(s) => s.draftConfig?.hostContext,
214-
);
212+
const draftHostContext = useHostContextStore((s) => s.draftHostContext);
215213
const baseHostContext = useMemo(
216214
() =>
217215
draftHostContext &&

mcpjam-inspector/client/src/components/chat-v2/thread/parts/__tests__/display-modes.test.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
22
import { render, screen } from "@testing-library/react";
33
import userEvent from "@testing-library/user-event";
44
import { ToolPart } from "../tool-part";
5-
import { useClientConfigStore } from "@/stores/client-config-store";
6-
import { storePresets } from "@/test/mocks";
5+
import { useHostContextStore } from "@/stores/host-context-store";
76

87
// Mock lucide-react icons
98
vi.mock("lucide-react", () => {
@@ -92,7 +91,19 @@ describe("ToolPart display mode controls", () => {
9291
beforeEach(() => {
9392
vi.clearAllMocks();
9493
onDisplayModeChange = vi.fn();
95-
useClientConfigStore.setState(storePresets.clientConfig());
94+
useHostContextStore.setState({
95+
activeWorkspaceId: null,
96+
defaultHostContext: {},
97+
savedHostContext: undefined,
98+
draftHostContext: {},
99+
hostContextText: "{}",
100+
hostContextError: null,
101+
isSaving: false,
102+
isDirty: false,
103+
pendingWorkspaceId: null,
104+
pendingSavedHostContext: undefined,
105+
isAwaitingRemoteEcho: false,
106+
});
96107
});
97108

98109
const renderWithDisplayModes = (
@@ -162,9 +173,18 @@ describe("ToolPart display mode controls", () => {
162173
});
163174

164175
it("disables modes that the host does not advertise even when the app supports them", () => {
165-
useClientConfigStore.setState(
166-
storePresets.clientConfigWithHostDisplayModes(["inline"]),
167-
);
176+
useHostContextStore.setState({
177+
draftHostContext: {
178+
availableDisplayModes: ["inline"],
179+
},
180+
hostContextText: JSON.stringify(
181+
{
182+
availableDisplayModes: ["inline"],
183+
},
184+
null,
185+
2,
186+
),
187+
});
168188

169189
renderWithDisplayModes(["inline", "pip", "fullscreen"]);
170190

mcpjam-inspector/client/src/components/chat-v2/thread/parts/tool-part.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import { CspDebugPanel } from "../csp-debug-panel";
3939
import { JsonEditor } from "@/components/ui/json-editor";
4040
import { cn } from "@/lib/chat-utils";
4141
import { TextPart } from "./text-part";
42-
import { useClientConfigStore } from "@/stores/client-config-store";
42+
import { useHostContextStore } from "@/stores/host-context-store";
4343
import { extractHostDisplayModes } from "@/lib/client-config";
4444
import { useChatboxHostTheme } from "@/contexts/chatbox-host-style-context";
4545

@@ -167,7 +167,7 @@ export function ToolPart({
167167
const widgetDebugInfo = useWidgetDebugStore((s) =>
168168
toolCallId ? s.widgets.get(toolCallId) : undefined,
169169
);
170-
const hostContext = useClientConfigStore((s) => s.draftConfig?.hostContext);
170+
const hostContext = useHostContextStore((s) => s.draftHostContext);
171171
const hostAvailableDisplayModes = useMemo(
172172
() => extractHostDisplayModes(hostContext),
173173
[hostContext],

0 commit comments

Comments
 (0)