@nanisoft/prism-mcp-server 0.3.0 → 0.4.1

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.
Files changed (49) hide show
  1. package/README.md +66 -0
  2. package/THIRD-PARTY-NOTICES.md +48 -0
  3. package/dist/descriptions.d.ts +22 -0
  4. package/dist/descriptions.js +33 -0
  5. package/dist/generated/built.d.ts +2 -0
  6. package/dist/generated/built.js +6 -0
  7. package/dist/generated/server-version.d.ts +1 -0
  8. package/dist/generated/server-version.js +5 -0
  9. package/dist/index.d.ts +11 -10
  10. package/dist/index.js +10 -9
  11. package/dist/render.d.ts +69 -44
  12. package/dist/render.js +422 -145
  13. package/dist/rules.d.ts +12 -0
  14. package/dist/rules.js +14 -0
  15. package/dist/schemas.d.ts +104 -0
  16. package/dist/schemas.js +102 -0
  17. package/dist/server.d.ts +22 -0
  18. package/dist/server.js +75 -0
  19. package/dist/version.d.ts +1 -10
  20. package/dist/version.js +10 -7
  21. package/dist/vocab.d.ts +13 -0
  22. package/dist/vocab.js +19 -0
  23. package/package.json +32 -23
  24. package/dist/factory.d.ts +0 -31
  25. package/dist/factory.d.ts.map +0 -1
  26. package/dist/factory.js +0 -33
  27. package/dist/factory.js.map +0 -1
  28. package/dist/index.d.ts.map +0 -1
  29. package/dist/index.js.map +0 -1
  30. package/dist/lookup.d.ts +0 -68
  31. package/dist/lookup.d.ts.map +0 -1
  32. package/dist/lookup.js +0 -113
  33. package/dist/lookup.js.map +0 -1
  34. package/dist/render.d.ts.map +0 -1
  35. package/dist/render.js.map +0 -1
  36. package/dist/search.d.ts +0 -34
  37. package/dist/search.d.ts.map +0 -1
  38. package/dist/search.js +0 -68
  39. package/dist/search.js.map +0 -1
  40. package/dist/store.d.ts +0 -62
  41. package/dist/store.d.ts.map +0 -1
  42. package/dist/store.js +0 -80
  43. package/dist/store.js.map +0 -1
  44. package/dist/tools.d.ts +0 -22
  45. package/dist/tools.d.ts.map +0 -1
  46. package/dist/tools.js +0 -122
  47. package/dist/tools.js.map +0 -1
  48. package/dist/version.d.ts.map +0 -1
  49. package/dist/version.js.map +0 -1
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @nanisoft/prism-mcp-server
2
+
3
+ Prism's read-only MCP tool surface. Eight retrieval tools answer over the
4
+ bundled `PrismDocsStore` corpus from the same Cloudflare Worker that serves the
5
+ site, at `https://prism.nanisoft.com/mcp`.
6
+
7
+ The package is **transport-free**: `createPrismMcpServer(store, options)` returns
8
+ an `McpServer`, and the Worker connects it to `createMcpHandler` from the Agents
9
+ SDK's MCP server entry. There is one implementation and no stdio binary at
10
+ launch; a stdio-only client bridges with `npx mcp-remote
11
+ https://prism.nanisoft.com/mcp`.
12
+
13
+ ## Commands
14
+
15
+ ```sh
16
+ pnpm --filter @nanisoft/prism-mcp-server build # stamp the corpus, then tsc into dist/
17
+ pnpm --filter @nanisoft/prism-mcp-server test # the Vitest floor (in-memory round-trips)
18
+ ```
19
+
20
+ `pretest` compiles the package first. The suite reaches the corpus through
21
+ `@nanisoft/prism-llms`'s emitted `data.json`.
22
+
23
+ ## The eight tools
24
+
25
+ Every tool is self-contained, idempotent, stateless and returns Markdown. A
26
+ lookup miss is an `isError` result with did-you-mean suggestions and a browse
27
+ pointer, never a throw. Every description carries the import rule and the
28
+ surface rule.
29
+
30
+ | Tool | Arguments | Purpose |
31
+ | --- | --- | --- |
32
+ | `list_items` | `{ kind?, category? }` | The kind-grouped catalogue index; `category` is Component-only. |
33
+ | `get_item_doc` | `{ name, kind? }` | The assembled per-item Markdown plus its footer. |
34
+ | `get_item_props` | `{ name, kind? }` | The `## Props` section, or `## Composition` for a Block or Page. |
35
+ | `get_item_source` | `{ name, kind? }` | The public import line plus the verbatim demo. |
36
+ | `get_theme_doc` | `{ pack?, mode?, group? }` | A pack's resolved values, or one bound scale. |
37
+ | `list_pages` | `{}` | The Overview, Foundation, Content and Changelogs page index. |
38
+ | `get_page` | `{ url }` | One non-item page as Markdown; a catalogue URL points at `get_item_doc`. |
39
+ | `search_docs` | `{ query, kind?, limit? }` | Substring search over names, descriptions and page bodies. |
40
+
41
+ `kind` is the closed union `component | block | page`; `get_theme_doc`'s `group`
42
+ is `semantic | motion | typography | spacing | shadow | breakpoint | container`.
43
+
44
+ ## The store
45
+
46
+ `createPrismMcpServer` runs `parsePrismDocsStore` from `@nanisoft/prism-llms` at
47
+ its door, so a raw `data.json` is validated once and every transport inherits the
48
+ same rejection. The Worker bundles `@nanisoft/prism-llms/data.json` as an ESM
49
+ module; there is no `fs`, `fetch`, KV, cache or runtime lookup at isolate scope.
50
+
51
+ ## The build stamp
52
+
53
+ `scripts/stamp-built.mjs` writes the gitignored `src/generated/built.ts` before
54
+ the build. The stamp is derived from the corpus source commit date plus the
55
+ corpus version, so the same commit rebuilds to the same value. When git or the
56
+ corpus is unavailable it is `undefined`, and `list_items` omits the
57
+ `(built ...)` clause rather than fabricating a date. The stamp lives in this lane,
58
+ never in the corpus `dist`, so corpus build-twice determinism is untouched.
59
+
60
+ ## Auth
61
+
62
+ Public read-only in version one: the corpus is public and the tools are pure
63
+ reads over an immutable blob. The Cloudflare Access escalation is pre-written in
64
+ `apps/site/worker/access.ts` and inert until enabled. It flips when a tool gains
65
+ anything non-public: org-internal examples, write-back, telemetry or a per-user
66
+ quota.
@@ -0,0 +1,48 @@
1
+ # Third-party notices
2
+
3
+ The Prism packages (`@nanisoft/prism-tokens`, `@nanisoft/prism-ui`,
4
+ `@nanisoft/prism-llms`, `@nanisoft/prism-mcp-server`) are MIT-licensed. See
5
+ [`LICENSE`](./LICENSE). This file covers the third-party works the packages and
6
+ the site depend on or redistribute. It is attribution, not a grant: each work
7
+ remains under its own license.
8
+
9
+ ## Runtime dependencies
10
+
11
+ The direct runtime dependencies below are MIT-licensed unless noted. License
12
+ texts ship with their packages and are available from the corresponding npm
13
+ package or repository.
14
+
15
+ | Package | Used by | License |
16
+ | --- | --- | --- |
17
+ | `@base-ui/react` | `@nanisoft/prism-ui` (internal accessibility behaviour) | MIT, copyright the MUI Team and contributors |
18
+ | `@modelcontextprotocol/sdk` | `@nanisoft/prism-mcp-server` | MIT, copyright Anthropic, PBC and contributors |
19
+ | `zod` | `@nanisoft/prism-mcp-server` | MIT, copyright Colin McDonnell |
20
+ | `react`, `react-dom` | `@nanisoft/prism-ui` (peer), the site | MIT, copyright Meta Platforms, Inc. and affiliates |
21
+ | `next` | the site | MIT, copyright Vercel, Inc. |
22
+ | `fumadocs-core`, `fumadocs-mdx` | the site | MIT, copyright Fuma Nama |
23
+ | `agents` | the site (MCP transport) | MIT, copyright Cloudflare, Inc. |
24
+ | `class-variance-authority` | `@nanisoft/prism-ui` (internal variant recipes, not re-exported) | Apache-2.0 |
25
+ | `clsx` | `@nanisoft/prism-ui` (internal class composition) | MIT, copyright Luke Edwards |
26
+ | `tailwind-merge` | `@nanisoft/prism-ui` (internal class composition) | MIT |
27
+ | `lucide-react` | `@nanisoft/prism-ui` and the site (icons) | ISC, copyright the Lucide contributors, with portions copyright Cole Bemis 2013 to 2023 as part of Feather (MIT) |
28
+ | `tailwindcss` | `@nanisoft/prism-ui` and the site (internal build dependency) | MIT, copyright Tailwind Labs, Inc. |
29
+
30
+ Tailwind 4 is not a consumer dependency. It runs only in Prism's build, and its
31
+ compiled output is part of the component package's precompiled `styles.css`.
32
+
33
+ ## Fonts
34
+
35
+ The documentation site self-hosts Inter under `apps/site/src/fonts/`, loaded
36
+ through `next/font/local`. The shipped files are `InterVariable.woff2` and
37
+ `InterVariable-Italic.woff2` from the official Inter release 4.1, and the site
38
+ is the only consumer. Inter is licensed under the **SIL Open Font License,
39
+ Version 1.1**; the license text is committed at
40
+ `apps/site/src/fonts/LICENSE.txt`. Inter is copyright The Inter Project Authors
41
+ (rsms.me/inter).
42
+
43
+ ## Build and development toolchain
44
+
45
+ TypeScript, Vitest, Turbo, pnpm, changesets, oxlint, Style Dictionary, publint
46
+ and Wrangler are development and build dependencies. They are not redistributed
47
+ with Prism artifacts and carry their own package licenses. Style Dictionary is
48
+ Apache-2.0; the rest ship their own license text with their packages.
@@ -0,0 +1,22 @@
1
+ export declare const DESCRIPTIONS: {
2
+ readonly list_items: string;
3
+ readonly get_item_doc: string;
4
+ readonly get_item_props: string;
5
+ readonly get_item_source: string;
6
+ readonly get_theme_doc: string;
7
+ readonly list_pages: string;
8
+ readonly get_page: string;
9
+ readonly search_docs: string;
10
+ readonly get_changelog: string;
11
+ };
12
+ export type ToolName = keyof typeof DESCRIPTIONS;
13
+ /**
14
+ * The registration order.
15
+ *
16
+ * The first eight are pinned by ticket 13 section 9 and keep their names and
17
+ * their positions. `get_changelog` is appended rather than inserted, because an
18
+ * agent holding a tool list from before this ticket finds every tool it knew at
19
+ * the index it knew it at. A Section joining the Corpus is a parameter on the
20
+ * existing tools, not a rename of them.
21
+ */
22
+ export declare const TOOL_ORDER: readonly ["list_items", "get_item_doc", "get_item_props", "get_item_source", "get_theme_doc", "list_pages", "get_page", "search_docs", "get_changelog"];
@@ -0,0 +1,33 @@
1
+ /** The tool descriptions, each composed with the two standing rules. */
2
+ import { describe } from './rules.js';
3
+ export const DESCRIPTIONS = {
4
+ list_items: describe('List every Prism Component, Block and Page in the catalogue, optionally filtered by kind or by Component category. Use this once to learn the roster, then read an item with `get_item_doc` or `get_item_props`.'),
5
+ get_item_doc: describe('Read the assembled documentation for one Prism item: its description, import line, prose, demo pointer and generated API section. Accepts a name or slug and an optional kind to disambiguate.'),
6
+ get_item_props: describe('Read only the generated Props section, or the Composition section for a Block or Page, for the loop that re-queries an API without re-reading the prose. Accepts a name or slug and an optional kind to disambiguate.'),
7
+ get_item_source: describe('Read the verbatim demo source for one Prism item plus its public import line. Returns copyable source only; use `get_item_doc` for the prose and `get_item_props` for the API.'),
8
+ get_theme_doc: describe('Read the Prism token contract: a pack\u2019s resolved semantic values for a mode, or one bound scale (motion, typography, spacing, shadow, breakpoint, container). Read the contract here instead of inventing a duration, a curve or a spacing step.'),
9
+ list_pages: describe('List the non-item Prism documentation pages: the Overview, the Foundation, the Content and the Changelogs. Use `get_page` to read one.'),
10
+ get_page: describe('Read one non-item Prism documentation page as Markdown by its URL. Only serves the Overview, Foundation, Content and Changelogs lanes; a catalogue item URL is a miss with a pointer to `get_item_doc`.'),
11
+ search_docs: describe('Substring match over item names, descriptions and page bodies. Returns ranked references, each with its kind, the field that matched, and the follow-up call to make. It does not return page or item contents; use `get_item_doc` or `get_page` for the body.'),
12
+ get_changelog: describe('Read a published Prism package\u2019s changelog, optionally one version of it. Returns the package\u2019s own file, so the text is the text that shipped. Call this before upgrading, or when behaviour changed under a version you depend on: a breaking change in a published package is here rather than in a guess.'),
13
+ };
14
+ /**
15
+ * The registration order.
16
+ *
17
+ * The first eight are pinned by ticket 13 section 9 and keep their names and
18
+ * their positions. `get_changelog` is appended rather than inserted, because an
19
+ * agent holding a tool list from before this ticket finds every tool it knew at
20
+ * the index it knew it at. A Section joining the Corpus is a parameter on the
21
+ * existing tools, not a rename of them.
22
+ */
23
+ export const TOOL_ORDER = [
24
+ 'list_items',
25
+ 'get_item_doc',
26
+ 'get_item_props',
27
+ 'get_item_source',
28
+ 'get_theme_doc',
29
+ 'list_pages',
30
+ 'get_page',
31
+ 'search_docs',
32
+ 'get_changelog',
33
+ ];
@@ -0,0 +1,2 @@
1
+ export declare const BUILT: string | undefined;
2
+ export declare const BUILT_CORPUS: string | undefined;
@@ -0,0 +1,6 @@
1
+ // Generated by scripts/stamp-built.mjs. Gitignored; do not edit.
2
+ // Derived from the corpus source commit date plus the corpus version. The
3
+ // fallback is undefined (git or the corpus unavailable), which makes
4
+ // list_items omit the (built ...) clause rather than fabricate a date.
5
+ export const BUILT = "2026-09-28";
6
+ export const BUILT_CORPUS = "0.7.0";
@@ -0,0 +1 @@
1
+ export declare const SERVER_VERSION: string;
@@ -0,0 +1,5 @@
1
+ // Generated by scripts/stamp-built.mjs. Gitignored; do not edit.
2
+ // Derived from this package's own package.json, which is the single place a
3
+ // release writes a version. There is no fallback value: an unreadable manifest
4
+ // throws in the step above rather than stamping a version this package is not.
5
+ export const SERVER_VERSION = "0.4.1";
package/dist/index.d.ts CHANGED
@@ -1,13 +1,14 @@
1
1
  /**
2
- * `@nanisoft/prism-mcp-server` — the Prism MCP tool surface (ADR-0004).
2
+ * @nanisoft/prism-mcp-server public surface.
3
3
  *
4
- * Transport-free: this package exports the pure `createPrismMcpServer(docs)`
5
- * factory plus the `PrismDocsStore` corpus contract it reads (this package is
6
- * that interface's canonical home — the consumer). It imports nothing from any
7
- * other workspace package at runtime; apps/site bundles the factory together
8
- * with `@nanisoft/prism-llms`' `data.json` at build time.
4
+ * One factory, the read-only tools, no transport: the Worker connects it to
5
+ * `createMcpHandler`, and the protocol tests connect it to an in-memory
6
+ * transport. The build stamp ships beside the factory so `list_items` can echo
7
+ * how fresh the bundled corpus is.
9
8
  */
