@apollo/client-ai-apps 0.5.1 → 0.5.2
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 +14 -0
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/mcp/core/McpAppManager.d.ts +2 -7
- package/dist/mcp/core/McpAppManager.d.ts.map +1 -1
- package/dist/mcp/core/McpAppManager.js +10 -1
- package/dist/mcp/core/McpAppManager.js.map +1 -1
- package/dist/mcp/react/hooks/useToolMetadata.d.ts +1 -7
- package/dist/mcp/react/hooks/useToolMetadata.d.ts.map +1 -1
- package/dist/openai/core/McpAppManager.d.ts.map +1 -1
- package/dist/openai/core/McpAppManager.js +13 -15
- package/dist/openai/core/McpAppManager.js.map +1 -1
- package/package.json +1 -1
- package/src/core/types.ts +7 -0
- package/src/mcp/core/McpAppManager.ts +11 -2
- package/src/mcp/link/__tests__/ToolCallLink.test.ts +12 -3
- package/src/openai/core/McpAppManager.ts +14 -17
- package/src/openai/core/__tests__/ApolloClient.test.ts +4 -4
- package/src/openai/react/hooks/__tests__/useToolInput.test.tsx +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 0.5.2 (2026-02-23)
|
|
2
|
+
|
|
3
|
+
### Fixes
|
|
4
|
+
|
|
5
|
+
#### Add fallback when `toolName` is not available from host context
|
|
6
|
+
|
|
7
|
+
Provides a fallback in MCP apps to get the executed tool name from `_meta.toolName` when the host does not provide `toolInfo` from host context, or `structuredContent.toolName` when the host does not forward `_meta` to the connected application.
|
|
8
|
+
|
|
9
|
+
#### Always use `window.openai.toolInput` to initialize the tool input value
|
|
10
|
+
|
|
11
|
+
ChatGPT doesn't always send the `ui/notifications/tool-input` notification before we get `ui/notifications/tool-result`. Other times it sends the notification more than once. Because of the inconsistency, we can't always accurately get the correct tool input value using the notification by the time we get the `ui/notifications/tool-result` notification. This results in the wrong value for `variables` and incorrectly writes the query data to the cache.
|
|
12
|
+
|
|
13
|
+
This fix falls back to get `toolInput` from `window.openai.toolInput` in ChatGPT apps after we receive the `ui/notification/tool-result` notification to ensure we have the correct tool input value.
|
|
14
|
+
|
|
1
15
|
## 0.5.1 (2026-02-19)
|
|
2
16
|
|
|
3
17
|
### Fixes
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import type { CallToolResult as McpCallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import type { FormattedExecutionResult } from "graphql";
|
|
3
3
|
export declare namespace ApolloMcpServerApps {
|
|
4
|
+
interface Meta {
|
|
5
|
+
toolName: string;
|
|
6
|
+
[x: string]: unknown;
|
|
7
|
+
}
|
|
4
8
|
interface StructuredContent {
|
|
5
9
|
result: FormattedExecutionResult;
|
|
6
10
|
prefetch?: Record<string, FormattedExecutionResult>;
|
|
11
|
+
toolName?: string;
|
|
7
12
|
[x: string]: unknown;
|
|
8
13
|
}
|
|
9
14
|
interface CallToolResult extends McpCallToolResult {
|
|
15
|
+
_meta?: ApolloMcpServerApps.Meta;
|
|
10
16
|
structuredContent: ApolloMcpServerApps.StructuredContent;
|
|
11
17
|
}
|
|
12
18
|
}
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC9F,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAExD,yBAAiB,mBAAmB,CAAC;IACnC,UAAiB,iBAAiB;QAChC,MAAM,EAAE,wBAAwB,CAAC;QACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;QACpD,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;KACtB;IAED,UAAiB,cAAe,SAAQ,iBAAiB;QACvD,iBAAiB,EAAE,mBAAmB,CAAC,iBAAiB,CAAC;KAC1D;CACF"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC9F,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAExD,yBAAiB,mBAAmB,CAAC;IACnC,UAAiB,IAAI;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;KACtB;IAED,UAAiB,iBAAiB;QAChC,MAAM,EAAE,wBAAwB,CAAC;QACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;QACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;KACtB;IAED,UAAiB,cAAe,SAAQ,iBAAiB;QACvD,KAAK,CAAC,EAAE,mBAAmB,CAAC,IAAI,CAAC;QACjC,iBAAiB,EAAE,mBAAmB,CAAC,iBAAiB,CAAC;KAC1D;CACF"}
|
package/dist/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { CallToolResult as McpCallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { FormattedExecutionResult } from \"graphql\";\n\nexport namespace ApolloMcpServerApps {\n export interface StructuredContent {\n result: FormattedExecutionResult;\n prefetch?: Record<string, FormattedExecutionResult>;\n [x: string]: unknown;\n }\n\n export interface CallToolResult extends McpCallToolResult {\n structuredContent: ApolloMcpServerApps.StructuredContent;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { CallToolResult as McpCallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { FormattedExecutionResult } from \"graphql\";\n\nexport namespace ApolloMcpServerApps {\n export interface Meta {\n toolName: string;\n [x: string]: unknown;\n }\n\n export interface StructuredContent {\n result: FormattedExecutionResult;\n prefetch?: Record<string, FormattedExecutionResult>;\n toolName?: string;\n [x: string]: unknown;\n }\n\n export interface CallToolResult extends McpCallToolResult {\n _meta?: ApolloMcpServerApps.Meta;\n structuredContent: ApolloMcpServerApps.StructuredContent;\n }\n}\n"]}
|
|
@@ -2,19 +2,14 @@ import { App } from "@modelcontextprotocol/ext-apps";
|
|
|
2
2
|
import type { ApplicationManifest } from "../../types/application-manifest";
|
|
3
3
|
import type { FormattedExecutionResult } from "graphql";
|
|
4
4
|
import type { DocumentNode, OperationVariables } from "@apollo/client";
|
|
5
|
+
import type { ApolloMcpServerApps } from "../../core/types";
|
|
5
6
|
/** @internal */
|
|
6
7
|
export declare class McpAppManager {
|
|
7
8
|
#private;
|
|
8
9
|
readonly app: App;
|
|
9
10
|
constructor(manifest: ApplicationManifest);
|
|
10
11
|
get toolName(): string | undefined;
|
|
11
|
-
get toolMetadata():
|
|
12
|
-
[x: string]: unknown;
|
|
13
|
-
progressToken?: string | number | undefined;
|
|
14
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
15
|
-
taskId: string;
|
|
16
|
-
} | undefined;
|
|
17
|
-
} | undefined;
|
|
12
|
+
get toolMetadata(): ApolloMcpServerApps.Meta | undefined;
|
|
18
13
|
get toolInput(): Record<string, unknown> | undefined;
|
|
19
14
|
waitForInitialization: (() => Promise<{
|
|
20
15
|
toolName: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpAppManager.d.ts","sourceRoot":"","sources":["../../../src/mcp/core/McpAppManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAwB,MAAM,gCAAgC,CAAC;AAE3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"McpAppManager.d.ts","sourceRoot":"","sources":["../../../src/mcp/core/McpAppManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAwB,MAAM,gCAAgC,CAAC;AAE3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAM5D,gBAAgB;AAChB,qBAAa,aAAa;;IACxB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;gBAMN,QAAQ,EAAE,mBAAmB;IAIzC,IAAI,QAAQ,uBAEX;IAED,IAAI,YAAY,yCAEf;IAED,IAAI,SAAS,wCAEZ;IAED,qBAAqB;;;;;;;MAqClB;IAEH,KAAK;IAIC,YAAY,CAAC,EACjB,KAAK,EACL,SAAS,GACV,EAAE;QACD,KAAK,EAAE,YAAY,CAAC;QACpB,SAAS,EAAE,kBAAkB,GAAG,SAAS,CAAC;KAC3C;YASa,OAAO;CAWtB"}
|
|
@@ -31,7 +31,16 @@ export class McpAppManager {
|
|
|
31
31
|
await this.connect();
|
|
32
32
|
const { structuredContent, _meta } = await toolResult.promise;
|
|
33
33
|
const { arguments: args } = await toolInput.promise;
|
|
34
|
-
|
|
34
|
+
// Some hosts do not provide toolInfo in the ui/initialize response, so we
|
|
35
|
+
// fallback to `_meta.toolName` provided by Apollo MCP server if the value
|
|
36
|
+
// is not available.
|
|
37
|
+
this.#toolName =
|
|
38
|
+
this.app.getHostContext()?.toolInfo?.tool.name ??
|
|
39
|
+
_meta?.toolName ??
|
|
40
|
+
// Some hosts do not forward `_meta` nor do they provide `toolInfo`. Our
|
|
41
|
+
// MCP server provides `toolName` in `structuredContent` as a workaround
|
|
42
|
+
// that we can use if all else fails
|
|
43
|
+
structuredContent.toolName;
|
|
35
44
|
this.#toolMetadata = _meta;
|
|
36
45
|
this.#toolInput = args;
|
|
37
46
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpAppManager.js","sourceRoot":"","sources":["../../../src/mcp/core/McpAppManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAK3E,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAOnE,gBAAgB;AAChB,MAAM,OAAO,aAAa;IACf,GAAG,CAAM;IAElB,SAAS,CAAqB;IAC9B,aAAa,
|
|
1
|
+
{"version":3,"file":"McpAppManager.js","sourceRoot":"","sources":["../../../src/mcp/core/McpAppManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { App, PostMessageTransport } from \"@modelcontextprotocol/ext-apps\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ApplicationManifest } from \"../../types/application-manifest\";\nimport type { FormattedExecutionResult } from \"graphql\";\nimport type { DocumentNode, OperationVariables } from \"@apollo/client\";\nimport { print } from \"@apollo/client/utilities\";\nimport { cacheAsync, promiseWithResolvers } from \"../../utilities\";\nimport type { ApolloMcpServerApps } from \"../../core/types\";\n\ntype ExecuteQueryCallToolResult = Omit<CallToolResult, \"structuredContent\"> & {\n structuredContent: FormattedExecutionResult;\n};\n\n/** @internal */\nexport class McpAppManager {\n readonly app: App;\n\n #toolName: string | undefined;\n #toolMetadata: ApolloMcpServerApps.CallToolResult[\"_meta\"] | undefined;\n #toolInput: Record<string, unknown> | undefined;\n\n constructor(manifest: ApplicationManifest) {\n this.app = new App({ name: manifest.name, version: manifest.appVersion });\n }\n\n get toolName() {\n return this.#toolName;\n }\n\n get toolMetadata() {\n return this.#toolMetadata;\n }\n\n get toolInput() {\n return this.#toolInput;\n }\n\n waitForInitialization = cacheAsync(async () => {\n let toolResult = promiseWithResolvers<ApolloMcpServerApps.CallToolResult>();\n let toolInput = promiseWithResolvers<Parameters<App[\"ontoolinput\"]>[0]>();\n\n this.app.ontoolresult = (params) => {\n toolResult.resolve(\n params as unknown as ApolloMcpServerApps.CallToolResult\n );\n };\n\n this.app.ontoolinput = (params) => {\n toolInput.resolve(params);\n };\n\n await this.connect();\n\n const { structuredContent, _meta } = await toolResult.promise;\n const { arguments: args } = await toolInput.promise;\n\n // Some hosts do not provide toolInfo in the ui/initialize response, so we\n // fallback to `_meta.toolName` provided by Apollo MCP server if the value\n // is not available.\n this.#toolName =\n this.app.getHostContext()?.toolInfo?.tool.name ??\n _meta?.toolName ??\n // Some hosts do not forward `_meta` nor do they provide `toolInfo`. Our\n // MCP server provides `toolName` in `structuredContent` as a workaround\n // that we can use if all else fails\n structuredContent.toolName;\n this.#toolMetadata = _meta;\n this.#toolInput = args;\n\n return {\n ...structuredContent,\n toolName: this.toolName,\n args,\n };\n });\n\n close() {\n return this.app.close();\n }\n\n async executeQuery({\n query,\n variables,\n }: {\n query: DocumentNode;\n variables: OperationVariables | undefined;\n }) {\n const result = (await this.app.callServerTool({\n name: \"execute\",\n arguments: { query: print(query), variables },\n })) as ExecuteQueryCallToolResult;\n\n return result.structuredContent;\n }\n\n private async connect() {\n try {\n return await this.app.connect(\n new PostMessageTransport(window.parent, window.parent)\n );\n } catch (e) {\n const error = e instanceof Error ? e : new Error(\"Failed to connect\");\n\n throw error;\n }\n }\n}\n"]}
|
|
@@ -1,8 +1,2 @@
|
|
|
1
|
-
export declare function useToolMetadata():
|
|
2
|
-
[x: string]: unknown;
|
|
3
|
-
progressToken?: string | number | undefined;
|
|
4
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
5
|
-
taskId: string;
|
|
6
|
-
} | undefined;
|
|
7
|
-
} | undefined;
|
|
1
|
+
export declare function useToolMetadata(): import("../../../core/types.js").ApolloMcpServerApps.Meta | undefined;
|
|
8
2
|
//# sourceMappingURL=useToolMetadata.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToolMetadata.d.ts","sourceRoot":"","sources":["../../../../src/mcp/react/hooks/useToolMetadata.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe
|
|
1
|
+
{"version":3,"file":"useToolMetadata.d.ts","sourceRoot":"","sources":["../../../../src/mcp/react/hooks/useToolMetadata.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,0EAE9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpAppManager.d.ts","sourceRoot":"","sources":["../../../src/openai/core/McpAppManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAwB,MAAM,gCAAgC,CAAC;AAE3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AASvE,gBAAgB;AAChB,qBAAa,aAAa;;IACxB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;gBAMN,QAAQ,EAAE,mBAAmB;IAIzC,IAAI,QAAQ,uBAEX;IAED,IAAI,YAAY,mCAEf;IAED,IAAI,SAAS,wCAEZ;IAED,qBAAqB;;;;;;;
|
|
1
|
+
{"version":3,"file":"McpAppManager.d.ts","sourceRoot":"","sources":["../../../src/openai/core/McpAppManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAwB,MAAM,gCAAgC,CAAC;AAE3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AASvE,gBAAgB;AAChB,qBAAa,aAAa;;IACxB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;gBAMN,QAAQ,EAAE,mBAAmB;IAIzC,IAAI,QAAQ,uBAEX;IAED,IAAI,YAAY,mCAEf;IAED,IAAI,SAAS,wCAEZ;IAED,qBAAqB;;;;;;;MAqClB;IAEH,KAAK;IAIC,YAAY,CAAC,EACjB,KAAK,EACL,SAAS,GACV,EAAE;QACD,KAAK,EAAE,YAAY,CAAC;QACpB,SAAS,EAAE,kBAAkB,GAAG,SAAS,CAAC;KAC3C;YASa,OAAO;CAWtB"}
|
|
@@ -21,33 +21,31 @@ export class McpAppManager {
|
|
|
21
21
|
}
|
|
22
22
|
waitForInitialization = cacheAsync(async () => {
|
|
23
23
|
let toolResult = promiseWithResolvers();
|
|
24
|
-
let toolInput = promiseWithResolvers();
|
|
25
24
|
this.app.ontoolresult = (params) => {
|
|
26
25
|
toolResult.resolve(params);
|
|
27
|
-
// OpenAI is not consistent about sending `ui/notifications/tool-input`
|
|
28
|
-
// before we get the rool result (which should happen according to the
|
|
29
|
-
// spec). We resolve this promise in case it wasn't sent to avoid stalling
|
|
30
|
-
// initialization indefinitely.
|
|
31
|
-
//
|
|
32
|
-
// When OpenAI fixes this issue and sends `ui/notifications/tool-input`
|
|
33
|
-
// consistently, this can be removed.
|
|
34
|
-
toolInput.resolve({});
|
|
35
|
-
};
|
|
36
|
-
this.app.ontoolinput = (params) => {
|
|
37
|
-
toolInput.resolve(params);
|
|
38
26
|
};
|
|
39
27
|
await this.connect();
|
|
40
28
|
const { structuredContent } = await toolResult.promise;
|
|
41
|
-
const { arguments: args } = await toolInput.promise;
|
|
42
29
|
this.#toolName = this.app.getHostContext()?.toolInfo?.tool.name;
|
|
43
|
-
|
|
30
|
+
// OpenAI is not consistent about sending `ui/notifications/tool-input`.
|
|
31
|
+
// Sometimes it doesn't send at all, other times it sends more than once
|
|
32
|
+
// before we get the tool result (which should always happen and at most
|
|
33
|
+
// once according to the spec). Rather than relying on the
|
|
34
|
+
// `ui/notifications/tool-input` notification to set the tool input value,
|
|
35
|
+
// we read from `window.openai.toolInput so that we hvae the most recent
|
|
36
|
+
// set value.
|
|
37
|
+
//
|
|
38
|
+
// When OpenAI fixes this issue and sends `ui/notifications/tool-input`
|
|
39
|
+
// consistently according to the MCP Apps specification, this can be
|
|
40
|
+
// reverrted to use the `app.ontoolinput` callback.
|
|
41
|
+
this.#toolInput = window.openai.toolInput;
|
|
44
42
|
// OpenAI doesn't provide access to `_meta`, so we need to use
|
|
45
43
|
// window.openai.toolResponseMetadata directly
|
|
46
44
|
this.#toolMetadata = window.openai.toolResponseMetadata;
|
|
47
45
|
return {
|
|
48
46
|
...structuredContent,
|
|
49
47
|
toolName: this.toolName,
|
|
50
|
-
args,
|
|
48
|
+
args: this.toolInput,
|
|
51
49
|
};
|
|
52
50
|
});
|
|
53
51
|
close() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpAppManager.js","sourceRoot":"","sources":["../../../src/openai/core/McpAppManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAK3E,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAOnE,gBAAgB;AAChB,MAAM,OAAO,aAAa;IACf,GAAG,CAAM;IAElB,SAAS,CAAqB;IAC9B,aAAa,GAAmC,IAAI,CAAC;IACrD,UAAU,CAAsC;IAEhD,YAAY,QAA6B;QACvC,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,qBAAqB,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;QAC5C,IAAI,UAAU,GAAG,oBAAoB,EAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"McpAppManager.js","sourceRoot":"","sources":["../../../src/openai/core/McpAppManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAK3E,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAOnE,gBAAgB;AAChB,MAAM,OAAO,aAAa;IACf,GAAG,CAAM;IAElB,SAAS,CAAqB;IAC9B,aAAa,GAAmC,IAAI,CAAC;IACrD,UAAU,CAAsC;IAEhD,YAAY,QAA6B;QACvC,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,qBAAqB,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;QAC5C,IAAI,UAAU,GAAG,oBAAoB,EAAsC,CAAC;QAE5E,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,MAAM,EAAE,EAAE;YACjC,UAAU,CAAC,OAAO,CAChB,MAAuD,CACxD,CAAC;QACJ,CAAC,CAAC;QAEF,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAErB,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC;QAEvD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC;QAEhE,wEAAwE;QACxE,wEAAwE;QACxE,wEAAwE;QACxE,0DAA0D;QAC1D,0EAA0E;QAC1E,wEAAwE;QACxE,aAAa;QACb,EAAE;QACF,uEAAuE;QACvE,oEAAoE;QACpE,mDAAmD;QACnD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QAE1C,8DAA8D;QAC9D,8CAA8C;QAC9C,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC;QAExD,OAAO;YACL,GAAG,iBAAiB;YACpB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,SAAS;SACrB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,KAAK;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EACjB,KAAK,EACL,SAAS,GAIV;QACC,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC;YAC5C,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE;SAC9C,CAAC,CAA+B,CAAC;QAElC,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAClC,CAAC;IAEO,KAAK,CAAC,OAAO;QACnB,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAC3B,IAAI,oBAAoB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CACvD,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YAEtE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF","sourcesContent":["import { App, PostMessageTransport } from \"@modelcontextprotocol/ext-apps\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ApplicationManifest } from \"../../types/application-manifest\";\nimport type { FormattedExecutionResult } from \"graphql\";\nimport type { DocumentNode, OperationVariables } from \"@apollo/client\";\nimport { print } from \"@apollo/client/utilities\";\nimport { cacheAsync, promiseWithResolvers } from \"../../utilities\";\nimport type { ApolloMcpServerApps } from \"../../core/types\";\n\ntype ExecuteQueryCallToolResult = Omit<CallToolResult, \"structuredContent\"> & {\n structuredContent: FormattedExecutionResult;\n};\n\n/** @internal */\nexport class McpAppManager {\n readonly app: App;\n\n #toolName: string | undefined;\n #toolMetadata: Record<string, unknown> | null = null;\n #toolInput: Record<string, unknown> | undefined;\n\n constructor(manifest: ApplicationManifest) {\n this.app = new App({ name: manifest.name, version: manifest.appVersion });\n }\n\n get toolName() {\n return this.#toolName;\n }\n\n get toolMetadata() {\n return this.#toolMetadata;\n }\n\n get toolInput() {\n return this.#toolInput;\n }\n\n waitForInitialization = cacheAsync(async () => {\n let toolResult = promiseWithResolvers<ApolloMcpServerApps.CallToolResult>();\n\n this.app.ontoolresult = (params) => {\n toolResult.resolve(\n params as unknown as ApolloMcpServerApps.CallToolResult\n );\n };\n\n await this.connect();\n\n const { structuredContent } = await toolResult.promise;\n\n this.#toolName = this.app.getHostContext()?.toolInfo?.tool.name;\n\n // OpenAI is not consistent about sending `ui/notifications/tool-input`.\n // Sometimes it doesn't send at all, other times it sends more than once\n // before we get the tool result (which should always happen and at most\n // once according to the spec). Rather than relying on the\n // `ui/notifications/tool-input` notification to set the tool input value,\n // we read from `window.openai.toolInput so that we hvae the most recent\n // set value.\n //\n // When OpenAI fixes this issue and sends `ui/notifications/tool-input`\n // consistently according to the MCP Apps specification, this can be\n // reverrted to use the `app.ontoolinput` callback.\n this.#toolInput = window.openai.toolInput;\n\n // OpenAI doesn't provide access to `_meta`, so we need to use\n // window.openai.toolResponseMetadata directly\n this.#toolMetadata = window.openai.toolResponseMetadata;\n\n return {\n ...structuredContent,\n toolName: this.toolName,\n args: this.toolInput,\n };\n });\n\n close() {\n return this.app.close();\n }\n\n async executeQuery({\n query,\n variables,\n }: {\n query: DocumentNode;\n variables: OperationVariables | undefined;\n }) {\n const result = (await this.app.callServerTool({\n name: \"execute\",\n arguments: { query: print(query), variables },\n })) as ExecuteQueryCallToolResult;\n\n return result.structuredContent;\n }\n\n private async connect() {\n try {\n return await this.app.connect(\n new PostMessageTransport(window.parent, window.parent)\n );\n } catch (e) {\n const error = e instanceof Error ? e : new Error(\"Failed to connect\");\n\n throw error;\n }\n }\n}\n"]}
|
package/package.json
CHANGED
package/src/core/types.ts
CHANGED
|
@@ -2,13 +2,20 @@ import type { CallToolResult as McpCallToolResult } from "@modelcontextprotocol/
|
|
|
2
2
|
import type { FormattedExecutionResult } from "graphql";
|
|
3
3
|
|
|
4
4
|
export namespace ApolloMcpServerApps {
|
|
5
|
+
export interface Meta {
|
|
6
|
+
toolName: string;
|
|
7
|
+
[x: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
export interface StructuredContent {
|
|
6
11
|
result: FormattedExecutionResult;
|
|
7
12
|
prefetch?: Record<string, FormattedExecutionResult>;
|
|
13
|
+
toolName?: string;
|
|
8
14
|
[x: string]: unknown;
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
export interface CallToolResult extends McpCallToolResult {
|
|
18
|
+
_meta?: ApolloMcpServerApps.Meta;
|
|
12
19
|
structuredContent: ApolloMcpServerApps.StructuredContent;
|
|
13
20
|
}
|
|
14
21
|
}
|
|
@@ -16,7 +16,7 @@ export class McpAppManager {
|
|
|
16
16
|
readonly app: App;
|
|
17
17
|
|
|
18
18
|
#toolName: string | undefined;
|
|
19
|
-
#toolMetadata: ApolloMcpServerApps.CallToolResult["_meta"];
|
|
19
|
+
#toolMetadata: ApolloMcpServerApps.CallToolResult["_meta"] | undefined;
|
|
20
20
|
#toolInput: Record<string, unknown> | undefined;
|
|
21
21
|
|
|
22
22
|
constructor(manifest: ApplicationManifest) {
|
|
@@ -54,7 +54,16 @@ export class McpAppManager {
|
|
|
54
54
|
const { structuredContent, _meta } = await toolResult.promise;
|
|
55
55
|
const { arguments: args } = await toolInput.promise;
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
// Some hosts do not provide toolInfo in the ui/initialize response, so we
|
|
58
|
+
// fallback to `_meta.toolName` provided by Apollo MCP server if the value
|
|
59
|
+
// is not available.
|
|
60
|
+
this.#toolName =
|
|
61
|
+
this.app.getHostContext()?.toolInfo?.tool.name ??
|
|
62
|
+
_meta?.toolName ??
|
|
63
|
+
// Some hosts do not forward `_meta` nor do they provide `toolInfo`. Our
|
|
64
|
+
// MCP server provides `toolName` in `structuredContent` as a workaround
|
|
65
|
+
// that we can use if all else fails
|
|
66
|
+
structuredContent.toolName;
|
|
58
67
|
this.#toolMetadata = _meta;
|
|
59
68
|
this.#toolInput = args;
|
|
60
69
|
|
|
@@ -3,6 +3,7 @@ import { gql, InMemoryCache } from "@apollo/client";
|
|
|
3
3
|
import { execute } from "@apollo/client/link";
|
|
4
4
|
import { ApolloClient } from "../../core/ApolloClient.js";
|
|
5
5
|
import {
|
|
6
|
+
minimalHostContextWithToolName,
|
|
6
7
|
mockApplicationManifest,
|
|
7
8
|
mockMcpHost,
|
|
8
9
|
ObservableStream,
|
|
@@ -23,15 +24,23 @@ test("delegates query execution to MCP host", async () => {
|
|
|
23
24
|
manifest: mockApplicationManifest(),
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
using host = await mockMcpHost(
|
|
27
|
+
using host = await mockMcpHost({
|
|
28
|
+
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
29
|
+
});
|
|
27
30
|
host.onCleanup(() => client.stop());
|
|
28
31
|
|
|
32
|
+
host.sendToolInput({ arguments: {} });
|
|
29
33
|
host.sendToolResult({
|
|
30
34
|
_meta: { toolName: "GetProduct" },
|
|
31
35
|
content: [],
|
|
32
|
-
structuredContent: {
|
|
36
|
+
structuredContent: {
|
|
37
|
+
result: {
|
|
38
|
+
data: {
|
|
39
|
+
product: null,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
33
43
|
});
|
|
34
|
-
host.sendToolInput({ arguments: {} });
|
|
35
44
|
|
|
36
45
|
host.mockToolCall("execute", () => ({
|
|
37
46
|
content: [],
|
|
@@ -37,34 +37,31 @@ export class McpAppManager {
|
|
|
37
37
|
|
|
38
38
|
waitForInitialization = cacheAsync(async () => {
|
|
39
39
|
let toolResult = promiseWithResolvers<ApolloMcpServerApps.CallToolResult>();
|
|
40
|
-
let toolInput = promiseWithResolvers<Parameters<App["ontoolinput"]>[0]>();
|
|
41
40
|
|
|
42
41
|
this.app.ontoolresult = (params) => {
|
|
43
42
|
toolResult.resolve(
|
|
44
43
|
params as unknown as ApolloMcpServerApps.CallToolResult
|
|
45
44
|
);
|
|
46
|
-
|
|
47
|
-
// OpenAI is not consistent about sending `ui/notifications/tool-input`
|
|
48
|
-
// before we get the rool result (which should happen according to the
|
|
49
|
-
// spec). We resolve this promise in case it wasn't sent to avoid stalling
|
|
50
|
-
// initialization indefinitely.
|
|
51
|
-
//
|
|
52
|
-
// When OpenAI fixes this issue and sends `ui/notifications/tool-input`
|
|
53
|
-
// consistently, this can be removed.
|
|
54
|
-
toolInput.resolve({});
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
this.app.ontoolinput = (params) => {
|
|
58
|
-
toolInput.resolve(params);
|
|
59
45
|
};
|
|
60
46
|
|
|
61
47
|
await this.connect();
|
|
62
48
|
|
|
63
49
|
const { structuredContent } = await toolResult.promise;
|
|
64
|
-
const { arguments: args } = await toolInput.promise;
|
|
65
50
|
|
|
66
51
|
this.#toolName = this.app.getHostContext()?.toolInfo?.tool.name;
|
|
67
|
-
|
|
52
|
+
|
|
53
|
+
// OpenAI is not consistent about sending `ui/notifications/tool-input`.
|
|
54
|
+
// Sometimes it doesn't send at all, other times it sends more than once
|
|
55
|
+
// before we get the tool result (which should always happen and at most
|
|
56
|
+
// once according to the spec). Rather than relying on the
|
|
57
|
+
// `ui/notifications/tool-input` notification to set the tool input value,
|
|
58
|
+
// we read from `window.openai.toolInput so that we hvae the most recent
|
|
59
|
+
// set value.
|
|
60
|
+
//
|
|
61
|
+
// When OpenAI fixes this issue and sends `ui/notifications/tool-input`
|
|
62
|
+
// consistently according to the MCP Apps specification, this can be
|
|
63
|
+
// reverrted to use the `app.ontoolinput` callback.
|
|
64
|
+
this.#toolInput = window.openai.toolInput;
|
|
68
65
|
|
|
69
66
|
// OpenAI doesn't provide access to `_meta`, so we need to use
|
|
70
67
|
// window.openai.toolResponseMetadata directly
|
|
@@ -73,7 +70,7 @@ export class McpAppManager {
|
|
|
73
70
|
return {
|
|
74
71
|
...structuredContent,
|
|
75
72
|
toolName: this.toolName,
|
|
76
|
-
args,
|
|
73
|
+
args: this.toolInput,
|
|
77
74
|
};
|
|
78
75
|
});
|
|
79
76
|
|
|
@@ -92,7 +92,7 @@ describe("Client Basics", () => {
|
|
|
92
92
|
|
|
93
93
|
describe("prefetchData", () => {
|
|
94
94
|
test("caches tool response when data is provided", async () => {
|
|
95
|
-
stubOpenAiGlobals();
|
|
95
|
+
stubOpenAiGlobals({ toolInput: { id: 1 } });
|
|
96
96
|
using _ = spyOnConsole("debug");
|
|
97
97
|
const client = new ApolloClient({
|
|
98
98
|
cache: new InMemoryCache(),
|
|
@@ -148,7 +148,7 @@ describe("prefetchData", () => {
|
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
test("caches prefetched data when prefetched data is provided", async () => {
|
|
151
|
-
stubOpenAiGlobals();
|
|
151
|
+
stubOpenAiGlobals({ toolInput: { id: 1 } });
|
|
152
152
|
using _ = spyOnConsole("debug");
|
|
153
153
|
const client = new ApolloClient({
|
|
154
154
|
cache: new InMemoryCache(),
|
|
@@ -226,7 +226,7 @@ describe("prefetchData", () => {
|
|
|
226
226
|
});
|
|
227
227
|
|
|
228
228
|
test("caches both prefetch and tool response when both are provided", async () => {
|
|
229
|
-
stubOpenAiGlobals();
|
|
229
|
+
stubOpenAiGlobals({ toolInput: { id: 1 } });
|
|
230
230
|
using _ = spyOnConsole("debug");
|
|
231
231
|
const client = new ApolloClient({
|
|
232
232
|
cache: new InMemoryCache(),
|
|
@@ -343,7 +343,7 @@ describe("prefetchData", () => {
|
|
|
343
343
|
});
|
|
344
344
|
|
|
345
345
|
test("excludes extra inputs when writing to cache", async () => {
|
|
346
|
-
stubOpenAiGlobals();
|
|
346
|
+
stubOpenAiGlobals({ toolInput: { id: 1, myOtherThing: 2 } });
|
|
347
347
|
using _ = spyOnConsole("debug");
|
|
348
348
|
const client = new ApolloClient({
|
|
349
349
|
cache: new InMemoryCache(),
|
|
@@ -21,7 +21,7 @@ afterEach(() => {
|
|
|
21
21
|
|
|
22
22
|
test("returns the tool input from the MCP host", async () => {
|
|
23
23
|
using _ = spyOnConsole("debug");
|
|
24
|
-
stubOpenAiGlobals({ toolResponseMetadata: {} });
|
|
24
|
+
stubOpenAiGlobals({ toolResponseMetadata: {}, toolInput: { id: "1" } });
|
|
25
25
|
const client = new ApolloClient({
|
|
26
26
|
cache: new InMemoryCache(),
|
|
27
27
|
manifest: mockApplicationManifest(),
|