@urbicon-ui/mcp-server 6.28.0 → 6.29.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/README.md +1 -1
- package/package.json +3 -3
- package/src/data/guide-loader.ts +29 -0
- package/src/data/template-loader.ts +7 -9
- package/src/resources/guides.ts +31 -12
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ All tools are read-only (`readOnlyHint: true`) — this server never touches the
|
|
|
97
97
|
| `urbicon://guide/design-quality` | AVOID/INSTEAD patterns from A/B-tested design-quality guidance (+33.8 % improvement in user study) |
|
|
98
98
|
| `urbicon://guide/component-families` | Six-family component taxonomy - ARIA roles and per-family border-token source |
|
|
99
99
|
| `urbicon://guide/customization` | `unstyled` / `slotClasses` / `preset` override system + `BlocksProvider` overrides |
|
|
100
|
-
| `urbicon://guide/auth
|
|
100
|
+
| `urbicon://guide/auth` | Complete auth reference - served verbatim from the bundled, tarball-canonical `AUTH.md` |
|
|
101
101
|
| `urbicon://guide/style-patterns` | Reusable style presets and composition templates |
|
|
102
102
|
| `urbicon://guide/tokens` | OKLCH token reference, same data as `get_css_reference` |
|
|
103
103
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urbicon-ui/mcp-server",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.29.0",
|
|
4
4
|
"description": "Model Context Protocol server exposing the Urbicon UI component catalog, recipes and design intelligence to LLM agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
|
-
"@urbicon-ui/design-content": "6.
|
|
43
|
-
"@urbicon-ui/design-engine": "6.
|
|
42
|
+
"@urbicon-ui/design-content": "6.29.0",
|
|
43
|
+
"@urbicon-ui/design-engine": "6.29.0",
|
|
44
44
|
"zod": "^4.3.6"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { getGuidePath } from '@urbicon-ui/design-content';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Reader for the bundle's canonical package guides (`guides/<slug>.md`) — the
|
|
6
|
+
* tarball-shipped guide documents (e.g. `packages/auth/docs/AUTH.md`) that
|
|
7
|
+
* docs-gen distributes into the design-content bundle. Unlike the template
|
|
8
|
+
* sections (template-loader.ts) these are complete documents, served verbatim.
|
|
9
|
+
* Cached per process, like the template sections.
|
|
10
|
+
*/
|
|
11
|
+
const cachedGuides = new Map<string, string>();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Load one bundled package guide by slug. `null` when the guide (or the
|
|
15
|
+
* bundle) is absent — the resource read degrades to a "not found" note, the
|
|
16
|
+
* same contract as a missing template section.
|
|
17
|
+
*/
|
|
18
|
+
export async function loadPackageGuide(slug: string): Promise<string | null> {
|
|
19
|
+
const cached = cachedGuides.get(slug);
|
|
20
|
+
if (cached !== undefined) return cached;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const content = await readFile(getGuidePath(slug), 'utf-8');
|
|
24
|
+
cachedGuides.set(slug, content);
|
|
25
|
+
return content;
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -2,9 +2,11 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { getTemplatePath } from '@urbicon-ui/design-content';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* The
|
|
5
|
+
* The six guide sections carved out of the single template document, keyed by
|
|
6
6
|
* guide id. Each value is the raw markdown of one `## …` section; the keys are
|
|
7
|
-
* the ids the guide resources ({@link registerGuideResources}) expose.
|
|
7
|
+
* the ids the guide resources ({@link registerGuideResources}) expose. The auth
|
|
8
|
+
* guide is deliberately NOT here — it is a canonical package guide served from
|
|
9
|
+
* the bundle's `guides/auth.md` (see `guide-loader.ts`), not a template slice.
|
|
8
10
|
*/
|
|
9
11
|
export interface TemplateSections {
|
|
10
12
|
'api-grammar': string;
|
|
@@ -13,7 +15,6 @@ export interface TemplateSections {
|
|
|
13
15
|
'design-quality': string;
|
|
14
16
|
customization: string;
|
|
15
17
|
'style-patterns': string;
|
|
16
|
-
'auth-setup': string;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
let cachedSections: TemplateSections | null = null;
|
|
@@ -34,9 +35,9 @@ function extractSection(lines: string[], startHeading: string, endMarker: string
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
|
-
* Load the template document once and slice it into the
|
|
38
|
+
* Load the template document once and slice it into the six
|
|
38
39
|
* {@link TemplateSections} by `## …` heading (each running up to the next `---`
|
|
39
|
-
* rule
|
|
40
|
+
* rule). Cached per process.
|
|
40
41
|
*/
|
|
41
42
|
export async function loadTemplateSections(): Promise<TemplateSections> {
|
|
42
43
|
if (cachedSections) return cachedSections;
|
|
@@ -51,10 +52,7 @@ export async function loadTemplateSections(): Promise<TemplateSections> {
|
|
|
51
52
|
tokens: extractSection(lines, '## Design Token System', '---'),
|
|
52
53
|
'design-quality': extractSection(lines, '## Design Quality', '---'),
|
|
53
54
|
customization: extractSection(lines, '## Customization', '---'),
|
|
54
|
-
'style-patterns': extractSection(lines, '## Style Patterns', '---')
|
|
55
|
-
// Auth Setup is the last section and contains no `---` rules of its own, so
|
|
56
|
-
// it extracts cleanly to EOF. Its `###` stage sub-headings carry the staging.
|
|
57
|
-
'auth-setup': extractSection(lines, '## Auth Setup', '---')
|
|
55
|
+
'style-patterns': extractSection(lines, '## Style Patterns', '---')
|
|
58
56
|
};
|
|
59
57
|
|
|
60
58
|
return cachedSections;
|
package/src/resources/guides.ts
CHANGED
|
@@ -1,67 +1,86 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { loadPackageGuide } from '../data/guide-loader.js';
|
|
2
3
|
import type { TemplateSections } from '../data/template-loader.js';
|
|
3
4
|
import { loadTemplateSections } from '../data/template-loader.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* The seven guide surfaces
|
|
7
|
-
*
|
|
8
|
-
* guide
|
|
7
|
+
* The seven guide surfaces. Six slice a `## …` section out of the template
|
|
8
|
+
* bundle ({@link TemplateSections}); the auth guide is a canonical package
|
|
9
|
+
* guide served verbatim from the bundle's `guides/auth.md` (the tarball-shipped
|
|
10
|
+
* `packages/auth/docs/AUTH.md` — one source, all channels, docs/DOCS-SURFACES.md).
|
|
11
|
+
* The `urbicon` CLI lists every bundled package guide dynamically
|
|
12
|
+
* (`urbicon guide`); this static list names the ones the server advertises.
|
|
9
13
|
*/
|
|
10
|
-
const GUIDE_RESOURCES:
|
|
14
|
+
const GUIDE_RESOURCES: (
|
|
15
|
+
| { id: string; name: string; source: 'template'; key: keyof TemplateSections }
|
|
16
|
+
| { id: string; name: string; source: 'package-guide'; slug: string }
|
|
17
|
+
)[] = [
|
|
11
18
|
{
|
|
12
19
|
id: 'api-grammar',
|
|
13
20
|
name: 'API Grammar Guide',
|
|
21
|
+
source: 'template',
|
|
14
22
|
key: 'api-grammar'
|
|
15
23
|
},
|
|
16
24
|
{
|
|
17
25
|
id: 'component-families',
|
|
18
26
|
name: 'Component Families Guide',
|
|
27
|
+
source: 'template',
|
|
19
28
|
key: 'component-families'
|
|
20
29
|
},
|
|
21
30
|
{
|
|
22
31
|
id: 'tokens',
|
|
23
32
|
name: 'Design Tokens Guide',
|
|
33
|
+
source: 'template',
|
|
24
34
|
key: 'tokens'
|
|
25
35
|
},
|
|
26
36
|
{
|
|
27
37
|
id: 'design-quality',
|
|
28
38
|
name: 'Design Quality Guide',
|
|
39
|
+
source: 'template',
|
|
29
40
|
key: 'design-quality'
|
|
30
41
|
},
|
|
31
42
|
{
|
|
32
43
|
id: 'customization',
|
|
33
44
|
name: 'Customization Guide',
|
|
45
|
+
source: 'template',
|
|
34
46
|
key: 'customization'
|
|
35
47
|
},
|
|
36
48
|
{
|
|
37
49
|
id: 'style-patterns',
|
|
38
50
|
name: 'Style Patterns Guide',
|
|
51
|
+
source: 'template',
|
|
39
52
|
key: 'style-patterns'
|
|
40
53
|
},
|
|
41
54
|
{
|
|
42
|
-
id: 'auth
|
|
43
|
-
name: 'Auth
|
|
44
|
-
|
|
55
|
+
id: 'auth',
|
|
56
|
+
name: 'Auth Reference',
|
|
57
|
+
source: 'package-guide',
|
|
58
|
+
slug: 'auth'
|
|
45
59
|
}
|
|
46
60
|
];
|
|
47
61
|
|
|
48
62
|
/**
|
|
49
63
|
* Register one `urbicon://guide/<id>` resource per {@link GUIDE_RESOURCES} entry.
|
|
50
|
-
* Each read
|
|
51
|
-
* a "not found" note if the
|
|
64
|
+
* Each read resolves its content lazily (template slice or bundled package
|
|
65
|
+
* guide) and degrades to a "not found" note if the content is missing.
|
|
52
66
|
*/
|
|
53
67
|
export function registerGuideResources(server: McpServer): void {
|
|
54
68
|
for (const guide of GUIDE_RESOURCES) {
|
|
55
69
|
server.resource(`guide-${guide.id}`, `urbicon://guide/${guide.id}`, async (uri) => {
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
let content: string | null;
|
|
71
|
+
if (guide.source === 'template') {
|
|
72
|
+
const sections = await loadTemplateSections();
|
|
73
|
+
content = sections[guide.key] || null;
|
|
74
|
+
} else {
|
|
75
|
+
content = await loadPackageGuide(guide.slug);
|
|
76
|
+
}
|
|
58
77
|
|
|
59
78
|
return {
|
|
60
79
|
contents: [
|
|
61
80
|
{
|
|
62
81
|
uri: uri.href,
|
|
63
82
|
mimeType: 'text/markdown',
|
|
64
|
-
text: content
|
|
83
|
+
text: content ?? `Guide "${guide.id}" not found.`
|
|
65
84
|
}
|
|
66
85
|
]
|
|
67
86
|
};
|