docs: standardize UI terminology to use "view" consistently (#325)

* docs: standardize UI terminology to use "view" consistently

Replaces "widget" and "Guest UI" terminology with "view" across
the codebase as decided in the community survey.

This change updates:
- Specification document
- SDK source code and JSDoc comments
- Example servers and documentation
- Plugin documentation and skills

Closes #71

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Liad Yosef 2026-01-23 04:36:52 +02:00 • committed by GitHub
commit 4fc71656a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 381 additions and 393 deletions

View file

@ -39,13 +39,13 @@ function index_overview(
readCallback: ReadResourceCallback,
) {
//#region index_overview
// Register a tool that displays a widget
// Register a tool that displays a view
registerAppTool(
server,
"weather",
{
description: "Get weather forecast",
_meta: { ui: { resourceUri: "ui://weather/widget.html" } },
_meta: { ui: { resourceUri: "ui://weather/view.html" } },
},
toolCallback,
);
@ -53,8 +53,8 @@ function index_overview(
// Register the HTML resource the tool references
registerAppResource(
server,
"Weather Widget",
"ui://weather/widget.html",
"Weather View",
"ui://weather/view.html",
{},
readCallback,
);
@ -74,7 +74,7 @@ function registerAppTool_basicUsage(server: McpServer) {
description: "Get current weather for a location",
inputSchema: { location: z.string() },
_meta: {
ui: { resourceUri: "ui://weather/widget.html" },
ui: { resourceUri: "ui://weather/view.html" },
},
},
async (args) => {
@ -143,17 +143,17 @@ function registerAppResource_basicUsage(server: McpServer) {
//#region registerAppResource_basicUsage
registerAppResource(
server,
"Weather Widget",
"ui://weather/widget.html",
"Weather View",
"ui://weather/view.html",
{
description: "Interactive weather display",
},
async () => ({
contents: [
{
uri: "ui://weather/widget.html",
uri: "ui://weather/view.html",
mimeType: RESOURCE_MIME_TYPE,
text: await fs.readFile("dist/widget.html", "utf-8"),
text: await fs.readFile("dist/view.html", "utf-8"),
},
],
}),

View file

@ -35,7 +35,7 @@ describe("registerAppTool", () => {
title: "My Tool",
description: "A test tool",
_meta: {
[RESOURCE_URI_META_KEY]: "ui://test/widget.html",
[RESOURCE_URI_META_KEY]: "ui://test/view.html",
},
},
handler,
@ -49,7 +49,7 @@ describe("registerAppTool", () => {
(capturedConfig?._meta as Record<string, unknown>)?.[
RESOURCE_URI_META_KEY
],
).toBe("ui://test/widget.html");
).toBe("ui://test/view.html");
expect(capturedHandler).toBe(handler);
});
@ -74,7 +74,7 @@ describe("registerAppTool", () => {
"my-tool",
{
_meta: {
ui: { resourceUri: "ui://test/widget.html" },
ui: { resourceUri: "ui://test/view.html" },
},
},
async () => ({ content: [{ type: "text" as const, text: "ok" }] }),
@ -83,10 +83,10 @@ describe("registerAppTool", () => {
const meta = capturedConfig?._meta as Record<string, unknown>;
// New format should be preserved
expect((meta.ui as { resourceUri: string }).resourceUri).toBe(
"ui://test/widget.html",
"ui://test/view.html",
);
// Legacy key should also be set
expect(meta[RESOURCE_URI_META_KEY]).toBe("ui://test/widget.html");
expect(meta[RESOURCE_URI_META_KEY]).toBe("ui://test/view.html");
});
it("should set _meta.ui.resourceUri when legacy key is provided", () => {
@ -109,7 +109,7 @@ describe("registerAppTool", () => {
"my-tool",
{
_meta: {
[RESOURCE_URI_META_KEY]: "ui://test/widget.html",
[RESOURCE_URI_META_KEY]: "ui://test/view.html",
},
},
async () => ({ content: [{ type: "text" as const, text: "ok" }] }),
@ -117,10 +117,10 @@ describe("registerAppTool", () => {
const meta = capturedConfig?._meta as Record<string, unknown>;
// Legacy key should be preserved
expect(meta[RESOURCE_URI_META_KEY]).toBe("ui://test/widget.html");
expect(meta[RESOURCE_URI_META_KEY]).toBe("ui://test/view.html");
// New format should also be set
expect((meta.ui as { resourceUri: string }).resourceUri).toBe(
"ui://test/widget.html",
"ui://test/view.html",
);
});
@ -145,7 +145,7 @@ describe("registerAppTool", () => {
{
_meta: {
ui: { visibility: ["app"] },
[RESOURCE_URI_META_KEY]: "ui://test/widget.html",
[RESOURCE_URI_META_KEY]: "ui://test/view.html",
},
} as any,
async () => ({ content: [{ type: "text" as const, text: "ok" }] }),
@ -154,7 +154,7 @@ describe("registerAppTool", () => {
const meta = capturedConfig?._meta as Record<string, unknown>;
const ui = meta.ui as { resourceUri: string; visibility: string[] };
// Should have merged resourceUri into existing ui object
expect(ui.resourceUri).toBe("ui://test/widget.html");
expect(ui.resourceUri).toBe("ui://test/view.html");
expect(ui.visibility).toEqual(["app"]);
});
@ -178,8 +178,8 @@ describe("registerAppTool", () => {
"my-tool",
{
_meta: {
ui: { resourceUri: "ui://new/widget.html" },
[RESOURCE_URI_META_KEY]: "ui://old/widget.html",
ui: { resourceUri: "ui://new/view.html" },
[RESOURCE_URI_META_KEY]: "ui://old/view.html",
},
} as any,
async () => ({ content: [{ type: "text" as const, text: "ok" }] }),
@ -188,9 +188,9 @@ describe("registerAppTool", () => {
const meta = capturedConfig?._meta as Record<string, unknown>;
// Both should remain unchanged
expect((meta.ui as { resourceUri: string }).resourceUri).toBe(
"ui://new/widget.html",
"ui://new/view.html",
);
expect(meta[RESOURCE_URI_META_KEY]).toBe("ui://old/widget.html");
expect(meta[RESOURCE_URI_META_KEY]).toBe("ui://old/view.html");
});
});
});
@ -215,7 +215,7 @@ describe("registerAppResource", () => {
const callback = async () => ({
contents: [
{
uri: "ui://test/widget.html",
uri: "ui://test/view.html",
mimeType: RESOURCE_MIME_TYPE,
text: "<html/>",
},
@ -225,7 +225,7 @@ describe("registerAppResource", () => {
registerAppResource(
mockServer as unknown as Pick<McpServer, "registerResource">,
"My Resource",
"ui://test/widget.html",
"ui://test/view.html",
{
description: "A test resource",
_meta: { ui: {} },
@ -235,7 +235,7 @@ describe("registerAppResource", () => {
expect(mockServer.registerResource).toHaveBeenCalledTimes(1);
expect(capturedName).toBe("My Resource");
expect(capturedUri).toBe("ui://test/widget.html");
expect(capturedUri).toBe("ui://test/view.html");
expect(capturedConfig?.mimeType).toBe(RESOURCE_MIME_TYPE);
expect(capturedConfig?.description).toBe("A test resource");
});
@ -255,7 +255,7 @@ describe("registerAppResource", () => {
registerAppResource(
mockServer as unknown as Pick<McpServer, "registerResource">,
"My Resource",
"ui://test/widget.html",
"ui://test/view.html",
{
mimeType: "text/html",
_meta: { ui: {} },
@ -263,7 +263,7 @@ describe("registerAppResource", () => {
async () => ({
contents: [
{
uri: "ui://test/widget.html",
uri: "ui://test/view.html",
mimeType: "text/html",
text: "<html/>",
},
@ -295,7 +295,7 @@ describe("registerAppResource", () => {
const expectedResult = {
contents: [
{
uri: "ui://test/widget.html",
uri: "ui://test/view.html",
mimeType: RESOURCE_MIME_TYPE,
text: "<html>content</html>",
},
@ -306,7 +306,7 @@ describe("registerAppResource", () => {
registerAppResource(
mockServer as unknown as Pick<McpServer, "registerResource">,
"My Resource",
"ui://test/widget.html",
"ui://test/view.html",
{ _meta: { ui: {} } },
callback,
);

View file

@ -70,7 +70,7 @@ export interface McpUiAppToolConfig extends ToolConfig {
* URI of the UI resource to display for this tool.
* This is converted to `_meta["ui/resourceUri"]`.
*
* @example "ui://weather/widget.html"
* @example "ui://weather/view.html"
*
* @deprecated Use `_meta.ui.resourceUri` instead.
*/