@react-aria/mcp 1.1.0 → 1.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 CHANGED
@@ -109,6 +109,10 @@ Follow Windsurf MCP [documentation](https://docs.windsurf.com/windsurf/cascade/m
109
109
  | `get_react_aria_page_info` | `{ page_name: string }` | Return page description and list of section titles. |
110
110
  | `get_react_aria_page` | `{ page_name: string, section_name?: string }` | Return full page markdown, or only the specified section. |
111
111
 
112
+ ## Privacy Policy
113
+
114
+ See [Adobe's privacy policy](https://www.adobe.com/privacy/policy.html).
115
+
112
116
  ## Development
113
117
 
114
118
  ### Testing locally
@@ -135,4 +139,19 @@ Update your MCP client configuration to use the local MCP server:
135
139
  }
136
140
  }
137
141
  }
142
+ ```
143
+
144
+ ## Bundling
145
+
146
+ To build an [MCP Bundle (MCPB)](https://github.com/modelcontextprotocol/mcpb), first prepare the staging directory:
147
+
148
+ ```bash
149
+ yarn workspace @react-spectrum/s2-docs generate:mcpb
150
+ ```
151
+
152
+ Then validate and pack using the [`@anthropic-ai/mcpb`](https://www.npmjs.com/package/@anthropic-ai/mcpb) CLI (paths are printed by the script above):
153
+
154
+ ```bash
155
+ npx @anthropic-ai/mcpb validate <staging-dir>
156
+ npx @anthropic-ai/mcpb pack <staging-dir> <output-path>
138
157
  ```
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /// <reference types="node" />
3
- import { errorToString } from '../../shared/src/utils.js';
3
+ import { errorToString, readPackageVersion } from '../../shared/src/utils.js';
4
4
  import { startServer } from '../../shared/src/server.js';
5
5
  // CLI entry for React Aria
6
6
  (async () => {
@@ -10,7 +10,7 @@ import { startServer } from '../../shared/src/server.js';
10
10
  console.log('Usage: npx @react-aria/mcp@latest\n\nStarts the MCP server for React Aria documentation.');
11
11
  process.exit(0);
12
12
  }
13
- await startServer('react-aria', '0.1.0');
13
+ await startServer('react-aria', readPackageVersion(import.meta.url));
14
14
  }
15
15
  catch (err) {
16
16
  console.error(errorToString(err));
@@ -67,7 +67,13 @@ export async function resolvePageRef(library, pageName) {
67
67
  return maybe;
68
68
  }
69
69
  const filePath = `${baseUrl}/${normalized}.md`;
70
- const stub = { key: normalized, name: path.basename(normalized), description: undefined, filePath, sections: [] };
70
+ const stub = {
71
+ key: normalized,
72
+ name: path.basename(normalized),
73
+ description: undefined,
74
+ filePath,
75
+ sections: []
76
+ };
71
77
  pageCache.set(stub.key, stub);
72
78
  return stub;
73
79
  }
@@ -4,11 +4,22 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { parseSectionsFromMarkdown } from './parser.js';
5
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
6
6
  import { z } from 'zod';
7
- export async function startServer(library, version, registerAdditionalTools) {
7
+ export async function startServer(library, version, options = {}) {
8
8
  const server = new McpServer({
9
9
  name: library === 's2' ? 's2-docs-server' : 'react-aria-docs-server',
10
10
  version
11
11
  });
12
+ const libraries = [library, ...(options.additionalLibraries ?? [])];
13
+ for (const lib of libraries) {
14
+ await registerLibraryDocsTools(server, lib);
15
+ }
16
+ if (options.registerAdditionalTools) {
17
+ await options.registerAdditionalTools(server);
18
+ }
19
+ const transport = new StdioServerTransport();
20
+ await server.connect(transport);
21
+ }
22
+ async function registerLibraryDocsTools(server, library) {
12
23
  // Build page index at startup.
13
24
  try {
14
25
  await buildPageIndex(library);
@@ -18,9 +29,12 @@ export async function startServer(library, version, registerAdditionalTools) {
18
29
  }
19
30
  const toolPrefix = library === 's2' ? 's2' : 'react_aria';
20
31
  server.registerTool(`list_${toolPrefix}_pages`, {
21
- title: library === 's2' ? 'List React Spectrum (@react-spectrum/s2) docs pages' : 'List React Aria docs pages',
32
+ title: library === 's2'
33
+ ? 'List React Spectrum (@react-spectrum/s2) docs pages'
34
+ : 'List React Aria docs pages',
22
35
  description: `Returns a list of available pages in the ${library} docs.`,
23
- inputSchema: { includeDescription: z.boolean().optional() }
36
+ inputSchema: { includeDescription: z.boolean().optional() },
37
+ annotations: { readOnlyHint: true, openWorldHint: true }
24
38
  }, async ({ includeDescription }) => {
25
39
  const pages = await buildPageIndex(library);
26
40
  const items = pages
@@ -33,7 +47,8 @@ export async function startServer(library, version, registerAdditionalTools) {
33
47
  server.registerTool(`get_${toolPrefix}_page_info`, {
34
48
  title: 'Get page info',
35
49
  description: 'Returns page description and list of sections for a given page.',
36
- inputSchema: { page_name: z.string() }
50
+ inputSchema: { page_name: z.string() },
51
+ annotations: { readOnlyHint: true, openWorldHint: true }
37
52
  }, async ({ page_name }) => {
38
53
  const ref = await resolvePageRef(library, page_name);
39
54
  const info = await ensureParsedPage(ref);
@@ -47,7 +62,8 @@ export async function startServer(library, version, registerAdditionalTools) {
47
62
  server.registerTool(`get_${toolPrefix}_page`, {
48
63
  title: 'Get page markdown',
49
64
  description: 'Returns the full markdown content for a page, or a specific section if provided.',
50
- inputSchema: { page_name: z.string(), section_name: z.string().optional() }
65
+ inputSchema: { page_name: z.string(), section_name: z.string().optional() },
66
+ annotations: { readOnlyHint: true, openWorldHint: true }
51
67
  }, async ({ page_name, section_name }) => {
52
68
  const ref = await resolvePageRef(library, page_name);
53
69
  let text;
@@ -68,9 +84,4 @@ export async function startServer(library, version, registerAdditionalTools) {
68
84
  const snippet = lines.slice(section.startLine, section.endLine).join('\n');
69
85
  return { content: [{ type: 'text', text: snippet }] };
70
86
  });
71
- if (registerAdditionalTools) {
72
- await registerAdditionalTools(server);
73
- }
74
- const transport = new StdioServerTransport();
75
- await server.connect(transport);
76
87
  }
@@ -1,8 +1,31 @@
1
+ import { dirname, join } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { readFileSync } from 'fs';
4
+ // Resolves the version from the nearest package.json above the CLI entry point.
5
+ // Both the npm-published layout (dist/<lib>/src/index.js) and the .mcpb bundle
6
+ // layout (server/<lib>/src/index.js) place package.json three levels up.
7
+ export function readPackageVersion(entryUrl) {
8
+ const entryDir = dirname(fileURLToPath(entryUrl));
9
+ const pkgPath = join(entryDir, '..', '..', '..', 'package.json');
10
+ try {
11
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
12
+ if (typeof pkg.version === 'string' && pkg.version.length > 0) {
13
+ return pkg.version;
14
+ }
15
+ }
16
+ catch {
17
+ // fall through
18
+ }
19
+ return '0.0.0';
20
+ }
1
21
  export function errorToString(err) {
2
22
  if (err && typeof err === 'object' && 'stack' in err && typeof err.stack === 'string') {
3
23
  return err.stack;
4
24
  }
5
- if (err && typeof err === 'object' && 'message' in err && typeof err.message === 'string') {
25
+ if (err &&
26
+ typeof err === 'object' &&
27
+ 'message' in err &&
28
+ typeof err.message === 'string') {
6
29
  return err.message;
7
30
  }
8
31
  try {
package/package.json CHANGED
@@ -1,9 +1,26 @@
1
1
  {
2
2
  "name": "@react-aria/mcp",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for React Aria documentation",
5
- "type": "module",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/adobe/react-spectrum"
9
+ },
6
10
  "bin": "dist/react-aria/src/index.js",
11
+ "source": "src/index.ts",
12
+ "files": [
13
+ "dist",
14
+ "src"
15
+ ],
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "main": "dist/main.js",
19
+ "module": "dist/module.js",
20
+ "types": "dist/types.d.ts",
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
7
24
  "scripts": {
8
25
  "prepublishOnly": "yarn build",
9
26
  "build": "tsc -p tsconfig.json",
@@ -21,22 +38,5 @@
21
38
  "engines": {
22
39
  "node": ">=18"
23
40
  },
24
- "license": "Apache-2.0",
25
- "publishConfig": {
26
- "access": "public"
27
- },
28
- "repository": {
29
- "type": "git",
30
- "url": "https://github.com/adobe/react-spectrum"
31
- },
32
- "files": [
33
- "dist",
34
- "src"
35
- ],
36
- "sideEffects": false,
37
- "main": "dist/main.js",
38
- "module": "dist/module.js",
39
- "types": "dist/types.d.ts",
40
- "source": "src/index.ts",
41
- "gitHead": "a6999bdf494a2e9c0381a5881908328bdd22ddae"
41
+ "gitHead": "3577a20859b9585a000010c720f6ee39c1c588cc"
42
42
  }
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /// <reference types="node" />
3
- import {errorToString} from '../../shared/src/utils.js';
3
+ import {errorToString, readPackageVersion} from '../../shared/src/utils.js';
4
4
  import {startServer} from '../../shared/src/server.js';
5
5
 
6
6
  // CLI entry for React Aria
@@ -8,10 +8,12 @@ import {startServer} from '../../shared/src/server.js';
8
8
  try {
9
9
  const arg = (process.argv[2] || '').trim();
10
10
  if (arg === '--help' || arg === '-h' || arg === 'help') {
11
- console.log('Usage: npx @react-aria/mcp@latest\n\nStarts the MCP server for React Aria documentation.');
11
+ console.log(
12
+ 'Usage: npx @react-aria/mcp@latest\n\nStarts the MCP server for React Aria documentation.'
13
+ );
12
14
  process.exit(0);
13
15
  }
14
- await startServer('react-aria', '0.1.0');
16
+ await startServer('react-aria', readPackageVersion(import.meta.url));
15
17
  } catch (err) {
16
18
  console.error(errorToString(err));
17
19
  process.exit(1);