@santi020k/lumen-mcp 0.1.0 → 0.2.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 +53 -9
- package/bin/lumen-mcp-http.mjs +20 -0
- package/bin/lumen-mcp-local.mjs +5 -5
- package/data/lumen-data.json +3983 -694
- package/dist/data.d.ts +26 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +110 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +95 -3
- package/dist/tools.d.ts +52 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +192 -16
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -15,7 +15,11 @@ not need a checkout of the Lumen repository.
|
|
|
15
15
|
| `lumen_list_components` | List components with descriptions, categories, framework availability, collections, and recipe membership. Filter by `framework`, `recipe`, or natural-language `query`. |
|
|
16
16
|
| `lumen_get_component` | Get a component for `astro`, `react`, or `elements` at `summary`, `usage`, or `source` detail. Usage includes imports, styles, props or attributes, examples, accessibility, guidance, and events. |
|
|
17
17
|
| `lumen_get_recipe` | Get a recipe or component set with its purpose, components, files, categories, and framework-specific install command. |
|
|
18
|
-
| `lumen_search` | Rank natural-language matches across component descriptions, curated collections, props, attributes, recipes, tokens, and agent rules. |
|
|
18
|
+
| `lumen_search` | Rank tolerant natural-language matches across component descriptions, curated collections, framework contracts, props, attributes, recipes, tokens, and agent rules. Optionally filter component contracts by framework. |
|
|
19
|
+
| `lumen_get_meta` | Return deterministic snapshot provenance, package versions, schema version, component count, and catalog hash. |
|
|
20
|
+
| `lumen_get_catalog_manifest` | Return stable per-component and per-recipe fingerprints that clients can retain between upgrades. |
|
|
21
|
+
| `lumen_diff_catalog` | Compare a retained manifest with the current snapshot and report added, changed, removed, and unchanged entries. |
|
|
22
|
+
| `lumen_diagnose` | Verify snapshot integrity and report framework coverage when testing a connection. |
|
|
19
23
|
| `lumen_get_tokens` | Return semantic token names, base colors, glass tokens, and the theme attribute. |
|
|
20
24
|
| `lumen_get_rules` | Return the Lumen agent rules from `llms.txt`. |
|
|
21
25
|
|
|
@@ -25,6 +29,9 @@ Every tool returns both readable text and validated `structuredContent`.
|
|
|
25
29
|
|
|
26
30
|
| Resource | Contents |
|
|
27
31
|
| --- | --- |
|
|
32
|
+
| `lumen://meta` | Snapshot provenance, package versions, and deterministic catalog hash. |
|
|
33
|
+
| `lumen://catalog-manifest` | Stable component and recipe fingerprints for change detection. |
|
|
34
|
+
| `lumen://diagnostics` | Snapshot integrity results and framework coverage. |
|
|
28
35
|
| `lumen://rules` | Agent rules as Markdown. |
|
|
29
36
|
| `lumen://tokens` | Structured design tokens. |
|
|
30
37
|
| `lumen://components` | Compact component catalog. |
|
|
@@ -39,6 +46,8 @@ The stdio command for any MCP client is:
|
|
|
39
46
|
npx -y @santi020k/lumen-mcp
|
|
40
47
|
```
|
|
41
48
|
|
|
49
|
+
Node.js 20.20 or newer is supported.
|
|
50
|
+
|
|
42
51
|
### Codex
|
|
43
52
|
|
|
44
53
|
Register it from the Codex CLI:
|
|
@@ -108,19 +117,38 @@ Use the equivalent of this generic configuration:
|
|
|
108
117
|
Client configuration envelopes differ, but the command and arguments remain
|
|
109
118
|
the same.
|
|
110
119
|
|
|
120
|
+
### Streamable HTTP
|
|
121
|
+
|
|
122
|
+
For local network clients or a self-hosted deployment, start the included
|
|
123
|
+
Streamable HTTP transport:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx -y --package @santi020k/lumen-mcp lumen-mcp-http
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
It binds to `127.0.0.1:3000` by default and exposes MCP at
|
|
130
|
+
`http://127.0.0.1:3000/mcp` plus a health check at `/health`. Configure it with
|
|
131
|
+
`LUMEN_MCP_HOST`, `LUMEN_MCP_PORT`, and a comma-separated
|
|
132
|
+
`LUMEN_MCP_ALLOWED_HOSTS`. Binding to a public interface requires the
|
|
133
|
+
deployment's authentication, TLS, rate limiting, and host allowlist; the
|
|
134
|
+
package does not provide those infrastructure controls.
|
|
135
|
+
|
|
111
136
|
## Recommended agent workflow
|
|
112
137
|
|
|
113
|
-
1. Read `lumen://
|
|
114
|
-
2.
|
|
115
|
-
3. Call `
|
|
116
|
-
4.
|
|
117
|
-
5.
|
|
118
|
-
6.
|
|
138
|
+
1. Read `lumen://meta` and call `lumen_diagnose` to identify and verify the bundled snapshot.
|
|
139
|
+
2. Read `lumen://rules`.
|
|
140
|
+
3. Call `lumen_search` with the requested use case and target framework.
|
|
141
|
+
4. Call `lumen_get_component` with `detail: "usage"`.
|
|
142
|
+
5. Follow the returned framework behavior section: mount Astro `UIPrimitives` once, use the named React hook/controller, or register custom elements once.
|
|
143
|
+
6. Inspect a related recipe with `lumen_get_recipe` when the UI needs multiple primitives.
|
|
144
|
+
7. Request `detail: "source"` only when the usage contract is insufficient.
|
|
145
|
+
8. Use `lumen_get_tokens` before adding custom styling.
|
|
146
|
+
9. Cache `lumen://catalog-manifest`; after an upgrade, pass it to `lumen_diff_catalog` to refresh only changed contracts.
|
|
119
147
|
|
|
120
148
|
Example calls:
|
|
121
149
|
|
|
122
150
|
```json
|
|
123
|
-
{ "name": "lumen_search", "arguments": { "query": "accessible date input", "limit": 5 } }
|
|
151
|
+
{ "name": "lumen_search", "arguments": { "query": "accessible date input", "framework": "react", "limit": 5 } }
|
|
124
152
|
```
|
|
125
153
|
|
|
126
154
|
```json
|
|
@@ -163,6 +191,9 @@ pnpm --filter @santi020k/lumen-mcp generate
|
|
|
163
191
|
pnpm --filter @santi020k/lumen-mcp build
|
|
164
192
|
pnpm --filter @santi020k/lumen-mcp test
|
|
165
193
|
pnpm --filter @santi020k/lumen-mcp test:coverage
|
|
194
|
+
pnpm --filter @santi020k/lumen-mcp check:snapshot
|
|
195
|
+
pnpm --filter @santi020k/lumen-mcp eval
|
|
196
|
+
pnpm --filter @santi020k/lumen-mcp smoke:package
|
|
166
197
|
```
|
|
167
198
|
|
|
168
199
|
## Programmatic use
|
|
@@ -172,11 +203,13 @@ The reusable handlers return readable text plus typed data:
|
|
|
172
203
|
```ts
|
|
173
204
|
import {
|
|
174
205
|
getComponent,
|
|
206
|
+
getMeta,
|
|
175
207
|
getRecipe,
|
|
176
208
|
search
|
|
177
209
|
} from '@santi020k/lumen-mcp/tools'
|
|
178
210
|
|
|
179
211
|
const matches = search({ limit: 5, query: 'date input' }).data.results
|
|
212
|
+
const snapshot = getMeta().data.meta
|
|
180
213
|
|
|
181
214
|
const component = getComponent({
|
|
182
215
|
detail: 'usage',
|
|
@@ -209,7 +242,18 @@ const server = createLumenServer()
|
|
|
209
242
|
- Design tokens, recipes, `docs/ai-usage.md`, and `llms.txt`.
|
|
210
243
|
|
|
211
244
|
The output is deterministic and carries the package version used by the MCP
|
|
212
|
-
initialization response.
|
|
245
|
+
initialization response. It also includes every framework package version, a
|
|
246
|
+
schema version, and a SHA-256 catalog hash. CI regenerates the snapshot and
|
|
247
|
+
fails when the committed file is stale. The release group versions the MCP
|
|
248
|
+
alongside Lumen framework packages, and the package smoke test installs the
|
|
249
|
+
packed artifact into a temporary consumer project before making a real stdio
|
|
250
|
+
handshake.
|
|
251
|
+
|
|
252
|
+
The evaluation gate also runs a curated natural-language search benchmark,
|
|
253
|
+
calls every available component/framework contract through MCP, parses all
|
|
254
|
+
Astro and custom-element examples, and type-checks every React example against
|
|
255
|
+
the built React package. A generated example that is syntactically valid but
|
|
256
|
+
uses an unsupported React prop therefore fails before release.
|
|
213
257
|
|
|
214
258
|
## License
|
|
215
259
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { startLumenMcpHttp } from '../dist/index.js'
|
|
3
|
+
|
|
4
|
+
const port = Number.parseInt(process.env.LUMEN_MCP_PORT ?? '3000', 10)
|
|
5
|
+
const host = process.env.LUMEN_MCP_HOST ?? '127.0.0.1'
|
|
6
|
+
|
|
7
|
+
const allowedHosts = process.env.LUMEN_MCP_ALLOWED_HOSTS
|
|
8
|
+
?.split(',')
|
|
9
|
+
.map((value) => value.trim())
|
|
10
|
+
.filter(Boolean)
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const { url } = await startLumenMcpHttp({ allowedHosts, host, port })
|
|
14
|
+
|
|
15
|
+
process.stderr.write(`lumen-mcp listening at ${url.href}\n`)
|
|
16
|
+
} catch (error) {
|
|
17
|
+
process.stderr.write('lumen-mcp HTTP transport failed to start: ' + String(error) + '\n')
|
|
18
|
+
|
|
19
|
+
process.exitCode = 1
|
|
20
|
+
}
|
package/bin/lumen-mcp-local.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { spawnSync } from 'node:child_process'
|
|
3
|
-
import
|
|
3
|
+
import * as fs from 'node:fs/promises'
|
|
4
4
|
import { dirname, join, resolve } from 'node:path'
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ const repoRoot = resolve(packageRoot, '../..')
|
|
|
9
9
|
const distEntry = join(packageRoot, 'dist/index.js')
|
|
10
10
|
|
|
11
11
|
const filesIn = async (directory) => {
|
|
12
|
-
const entries = await
|
|
12
|
+
const entries = await fs.readdir(directory, { withFileTypes: true })
|
|
13
13
|
|
|
14
14
|
const nested = await Promise.all(entries.map((entry) => {
|
|
15
15
|
const path = join(directory, entry.name)
|
|
@@ -22,14 +22,14 @@ const filesIn = async (directory) => {
|
|
|
22
22
|
|
|
23
23
|
const needsBuild = async () => {
|
|
24
24
|
try {
|
|
25
|
-
await access(distEntry)
|
|
25
|
+
await fs.access(distEntry)
|
|
26
26
|
} catch {
|
|
27
27
|
return true
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const outputTime = (await
|
|
30
|
+
const outputTime = (await fs.stat(distEntry)).mtimeMs
|
|
31
31
|
const sourceFiles = await filesIn(join(packageRoot, 'src'))
|
|
32
|
-
const sourceTimes = await Promise.all(sourceFiles.map(async (path) => (await
|
|
32
|
+
const sourceTimes = await Promise.all(sourceFiles.map(async (path) => (await fs.stat(path)).mtimeMs))
|
|
33
33
|
|
|
34
34
|
return sourceTimes.some((modifiedTime) => modifiedTime > outputTime)
|
|
35
35
|
}
|