@primer/mcp 1.0.0 → 1.1.0-rc.0ba38ed4c

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/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as server, t as createServer } from "./server-MtARfEmu.js";
1
+ import { n as server, t as createServer } from "./server-CnGefk-j.js";
2
2
  export { createServer, server };
@@ -40,11 +40,31 @@ const patterns = [
40
40
  name: "Copy",
41
41
  category: "scenario"
42
42
  },
43
+ {
44
+ id: "create",
45
+ name: "Create",
46
+ category: "scenario"
47
+ },
48
+ {
49
+ id: "customize",
50
+ name: "Customize",
51
+ category: "scenario"
52
+ },
53
+ {
54
+ id: "delegate",
55
+ name: "Delegate",
56
+ category: "scenario"
57
+ },
43
58
  {
44
59
  id: "delete",
45
60
  name: "Delete",
46
61
  category: "scenario"
47
62
  },
63
+ {
64
+ id: "edit",
65
+ name: "Edit",
66
+ category: "scenario"
67
+ },
48
68
  {
49
69
  id: "filter",
50
70
  name: "Filter",
@@ -55,6 +75,11 @@ const patterns = [
55
75
  name: "Search",
56
76
  category: "scenario"
57
77
  },
78
+ {
79
+ id: "view",
80
+ name: "View",
81
+ category: "scenario"
82
+ },
58
83
  {
59
84
  id: "data-visualization",
60
85
  name: "Data Visualization",
@@ -395,10 +420,12 @@ function loadAllTokensWithGuidelines() {
395
420
  }
396
421
  }
397
422
  function loadDesignTokensGuide() {
398
- return readFileSync(createRequire(import.meta.url).resolve("@primer/primitives/DESIGN_TOKENS_GUIDE.md"), "utf-8");
423
+ const guidePath = createRequire(import.meta.url).resolve("@primer/primitives/DESIGN_TOKENS_GUIDE.md");
424
+ return readFileSync(guidePath, "utf-8");
399
425
  }
400
426
  function loadDesignTokensSpec() {
401
- return readFileSync(createRequire(import.meta.url).resolve("@primer/primitives/DESIGN_TOKENS_SPEC.md"), "utf-8");
427
+ const specPath = createRequire(import.meta.url).resolve("@primer/primitives/DESIGN_TOKENS_SPEC.md");
428
+ return readFileSync(specPath, "utf-8");
402
429
  }
403
430
  function getDesignTokenSpecsText(groups) {
404
431
  return `
@@ -690,7 +717,7 @@ function runStylelint(css) {
690
717
  }
691
718
  //#endregion
692
719
  //#region package.json
693
- var version = "1.0.0";
720
+ var version = "1.1.0";
694
721
  //#endregion
695
722
  //#region src/server.ts
696
723
  const turndownService = new TurndownService();
@@ -898,7 +925,7 @@ ${turndownService.turndown(source)}`
898
925
  }] };
899
926
  });
