Skip to main content
Glama

Nx MCP Server

Official
by nrwl
main.ts7.19 kB
import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import { FormValuesService } from './form-values.service'; import { IdeCommunicationController } from './ide-communication.controller'; import { getGeneratorNameTitleCase } from './utils/generator-schema-utils'; import './components/index'; import { SearchBar } from './components/search-bar'; @customElement('root-element') export class Root extends LitElement { icc: IdeCommunicationController; private formValuesService: FormValuesService; @state() private searchValue = ''; private rootStyles = css` --border-width: 1; `; constructor() { super(); this.icc = new IdeCommunicationController(this); this.formValuesService = new FormValuesService(this); window.addEventListener('keydown', (e) => this.handleGlobalKeyboardShortcuts(e), ); } render() { const options = this.icc.generatorSchema?.options; return html` <div class="text-foreground m-auto flex h-screen max-w-screen-xl flex-col p-6" style="${this.rootStyles}" > <div class="bg-background border-separator sticky top-0 z-50 w-full border-b-2 pb-3" > ${this.renderHeader()} </div> <div class="grow overflow-auto"> ${!options || options.length === 0 ? html`<p>No options</p>` : html` <field-list class="h-full" .options="${options}" .searchValue="${this.searchValue}" @clear-search="${() => this.clearSearch()}" ></field-list>`} </div> </div>`; } openNxDev(link: string) { const a = document.createElement('a'); a.href = link; a.target = '_blank'; // Optional: Open in new tab a.style.display = 'none'; document.body.appendChild(a); a.click(); document.body.removeChild(a); } fillWithCopilot() { this.icc.postMessageToIde({ payloadType: 'fill-with-copilot', payload: { generatorName: `${this.icc.generatorSchema?.collectionName}:${this.icc.generatorSchema?.generatorName}`, formValues: this.formValuesService.getFormValues(), }, }); } protected createRenderRoot() { return this; } private renderHeader() { const isNxGenerator = this.icc.generatorSchema?.collectionName?.includes('@nx') || this.icc.generatorSchema?.collectionName?.includes('@nrwl'); const nxDevLink = `https://nx.dev/packages/${this.icc.generatorSchema?.collectionName ?.replace('@nrwl/', '') ?.replace('@nx/', '')}/generators/${ this.icc.generatorSchema?.generatorName }`; return html` <div> <header class="flex items-center justify-between"> <div class="flex flex-col flex-wrap items-start gap-2"> <h1 class="text-xl font-bold leading-none" data-cy="title"> ${getGeneratorNameTitleCase(this.icc.generatorSchema)} </h1> <h2 class="inline-flex text-lg font-medium leading-none" data-cy="subtitle" > ${this.icc.generatorSchema?.collectionName} <popover-element class="flex items-center pl-2 text-base" .content="${this.icc.generatorSchema?.description}" > <icon-element class="flex items-start" icon="info"> </icon-element> </popover-element> </h2> </div> <div class="flex shrink-0"> ${when( this.icc.editor === 'vscode' && this.icc.configuration?.hasCopilot, () => html` <button-element @click="${() => this.fillWithCopilot()}" title="Fill Generate UI with Copilot" appearance="icon" text="copilot" class="self-center py-2 pl-3" > </button-element> `, )} ${when( isNxGenerator && this.icc.editor === 'vscode', () => html` <button-element @click="${() => this.openNxDev(nxDevLink)}" title="Open generator documentation on nx.dev" appearance="icon" text="link-external" class="self-center py-2 pl-3" > </button-element> `, )} <button-element class="self-center py-2 pl-3" appearance="icon" text="copy" title="Copy generate command to clipboard" @click="${() => this.formValuesService.copyCommandToClipboard()}" data-cy="copy-button" > </button-element> ${when( !this.icc.configuration?.enableTaskExecutionDryRunOnChange, () => html` <button-element class="self-center py-2 pl-3 sm:hidden" @click="${() => this.formValuesService.runGenerator(true)}" text="debug" appearance="icon" title="Dry Run" > </button-element> <button-element class="hidden py-2 pl-3 sm:block" @click="${() => this.formValuesService.runGenerator(true)}" text="Dry Run" appearance="secondary" > </button-element> `, )} <button-element class="py-2 pl-3" @click="${() => this.formValuesService.runGenerator()}" text="Generate" data-cy="generate-button" > </button-element> </div> </header> ${when( this.icc.banner, () => html` <banner-element message="${this.icc.banner?.message}" type="${this.icc.banner?.type}" ></banner-element>`, )} <div class="mt-5"> <search-bar @search-input="${this.handleSearchValueChange}" ></search-bar> <cwd-breadcrumb></cwd-breadcrumb> </div> </div> `; } private handleSearchValueChange(e: CustomEvent) { this.searchValue = e.detail; } private clearSearch() { const searchBar = this.renderRoot.querySelector('search-bar'); if (searchBar) { (searchBar as SearchBar).clearSearch(); } } private handleGlobalKeyboardShortcuts(e: KeyboardEvent) { if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); if (e.shiftKey) { this.formValuesService.runGenerator(true); } else { this.formValuesService.runGenerator(); } } if (e.key === 's' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); const searchBar = this.renderRoot.querySelector('[id="search-bar"]'); if (searchBar) { (searchBar as HTMLElement).focus(); } } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nrwl/nx-console'

If you have feedback or need assistance with the MCP directory API, please join our Discord server