Merge pull request #294 from matteo8p/create-helper-functions-tool-visibility
Add `isToolVisibilityModelOnly` and `isToolVisibilityAppOnly` helper functions
This commit is contained in:
commit
398f5b4e4a
2 changed files with 182 additions and 1 deletions
|
|
@ -17,6 +17,8 @@ import { App } from "./app";
|
|||
import {
|
||||
AppBridge,
|
||||
getToolUiResourceUri,
|
||||
isToolVisibilityModelOnly,
|
||||
isToolVisibilityAppOnly,
|
||||
type McpUiHostCapabilities,
|
||||
} from "./app-bridge";
|
||||
|
||||
|
|
@ -921,3 +923,153 @@ describe("getToolUiResourceUri", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("isToolVisibilityModelOnly", () => {
|
||||
describe("returns true", () => {
|
||||
it("when visibility is exactly ['model']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["model"] } },
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("returns false", () => {
|
||||
it("when visibility is ['app']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["app"] } },
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is ['model', 'app']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["model", "app"] } },
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is ['app', 'model']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["app", "model"] } },
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is empty array", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: [] } },
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is undefined", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: {} },
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when _meta.ui is missing", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: {},
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when _meta is missing", () => {
|
||||
const tool = { name: "test-tool" };
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when tool has resourceUri but no visibility", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { resourceUri: "ui://server/app.html" } },
|
||||
};
|
||||
expect(isToolVisibilityModelOnly(tool)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("isToolVisibilityAppOnly", () => {
|
||||
describe("returns true", () => {
|
||||
it("when visibility is exactly ['app']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["app"] } },
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("returns false", () => {
|
||||
it("when visibility is ['model']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["model"] } },
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is ['model', 'app']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["model", "app"] } },
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is ['app', 'model']", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: ["app", "model"] } },
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is empty array", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { visibility: [] } },
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when visibility is undefined", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: {} },
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when _meta.ui is missing", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: {},
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when _meta is missing", () => {
|
||||
const tool = { name: "test-tool" };
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
|
||||
it("when tool has resourceUri but no visibility", () => {
|
||||
const tool = {
|
||||
name: "test-tool",
|
||||
_meta: { ui: { resourceUri: "ui://server/app.html" } },
|
||||
};
|
||||
expect(isToolVisibilityAppOnly(tool)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ import {
|
|||
McpUiRequestDisplayModeRequestSchema,
|
||||
McpUiRequestDisplayModeResult,
|
||||
McpUiResourcePermissions,
|
||||
McpUiToolMeta,
|
||||
} from "./types";
|
||||
export * from "./types";
|
||||
export { RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE } from "./app";
|
||||
|
|
@ -110,7 +111,7 @@ export { PostMessageTransport } from "./message-transport";
|
|||
*/
|
||||
export function getToolUiResourceUri(tool: Partial<Tool>): string | undefined {
|
||||
// Try new nested format first: _meta.ui.resourceUri
|
||||
const uiMeta = tool._meta?.ui as { resourceUri?: unknown } | undefined;
|
||||
const uiMeta = tool._meta?.ui as McpUiToolMeta | undefined;
|
||||
let uri: unknown = uiMeta?.resourceUri;
|
||||
|
||||
// Fall back to deprecated flat format: _meta["ui/resourceUri"]
|
||||
|
|
@ -126,6 +127,34 @@ export function getToolUiResourceUri(tool: Partial<Tool>): string | undefined {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tool is visible to the model only.
|
||||
*
|
||||
* @param tool - Tool object with visibility metadata
|
||||
* @returns True if the tool is visible to the model only, false otherwise
|
||||
*/
|
||||
export function isToolVisibilityModelOnly(tool: Partial<Tool>): boolean {
|
||||
const uiMeta = tool._meta?.ui as McpUiToolMeta | undefined;
|
||||
const visibility = uiMeta?.visibility as Array<"model" | "app"> | undefined;
|
||||
if (!visibility) return false;
|
||||
if (visibility.length === 1 && visibility[0] === "model") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tool is visible to the app only.
|
||||
*
|
||||
* @param tool - Tool object with visibility metadata
|
||||
* @returns True if the tool is visible to the app only, false otherwise
|
||||
*/
|
||||
export function isToolVisibilityAppOnly(tool: Partial<Tool>): boolean {
|
||||
const uiMeta = tool._meta?.ui as McpUiToolMeta | undefined;
|
||||
const visibility = uiMeta?.visibility as Array<"model" | "app"> | undefined;
|
||||
if (!visibility) return false;
|
||||
if (visibility.length === 1 && visibility[0] === "app") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build iframe `allow` attribute string from permissions.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue