From 7560ebef7a91a7d4722bc2c5f9357569ae587fe1 Mon Sep 17 00:00:00 2001 From: Cory Rylan Date: Tue, 28 Jul 2026 15:22:15 -0500 Subject: [PATCH 1/2] fix(cli): update mcp sdk - Updated the package dependency in package.json and pnpm-lock.yaml. - Modified the NOTICE.md and README.md files to reflect the new server package. - Adjusted the MCP server implementation in index.ts to utilize the new server API. - Updated tests to ensure compatibility with the new server structure. Signed-off-by: Cory Rylan --- NOTICE.md | 4 +- pnpm-lock.yaml | 23 ++++++- projects/cli/DEVELOPMENT.md | 17 +++--- projects/cli/NOTICE.md | 4 +- projects/cli/README.md | 1 + projects/cli/package.json | 4 +- projects/cli/src/mcp/index.test.ts | 97 +++++++++++++++++++++--------- projects/cli/src/mcp/index.ts | 81 +++++++++++++------------ 8 files changed, 150 insertions(+), 81 deletions(-) diff --git a/NOTICE.md b/NOTICE.md index 4e00a03761..4a0f207a45 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -28,7 +28,7 @@ This product includes the following bundled third-party software: - @modelcontextprotocol/ext-apps v1.7.5 [MIT] (used by: @nvidia-elements/cli) Copyright: Olivier Chafik -- @modelcontextprotocol/sdk v1.30.0 [MIT] (used by: @nvidia-elements/cli) +- @modelcontextprotocol/server v2.0.0 [MIT] (used by: @nvidia-elements/cli) Copyright: Anthropic, PBC (https://anthropic.com) - adm-zip v0.5.17 [MIT] (used by: @nvidia-elements/cli) @@ -308,7 +308,7 @@ The following bundled components are provided under the MIT license: @html-eslint/parser v0.61.0 - Copyright yeonjuan (https://github.com/yeonjuan) @inquirer/prompts v8.5.0 - Copyright Simon Boudrias @modelcontextprotocol/ext-apps v1.7.5 - Copyright Olivier Chafik -@modelcontextprotocol/sdk v1.30.0 - Copyright Anthropic, PBC (https://anthropic.com) +@modelcontextprotocol/server v2.0.0 - Copyright Anthropic, PBC (https://anthropic.com) adm-zip v0.5.17 - Copyright Nasca Iacob (https://github.com/cthackers) archiver v8.0.0 - Copyright Chris Talkington (http://christalkington.com/) markdown-it v14.3.0 - Copyright Unknown diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 425a7d415a..dc7cd81751 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -477,9 +477,9 @@ importers: '@modelcontextprotocol/ext-apps': specifier: 'catalog:' version: 1.7.5(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.4.3) - '@modelcontextprotocol/sdk': - specifier: 'catalog:' - version: 1.30.0(zod@4.4.3) + '@modelcontextprotocol/server': + specifier: 2.0.0 + version: 2.0.0 '@nvidia-elements/code': specifier: workspace:* version: link:../code @@ -3927,6 +3927,10 @@ packages: engines: {node: '>=18'} hasBin: true + '@modelcontextprotocol/core@2.0.0': + resolution: {integrity: sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==} + engines: {node: '>=20'} + '@modelcontextprotocol/ext-apps@1.7.5': resolution: {integrity: sha512-TjPH2S2y5UEGKhmI6+XGFuqfqOV4ppe1x6DA3txnUaEWkgtA4G5vo14jGKFZmegdkZ1H4QMLyujLvoU1BEdnAg==} engines: {node: '>=20'} @@ -3961,6 +3965,10 @@ packages: '@cfworker/json-schema': optional: true + '@modelcontextprotocol/server@2.0.0': + resolution: {integrity: sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==} + engines: {node: '>=20'} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} cpu: [arm64] @@ -16080,6 +16088,10 @@ snapshots: - encoding - supports-color + '@modelcontextprotocol/core@2.0.0': + dependencies: + zod: 4.4.3 + '@modelcontextprotocol/ext-apps@1.7.5(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.4.3)': dependencies: '@modelcontextprotocol/sdk': 1.30.0(zod@4.4.3) @@ -16133,6 +16145,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/server@2.0.0': + dependencies: + '@modelcontextprotocol/core': 2.0.0 + zod: 4.4.3 + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true diff --git a/projects/cli/DEVELOPMENT.md b/projects/cli/DEVELOPMENT.md index 8b881a82ca..d97d255fea 100644 --- a/projects/cli/DEVELOPMENT.md +++ b/projects/cli/DEVELOPMENT.md @@ -17,7 +17,7 @@ The package has two entry points: - **`./dist/index.js`** (`nve` command) - Interactive CLI using Yargs with Inquirer for prompts -- **`./dist/mcp/index.js`** (`nve mcp` command) - MCP server using @modelcontextprotocol/sdk +- **`./dist/mcp/index.js`** (`nve mcp` command) - MCP server using `@modelcontextprotocol/server` ### Tool System @@ -60,7 +60,7 @@ tools.forEach(tool => { #### MCP Mode (`src/mcp/index.ts`) - Sets `process.env.ELEMENTS_ENV = 'mcp'` -- Creates MCP server instance with stdio transport +- Serves an MCP server factory over stdio - **Tool registration** - Registers all tools with MCP server using Zod schemas - **Prompt registration** - Registers 6 built-in prompts (about, doctor, search, playground, new-project, migrate) - **Structured output** - Returns results with status, message, and structured content @@ -69,13 +69,14 @@ Example MCP tool registration: ```typescript // Convert JSON Schema to Zod and register with MCP -server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools: tools.map(tool => ({ - name: tool.toolName, +server.registerTool( + tool.toolName, + { description: tool.description, - inputSchema: zodToJsonSchema(jsonSchemaToZod(tool.inputSchema)) - })) -})); + inputSchema: jsonSchemaToZod(tool.inputSchema) + }, + async params => tool(params) +); ``` ## Data Flow diff --git a/projects/cli/NOTICE.md b/projects/cli/NOTICE.md index 7cbe48f427..175685cfaa 100644 --- a/projects/cli/NOTICE.md +++ b/projects/cli/NOTICE.md @@ -11,7 +11,7 @@ This project includes the following bundled third-party software: - @modelcontextprotocol/ext-apps v1.7.5 [MIT] Copyright: Olivier Chafik -- @modelcontextprotocol/sdk v1.30.0 [MIT] +- @modelcontextprotocol/server v2.0.0 [MIT] Copyright: Anthropic, PBC (https://anthropic.com) - adm-zip v0.5.17 [MIT] @@ -49,7 +49,7 @@ The following bundled components are provided under the MIT license: @inquirer/prompts v8.5.0 - Copyright Simon Boudrias @modelcontextprotocol/ext-apps v1.7.5 - Copyright Olivier Chafik -@modelcontextprotocol/sdk v1.30.0 - Copyright Anthropic, PBC (https://anthropic.com) +@modelcontextprotocol/server v2.0.0 - Copyright Anthropic, PBC (https://anthropic.com) adm-zip v0.5.17 - Copyright Nasca Iacob (https://github.com/cthackers) archiver v8.0.0 - Copyright Chris Talkington (http://christalkington.com/) marked v18.0.3 - Copyright Christopher Jeffrey diff --git a/projects/cli/README.md b/projects/cli/README.md index f3fddbaff9..4c7b896777 100644 --- a/projects/cli/README.md +++ b/projects/cli/README.md @@ -197,3 +197,4 @@ This hosted route does not install the Elements CLI or configure the MCP server. - [Changelog](https://NVIDIA.github.io/elements/docs/changelog/) - [GitHub Repo](https://github.com/NVIDIA/elements) - [npm](https://www.npmjs.com/package/@nvidia-elements/cli) +- [MCP Registry](https://registry.modelcontextprotocol.io/?q=io.github.NVIDIA%2Felements) diff --git a/projects/cli/package.json b/projects/cli/package.json index e6187f51cb..71bddc6b1e 100644 --- a/projects/cli/package.json +++ b/projects/cli/package.json @@ -35,7 +35,7 @@ "dist/**/*.js" ], "scripts": { - "dev": "pnpm run cli:install && npx @modelcontextprotocol/inspector@0.22.0 node ./dist/index.js mcp", + "dev": "pnpm run cli:install && npx @modelcontextprotocol/inspector@2.0.0 node ./dist/index.js mcp", "ci": "wireit", "build": "wireit", "lint": "wireit", @@ -47,8 +47,8 @@ }, "dependencies": { "@inquirer/prompts": "8.5.0", - "@modelcontextprotocol/sdk": "catalog:", "@modelcontextprotocol/ext-apps": "catalog:", + "@modelcontextprotocol/server": "2.0.0", "@nvidia-elements/code": "workspace:*", "@nvidia-elements/lint": "workspace:^", "adm-zip": "0.5.17", diff --git a/projects/cli/src/mcp/index.test.ts b/projects/cli/src/mcp/index.test.ts index bff4bc6f17..6e3b1ac858 100644 --- a/projects/cli/src/mcp/index.test.ts +++ b/projects/cli/src/mcp/index.test.ts @@ -8,15 +8,15 @@ const { mockRegisterPrompt, mockRegisterResource, mockRegisterCapabilities, - mockConnect, + mockServeStdio, + mockNotify, mcpTool, cliTool, allTool, uiTool, - mockPrompt, - mockZodSchema + mockPrompt } = vi.hoisted(() => { - const zodSchema = { shape: {}, optional: () => zodSchema }; + const stdioHandle = { close: vi.fn().mockResolvedValue(undefined) }; const createMockTool = (overrides: Record) => { const fn = vi.fn().mockResolvedValue({ status: 'complete', result: 'test' }); @@ -40,8 +40,11 @@ const { mockRegisterPrompt: vi.fn(), mockRegisterResource: vi.fn(), mockRegisterCapabilities: vi.fn(), - mockConnect: vi.fn().mockResolvedValue(undefined), - mockZodSchema: zodSchema, + mockServeStdio: vi.fn((factory: () => unknown) => { + factory(); + return stdioHandle; + }), + mockNotify: vi.fn().mockResolvedValue(undefined), mcpTool: createMockTool({ support: 1, toolName: 'mcp_tool', @@ -83,28 +86,37 @@ const { }; }); -vi.mock('@modelcontextprotocol/sdk/server/mcp.js', () => ({ +vi.mock('@modelcontextprotocol/server', () => ({ McpServer: vi.fn(function () { return { registerTool: mockRegisterTool, registerPrompt: mockRegisterPrompt, registerResource: mockRegisterResource, - server: { registerCapabilities: mockRegisterCapabilities }, - connect: mockConnect + server: { registerCapabilities: mockRegisterCapabilities } }; }) })); -vi.mock('@modelcontextprotocol/sdk/server/stdio.js', () => ({ - StdioServerTransport: vi.fn() +vi.mock('@modelcontextprotocol/server/stdio', () => ({ + serveStdio: mockServeStdio })); -vi.mock('@internals/tools', () => ({ - tools: [mcpTool, cliTool, allTool, uiTool], - prompts: [mockPrompt], - jsonSchemaToZod: vi.fn(() => mockZodSchema), - ToolSupport: { None: 0, MCP: 1, CLI: 2, All: 3 } -})); +vi.mock('@internals/tools', async () => { + const { default: z } = await import('zod'); + return { + tools: [mcpTool, cliTool, allTool, uiTool], + prompts: [mockPrompt], + jsonSchemaToZod: vi.fn(() => z.object({})), + ToolSupport: { None: 0, MCP: 1, CLI: 2, All: 3 } + }; +}); + +const createRequestContext = () => ({ + mcpReq: { + _meta: {}, + notify: mockNotify + } +}); describe('MCP server', () => { beforeEach(() => { @@ -151,12 +163,12 @@ describe('MCP server', () => { ); }); - it('should handle tools without inputSchema', async () => { + it('should register tools without inputSchema using an empty Zod object', async () => { const { startMcpServer } = await import('./index.js'); await startMcpServer(); // mcpTool has no inputSchema — should still register without error const mcpToolCall = mockRegisterTool.mock.calls.find(call => call[0] === 'mcp_tool'); - expect(mcpToolCall[1].inputSchema).toEqual({}); + expect(mcpToolCall[1].inputSchema.shape).toEqual({}); }); it('should register prompts', async () => { @@ -182,17 +194,19 @@ describe('MCP server', () => { expect(result).toEqual({ messages: [] }); }); - it('should connect to stdio transport', async () => { + it('should serve an MCP server factory over stdio', async () => { const { startMcpServer } = await import('./index.js'); await startMcpServer(); - expect(mockConnect).toHaveBeenCalledTimes(1); + expect(mockServeStdio).toHaveBeenCalledWith(expect.any(Function), { + onerror: expect.any(Function) + }); }); it('should return string result as text content', async () => { const { startMcpServer } = await import('./index.js'); await startMcpServer(); const handler = mockRegisterTool.mock.calls[0][2]; - const result = await handler({}); + const result = await handler({}, createRequestContext()); expect(result).toEqual({ structuredContent: { status: 'complete', result: 'test' }, content: [{ type: 'text', text: 'test' }] @@ -205,7 +219,7 @@ describe('MCP server', () => { const handler = mockRegisterTool.mock.calls[0][2]; const errorResult = { status: 'error', message: 'failed' }; mcpTool.mockResolvedValueOnce(errorResult); - const result = await handler({}); + const result = await handler({}, createRequestContext()); expect(result.content[0].text).toBe(JSON.stringify(errorResult)); }); @@ -215,10 +229,37 @@ describe('MCP server', () => { const handler = mockRegisterTool.mock.calls[0][2]; const objResult = { status: 'complete', result: { key: 'value' } }; mcpTool.mockResolvedValueOnce(objResult); - const result = await handler({}); + const result = await handler({}, createRequestContext()); expect(result.content[0].text).toBe(JSON.stringify(objResult)); }); + it('should report progress through the v2 request context', async () => { + const { startMcpServer } = await import('./index.js'); + await startMcpServer(); + const handler = mockRegisterTool.mock.calls[0][2]; + const params: Record = {}; + await handler(params, { + mcpReq: { + _meta: { progressToken: 'progress-token' }, + notify: mockNotify + } + }); + + if (typeof params.onProgress !== 'function') { + throw new TypeError('Expected an onProgress callback'); + } + params.onProgress('Loading metadata'); + + expect(mockNotify).toHaveBeenCalledWith({ + method: 'notifications/progress', + params: { + progressToken: 'progress-token', + progress: 1, + message: 'Loading metadata' + } + }); + }); + it('should advertise the io.modelcontextprotocol/ui extension capability', async () => { const { startMcpServer } = await import('./index.js'); await startMcpServer(); @@ -359,15 +400,17 @@ describe('MCP server', () => { expect(mcpToolCall![1]._meta).toBeUndefined(); }); - it('should exit on connection error', async () => { - mockConnect.mockRejectedValueOnce(new Error('Connection failed')); + it('should exit on stdio error', async () => { const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined as never); const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const { startMcpServer } = await import('./index.js'); await startMcpServer(); + const options = mockServeStdio.mock.calls[0][1]; + const error = new Error('Connection failed'); + options.onerror(error); - expect(errorSpy).toHaveBeenCalledWith(expect.any(Error)); + expect(errorSpy).toHaveBeenCalledWith(error); expect(exitSpy).toHaveBeenCalledWith(1); }); }); diff --git a/projects/cli/src/mcp/index.ts b/projects/cli/src/mcp/index.ts index ad5e735efd..668bae917a 100644 --- a/projects/cli/src/mcp/index.ts +++ b/projects/cli/src/mcp/index.ts @@ -2,15 +2,23 @@ // SPDX-License-Identifier: Apache-2.0 /* istanbul ignore file -- @preserve */ -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { McpServer, type ServerContext, type ToolAnnotations } from '@modelcontextprotocol/server'; +import { serveStdio } from '@modelcontextprotocol/server/stdio'; import { tools, prompts, jsonSchemaToZod, ToolSupport } from '@internals/tools'; -import z, { type ZodObject } from 'zod'; -import { type ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'; +import z from 'zod'; import { MCP_UI_MIME_TYPE, uiResources } from './ui/index.js'; const VERSION = '0.0.0'; +function getObjectSchema(schema: Parameters[0] | undefined) { + if (!schema) return z.object({}); + const zodSchema = jsonSchemaToZod(schema); + if (!(zodSchema instanceof z.ZodObject)) { + throw new TypeError('Expected an object JSON Schema'); + } + return zodSchema; +} + function registerCapabilities(server: McpServer): void { server.server.registerCapabilities({ extensions: { 'io.modelcontextprotocol/ui': { mimeTypes: [MCP_UI_MIME_TYPE] } } @@ -30,18 +38,14 @@ function registerResources(server: McpServer): void { }); } -function attachProgress( - params: Record, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - extra: any -): void { - const progressToken = extra?._meta?.progressToken; +function attachProgress(params: Record, ctx: ServerContext): void { + const progressToken = ctx.mcpReq._meta?.progressToken; if (progressToken === undefined) return; let progressCount = 0; params.onProgress = (message: string) => { progressCount++; - extra - .sendNotification({ + ctx.mcpReq + .notify({ method: 'notifications/progress', params: { progressToken, progress: progressCount, message } }) @@ -54,18 +58,16 @@ function registerTools(server: McpServer): void { .filter(tool => tool.metadata.support & ToolSupport.MCP) .forEach(tool => { const { summary, description, title, toolName } = tool.metadata; - const inputSchema = tool.metadata.inputSchema - ? (jsonSchemaToZod(tool.metadata.inputSchema) as ZodObject>).shape - : {}; + const inputSchema = getObjectSchema(tool.metadata.inputSchema); const resultSchema = tool.metadata.outputSchema ? jsonSchemaToZod(tool.metadata.outputSchema) : z.any(); const config = { title, inputSchema, - outputSchema: { + outputSchema: z.object({ status: z.enum(['complete', 'error']).optional(), message: z.string().optional(), result: resultSchema.optional() - }, + }), description: description ? description : summary, annotations: { title, @@ -77,8 +79,8 @@ function registerTools(server: McpServer): void { } as ToolAnnotations, _meta: !tool.metadata.app ? undefined : { ui: { resourceUri: tool.metadata.app.resourceUri } } }; - server.registerTool(toolName, config, async (params, extra) => { - attachProgress(params as Record, extra); + server.registerTool(toolName, config, async (params, ctx) => { + attachProgress(params as Record, ctx); const structuredContent = (await tool(params)) as unknown as { [x: string]: unknown }; // https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1624 const text = @@ -92,31 +94,36 @@ function registerTools(server: McpServer): void { function registerPrompts(server: McpServer): void { prompts.forEach(prompt => { - const argsSchema = (jsonSchemaToZod(prompt.argsSchema ?? {}) as ZodObject>).shape; + const argsSchema = getObjectSchema(prompt.argsSchema); const config = { title: prompt.title, description: prompt.description, argsSchema }; server.registerPrompt(prompt.name, config, async params => prompt.handler(params)); }); } -export async function startMcpServer() { +export function startMcpServer() { process.env.ELEMENTS_ENV = 'mcp'; - const server = new McpServer({ - name: 'io.github.NVIDIA/elements', - version: VERSION, - description: - 'NVIDIA Elements UI Design System (nve-*), custom element schemas, APIs and examples. Use the "elements" skill for more guidance if available.' - }); + return serveStdio( + () => { + const server = new McpServer({ + name: 'io.github.NVIDIA/elements', + version: VERSION, + description: + 'NVIDIA Elements UI Design System (nve-*), custom element schemas, APIs and examples. Use the "elements" skill for more guidance if available.' + }); - registerCapabilities(server); - registerResources(server); - registerTools(server); - registerPrompts(server); + registerCapabilities(server); + registerResources(server); + registerTools(server); + registerPrompts(server); - try { - await server.connect(new StdioServerTransport()); - } catch (error) { - console.error(error); - process.exit(1); - } + return server; + }, + { + onerror(error) { + console.error(error); + process.exit(1); + } + } + ); } From f1ba54029991adcb95a431e2a25b9be8b48fb81f Mon Sep 17 00:00:00 2001 From: Cory Rylan Date: Tue, 28 Jul 2026 17:05:32 -0500 Subject: [PATCH 2/2] chore(docs): fix sitemap Signed-off-by: Cory Rylan --- projects/site/src/_11ty/plugins/sitemap-xml.js | 7 +------ projects/site/src/_11ty/plugins/sitemap-xml.test.ts | 4 ++-- projects/site/src/docs/mcp/index.md | 8 ++++++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/projects/site/src/_11ty/plugins/sitemap-xml.js b/projects/site/src/_11ty/plugins/sitemap-xml.js index 71b1027864..5c647d81a9 100644 --- a/projects/site/src/_11ty/plugins/sitemap-xml.js +++ b/projects/site/src/_11ty/plugins/sitemap-xml.js @@ -4,7 +4,6 @@ import { getSiteUrl } from '../utils/site-url.js'; const EXCLUDED_PREFIXES = ['/docs/changelog/', '/docs/metrics/', '/examples/', '/404']; const UTILITY_FILE_URLS = ['/llms.txt', '/llms-full.txt']; -const INDEXABLE_FILE_URLS = ['/DESIGN.md']; const ROBOTS_NOINDEX = /]*name=["']robots["'][^>]*content=["'][^"']*\bnoindex\b/i; const JSON_LD_SCRIPT = /]*\btype=(?:"application\/ld\+json"|'application\/ld\+json'|application\/ld\+json)[^>]*>([\s\S]*?)<\/script>/gi; @@ -12,7 +11,6 @@ const JSON_LD_SCRIPT = export function isSitemapPageUrl(url) { if (!url) return false; if (UTILITY_FILE_URLS.includes(url)) return false; - if (INDEXABLE_FILE_URLS.includes(url)) return true; if (!url.endsWith('/') && !url.endsWith('.html')) return false; if (EXCLUDED_PREFIXES.some(prefix => url.startsWith(prefix))) return false; return true; @@ -38,10 +36,7 @@ function getResultModifiedDate(result) { } export function renderSitemap(results = []) { - const pages = new Map([ - ...INDEXABLE_FILE_URLS.map(url => [url, { url }]), - ...results.filter(isPublishableResult).map(result => [result.url, result]) - ]); + const pages = new Map(results.filter(isPublishableResult).map(result => [result.url, result])); const entries = [...pages.values()] .sort((left, right) => left.url.localeCompare(right.url)) .map(result => { diff --git a/projects/site/src/_11ty/plugins/sitemap-xml.test.ts b/projects/site/src/_11ty/plugins/sitemap-xml.test.ts index 02f5de0abb..55b33c1492 100644 --- a/projects/site/src/_11ty/plugins/sitemap-xml.test.ts +++ b/projects/site/src/_11ty/plugins/sitemap-xml.test.ts @@ -8,12 +8,12 @@ describe('isSitemapPageUrl', () => { expect(isSitemapPageUrl('/docs/cli/')).toBe(true); expect(isSitemapPageUrl('/docs/elements/')).toBe(true); expect(isSitemapPageUrl('/docs/foundations/')).toBe(true); - expect(isSitemapPageUrl('/DESIGN.md')).toBe(true); }); it('should exclude agent utility files from sitemap pages', () => { expect(isSitemapPageUrl('/llms.txt')).toBe(false); expect(isSitemapPageUrl('/llms-full.txt')).toBe(false); + expect(isSitemapPageUrl('/DESIGN.md')).toBe(false); }); it('should exclude non-indexable site sections', () => { @@ -39,7 +39,7 @@ describe('isSitemapPageUrl', () => { 'https://nvidia.github.io/elements/docs/whats-new/06-2026/\n2026-07-24T00:00:00.000Z' ); expect(sitemap).toContain('https://nvidia.github.io/elements/docs/about/support/'); - expect(sitemap).toContain('https://nvidia.github.io/elements/DESIGN.md'); + expect(sitemap).not.toContain('https://nvidia.github.io/elements/DESIGN.md'); expect(sitemap.match(//g)).toHaveLength(1); }); }); diff --git a/projects/site/src/docs/mcp/index.md b/projects/site/src/docs/mcp/index.md index fa9d501318..d1d0d21e20 100644 --- a/projects/site/src/docs/mcp/index.md +++ b/projects/site/src/docs/mcp/index.md @@ -8,7 +8,7 @@ # {{title}} -

The Elements MCP server connects AI coding assistants to the Elements design system. It gives tools like Claude Code, Cursor, and Codex direct access to component APIs, design tokens, skills, template validation, project scaffolding, and interactive MCP Apps views so your AI assistant can build with Elements effectively

+

The NVIDIA Elements MCP server connects AI coding assistants to the Elements design system. It gives tools like Claude Code, Cursor, and Codex direct access to component APIs, design tokens, skills, template validation, project scaffolding, and interactive MCP Apps views so your AI assistant can build with Elements effectively

{% install-cli %} @@ -81,7 +81,7 @@ After adding the configuration in the root of your project, restart Codex for th
-```toml +```shell # .codex/config.toml [mcp_servers.elements] description = "NVIDIA Elements UI Design System (nve-*), custom element schemas, APIs and examples" @@ -328,3 +328,7 @@ npm config set registry {{ELEMENTS_REGISTRY_URL}} && npm login --auth-type=legac ### Unsupported Engine An `Unsupported engine` warning means your Node.js version is out of date. The CLI requires Node.js v20 or later. Update Node.js and try again. + +## Links + +- [MCP Registry](https://registry.modelcontextprotocol.io/?q=io.github.NVIDIA%2Felements)