@mk-kit/mcp 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/data/llms.txt ADDED
@@ -0,0 +1,88 @@
1
+ # mk-kit
2
+
3
+ > Themable, accessible Angular 22 component library for admin dashboards and UIs. Signals-based, WCAG 2.1 AA, controlled entirely through CSS variables with light/dark out of the box. — `@mk-kit/ui` 0.44.0. 170 components, 41 directives, 16 services and 130 helper functions across 23 tree-shakeable entry points. MIT licensed, zero runtime dependencies beyond Angular. Standalone components, signals, OnPush, zoneless-ready, SSR-safe, RTL and i18n via `provideMkI18n`.
4
+
5
+ Install with `ng add @mk-kit/ui` (or `npm i @mk-kit/ui` + import `@mk-kit/ui/styles/mk-kit.css`). Import from the group entry points (`@mk-kit/ui/forms`, `@mk-kit/ui/table`, …) so each lazy chunk only carries what it uses; the root `@mk-kit/ui` entry re-exports everything. Every component is standalone: add the class to a component's `imports`. Theme with `--mk-*` CSS custom properties; `MkThemeService` switches light/dark/system and density.
6
+
7
+ ## Docs
8
+
9
+ - [mk-kit — Introduction](https://mk-kit.dev/introduction)
10
+ - [Getting started](https://mk-kit.dev/getting-started)
11
+ - [Accessibility](https://mk-kit.dev/accessibility)
12
+ - [Bundle cost](https://mk-kit.dev/cost)
13
+ - [Theming](https://mk-kit.dev/theming)
14
+ - [Core & services](https://mk-kit.dev/core-services)
15
+ - [Touch & mobile](https://mk-kit.dev/touch)
16
+ - [Material migration](https://mk-kit.dev/migration)
17
+ - [Blog](https://mk-kit.dev/blog)
18
+ - [All components](https://mk-kit.dev/components-index)
19
+ - [Changelog](https://mk-kit.dev/changelog)
20
+
21
+ ## Component pages
22
+
23
+ - [Badges & labels](https://mk-kit.dev/components/badges-avatars)
24
+ - [Cards & lists](https://mk-kit.dev/components/cards-lists)
25
+ - [Table & data grid](https://mk-kit.dev/components/table)
26
+ - [Loading & progress](https://mk-kit.dev/components/loading)
27
+ - [Text inputs](https://mk-kit.dev/components/text-inputs)
28
+ - [Phone & postal code](https://mk-kit.dev/components/phone-postal)
29
+ - [Money & payment](https://mk-kit.dev/components/payment)
30
+ - [Signature pad](https://mk-kit.dev/components/signature)
31
+ - [Keypad & on-screen keyboard](https://mk-kit.dev/components/touch-keys)
32
+ - [Images & lightbox](https://mk-kit.dev/components/images)
33
+ - [Media manager](https://mk-kit.dev/components/media-manager)
34
+ - [Toggles & switches](https://mk-kit.dev/components/toggles)
35
+ - [Sliders & rating](https://mk-kit.dev/components/sliders)
36
+ - [Tooltips & popovers](https://mk-kit.dev/components/popovers)
37
+ - [Dialogs](https://mk-kit.dev/components/dialogs)
38
+ - [Status & notifications](https://mk-kit.dev/components/status)
39
+ - [Proportion & KPI charts](https://mk-kit.dev/components/proportion-charts)
40
+ - [Dashboard example](https://mk-kit.dev/examples/dashboard)
41
+ - [Data table example](https://mk-kit.dev/examples/data-table)
42
+ - [Content editor](https://mk-kit.dev/components/content-editor)
43
+ - [Date & time](https://mk-kit.dev/components/date-time)
44
+ - [Drag & drop](https://mk-kit.dev/components/drag-drop)
45
+ - [Context menu](https://mk-kit.dev/components/context-menu)
46
+ - [Buttons](https://mk-kit.dev/components/buttons)
47
+ - [Dynamic form](https://mk-kit.dev/components/dynamic-form)
48
+ - [Forms](https://mk-kit.dev/components/forms)
49
+ - [Signal Forms](https://mk-kit.dev/components/signal-forms)
50
+ - [Selection](https://mk-kit.dev/components/selection)
51
+ - [Rich text](https://mk-kit.dev/components/rich-text)
52
+ - [Code & content](https://mk-kit.dev/components/markdown)
53
+ - [Stepper](https://mk-kit.dev/components/stepper)
54
+ - [Organisation chart](https://mk-kit.dev/components/org-chart)
55
+ - [Tree](https://mk-kit.dev/components/tree)
56
+ - [Icon](https://mk-kit.dev/components/icon)
57
+ - [Snackbar](https://mk-kit.dev/components/snackbar)
58
+ - [Bottom sheet](https://mk-kit.dev/components/bottom-sheet)
59
+ - [Sort](https://mk-kit.dev/components/sort)
60
+ - [Trend charts](https://mk-kit.dev/components/charts)
61
+ - [Empty state & timeline](https://mk-kit.dev/components/empty-timeline)
62
+ - [Structure](https://mk-kit.dev/components/structure)
63
+ - [Layout](https://mk-kit.dev/components/layout)
64
+ - [Chat](https://mk-kit.dev/components/chat)
65
+ - [Query builder](https://mk-kit.dev/components/query-builder)
66
+ - [Drawer](https://mk-kit.dev/components/drawer)
67
+ - [Command palette & nav](https://mk-kit.dev/components/command-nav)
68
+ - [Misc display](https://mk-kit.dev/components/data)
69
+ - [Feedback](https://mk-kit.dev/components/feedback)
70
+ - [Navigation](https://mk-kit.dev/components/navigation)
71
+ - [Utilities](https://mk-kit.dev/components/utilities)
72
+ - [Kanban](https://mk-kit.dev/components/kanban)
73
+
74
+ ## API reference
75
+
76
+ - [API reference (browsable)](https://mk-kit.dev/api)
77
+ - [api.json](https://mk-kit.dev/api.json): every export with inputs, outputs, methods and types, machine-readable
78
+ - [llms-full.txt](https://mk-kit.dev/llms-full.txt): the complete API reference as Markdown in one file
79
+
80
+ ## For AI assistants
81
+
82
+ - MCP server: `npx -y @mk-kit/mcp` (tools: search_mk_kit, get_mk_kit_export, list_mk_kit_exports, get_mk_kit_overview) — https://www.npmjs.com/package/@mk-kit/mcp
83
+
84
+ ## Source
85
+
86
+ - [GitHub](https://github.com/mk-kit/mk-kit)
87
+ - [npm](https://www.npmjs.com/package/@mk-kit/ui)
88
+ - [Changelog](https://github.com/mk-kit/mk-kit/blob/main/CHANGELOG.md)
package/data.js ADDED
@@ -0,0 +1,58 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ /**
3
+ * Load the API snapshot. The package bundles the artefacts of the release it
4
+ * shipped with (`data/`); unless `MK_KIT_MCP_OFFLINE` is set, a newer set is
5
+ * fetched from the docs site (`MK_KIT_SITE`, default https://mk-kit.dev) so
6
+ * an old install still answers for the current library version. Any network
7
+ * problem silently keeps the bundled copy.
8
+ */
9
+ export async function loadData(env = process.env) {
10
+ const bundled = await loadBundled();
11
+ if (env['MK_KIT_MCP_OFFLINE'])
12
+ return bundled;
13
+ const site = (env['MK_KIT_SITE'] ?? bundled.api.site ?? 'https://mk-kit.dev').replace(/\/$/, '');
14
+ try {
15
+ const remote = await fetchRemote(site);
16
+ return newer(remote.api.version, bundled.api.version) ? remote : bundled;
17
+ }
18
+ catch {
19
+ return bundled;
20
+ }
21
+ }
22
+ async function loadBundled() {
23
+ const dir = new URL('./data/', import.meta.url);
24
+ const [apiText, llms, llmsFull] = await Promise.all([
25
+ readFile(new URL('api.json', dir), 'utf8'),
26
+ readFile(new URL('llms.txt', dir), 'utf8'),
27
+ readFile(new URL('llms-full.txt', dir), 'utf8'),
28
+ ]);
29
+ return { api: JSON.parse(apiText), llms, llmsFull, source: 'bundled' };
30
+ }
31
+ async function fetchRemote(site) {
32
+ const get = async (path) => {
33
+ const res = await fetch(`${site}${path}`, { signal: AbortSignal.timeout(4000) });
34
+ if (!res.ok)
35
+ throw new Error(`${path}: ${res.status}`);
36
+ return res.text();
37
+ };
38
+ const apiText = await get('/api.json');
39
+ const api = JSON.parse(apiText);
40
+ if (!api?.entries?.length || typeof api.version !== 'string')
41
+ throw new Error('bad api.json');
42
+ const [llms, llmsFull] = await Promise.all([get('/llms.txt'), get('/llms-full.txt')]);
43
+ return { api, llms, llmsFull, source: site };
44
+ }
45
+ /** semver-ish: is `a` newer than `b`? */
46
+ export function newer(a, b) {
47
+ const pa = a.split(/[.-]/).map(Number);
48
+ const pb = b.split(/[.-]/).map(Number);
49
+ for (let i = 0; i < 3; i++) {
50
+ const x = pa[i] ?? 0;
51
+ const y = pb[i] ?? 0;
52
+ if (Number.isNaN(x) || Number.isNaN(y))
53
+ return false;
54
+ if (x !== y)
55
+ return x > y;
56
+ }
57
+ return false;
58
+ }
package/index.js ADDED
@@ -0,0 +1,225 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod';
3
+ export const API_KINDS = [
4
+ 'component',
5
+ 'directive',
6
+ 'pipe',
7
+ 'service',
8
+ 'class',
9
+ 'function',
10
+ 'token',
11
+ 'const',
12
+ 'interface',
13
+ 'type',
14
+ 'enum',
15
+ ];
16
+ export class MkKitIndex {
17
+ data;
18
+ items = [];
19
+ byName = new Map();
20
+ bySelector = new Map();
21
+ constructor(data) {
22
+ this.data = data;
23
+ const sections = splitSections(data.llmsFull);
24
+ for (const entry of data.api.entries) {
25
+ for (const item of entry.exports) {
26
+ const markdown = sections.get(`${entry.name}/${item.name}`) ?? renderFallback(item, entry);
27
+ const ix = { entry, item, markdown };
28
+ this.items.push(ix);
29
+ // First entry wins on a duplicate name (root re-export order).
30
+ if (!this.byName.has(item.name.toLowerCase()))
31
+ this.byName.set(item.name.toLowerCase(), ix);
32
+ for (const s of item.selectors ?? []) {
33
+ if (!this.bySelector.has(s.toLowerCase()))
34
+ this.bySelector.set(s.toLowerCase(), ix);
35
+ }
36
+ }
37
+ }
38
+ }
39
+ /** Exact lookup by class name (`MkSelect`), selector (`mk-select`, `mkButton`) or pipe name. */
40
+ get(name) {
41
+ const q = name.trim().toLowerCase().replace(/^<|>$/g, '').replace(/^\[|\]$/g, '');
42
+ return this.byName.get(q) ?? this.bySelector.get(q);
43
+ }
44
+ search(query, opts = {}) {
45
+ const q = query.trim().toLowerCase();
46
+ const words = q.split(/\s+/).filter(Boolean);
47
+ const limit = opts.limit ?? 10;
48
+ const scored = [];
49
+ for (const ix of this.items) {
50
+ if (opts.kind && ix.item.kind !== opts.kind)
51
+ continue;
52
+ if (opts.entry && ix.entry.name !== opts.entry)
53
+ continue;
54
+ const name = ix.item.name.toLowerCase();
55
+ const sels = (ix.item.selectors ?? []).map((s) => s.toLowerCase());
56
+ const desc = ix.item.description.toLowerCase();
57
+ let score = 0;
58
+ if (name === q || sels.includes(q))
59
+ score = 100;
60
+ else if (name.startsWith(q) || sels.some((s) => s.startsWith(q)))
61
+ score = 60;
62
+ else if (name.includes(q) || sels.some((s) => s.includes(q)))
63
+ score = 40;
64
+ else if (words.length && words.every((w) => name.includes(w) || sels.some((s) => s.includes(w)) || desc.includes(w))) {
65
+ score = 10 + words.filter((w) => name.includes(w)).length * 5;
66
+ }
67
+ if (!score)
68
+ continue;
69
+ // Components and directives are what people usually mean.
70
+ if (ix.item.kind === 'component' || ix.item.kind === 'directive')
71
+ score += 3;
72
+ else if (ix.item.kind === 'service' || ix.item.kind === 'function')
73
+ score += 1;
74
+ scored.push({ ix, score });
75
+ }
76
+ scored.sort((a, b) => b.score - a.score || a.ix.item.name.localeCompare(b.ix.item.name));
77
+ return scored.slice(0, limit).map((s) => s.ix);
78
+ }
79
+ }
80
+ /** Map `entry/Name` → Markdown section from llms-full.txt. */
81
+ function splitSections(full) {
82
+ const out = new Map();
83
+ let entry = '';
84
+ let current = null;
85
+ const flush = () => {
86
+ if (current)
87
+ out.set(current.key, current.lines.join('\n').trim());
88
+ current = null;
89
+ };
90
+ for (const line of full.split('\n')) {
91
+ const h2 = /^## @mk-kit\/ui\/([\w-]+)\s*$/.exec(line);
92
+ if (h2) {
93
+ flush();
94
+ entry = h2[1];
95
+ continue;
96
+ }
97
+ const h3 = /^### (\w+) \((\w+)\)\s*$/.exec(line);
98
+ if (h3) {
99
+ flush();
100
+ current = { key: `${entry}/${h3[1]}`, lines: [line] };
101
+ continue;
102
+ }
103
+ if (current)
104
+ current.lines.push(line);
105
+ }
106
+ flush();
107
+ return out;
108
+ }
109
+ function renderFallback(item, entry) {
110
+ const lines = [`### ${item.name} (${item.kind})`, ''];
111
+ if (item.selector)
112
+ lines.push(`Selector: \`${item.selector}\``, '');
113
+ lines.push(`Import: \`import { ${item.name} } from '${entry.import}';\``, '');
114
+ if (item.description)
115
+ lines.push(item.description, '');
116
+ return lines.join('\n').trim();
117
+ }
118
+ export function brief(item, max = 140) {
119
+ const first = item.description.split(/\n\s*\n/)[0]?.replace(/\s+/g, ' ').replace(/`/g, '') ?? '';
120
+ return first.length > max ? first.slice(0, max - 1) + '…' : first;
121
+ }
122
+ function line(ix) {
123
+ const sel = ix.item.selector ? ` \`${ix.item.selector}\`` : ix.item.kind === 'pipe' ? '' : '';
124
+ const dep = ix.item.deprecated ? ' [deprecated]' : '';
125
+ const b = brief(ix.item);
126
+ return `- **${ix.item.name}** (${ix.item.kind})${sel} — ${ix.entry.import}${dep}${b ? `\n ${b}` : ''}`;
127
+ }
128
+ /* ------------------------------------------------------------------------ */
129
+ /* Server */
130
+ /* ------------------------------------------------------------------------ */
131
+ const KIND = z.enum(API_KINDS);
132
+ /**
133
+ * Build the mk-kit MCP server over a data snapshot. Pure — no I/O, so it is
134
+ * unit-testable over an in-memory transport; `bin.ts` wires stdio.
135
+ */
136
+ export function createMkKitServer(data) {
137
+ const index = new MkKitIndex(data);
138
+ const { api } = data;
139
+ const version = `${api.package} ${api.version}`;
140
+ const server = new McpServer({ name: 'mk-kit', version: api.version }, {
141
+ instructions: `Reference for ${version}, the Angular component library (mk-kit.dev). ` +
142
+ `Use search_mk_kit to find a component/directive/service/helper by name, selector or what it does, ` +
143
+ `then get_mk_kit_export for its full API (inputs, outputs, methods, import path). ` +
144
+ `Call get_mk_kit_overview once for install/setup conventions. ` +
145
+ `Every component is standalone: import the class from the entry point shown and add it to \`imports\`.`,
146
+ });
147
+ server.registerTool('search_mk_kit', {
148
+ title: 'Search the mk-kit API',
149
+ description: `Find exports of ${version} by name, selector (mk-select, mkButton) or free text describing what you need ` +
150
+ `("date range", "toast", "csv export"). Returns the best matches with kind, import path and a one-line summary. ` +
151
+ `Follow up with get_mk_kit_export for the full API.`,
152
+ inputSchema: {
153
+ query: z.string().min(1).describe('Name, selector or free-text description'),
154
+ kind: KIND.optional().describe('Restrict to one kind of export'),
155
+ entry: z.string().optional().describe('Restrict to one entry point, e.g. "forms" or "table"'),
156
+ limit: z.number().int().min(1).max(50).optional().describe('Max results (default 10)'),
157
+ },
158
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
159
+ }, ({ query, kind, entry, limit }) => {
160
+ const hits = index.search(query, { kind, entry, limit });
161
+ const text = hits.length
162
+ ? `${hits.length} result${hits.length === 1 ? '' : 's'} for "${query}":\n\n${hits.map(line).join('\n')}`
163
+ : `No export of ${api.package} matches "${query}". Try a shorter term, a selector (mk-…) or list_mk_kit_exports.`;
164
+ return { content: [{ type: 'text', text }] };
165
+ });
166
+ server.registerTool('get_mk_kit_export', {
167
+ title: 'Get one mk-kit export',
168
+ description: `Full API of one export of ${version} as Markdown: import path, selector, description with usage example, ` +
169
+ `inputs (type, default, two-way), outputs, methods, properties or type definition, and the docs page. ` +
170
+ `Accepts a class name (MkSelect), a selector (mk-select, mkButton) or a helper/type name (mkToCsv, MkTone).`,
171
+ inputSchema: {
172
+ name: z.string().min(1).describe('Class name, selector or exported symbol'),
173
+ },
174
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
175
+ }, ({ name }) => {
176
+ const ix = index.get(name);
177
+ if (ix)
178
+ return { content: [{ type: 'text', text: ix.markdown }] };
179
+ const near = index.search(name, { limit: 5 });
180
+ const text = near.length
181
+ ? `No export named "${name}". Did you mean:\n\n${near.map(line).join('\n')}`
182
+ : `No export named "${name}" in ${version}.`;
183
+ return { content: [{ type: 'text', text }], isError: true };
184
+ });
185
+ server.registerTool('list_mk_kit_exports', {
186
+ title: 'List mk-kit exports',
187
+ description: `Browse ${version}: every entry point with its exports, or one entry point / one kind. ` +
188
+ `Use it to see what exists before searching; each line carries a one-line summary.`,
189
+ inputSchema: {
190
+ entry: z.string().optional().describe('Entry point name, e.g. "forms", "table", "core"'),
191
+ kind: KIND.optional().describe('Only this kind of export'),
192
+ },
193
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
194
+ }, ({ entry, kind }) => {
195
+ const entries = entry ? api.entries.filter((e) => e.name === entry) : api.entries;
196
+ if (!entries.length) {
197
+ return {
198
+ content: [{ type: 'text', text: `Unknown entry point "${entry}". Entry points: ${api.entries.map((e) => e.name).join(', ')}.` }],
199
+ isError: true,
200
+ };
201
+ }
202
+ const detailed = !!entry || !!kind;
203
+ const blocks = entries.map((e) => {
204
+ const items = kind ? e.exports.filter((x) => x.kind === kind) : e.exports;
205
+ if (!detailed) {
206
+ const comps = e.exports.filter((x) => x.kind === 'component' || x.kind === 'directive');
207
+ const names = comps.map((x) => x.selector ? `${x.name} (${x.selector})` : x.name);
208
+ return `## ${e.import} — ${e.exports.length} exports\n${names.length ? names.join(', ') : '(types and helpers)'}`;
209
+ }
210
+ return `## ${e.import} — ${items.length} export${items.length === 1 ? '' : 's'}${kind ? ` of kind ${kind}` : ''}\n${items.map((x) => line({ entry: e, item: x, markdown: '' })).join('\n') || '(none)'}`;
211
+ });
212
+ return { content: [{ type: 'text', text: blocks.join('\n\n') }] };
213
+ });
214
+ server.registerTool('get_mk_kit_overview', {
215
+ title: 'mk-kit overview',
216
+ description: `What ${version} is, how to install and set it up (ng add, theme stylesheet, entry points, theming, i18n), ` +
217
+ `and links to every docs page. Read once before using the library.`,
218
+ inputSchema: {},
219
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
220
+ }, () => ({ content: [{ type: 'text', text: data.llms }] }));
221
+ server.registerResource('llms.txt', 'mk-kit://llms.txt', { title: 'mk-kit llms.txt', description: 'Docs index for LLMs', mimeType: 'text/markdown' }, (uri) => ({ contents: [{ uri: uri.href, mimeType: 'text/markdown', text: data.llms }] }));
222
+ server.registerResource('llms-full.txt', 'mk-kit://llms-full.txt', { title: 'mk-kit full API reference', description: 'Every export as Markdown', mimeType: 'text/markdown' }, (uri) => ({ contents: [{ uri: uri.href, mimeType: 'text/markdown', text: data.llmsFull }] }));
223
+ server.registerResource('api.json', 'mk-kit://api.json', { title: 'mk-kit api.json', description: 'Machine-readable API surface', mimeType: 'application/json' }, (uri) => ({ contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(api) }] }));
224
+ return server;
225
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@mk-kit/mcp",
3
+ "version": "0.44.0",
4
+ "description": "MCP server for @mk-kit/ui — lets AI coding assistants look up every component, directive, service and helper of the mk-kit Angular library (inputs, outputs, methods, import paths, docs links).",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "mk-kit-mcp": "bin.js"
9
+ },
10
+ "main": "index.js",
11
+ "files": [
12
+ "*.js",
13
+ "data/",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "model-context-protocol",
23
+ "angular",
24
+ "components",
25
+ "mk-kit",
26
+ "ai",
27
+ "claude",
28
+ "cursor",
29
+ "copilot"
30
+ ],
31
+ "homepage": "https://mk-kit.dev/api",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/mk-kit/mk-kit.git",
35
+ "directory": "projects/mcp"
36
+ },
37
+ "bugs": "https://github.com/mk-kit/mk-kit/issues",
38
+ "dependencies": {
39
+ "@modelcontextprotocol/sdk": "^1.30.0",
40
+ "zod": "^4.0.0"
41
+ }
42
+ }