10
- export { createPrismMcpServer, type PrismMcpServerOptions } from './factory.js';
11
- export { parsePrismDocsStore } from './store.js';
12
- export type { PrismDocsStore, PrismDocsItem, PrismDocsPage, PrismDocsTheme } from './store.js';
13
- //# sourceMappingURL=index.d.ts.map
9
+ export { createPrismMcpServer } from './server.js';
10
+ export type { PrismMcpServerOptions } from './server.js';
11
+ export { BUILT, BUILT_CORPUS } from './generated/built.js';
12
+ export { IMPORT_RULE, NO_INVENTION_RULE, SURFACE_RULE, describe } from './rules.js';
13
+ export { SERVER_NAME, SERVER_VERSION } from './version.js';
14
+ export { TOOL_ORDER } from './descriptions.js';
package/dist/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  /**
2
- * `@nanisoft/prism-mcp-server` — the Prism MCP tool surface (ADR-0004).
2
+ * @nanisoft/prism-mcp-server public surface.
3
3
  *
4
- * Transport-free: this package exports the pure `createPrismMcpServer(docs)`
5
- * factory plus the `PrismDocsStore` corpus contract it reads (this package is
6
- * that interface's canonical home — the consumer). It imports nothing from any
7
- * other workspace package at runtime; apps/site bundles the factory together
8
- * with `@nanisoft/prism-llms`' `data.json` at build time.
4
+ * One factory, the read-only tools, no transport: the Worker connects it to
5
+ * `createMcpHandler`, and the protocol tests connect it to an in-memory
6
+ * transport. The build stamp ships beside the factory so `list_items` can echo
7
+ * how fresh the bundled corpus is.
9
8
  */
