@apollo/client-ai-apps 0.6.5 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/CONTRIBUTING.md +195 -0
- package/README.md +74 -0
- package/dist/core/AbstractApolloClient.d.ts +33 -0
- package/dist/core/AbstractApolloClient.d.ts.map +1 -0
- package/dist/core/AbstractApolloClient.js +129 -0
- package/dist/core/AbstractApolloClient.js.map +1 -0
- package/dist/core/ApolloClient.d.ts +3 -7
- package/dist/core/ApolloClient.d.ts.map +1 -1
- package/dist/core/ApolloClient.js +5 -4
- package/dist/core/ApolloClient.js.map +1 -1
- package/dist/{mcp/core → core}/McpAppManager.d.ts +14 -10
- package/dist/core/McpAppManager.d.ts.map +1 -0
- package/dist/core/McpAppManager.js +56 -0
- package/dist/core/McpAppManager.js.map +1 -0
- package/dist/core/typeRegistration.d.ts +0 -14
- package/dist/core/typeRegistration.d.ts.map +1 -1
- package/dist/core/typeRegistration.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mcp.d.ts +0 -1
- package/dist/index.mcp.d.ts.map +1 -1
- package/dist/index.mcp.js +0 -1
- package/dist/index.mcp.js.map +1 -1
- package/dist/index.openai.d.ts +0 -1
- package/dist/index.openai.d.ts.map +1 -1
- package/dist/index.openai.js +0 -1
- package/dist/index.openai.js.map +1 -1
- package/dist/link/ToolCallLink.d.ts +6 -1
- package/dist/link/ToolCallLink.d.ts.map +1 -1
- package/dist/link/ToolCallLink.js +17 -4
- package/dist/link/ToolCallLink.js.map +1 -1
- package/dist/link/ToolHydrationLink.d.ts +21 -0
- package/dist/link/ToolHydrationLink.d.ts.map +1 -0
- package/dist/link/ToolHydrationLink.js +57 -0
- package/dist/link/ToolHydrationLink.js.map +1 -0
- package/dist/mcp/core/ApolloClient.d.ts +3 -20
- package/dist/mcp/core/ApolloClient.d.ts.map +1 -1
- package/dist/mcp/core/ApolloClient.js +20 -101
- package/dist/mcp/core/ApolloClient.js.map +1 -1
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/openai/core/ApolloClient.d.ts +3 -20
- package/dist/openai/core/ApolloClient.d.ts.map +1 -1
- package/dist/openai/core/ApolloClient.js +36 -101
- package/dist/openai/core/ApolloClient.js.map +1 -1
- package/dist/openai/index.d.ts +0 -1
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +0 -1
- package/dist/openai/index.js.map +1 -1
- package/dist/openai/react/index.d.ts +0 -7
- package/dist/openai/react/index.d.ts.map +1 -1
- package/dist/openai/react/index.js +0 -7
- package/dist/openai/react/index.js.map +1 -1
- package/dist/react/ApolloProvider.d.ts.map +1 -1
- package/dist/react/ApolloProvider.js +1 -1
- package/dist/react/ApolloProvider.js.map +1 -1
- package/dist/{mcp/react/hooks → react}/createHydrationUtils.d.ts +1 -1
- package/dist/react/createHydrationUtils.d.ts.map +1 -0
- package/dist/{mcp/react/hooks → react}/createHydrationUtils.js +7 -9
- package/dist/react/createHydrationUtils.js.map +1 -0
- package/dist/react/hooks/internal/useApolloClient.d.ts +3 -0
- package/dist/react/hooks/internal/useApolloClient.d.ts.map +1 -0
- package/dist/{mcp/react/hooks → react/hooks/internal}/useApolloClient.js +3 -3
- package/dist/react/hooks/internal/useApolloClient.js.map +1 -0
- package/dist/react/hooks/useApp.d.ts.map +1 -0
- package/dist/react/hooks/useApp.js +5 -0
- package/dist/react/hooks/useApp.js.map +1 -0
- package/dist/react/hooks/useHostContext.d.ts.map +1 -0
- package/dist/{openai/react → react}/hooks/useHostContext.js +1 -1
- package/dist/react/hooks/useHostContext.js.map +1 -0
- package/dist/react/hooks/useToolInfo.d.ts +3 -0
- package/dist/react/hooks/useToolInfo.d.ts.map +1 -0
- package/dist/react/hooks/useToolInfo.js +5 -0
- package/dist/react/hooks/useToolInfo.js.map +1 -0
- package/dist/react/hooks/useToolMetadata.d.ts +2 -0
- package/dist/react/hooks/useToolMetadata.d.ts.map +1 -0
- package/dist/react/hooks/useToolMetadata.js +5 -0
- package/dist/react/hooks/useToolMetadata.js.map +1 -0
- package/dist/react/index.d.ts +5 -16
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -19
- package/dist/react/index.js.map +1 -1
- package/dist/utilities/connectToHost.d.ts +3 -0
- package/dist/utilities/connectToHost.d.ts.map +1 -0
- package/dist/utilities/connectToHost.js +11 -0
- package/dist/utilities/connectToHost.js.map +1 -0
- package/dist/utilities/index.d.ts +1 -0
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/index.js +1 -0
- package/dist/utilities/index.js.map +1 -1
- package/package.json +17 -26
- package/src/core/AbstractApolloClient.ts +217 -0
- package/src/core/ApolloClient.ts +8 -10
- package/src/core/McpAppManager.ts +106 -0
- package/src/core/typeRegistration.ts +0 -15
- package/src/index.mcp.ts +0 -1
- package/src/index.openai.ts +0 -1
- package/src/index.ts +1 -6
- package/src/link/ToolCallLink.ts +27 -5
- package/src/link/ToolHydrationLink.ts +90 -0
- package/src/link/__tests__/ToolCallLink.test.ts +99 -0
- package/src/mcp/core/ApolloClient.ts +32 -170
- package/src/mcp/core/__tests__/ApolloClient.test.ts +398 -140
- package/src/mcp/index.ts +0 -1
- package/src/openai/core/ApolloClient.ts +48 -166
- package/src/openai/core/__tests__/ApolloClient.test.ts +680 -185
- package/src/openai/index.ts +0 -1
- package/src/openai/react/index.ts +0 -7
- package/src/react/ApolloProvider.tsx +1 -6
- package/src/react/__tests__/ApolloProvider/mcp.test.tsx +66 -29
- package/src/react/__tests__/ApolloProvider/openai.test.tsx +16 -41
- package/src/react/__tests__/createHydrationUtils.test.tsx +1260 -0
- package/src/{mcp/react/hooks → react}/createHydrationUtils.ts +7 -10
- package/src/react/hooks/__tests__/useApp.test.tsx +46 -0
- package/src/react/hooks/__tests__/useHostContext.test.tsx +99 -0
- package/src/react/hooks/__tests__/useToolInfo.test.tsx +98 -0
- package/src/react/hooks/__tests__/useToolMetadata.test.tsx +58 -0
- package/src/{mcp/react/hooks → react/hooks/internal}/useApolloClient.ts +3 -3
- package/src/{mcp/react → react}/hooks/useApp.ts +1 -1
- package/src/{openai/react → react}/hooks/useHostContext.ts +1 -1
- package/src/react/hooks/useToolInfo.ts +6 -0
- package/src/react/hooks/useToolMetadata.ts +5 -0
- package/src/react/index.ts +5 -36
- package/src/testing/internal/graphql/parseManifestOperation.ts +87 -0
- package/src/testing/internal/index.ts +3 -0
- package/src/testing/internal/matchers/index.ts +1 -0
- package/src/testing/internal/matchers/toEmitAnything.ts +43 -0
- package/src/testing/internal/matchers/types.ts +1 -0
- package/src/testing/internal/mcp/mockMcpHost.ts +25 -4
- package/src/testing/internal/tests/eachHostEnv.ts +22 -0
- package/src/testing/internal/utilities/createHostEnv.ts +117 -0
- package/src/utilities/connectToHost.ts +13 -0
- package/src/utilities/index.ts +1 -0
- package/tsconfig.vite.json +1 -1
- package/vitest.config.ts +13 -0
- package/dist/mcp/core/McpAppManager.d.ts.map +0 -1
- package/dist/mcp/core/McpAppManager.js +0 -88
- package/dist/mcp/core/McpAppManager.js.map +0 -1
- package/dist/mcp/link/ToolCallLink.d.ts +0 -28
- package/dist/mcp/link/ToolCallLink.d.ts.map +0 -1
- package/dist/mcp/link/ToolCallLink.js +0 -35
- package/dist/mcp/link/ToolCallLink.js.map +0 -1
- package/dist/mcp/react/hooks/createHydrationUtils.d.ts.map +0 -1
- package/dist/mcp/react/hooks/createHydrationUtils.js.map +0 -1
- package/dist/mcp/react/hooks/useApolloClient.d.ts +0 -3
- package/dist/mcp/react/hooks/useApolloClient.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useApolloClient.js.map +0 -1
- package/dist/mcp/react/hooks/useApp.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useApp.js +0 -5
- package/dist/mcp/react/hooks/useApp.js.map +0 -1
- package/dist/mcp/react/hooks/useHostContext.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useHostContext.js +0 -7
- package/dist/mcp/react/hooks/useHostContext.js.map +0 -1
- package/dist/mcp/react/hooks/useToolInfo.d.ts +0 -3
- package/dist/mcp/react/hooks/useToolInfo.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolInfo.js +0 -10
- package/dist/mcp/react/hooks/useToolInfo.js.map +0 -1
- package/dist/mcp/react/hooks/useToolInput.d.ts +0 -7
- package/dist/mcp/react/hooks/useToolInput.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolInput.js +0 -9
- package/dist/mcp/react/hooks/useToolInput.js.map +0 -1
- package/dist/mcp/react/hooks/useToolMetadata.d.ts +0 -2
- package/dist/mcp/react/hooks/useToolMetadata.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolMetadata.js +0 -5
- package/dist/mcp/react/hooks/useToolMetadata.js.map +0 -1
- package/dist/mcp/react/hooks/useToolName.d.ts +0 -7
- package/dist/mcp/react/hooks/useToolName.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolName.js +0 -9
- package/dist/mcp/react/hooks/useToolName.js.map +0 -1
- package/dist/mcp/react/index.d.ts +0 -8
- package/dist/mcp/react/index.d.ts.map +0 -1
- package/dist/mcp/react/index.js +0 -8
- package/dist/mcp/react/index.js.map +0 -1
- package/dist/openai/core/McpAppManager.d.ts +0 -37
- package/dist/openai/core/McpAppManager.d.ts.map +0 -1
- package/dist/openai/core/McpAppManager.js +0 -97
- package/dist/openai/core/McpAppManager.js.map +0 -1
- package/dist/openai/link/ToolCallLink.d.ts +0 -28
- package/dist/openai/link/ToolCallLink.d.ts.map +0 -1
- package/dist/openai/link/ToolCallLink.js +0 -35
- package/dist/openai/link/ToolCallLink.js.map +0 -1
- package/dist/openai/react/hooks/createHydrationUtils.d.ts +0 -15
- package/dist/openai/react/hooks/createHydrationUtils.d.ts.map +0 -1
- package/dist/openai/react/hooks/createHydrationUtils.js +0 -113
- package/dist/openai/react/hooks/createHydrationUtils.js.map +0 -1
- package/dist/openai/react/hooks/useApp.d.ts +0 -2
- package/dist/openai/react/hooks/useApp.d.ts.map +0 -1
- package/dist/openai/react/hooks/useApp.js +0 -5
- package/dist/openai/react/hooks/useApp.js.map +0 -1
- package/dist/openai/react/hooks/useHostContext.d.ts +0 -2
- package/dist/openai/react/hooks/useHostContext.d.ts.map +0 -1
- package/dist/openai/react/hooks/useHostContext.js.map +0 -1
- package/dist/openai/react/hooks/useToolInfo.d.ts +0 -3
- package/dist/openai/react/hooks/useToolInfo.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolInfo.js +0 -10
- package/dist/openai/react/hooks/useToolInfo.js.map +0 -1
- package/dist/openai/react/hooks/useToolInput.d.ts +0 -7
- package/dist/openai/react/hooks/useToolInput.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolInput.js +0 -9
- package/dist/openai/react/hooks/useToolInput.js.map +0 -1
- package/dist/openai/react/hooks/useToolMetadata.d.ts +0 -2
- package/dist/openai/react/hooks/useToolMetadata.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolMetadata.js +0 -5
- package/dist/openai/react/hooks/useToolMetadata.js.map +0 -1
- package/dist/openai/react/hooks/useToolName.d.ts +0 -7
- package/dist/openai/react/hooks/useToolName.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolName.js +0 -9
- package/dist/openai/react/hooks/useToolName.js.map +0 -1
- package/dist/react/index.mcp.d.ts +0 -3
- package/dist/react/index.mcp.d.ts.map +0 -1
- package/dist/react/index.mcp.js +0 -3
- package/dist/react/index.mcp.js.map +0 -1
- package/dist/react/index.openai.d.ts +0 -3
- package/dist/react/index.openai.d.ts.map +0 -1
- package/dist/react/index.openai.js +0 -3
- package/dist/react/index.openai.js.map +0 -1
- package/dist/react/missingHook.d.ts +0 -2
- package/dist/react/missingHook.d.ts.map +0 -1
- package/dist/react/missingHook.js +0 -6
- package/dist/react/missingHook.js.map +0 -1
- package/src/mcp/core/McpAppManager.ts +0 -136
- package/src/mcp/link/ToolCallLink.ts +0 -40
- package/src/mcp/link/__tests__/ToolCallLink.test.ts +0 -113
- package/src/mcp/react/hooks/__tests__/createHydrationUtils.test.tsx +0 -1228
- package/src/mcp/react/hooks/__tests__/useApp.test.tsx +0 -46
- package/src/mcp/react/hooks/__tests__/useHostContext.test.tsx +0 -95
- package/src/mcp/react/hooks/__tests__/useToolInfo.test.tsx +0 -53
- package/src/mcp/react/hooks/__tests__/useToolInput.test.tsx +0 -50
- package/src/mcp/react/hooks/__tests__/useToolMetadata.test.tsx +0 -53
- package/src/mcp/react/hooks/__tests__/useToolName.test.tsx +0 -50
- package/src/mcp/react/hooks/useHostContext.ts +0 -14
- package/src/mcp/react/hooks/useToolInfo.ts +0 -13
- package/src/mcp/react/hooks/useToolInput.ts +0 -10
- package/src/mcp/react/hooks/useToolMetadata.ts +0 -5
- package/src/mcp/react/hooks/useToolName.ts +0 -10
- package/src/mcp/react/index.ts +0 -7
- package/src/openai/core/McpAppManager.ts +0 -148
- package/src/openai/link/ToolCallLink.ts +0 -40
- package/src/openai/react/hooks/__tests__/createHydrationUtils.test.tsx +0 -1333
- package/src/openai/react/hooks/__tests__/useToolInfo.test.tsx +0 -92
- package/src/openai/react/hooks/__tests__/useToolInput.test.tsx +0 -85
- package/src/openai/react/hooks/__tests__/useToolMetadata.test.tsx +0 -86
- package/src/openai/react/hooks/__tests__/useToolName.test.tsx +0 -50
- package/src/openai/react/hooks/createHydrationUtils.ts +0 -182
- package/src/openai/react/hooks/useApp.ts +0 -5
- package/src/openai/react/hooks/useToolInfo.ts +0 -13
- package/src/openai/react/hooks/useToolInput.ts +0 -10
- package/src/openai/react/hooks/useToolMetadata.ts +0 -5
- package/src/openai/react/hooks/useToolName.ts +0 -10
- package/src/react/index.mcp.ts +0 -10
- package/src/react/index.openai.ts +0 -10
- package/src/react/missingHook.ts +0 -9
- /package/dist/{mcp/react → react}/hooks/useApp.d.ts +0 -0
- /package/dist/{mcp/react → react}/hooks/useHostContext.d.ts +0 -0
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
disableActEnvironment,
|
|
4
|
-
renderHookToSnapshotStream,
|
|
5
|
-
} from "@testing-library/react-render-stream";
|
|
6
|
-
import { Suspense } from "react";
|
|
7
|
-
import { InMemoryCache } from "@apollo/client";
|
|
8
|
-
import { App } from "@modelcontextprotocol/ext-apps";
|
|
9
|
-
|
|
10
|
-
import { useApp } from "../useApp.js";
|
|
11
|
-
import { ApolloClient } from "../../../core/ApolloClient.js";
|
|
12
|
-
import {
|
|
13
|
-
mockApplicationManifest,
|
|
14
|
-
mockMcpHost,
|
|
15
|
-
spyOnConsole,
|
|
16
|
-
} from "../../../../testing/internal/index.js";
|
|
17
|
-
import { ApolloProvider } from "../../../../react/ApolloProvider.js";
|
|
18
|
-
|
|
19
|
-
test("returns app instance created by ApolloClient", async () => {
|
|
20
|
-
using _ = spyOnConsole("debug");
|
|
21
|
-
const client = new ApolloClient({
|
|
22
|
-
cache: new InMemoryCache(),
|
|
23
|
-
manifest: mockApplicationManifest(),
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
using host = await mockMcpHost();
|
|
27
|
-
host.onCleanup(() => client.stop());
|
|
28
|
-
|
|
29
|
-
host.sendToolInput({ arguments: {} });
|
|
30
|
-
host.sendToolResult({
|
|
31
|
-
_meta: { toolName: "Test" },
|
|
32
|
-
content: [],
|
|
33
|
-
structuredContent: {},
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
using _disabledAct = disableActEnvironment();
|
|
37
|
-
const { takeSnapshot } = await renderHookToSnapshotStream(() => useApp(), {
|
|
38
|
-
wrapper: ({ children }) => (
|
|
39
|
-
<Suspense>
|
|
40
|
-
<ApolloProvider client={client}>{children}</ApolloProvider>
|
|
41
|
-
</Suspense>
|
|
42
|
-
),
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
await expect(takeSnapshot()).resolves.toBeInstanceOf(App);
|
|
46
|
-
});
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
2
|
-
import { InMemoryCache } from "@apollo/client";
|
|
3
|
-
import {
|
|
4
|
-
graphqlToolResult,
|
|
5
|
-
minimalHostContextWithToolName,
|
|
6
|
-
mockApplicationManifest,
|
|
7
|
-
mockMcpHost,
|
|
8
|
-
spyOnConsole,
|
|
9
|
-
} from "../../../../testing/internal/index.js";
|
|
10
|
-
import { ApolloClient } from "../../../core/ApolloClient.js";
|
|
11
|
-
import {
|
|
12
|
-
disableActEnvironment,
|
|
13
|
-
renderHookToSnapshotStream,
|
|
14
|
-
} from "@testing-library/react-render-stream";
|
|
15
|
-
import { useHostContext } from "../useHostContext.js";
|
|
16
|
-
import { ApolloProvider } from "../../../../react/ApolloProvider.js";
|
|
17
|
-
|
|
18
|
-
test("returns the host context from the host", async () => {
|
|
19
|
-
using _ = spyOnConsole("debug");
|
|
20
|
-
const client = new ApolloClient({
|
|
21
|
-
cache: new InMemoryCache(),
|
|
22
|
-
manifest: mockApplicationManifest(),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
using host = await mockMcpHost({
|
|
26
|
-
hostContext: {
|
|
27
|
-
...minimalHostContextWithToolName("GetProduct"),
|
|
28
|
-
theme: "light",
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
host.onCleanup(() => client.stop());
|
|
32
|
-
|
|
33
|
-
host.sendToolInput({ arguments: {} });
|
|
34
|
-
host.sendToolResult(graphqlToolResult({ data: { product: null } }));
|
|
35
|
-
|
|
36
|
-
using _disabledAct = disableActEnvironment();
|
|
37
|
-
const { takeSnapshot } = await renderHookToSnapshotStream(
|
|
38
|
-
() => useHostContext(),
|
|
39
|
-
{
|
|
40
|
-
wrapper: ({ children }) => (
|
|
41
|
-
<ApolloProvider client={client}>{children}</ApolloProvider>
|
|
42
|
-
),
|
|
43
|
-
}
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
await expect(takeSnapshot()).resolves.toStrictEqual({
|
|
47
|
-
...minimalHostContextWithToolName("GetProduct"),
|
|
48
|
-
theme: "light",
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
await expect(takeSnapshot).not.toRerender();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("rerenders when the host context changes", async () => {
|
|
55
|
-
using _ = spyOnConsole("debug");
|
|
56
|
-
const client = new ApolloClient({
|
|
57
|
-
cache: new InMemoryCache(),
|
|
58
|
-
manifest: mockApplicationManifest(),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
using host = await mockMcpHost({
|
|
62
|
-
hostContext: {
|
|
63
|
-
...minimalHostContextWithToolName("GetProduct"),
|
|
64
|
-
theme: "light",
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
host.onCleanup(() => client.stop());
|
|
68
|
-
|
|
69
|
-
host.sendToolInput({ arguments: {} });
|
|
70
|
-
host.sendToolResult(graphqlToolResult({ data: { product: null } }));
|
|
71
|
-
|
|
72
|
-
using _disabledAct = disableActEnvironment();
|
|
73
|
-
const { takeSnapshot } = await renderHookToSnapshotStream(
|
|
74
|
-
() => useHostContext(),
|
|
75
|
-
{
|
|
76
|
-
wrapper: ({ children }) => (
|
|
77
|
-
<ApolloProvider client={client}>{children}</ApolloProvider>
|
|
78
|
-
),
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
await expect(takeSnapshot()).resolves.toStrictEqual({
|
|
83
|
-
...minimalHostContextWithToolName("GetProduct"),
|
|
84
|
-
theme: "light",
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
host.sendHostContextChanged({ theme: "dark" });
|
|
88
|
-
|
|
89
|
-
await expect(takeSnapshot()).resolves.toStrictEqual({
|
|
90
|
-
...minimalHostContextWithToolName("GetProduct"),
|
|
91
|
-
theme: "dark",
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
await expect(takeSnapshot).not.toRerender();
|
|
95
|
-
});
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
disableActEnvironment,
|
|
4
|
-
renderHookToSnapshotStream,
|
|
5
|
-
} from "@testing-library/react-render-stream";
|
|
6
|
-
import { Suspense } from "react";
|
|
7
|
-
import { InMemoryCache } from "@apollo/client";
|
|
8
|
-
|
|
9
|
-
import { useToolInfo } from "../useToolInfo.js";
|
|
10
|
-
import { ApolloClient } from "../../../core/ApolloClient.js";
|
|
11
|
-
import {
|
|
12
|
-
graphqlToolResult,
|
|
13
|
-
minimalHostContextWithToolName,
|
|
14
|
-
mockApplicationManifest,
|
|
15
|
-
mockMcpHost,
|
|
16
|
-
spyOnConsole,
|
|
17
|
-
} from "../../../../testing/internal/index.js";
|
|
18
|
-
import { ApolloProvider } from "../../../../react/ApolloProvider.js";
|
|
19
|
-
|
|
20
|
-
test("returns tool name and input combined", async () => {
|
|
21
|
-
using _ = spyOnConsole("debug");
|
|
22
|
-
const client = new ApolloClient({
|
|
23
|
-
cache: new InMemoryCache(),
|
|
24
|
-
manifest: mockApplicationManifest(),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
using host = await mockMcpHost({
|
|
28
|
-
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
29
|
-
});
|
|
30
|
-
host.onCleanup(() => client.stop());
|
|
31
|
-
|
|
32
|
-
host.sendToolInput({ arguments: { id: "1" } });
|
|
33
|
-
host.sendToolResult(graphqlToolResult({ data: { product: null } }));
|
|
34
|
-
|
|
35
|
-
using _disabledAct = disableActEnvironment();
|
|
36
|
-
const { takeSnapshot } = await renderHookToSnapshotStream(
|
|
37
|
-
() => useToolInfo(),
|
|
38
|
-
{
|
|
39
|
-
wrapper: ({ children }) => (
|
|
40
|
-
<Suspense>
|
|
41
|
-
<ApolloProvider client={client}>{children}</ApolloProvider>
|
|
42
|
-
</Suspense>
|
|
43
|
-
),
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
await expect(takeSnapshot()).resolves.toEqual({
|
|
48
|
-
toolName: "GetProduct",
|
|
49
|
-
toolInput: { id: "1" },
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
await expect(takeSnapshot).not.toRerender();
|
|
53
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
disableActEnvironment,
|
|
4
|
-
renderHookToSnapshotStream,
|
|
5
|
-
} from "@testing-library/react-render-stream";
|
|
6
|
-
import { Suspense } from "react";
|
|
7
|
-
import { InMemoryCache } from "@apollo/client";
|
|
8
|
-
|
|
9
|
-
import { useToolInput } from "../useToolInput.js";
|
|
10
|
-
import { ApolloClient } from "../../../core/ApolloClient.js";
|
|
11
|
-
import {
|
|
12
|
-
graphqlToolResult,
|
|
13
|
-
minimalHostContextWithToolName,
|
|
14
|
-
mockApplicationManifest,
|
|
15
|
-
mockMcpHost,
|
|
16
|
-
spyOnConsole,
|
|
17
|
-
} from "../../../../testing/internal/index.js";
|
|
18
|
-
import { ApolloProvider } from "../../../../react/ApolloProvider.js";
|
|
19
|
-
|
|
20
|
-
test("returns the tool input from the MCP host", async () => {
|
|
21
|
-
using _ = spyOnConsole("debug");
|
|
22
|
-
const client = new ApolloClient({
|
|
23
|
-
cache: new InMemoryCache(),
|
|
24
|
-
manifest: mockApplicationManifest(),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
using host = await mockMcpHost({
|
|
28
|
-
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
29
|
-
});
|
|
30
|
-
host.onCleanup(() => client.stop());
|
|
31
|
-
|
|
32
|
-
host.sendToolInput({ arguments: { id: "1" } });
|
|
33
|
-
host.sendToolResult(graphqlToolResult({ data: { product: null } }));
|
|
34
|
-
|
|
35
|
-
using _disabledAct = disableActEnvironment();
|
|
36
|
-
const { takeSnapshot } = await renderHookToSnapshotStream(
|
|
37
|
-
() => useToolInput(),
|
|
38
|
-
{
|
|
39
|
-
wrapper: ({ children }) => (
|
|
40
|
-
<Suspense>
|
|
41
|
-
<ApolloProvider client={client}>{children}</ApolloProvider>
|
|
42
|
-
</Suspense>
|
|
43
|
-
),
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
await expect(takeSnapshot()).resolves.toEqual({ id: "1" });
|
|
48
|
-
|
|
49
|
-
await expect(takeSnapshot).not.toRerender();
|
|
50
|
-
});
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
disableActEnvironment,
|
|
4
|
-
renderHookToSnapshotStream,
|
|
5
|
-
} from "@testing-library/react-render-stream";
|
|
6
|
-
import { Suspense } from "react";
|
|
7
|
-
import { InMemoryCache } from "@apollo/client";
|
|
8
|
-
|
|
9
|
-
import { useToolMetadata } from "../useToolMetadata.js";
|
|
10
|
-
import { ApolloClient } from "../../../core/ApolloClient.js";
|
|
11
|
-
import {
|
|
12
|
-
mockApplicationManifest,
|
|
13
|
-
mockMcpHost,
|
|
14
|
-
spyOnConsole,
|
|
15
|
-
} from "../../../../testing/internal/index.js";
|
|
16
|
-
import { ApolloProvider } from "../../../../react/ApolloProvider.js";
|
|
17
|
-
|
|
18
|
-
test("returns the tool metadata from the MCP host", async () => {
|
|
19
|
-
using _ = spyOnConsole("debug");
|
|
20
|
-
const client = new ApolloClient({
|
|
21
|
-
cache: new InMemoryCache(),
|
|
22
|
-
manifest: mockApplicationManifest(),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
using host = await mockMcpHost();
|
|
26
|
-
host.onCleanup(() => client.stop());
|
|
27
|
-
|
|
28
|
-
host.sendToolInput({ arguments: {} });
|
|
29
|
-
host.sendToolResult({
|
|
30
|
-
_meta: { toolName: "TestTool", customField: "customValue" },
|
|
31
|
-
content: [],
|
|
32
|
-
structuredContent: {},
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
using _disabledAct = disableActEnvironment();
|
|
36
|
-
const { takeSnapshot } = await renderHookToSnapshotStream(
|
|
37
|
-
() => useToolMetadata(),
|
|
38
|
-
{
|
|
39
|
-
wrapper: ({ children }) => (
|
|
40
|
-
<Suspense>
|
|
41
|
-
<ApolloProvider client={client}>{children}</ApolloProvider>
|
|
42
|
-
</Suspense>
|
|
43
|
-
),
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
await expect(takeSnapshot()).resolves.toEqual({
|
|
48
|
-
toolName: "TestTool",
|
|
49
|
-
customField: "customValue",
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
await expect(takeSnapshot).not.toRerender();
|
|
53
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
disableActEnvironment,
|
|
4
|
-
renderHookToSnapshotStream,
|
|
5
|
-
} from "@testing-library/react-render-stream";
|
|
6
|
-
import { Suspense } from "react";
|
|
7
|
-
import { InMemoryCache } from "@apollo/client";
|
|
8
|
-
|
|
9
|
-
import { useToolName } from "../useToolName.js";
|
|
10
|
-
import { ApolloClient } from "../../../core/ApolloClient.js";
|
|
11
|
-
import {
|
|
12
|
-
graphqlToolResult,
|
|
13
|
-
minimalHostContextWithToolName,
|
|
14
|
-
mockApplicationManifest,
|
|
15
|
-
mockMcpHost,
|
|
16
|
-
spyOnConsole,
|
|
17
|
-
} from "../../../../testing/internal/index.js";
|
|
18
|
-
import { ApolloProvider } from "../../../../react/ApolloProvider.js";
|
|
19
|
-
|
|
20
|
-
test("returns the tool name from the MCP host", async () => {
|
|
21
|
-
using _ = spyOnConsole("debug");
|
|
22
|
-
const client = new ApolloClient({
|
|
23
|
-
cache: new InMemoryCache(),
|
|
24
|
-
manifest: mockApplicationManifest(),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
using host = await mockMcpHost({
|
|
28
|
-
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
29
|
-
});
|
|
30
|
-
host.onCleanup(() => client.stop());
|
|
31
|
-
|
|
32
|
-
host.sendToolInput({ arguments: {} });
|
|
33
|
-
host.sendToolResult(graphqlToolResult({ data: { product: null } }));
|
|
34
|
-
|
|
35
|
-
using _disabledAct = disableActEnvironment();
|
|
36
|
-
const { takeSnapshot } = await renderHookToSnapshotStream(
|
|
37
|
-
() => useToolName(),
|
|
38
|
-
{
|
|
39
|
-
wrapper: ({ children }) => (
|
|
40
|
-
<Suspense>
|
|
41
|
-
<ApolloProvider client={client}>{children}</ApolloProvider>
|
|
42
|
-
</Suspense>
|
|
43
|
-
),
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
await expect(takeSnapshot()).resolves.toBe("GetProduct");
|
|
48
|
-
|
|
49
|
-
await expect(takeSnapshot).not.toRerender();
|
|
50
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { useCallback, useSyncExternalStore } from "react";
|
|
2
|
-
import { useApolloClient } from "./useApolloClient";
|
|
3
|
-
|
|
4
|
-
export function useHostContext() {
|
|
5
|
-
const appManager = useApolloClient()["appManager"];
|
|
6
|
-
|
|
7
|
-
return useSyncExternalStore(
|
|
8
|
-
useCallback(
|
|
9
|
-
(update) => appManager.onHostContextChanged(update),
|
|
10
|
-
[appManager]
|
|
11
|
-
),
|
|
12
|
-
() => appManager.app.getHostContext()
|
|
13
|
-
);
|
|
14
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ToolInfo } from "../../../core/typeRegistration.js";
|
|
2
|
-
import { useApolloClient } from "./useApolloClient.js";
|
|
3
|
-
|
|
4
|
-
export function useToolInfo(): ToolInfo | undefined {
|
|
5
|
-
const appManager = useApolloClient()["appManager"];
|
|
6
|
-
const toolName = appManager.toolName;
|
|
7
|
-
|
|
8
|
-
if (!toolName) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return { toolName, toolInput: appManager.toolInput };
|
|
13
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ToolInput } from "../../../core/typeRegistration.js";
|
|
2
|
-
import { useApolloClient } from "./useApolloClient.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @deprecated Please use the `useToolInfo` hook. `useToolInput` will be removed
|
|
6
|
-
* in the next major version.
|
|
7
|
-
*/
|
|
8
|
-
export function useToolInput(): ToolInput | undefined {
|
|
9
|
-
return useApolloClient()["appManager"].toolInput;
|
|
10
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ToolName } from "../../../core/typeRegistration.js";
|
|
2
|
-
import { useApolloClient } from "./useApolloClient.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @deprecated Please use the `useToolInfo` hook. `useToolName` will be removed
|
|
6
|
-
* in the next major version.
|
|
7
|
-
*/
|
|
8
|
-
export function useToolName(): ToolName | undefined {
|
|
9
|
-
return useApolloClient()["appManager"].toolName;
|
|
10
|
-
}
|
package/src/mcp/react/index.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { useApp } from "./hooks/useApp.js";
|
|
2
|
-
export { useHostContext } from "./hooks/useHostContext.js";
|
|
3
|
-
export { useToolName } from "./hooks/useToolName.js";
|
|
4
|
-
export { useToolMetadata } from "./hooks/useToolMetadata.js";
|
|
5
|
-
export { useToolInput } from "./hooks/useToolInput.js";
|
|
6
|
-
export { useToolInfo } from "./hooks/useToolInfo.js";
|
|
7
|
-
export { createHydrationUtils } from "./hooks/createHydrationUtils.js";
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
App,
|
|
3
|
-
PostMessageTransport,
|
|
4
|
-
type McpUiHostContextChangedNotification,
|
|
5
|
-
} from "@modelcontextprotocol/ext-apps";
|
|
6
|
-
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
-
import type { ApplicationManifest } from "../../types/application-manifest";
|
|
8
|
-
import type { FormattedExecutionResult } from "graphql";
|
|
9
|
-
import type { DocumentNode, OperationVariables } from "@apollo/client";
|
|
10
|
-
import { print } from "@apollo/client/utilities";
|
|
11
|
-
import { cacheAsync, promiseWithResolvers } from "../../utilities";
|
|
12
|
-
import type { ApolloMcpServerApps } from "../../core/types";
|
|
13
|
-
|
|
14
|
-
type ExecuteQueryCallToolResult = Omit<CallToolResult, "structuredContent"> & {
|
|
15
|
-
structuredContent: FormattedExecutionResult;
|
|
16
|
-
_meta?: { structuredContent?: FormattedExecutionResult };
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/** @internal */
|
|
20
|
-
export class McpAppManager {
|
|
21
|
-
readonly app: App;
|
|
22
|
-
|
|
23
|
-
#toolName: string | undefined;
|
|
24
|
-
#toolMetadata: Record<string, unknown> | null = null;
|
|
25
|
-
#toolInput: Record<string, unknown> | undefined;
|
|
26
|
-
|
|
27
|
-
#hostContextCallbacks = new Set<
|
|
28
|
-
(params: McpUiHostContextChangedNotification["params"]) => void
|
|
29
|
-
>();
|
|
30
|
-
|
|
31
|
-
constructor(manifest: ApplicationManifest) {
|
|
32
|
-
this.app = new App({ name: manifest.name, version: manifest.appVersion });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get toolName() {
|
|
36
|
-
return this.#toolName;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get toolMetadata() {
|
|
40
|
-
return this.#toolMetadata;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get toolInput() {
|
|
44
|
-
return this.#toolInput;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
onHostContextChanged(
|
|
48
|
-
cb: (params: McpUiHostContextChangedNotification["params"]) => void
|
|
49
|
-
) {
|
|
50
|
-
this.#hostContextCallbacks.add(cb);
|
|
51
|
-
return () => {
|
|
52
|
-
this.#hostContextCallbacks.delete(cb);
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
connect = cacheAsync(async () => {
|
|
57
|
-
let toolResult = promiseWithResolvers<ApolloMcpServerApps.CallToolResult>();
|
|
58
|
-
|
|
59
|
-
this.app.ontoolresult = (params) => {
|
|
60
|
-
toolResult.resolve(
|
|
61
|
-
params as unknown as ApolloMcpServerApps.CallToolResult
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
this.app.onhostcontextchanged = (params) => {
|
|
66
|
-
this.#hostContextCallbacks.forEach((cb) => cb(params));
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
await this.connectToHost();
|
|
70
|
-
|
|
71
|
-
// After a page refresh, OpenAI does not re-send `ui/notifications/tool-result`.
|
|
72
|
-
// Instead, the tool result is available immediately via `window.openai.toolOutput`.
|
|
73
|
-
// If it's already set, resolve the promise now rather than waiting for the
|
|
74
|
-
// notification that will never arrive.
|
|
75
|
-
if (window.openai.toolOutput !== null) {
|
|
76
|
-
toolResult.resolve({
|
|
77
|
-
structuredContent: window.openai.toolOutput,
|
|
78
|
-
content: [],
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const { structuredContent } = await toolResult.promise;
|
|
83
|
-
|
|
84
|
-
this.#toolName = this.app.getHostContext()?.toolInfo?.tool.name;
|
|
85
|
-
|
|
86
|
-
// OpenAI is not consistent about sending `ui/notifications/tool-input`.
|
|
87
|
-
// Sometimes it doesn't send at all, other times it sends more than once
|
|
88
|
-
// before we get the tool result (which should always happen and at most
|
|
89
|
-
// once according to the spec). Rather than relying on the
|
|
90
|
-
// `ui/notifications/tool-input` notification to set the tool input value,
|
|
91
|
-
// we read from `window.openai.toolInput so that we have the most recent
|
|
92
|
-
// set value.
|
|
93
|
-
//
|
|
94
|
-
// When OpenAI fixes this issue and sends `ui/notifications/tool-input`
|
|
95
|
-
// consistently according to the MCP Apps specification, this can be
|
|
96
|
-
// reverted to use the `app.ontoolinput` callback.
|
|
97
|
-
this.#toolInput = window.openai.toolInput;
|
|
98
|
-
|
|
99
|
-
// OpenAI doesn't provide access to `_meta`, so we need to use
|
|
100
|
-
// window.openai.toolResponseMetadata directly
|
|
101
|
-
this.#toolMetadata = window.openai.toolResponseMetadata;
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
structuredContent: {
|
|
105
|
-
...structuredContent,
|
|
106
|
-
...(
|
|
107
|
-
window.openai.toolResponseMetadata as ApolloMcpServerApps.Meta | null
|
|
108
|
-
)?.structuredContent,
|
|
109
|
-
},
|
|
110
|
-
toolName: this.toolName,
|
|
111
|
-
args: this.#toolInput,
|
|
112
|
-
};
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
close() {
|
|
116
|
-
return this.app.close();
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async executeQuery({
|
|
120
|
-
query,
|
|
121
|
-
variables,
|
|
122
|
-
}: {
|
|
123
|
-
query: DocumentNode;
|
|
124
|
-
variables: OperationVariables | undefined;
|
|
125
|
-
}) {
|
|
126
|
-
const result = (await this.app.callServerTool({
|
|
127
|
-
name: "execute",
|
|
128
|
-
arguments: { query: print(query), variables },
|
|
129
|
-
})) as ExecuteQueryCallToolResult;
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
...result.structuredContent,
|
|
133
|
-
...result._meta?.structuredContent,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
private async connectToHost() {
|
|
138
|
-
try {
|
|
139
|
-
return await this.app.connect(
|
|
140
|
-
new PostMessageTransport(window.parent, window.parent)
|
|
141
|
-
);
|
|
142
|
-
} catch (e) {
|
|
143
|
-
const error = e instanceof Error ? e : new Error("Failed to connect");
|
|
144
|
-
|
|
145
|
-
throw error;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { ApolloLink, Observable } from "@apollo/client";
|
|
2
|
-
import { from } from "rxjs";
|
|
3
|
-
import type { ApolloClient as OpenAiApolloClient } from "../core/ApolloClient";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A terminating link that sends a GraphQL request through an agent tool call.
|
|
7
|
-
* When providing a custom link chain to `ApolloClient`, `ApolloClient` will
|
|
8
|
-
* validate that the terminating link is an instance of this link.
|
|
9
|
-
*
|
|
10
|
-
* @example Providing a custom link chain
|
|
11
|
-
*
|
|
12
|
-
* ```ts
|
|
13
|
-
* import { ApolloLink } from "@apollo/client";
|
|
14
|
-
* import { ApolloClient, ToolCallLink } from "@apollo/client-ai-apps";
|
|
15
|
-
*
|
|
16
|
-
* const link = ApolloLink.from([
|
|
17
|
-
* ...otherLinks,
|
|
18
|
-
* new ToolCallLink()
|
|
19
|
-
* ]);
|
|
20
|
-
*
|
|
21
|
-
* const client = new ApolloClient({
|
|
22
|
-
* link,
|
|
23
|
-
* // ...
|
|
24
|
-
* });
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export class ToolCallLink extends ApolloLink {
|
|
28
|
-
readonly name = "ToolCallLink";
|
|
29
|
-
|
|
30
|
-
request(operation: ApolloLink.Operation): Observable<ApolloLink.Result> {
|
|
31
|
-
const client = operation.client as OpenAiApolloClient;
|
|
32
|
-
|
|
33
|
-
return from(
|
|
34
|
-
client["appManager"].executeQuery({
|
|
35
|
-
query: operation.query,
|
|
36
|
-
variables: operation.variables,
|
|
37
|
-
})
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
}
|