900
927
  server.registerTool("list_patterns", {
901
- description: "List all of the patterns available from Primer React. Scenario patterns describe specific user tasks (copy, delete, filter, search). Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.",
928
+ description: "List all of the patterns available from Primer React. Scenario patterns describe specific user tasks. Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.",
902
929
  annotations: { readOnlyHint: true }
903
930
  }, async () => {
904
931
  const all = listPatterns();
@@ -918,7 +945,7 @@ ${ui.join("\n")}`
918
945
  }] };
919
946
  });
920
947
  server.registerTool("get_pattern", {
921
- description: "Get a specific pattern by name. Scenario patterns describe specific user tasks (copy, delete, filter, search). Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.",
948
+ description: "Get a specific pattern by name. Scenario patterns describe specific user tasks. Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.",
922
949
  inputSchema: z.object({ name: z.string().describe("The name of the pattern to retrieve") }),
923
950
  annotations: { readOnlyHint: true }
924
951
  }, async ({ name }) => {
@@ -957,7 +984,8 @@ ${turndownService.turndown(source)}`
957
984
  let effectiveGroup = resolvedGroup;
958
985
  const filteredKeywords = [];
959
986
  for (const kw of rawKeywords) {
960
- const aliasMatch = GROUP_ALIASES[kw.replace(/\s+/g, "")];
987
+ const normalized = kw.replace(/\s+/g, "");
988
+ const aliasMatch = GROUP_ALIASES[normalized];
961
989
  if (aliasMatch && !effectiveGroup) effectiveGroup = aliasMatch;
962
990
  else filteredKeywords.push(kw);
963
991
  }
@@ -1002,7 +1030,8 @@ ${validGroups}
1002
1030
  annotations: { readOnlyHint: true }
1003
1031
  }, async ({ groups }) => {
1004
1032
  const resolvedGroups = groups.map((g) => {
1005
- return GROUP_ALIASES[g.toLowerCase().replace(/\s+/g, "")] || g;
1033
+ const normalized = g.toLowerCase().replace(/\s+/g, "");
1034
+ return GROUP_ALIASES[normalized] || g;
1006
1035
  });
1007
1036
  const matched = allTokensWithGuidelines.filter((token) => resolvedGroups.some((rg) => tokenMatchesGroup(token, rg)));
1008
1037
  if (matched.length === 0) {
package/dist/stdio.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createServer } from "./server-MtARfEmu.js";
1
+ import { t as createServer } from "./server-CnGefk-j.js";
2
2
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
3
3
  //#region src/transports/stdio.ts
4
4
  serveStdio(createServer);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@primer/mcp",
3
3
  "description": "An MCP server that connects AI tools to the Primer Design System",
4
- "version": "1.0.0",
4
+ "version": "1.1.0-rc.0ba38ed4c",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mcp": "./bin/mcp.js"
@@ -41,7 +41,7 @@
41
41
  "@modelcontextprotocol/server": "^2.0.0",
42
42
  "@primer/octicons": "^19.15.5",
43
43
  "@primer/primitives": "10.x || 11.x",
44
- "@primer/react": "^38.35.0",
44
+ "@primer/react": "^38.38.0",
45
45
  "cheerio": "^1.0.0",
46
46
  "turndown": "^7.2.0",
47
47
  "zod": "^4.3.5"
@@ -51,7 +51,7 @@
51
51
  "@primer/vitest-config": "^0.0.0",
52
52
  "@types/turndown": "^5.0.5",
53
53
  "rimraf": "^6.0.1",
54
- "rolldown": "^1.2.0",
54
+ "rolldown": "^1.2.6",
55
55
  "rolldown-plugin-dts": "^0.26.0",
56
56
  "typescript": "^6.0.3"
57
57
  }
package/src/primer.ts CHANGED
@@ -51,11 +51,31 @@ const patterns: Array<Pattern> = [
51
51
  name: 'Copy',
52
52
  category: 'scenario',
53
53
  },
54
+ {
55
+ id: 'create',
56
+ name: 'Create',
57
+ category: 'scenario',
58
+ },
59
+ {
60
+ id: 'customize',
61
+ name: 'Customize',
62
+ category: 'scenario',
63
+ },
64
+ {
65
+ id: 'delegate',
66
+ name: 'Delegate',
67
+ category: 'scenario',
68
+ },
54
69
  {
55
70
  id: 'delete',
56
71
  name: 'Delete',
57
72
  category: 'scenario',
58
73
  },
74
+ {
75
+ id: 'edit',
76
+ name: 'Edit',
77
+ category: 'scenario',
78
+ },
59
79
  {
60
80
  id: 'filter',
61
81
  name: 'Filter',
@@ -66,6 +86,11 @@ const patterns: Array<Pattern> = [
66
86
  name: 'Search',
67
87
  category: 'scenario',
68
88
  },
89
+ {
90
+ id: 'view',
91
+ name: 'View',
92
+ category: 'scenario',
93
+ },
69
94
  {
70
95
  id: 'data-visualization',
71
96
  name: 'Data Visualization',
@@ -72,6 +72,44 @@ describe('MCP server', () => {
72
72
  )
73
73
  })
74
74
 
75
+ it('lists every published scenario pattern', async () => {
76
+ const result = await client.callTool({name: 'list_patterns'})
77
+ const scenarioPatterns = ['Copy', 'Create', 'Customize', 'Delegate', 'Delete', 'Edit', 'Filter', 'Search', 'View']
78
+
79
+ expect(result.content).toContainEqual(
80
+ expect.objectContaining({
81
+ type: 'text',
82
+ text: expect.stringContaining(
83
+ `## Scenario patterns\n\n${scenarioPatterns.map(name => `- ${name}`).join('\n')}`,
84
+ ),
85
+ }),
86
+ )
87
+ })
88
+
89
+ it.each([
90
+ {name: 'Create', id: 'create'},
91
+ {name: 'Customize', id: 'customize'},
92
+ {name: 'Delegate', id: 'delegate'},
93
+ {name: 'Edit', id: 'edit'},
94
+ {name: 'View', id: 'view'},
95
+ ])('retrieves the $name scenario pattern from its published URL', async ({name, id}) => {
96
+ vi.mocked(fetch).mockResolvedValue(new Response(`<main><h1>${name}</h1></main>`))
97
+
98
+ const result = await client.callTool({
99
+ name: 'get_pattern',
100
+ arguments: {name},
101
+ })
102
+
103
+ expect(fetch).toHaveBeenCalledTimes(1)
104
+ expect(vi.mocked(fetch).mock.calls[0]?.[0].toString()).toBe(`https://primer.style/product/scenario-patterns/${id}`)
105
+ expect(result.content).toContainEqual(
106
+ expect.objectContaining({
107
+ type: 'text',
108
+ text: expect.stringContaining(`Here are the guidelines for the \`${name}\` pattern for Primer:`),
109
+ }),
110
+ )
111
+ })
112
+
75
113
  it('requires between 2 and 10 names', async () => {
76
114
  const tooFew = await callBatch(['Button'])
77
115
  const tooMany = await callBatch(Array.from({length: 11}, (_, index) => `Component${index}`))
package/src/server.ts CHANGED
@@ -441,7 +441,7 @@ ${text}`,
441
441
  'list_patterns',
442
442
  {
443
443
  description:
444
- 'List all of the patterns available from Primer React. Scenario patterns describe specific user tasks (copy, delete, filter, search). Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.',
444
+ 'List all of the patterns available from Primer React. Scenario patterns describe specific user tasks. Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.',
445
445
  annotations: {readOnlyHint: true},
446
446
  },
447
447
  async () => {
@@ -471,7 +471,7 @@ ${ui.join('\n')}`,
471
471
  'get_pattern',
472
472
  {
473
473
  description:
474
- 'Get a specific pattern by name. Scenario patterns describe specific user tasks (copy, delete, filter, search). Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.',
474
+ 'Get a specific pattern by name. Scenario patterns describe specific user tasks. Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.',
475
475
  inputSchema: z.object({
476
476
  name: z.string().describe('The name of the pattern to retrieve'),
477
477
  }),