* feat(apps): add isAppTool helper in core (#1260) Adds @modelcontextprotocol/ext-apps as a dependency (root + clients/web) and a thin core/mcp/apps.ts wrapper exposing: - getAppResourceUri(tool): re-export of getToolUiResourceUri so all Inspector clients consume the same nested/flat _meta resolution. - isAppTool(tool): boolean predicate built on top of getAppResourceUri. Both surface the underlying ext-apps throw on a malformed _meta.ui.resourceUri (string that does not start with "ui://") rather than swallowing it — server bugs should be visible. Tests cover nested format, deprecated flat format, nested-wins precedence, missing _meta, and the invalid-URI throw. Refs #1260 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(apps): address PR #1272 review feedback - core/mcp/apps.ts: convert getAppResourceUri from a typed const re-export to a function declaration so its export style matches isAppTool. Behavior is unchanged. - core/mcp/apps.ts: document the filter-iteration implication on isAppTool — callers using tools.filter(isAppTool) will halt on a server-malformed URI. - apps.test.ts: add the symmetric isAppTool false-case for `_meta.ui` present without `resourceUri`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
37 lines
1.5 KiB
TypeScript
37 lines
1.5 KiB
TypeScript
import { getToolUiResourceUri } from "@modelcontextprotocol/ext-apps/app-bridge";
|
|
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
|
|
/**
|
|
* Returns the UI resource URI advertised by an MCP App tool, or `undefined`
|
|
* for non-App tools.
|
|
*
|
|
* Reads from `tool._meta.ui.resourceUri` (preferred nested format) and falls
|
|
* back to the deprecated flat `tool._meta["ui/resourceUri"]` key. The nested
|
|
* format wins when both are present.
|
|
*
|
|
* Throws when `_meta` advertises a UI resource URI that is not a string
|
|
* starting with `ui://`. We surface the underlying ext-apps error rather than
|
|
* silently dropping the tool, because a malformed URI is a server bug worth
|
|
* making visible.
|
|
*
|
|
* Wraps `getToolUiResourceUri` from `@modelcontextprotocol/ext-apps/app-bridge`
|
|
* so that web, CLI, and TUI all consume the same implementation through
|
|
* `@inspector/core`.
|
|
*/
|
|
export function getAppResourceUri(tool: Tool): string | undefined {
|
|
return getToolUiResourceUri(tool);
|
|
}
|
|
|
|
/**
|
|
* Single source of truth for App-tool detection across all Inspector clients.
|
|
* Wraps {@link getAppResourceUri}; throws on a malformed `_meta.ui.resourceUri`
|
|
* for the same reason.
|
|
*
|
|
* Note: because this throws on malformed URIs, callers using
|
|
* `tools.filter(isAppTool)` will halt iteration on the first bad tool. Wrap in
|
|
* a try/catch (or a safe-predicate helper) at the call site if you need to
|
|
* tolerate mixed-validity tool lists.
|
|
*/
|
|
export function isAppTool(tool: Tool): boolean {
|
|
return getAppResourceUri(tool) !== undefined;
|
|
}
|