Skip to content

Commit 5d65b4d

Browse files
committed
[mcp] Refine passes returned
Adds some new options to request the HIR, ReactiveFunction passes
1 parent 545dbfd commit 5d65b4d

File tree

3 files changed

+99
-15
lines changed

3 files changed

+99
-15
lines changed

compiler/packages/react-mcp-server/src/compiler/index.ts

+10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ import * as prettier from 'prettier';
1414

1515
export let lastResult: BabelCore.BabelFileResult | null = null;
1616

17+
export type PrintedCompilerPipelineValue =
18+
| {
19+
kind: 'hir';
20+
name: string;
21+
fnName: string | null;
22+
value: string;
23+
}
24+
| {kind: 'reactive'; name: string; fnName: string | null; value: string}
25+
| {kind: 'debug'; name: string; fnName: string | null; value: string};
26+
1727
type CompileOptions = {
1828
text: string;
1929
file: string;

compiler/packages/react-mcp-server/src/index.ts

+76-15
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from '@modelcontextprotocol/sdk/server/mcp.js';
1212
import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js';
1313
import {z} from 'zod';
14-
import {compile} from './compiler';
14+
import {compile, type PrintedCompilerPipelineValue} from './compiler';
1515
import {
1616
CompilerPipelineValue,
1717
printReactiveFunctionWithOutlined,
@@ -22,19 +22,9 @@ import {
2222
import * as cheerio from 'cheerio';
2323
import TurndownService from 'turndown';
2424
import {queryAlgolia} from './utils/algolia';
25+
import assertExhaustive from './utils/assertExhaustive';
2526

2627
const turndownService = new TurndownService();
27-
28-
export type PrintedCompilerPipelineValue =
29-
| {
30-
kind: 'hir';
31-
name: string;
32-
fnName: string | null;
33-
value: string;
34-
}
35-
| {kind: 'reactive'; name: string; fnName: string | null; value: string}
36-
| {kind: 'debug'; name: string; fnName: string | null; value: string};
37-
3828
const server = new McpServer({
3929
name: 'React',
4030
version: '0.0.0',
@@ -114,7 +104,7 @@ server.tool(
114104
'Compile code with React Compiler. Optionally, for debugging provide a pass name like "HIR" to see more information.',
115105
{
116106
text: z.string(),
117-
passName: z.string().optional(),
107+
passName: z.enum(['HIR', 'ReactiveFunction', 'All', '@DEBUG']).optional(),
118108
},
119109
async ({text, passName}) => {
120110
const pipelinePasses = new Map<
@@ -164,8 +154,7 @@ server.tool(
164154
break;
165155
}
166156
default: {
167-
const _: never = result;
168-
throw new Error(`Unhandled result ${result}`);
157+
assertExhaustive(result, `Unhandled result ${result}`);
169158
}
170159
}
171160
};
@@ -205,6 +194,78 @@ server.tool(
205194
}
206195
const requestedPasses: Array<{type: 'text'; text: string}> = [];
207196
if (passName != null) {
197+
switch (passName) {
198+
case 'All': {
199+
const hir = pipelinePasses.get('PropagateScopeDependenciesHIR');
200+
if (hir !== undefined) {
201+
for (const pipelineValue of hir) {
202+
requestedPasses.push({
203+
type: 'text' as const,
204+
text: pipelineValue.value,
205+
});
206+
}
207+
}
208+
const reactiveFunc = pipelinePasses.get('PruneHoistedContexts');
209+
if (reactiveFunc !== undefined) {
210+
for (const pipelineValue of reactiveFunc) {
211+
requestedPasses.push({
212+
type: 'text' as const,
213+
text: pipelineValue.value,
214+
});
215+
}
216+
}
217+
break;
218+
}
219+
case 'HIR': {
220+
// Last pass before HIR -> ReactiveFunction
221+
const requestedPass = pipelinePasses.get(
222+
'PropagateScopeDependenciesHIR',
223+
);
224+
if (requestedPass !== undefined) {
225+
for (const pipelineValue of requestedPass) {
226+
requestedPasses.push({
227+
type: 'text' as const,
228+
text: pipelineValue.value,
229+
});
230+
}
231+
} else {
232+
console.error(`Could not find requested pass ${passName}`);
233+
}
234+
break;
235+
}
236+
case 'ReactiveFunction': {
237+
// Last pass
238+
const requestedPass = pipelinePasses.get('PruneHoistedContexts');
239+
if (requestedPass !== undefined) {
240+
for (const pipelineValue of requestedPass) {
241+
requestedPasses.push({
242+
type: 'text' as const,
243+
text: pipelineValue.value,
244+
});
245+
}
246+
} else {
247+
console.error(`Could not find requested pass ${passName}`);
248+
}
249+
break;
250+
}
251+
case '@DEBUG': {
252+
for (const [, pipelinePass] of pipelinePasses) {
253+
for (const pass of pipelinePass) {
254+
requestedPasses.push({
255+
type: 'text' as const,
256+
text: `${pass.name}\n\n${pass.value}`,
257+
});
258+
}
259+
}
260+
break;
261+
}
262+
default: {
263+
assertExhaustive(
264+
passName,
265+
`Unhandled passName option: ${passName}`,
266+
);
267+
}
268+
}
208269
const requestedPass = pipelinePasses.get(passName);
209270
if (requestedPass !== undefined) {
210271
for (const pipelineValue of requestedPass) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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+
/**
9+
* Trigger an exhaustiveness check in TypeScript and throw at runtime.
10+
*/
11+
export default function assertExhaustive(_: never, errorMsg: string): never {
12+
throw new Error(errorMsg);
13+
}

0 commit comments

Comments
 (0)