10
- export { createPrismMcpServer } from './factory.js';
11
- export { parsePrismDocsStore } from './store.js';
12
- //# sourceMappingURL=index.js.map
9
+ export { createPrismMcpServer } from './server.js';
10
+ export { BUILT, BUILT_CORPUS } from './generated/built.js';
11
+ export { IMPORT_RULE, NO_INVENTION_RULE, SURFACE_RULE, describe } from './rules.js';
12
+ export { SERVER_NAME, SERVER_VERSION } from './version.js';
13
+ export { TOOL_ORDER } from './descriptions.js';
package/dist/render.d.ts CHANGED
@@ -1,48 +1,73 @@
1
1
  /**
2
- * The markdown every tool answers with — the corpus is Markdown, so JSON
3
- * envelopes would only add tokens and quoting (ADR-0004 §2). All of these are
4
- * pure string builders over already-resolved data; lookup/search logic lives
5
- * elsewhere. Result text always prints the next call to make (§7).
2
+ * The pure renderers behind the tools.
3
+ *
4
+ * Every tool returns markdown and never touches I/O: the store is the whole
5
+ * input. A lookup miss is an `isError` result with did-you-mean suggestions and
6
+ * a browse pointer, never a throw, so a client sees the same contract on every
7
+ * transport.
6
8
  */
