Skip to content

Commit 0807592

Browse files
authored
[compiler] Init react-mcp-server (facebook#32859)
Just trying this out as a small hack for fun. Nothing serious is planned. Inits an MCP server that has 1 assistant prompt and two capabilities.
1 parent 4eea4fc commit 0807592

File tree

10 files changed

+1588
-6
lines changed

10 files changed

+1588
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# React MCP Server (experimental)
2+
3+
An experimental MCP Server for React.
4+
5+
## Development
6+
7+
First, add this file if you're using Claude Desktop: `code ~/Library/Application\ Support/Claude/claude_desktop_config.json`. Copy the absolute path from `which node` and from `react/compiler/react-mcp-server/dist/index.js` and paste, for example:
8+
9+
```json
10+
{
11+
"mcpServers": {
12+
"react": {
13+
"command": "/Users/<username>/.asdf/shims/node",
14+
"args": [
15+
"/Users/<username>/code/react/compiler/packages/react-mcp-server/dist/index.js"
16+
]
17+
}
18+
}
19+
}
20+
```
21+
22+
Next, run `yarn workspace react-mcp-server watch` from the `react/compiler` directory and make changes as needed. You will need to restart Claude everytime you want to try your changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "react-mcp-server",
3+
"version": "0.0.0",
4+
"description": "React MCP Server (experimental)",
5+
"bin": {
6+
"react-mcp-server": "./dist/index.js"
7+
},
8+
"scripts": {
9+
"build": "rimraf dist && tsup",
10+
"test": "echo 'no tests'",
11+
"watch": "yarn build --watch"
12+
},
13+
"dependencies": {
14+
"@babel/core": "^7.26.0",
15+
"@babel/parser": "^7.26",
16+
"@babel/plugin-syntax-typescript": "^7.25.9",
17+
"@modelcontextprotocol/sdk": "^1.9.0",
18+
"algoliasearch": "^5.23.3",
19+
"cheerio": "^1.0.0",
20+
"prettier": "^3.3.3",
21+
"turndown": "^7.2.0",
22+
"zod": "^3.23.8"
23+
},
24+
"devDependencies": {
25+
"@types/turndown": "^5.0.5"
26+
},
27+
"license": "MIT",
28+
"repository": {
29+
"type": "git",
30+
"url": "git+https://github.com/facebook/react.git",
31+
"directory": "compiler/packages/react-mcp-server"
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import type * as BabelCore from '@babel/core';
9+
import {parseAsync, transformFromAstAsync} from '@babel/core';
10+
import BabelPluginReactCompiler, {
11+
type PluginOptions,
12+
} from 'babel-plugin-react-compiler/src';
13+
import * as prettier from 'prettier';
14+
15+
export let lastResult: BabelCore.BabelFileResult | null = null;
16+
17+
type CompileOptions = {
18+
text: string;
19+
file: string;
20+
options: Partial<PluginOptions> | null;
21+
};
22+
export async function compile({
23+
text,
24+
file,
25+
options,
26+
}: CompileOptions): Promise<BabelCore.BabelFileResult> {
27+
const ast = await parseAsync(text, {
28+
sourceFileName: file,
29+
parserOpts: {
30+
plugins: ['typescript', 'jsx'],
31+
},
32+
sourceType: 'module',
33+
});
34+
if (ast == null) {
35+
throw new Error('Could not parse');
36+
}
37+
const plugins =
38+
options != null
39+
? [[BabelPluginReactCompiler, options]]
40+
: [[BabelPluginReactCompiler]];
41+
const result = await transformFromAstAsync(ast, text, {
42+
filename: file,
43+
highlightCode: false,
44+
retainLines: true,
45+
plugins,
46+
sourceType: 'module',
47+
sourceFileName: file,
48+
});
49+
if (result?.code == null) {
50+
throw new Error(
51+
`Expected BabelPluginReactCompiler to compile successfully, got ${result}`,
52+
);
53+
}
54+
try {
55+
result.code = await prettier.format(result.code, {
56+
semi: false,
57+
parser: 'babel-ts',
58+
});
59+
if (result.code != null) {
60+
lastResult = result;
61+
}
62+
} catch (err) {
63+
// If prettier failed just log, no need to crash
64+
console.error(err);
65+
}
66+
return result;
67+
}

0 commit comments

Comments
 (0)