7
- import type { PrismDocsItem, PrismDocsPage, PrismDocsStore, PrismDocsTheme } from './store.js';
8
- import { type ItemKind } from './lookup.js';
9
- import type { SearchHit } from './search.js';
10
- /** The one import rule every description and every miss carries. */
11
- export declare const IMPORT_RULE = "Always import from '@nanisoft/prism-ui', never from antd directly.";
9
+ import type { CallToolResult } from '@modelcontextprotocol/server';
10
+ import { type PrismDocsStore, type PrismDocsStoreEntry } from '@nanisoft/prism-llms';
11
+ import type { ComponentCategory, ItemKind, SearchKind } from './vocab.js';
12
+ /** Every exact name or slug match in the optional kind, case-insensitively. */
13
+ export declare function matchesFor(store: PrismDocsStore, name: string, kind?: ItemKind): PrismDocsStoreEntry[];
14
+ export interface ListItemsArgs {
15
+ kind?: ItemKind;
16
+ category?: ComponentCategory;
17
+ }
18
+ export declare function renderListItems(store: PrismDocsStore, args: ListItemsArgs, built?: string): CallToolResult;
19
+ export interface ItemArgs {
20
+ name: string;
21
+ kind?: ItemKind;
22
+ }
23
+ export declare function renderItemDoc(store: PrismDocsStore, args: ItemArgs): CallToolResult;
24
+ export declare function renderItemProps(store: PrismDocsStore, args: ItemArgs): CallToolResult;
25
+ export declare function renderItemSource(store: PrismDocsStore, args: ItemArgs): CallToolResult;
26
+ export interface ThemeDocArgs {
27
+ pack?: string;
28
+ mode?: string;
29
+ group?: string;
30
+ }
31
+ export declare function renderThemeDoc(store: PrismDocsStore, args: ThemeDocArgs): CallToolResult;
32
+ export declare function renderListPages(store: PrismDocsStore): CallToolResult;
33
+ export interface PageArgs {
34
+ url: string;
35
+ }
36
+ export declare function renderPage(store: PrismDocsStore, args: PageArgs): CallToolResult;
37
+ export interface SearchArgs {
38
+ query: string;
39
+ kind?: SearchKind;
40
+ limit?: number;
41
+ }
42
+ interface Candidate {
43
+ title: string;
44
+ kind: SearchKind;
45
+ url: string;
46
+ snippet: string;
47
+ content: string;
48
+ followUp: string;
49
+ }
50
+ export declare function searchCandidates(store: PrismDocsStore, kind?: SearchKind): Candidate[];
51
+ export declare function searchDocs(store: PrismDocsStore, args: SearchArgs): CallToolResult;
52
+ export interface ChangelogArgs {
53
+ package: string;
54
+ version?: string;
55
+ }
12
56
  /**
13
- * `list_items` — the cold-start catalog. The header line carries the corpus
14
- * version (mismatch detection) and, when the bundler supplies one, the build
15
- * date; pass-throughs are marked with their antd base so the delegation seam
16
- * is visible before any per-item call.
57
+ * One published package's changelog, or one version entry of it.
58
+ *
59
+ * The text is the package's own file, byte for byte, because the Store carries
60
+ * the bytes rather than a summary of them. A generated summary would drift the
61
+ * moment a release was published, which is the one thing a changelog cannot do:
62
+ * a breaking change in a published package has to be discoverable by an agent
63
+ * that never saw the release notes anywhere else. The reference design system
64
+ * shipped a breaking module-system change that no agent using it could find, and
65
+ * the reason is precisely that its corpus had no changelog and no tool to return
66
+ * one.
67
+ *
68
+ * The footers state where the text is published, so an agent holding an older
69
+ * corpus can still fetch the same bytes over HTTP, and which versions exist, so
70
+ * one call can pick the next `version` to ask for.
17
71
  */
18
- export declare function catalogMarkdown(docs: PrismDocsStore, kind?: ItemKind, built?: string): string;
19
- /**
20
- * `get_item_doc` — the generator's page verbatim (usage rules, props, example,
21
- * the `> Extends:` seam), plus at most one steering footer built from the data.
22
- */
23
- export declare function itemDocMarkdown(item: PrismDocsItem): string;
24
- /**
25
- * `get_item_props` — only the Prism-added delta. A pass-through's answer *is*
26
- * the routing instruction (ADR-0004 §4: plasma's `_No additional props…_` line
27
- * is the switch-servers signal).
28
- */
29
- export declare function itemPropsMarkdown(item: PrismDocsItem): string;
30
- /** `get_item_source` — the documented example, verbatim, in one fenced block. */
31
- export declare function itemSourceMarkdown(item: PrismDocsItem, example: {
32
- readonly slug: string;
33
- readonly title?: string;
34
- readonly code: string;
35
- }): string;
36
- /** `get_theme_doc` — the pack × mode atom verbatim, plus the sibling slugs. */
37
- export declare function themeMarkdown(theme: PrismDocsTheme, all: readonly PrismDocsTheme[]): string;
38
- /** `list_pages` — the site's llms.txt body as an index. */
39
- export declare function pagesIndexMarkdown(pages: readonly PrismDocsPage[], baseUrl: string): string;
40
- /** `get_page` — the prerendered page verbatim, cited back to the site. */
41
- export declare function pageMarkdown(page: PrismDocsPage, baseUrl: string): string;
42
- /** `search_docs` — ranked hits, each printing its own next call. */
43
- export declare function searchResultsMarkdown(query: string, hits: readonly SearchHit[]): string;
44
- /** A lookup miss: the closest names plus the browse pointer, as an error. */
45
- export declare function missMarkdown(target: string, suggestions: readonly string[], browseHint: string): string;
46
- /** A name hit whose `kind` argument pointed somewhere else. */
47
- export declare function kindMismatchMarkdown(item: PrismDocsItem, requested: ItemKind): string;
48
- //# sourceMappingURL=render.d.ts.map
72
+ export declare function renderChangelog(store: PrismDocsStore, args: ChangelogArgs): CallToolResult;
73
+ export {};