rnr-mcp-server
Version:
A Model Context Protocol (MCP) server for React Native Reusables components, providing AI assistants with access to component source code, demos, and metadata for React Native development.
297 lines (296 loc) • 15.6 kB
JavaScript
/**
* Resource templates implementation for the Model Context Protocol (MCP) server.
*
* This file defines resource templates that can be used to dynamically generate
* resources based on parameters in the URI.
*/
import { getFramework } from "./utils/framework.js";
/**
* Resource template definitions exported to the MCP handler
* Each template has a name, description, uriTemplate and contentType
*/
export const resourceTemplates = [
{
name: "get_install_script_for_component",
description: "Generate installation script for a specific React Native Reusables component based on package manager",
uriTemplate: "resource-template:get_install_script_for_component?packageManager={packageManager}&component={component}",
contentType: "text/plain",
},
{
name: "get_installation_guide",
description: "Get the installation guide for React Native Reusables based on build tool and package manager",
uriTemplate: "resource-template:get_installation_guide?buildTool={buildTool}&packageManager={packageManager}",
contentType: "text/plain",
},
];
// Create a map for easier access in getResourceTemplate
const resourceTemplateMap = {
get_install_script_for_component: resourceTemplates[0],
get_installation_guide: resourceTemplates[1],
};
/**
* Extract parameters from URI
* @param uri URI to extract from
* @param paramName Name of parameter to extract
* @returns Parameter value or undefined
*/
function extractParam(uri, paramName) {
const match = uri.match(new RegExp(`${paramName}=([^&]+)`));
return match?.[1];
}
/**
* Gets a resource template handler for a given URI
* @param uri The URI of the resource template
* @returns A function that generates the resource
*/
export const getResourceTemplate = (uri) => {
// Component installation script template
if (uri.startsWith("resource-template:get_install_script_for_component")) {
return async () => {
try {
const packageManager = extractParam(uri, "packageManager");
const component = extractParam(uri, "component");
if (!packageManager) {
return {
content: "Missing packageManager parameter. Please specify npm, pnpm, or yarn.",
contentType: "text/plain",
};
}
if (!component) {
return {
content: "Missing component parameter. Please specify the component name.",
contentType: "text/plain",
};
}
// Get current framework and determine package name
const framework = getFramework();
const packageName = framework === "expo"
? "@react-native-reusables/cli"
: "@react-native-reusables/cli";
// Generate installation script based on package manager
let installCommand;
switch (packageManager.toLowerCase()) {
case "npm":
installCommand = `npx ${packageName}@latest add ${component}`;
break;
case "pnpm":
installCommand = `pnpm dlx ${packageName}@latest add ${component}`;
break;
case "yarn":
installCommand = `yarn dlx ${packageName}@latest add ${component}`;
break;
case "bun":
installCommand = `bunx --bun ${packageName}@latest add ${component}`;
break;
default:
installCommand = `npx ${packageName}@latest add ${component}`;
}
return {
content: installCommand,
contentType: "text/plain",
};
}
catch (error) {
return {
content: `Error generating installation script: ${error instanceof Error ? error.message : String(error)}`,
contentType: "text/plain",
};
}
};
}
// Installation guide template
if (uri.startsWith("resource-template:get_installation_guide")) {
return async () => {
try {
const buildTool = extractParam(uri, "buildTool");
const packageManager = extractParam(uri, "packageManager");
// Get current framework first since it's used in validation
const currentFramework = getFramework();
if (!buildTool) {
return {
content: currentFramework === "expo"
? "Missing buildTool parameter. Available options: expo, react-native"
: "Missing buildTool parameter. Please specify expo, react-native, etc.",
contentType: "text/plain",
};
}
// Validate build tool for Expo
if (currentFramework === "expo" &&
!["expo", "react-native"].includes(buildTool.toLowerCase())) {
return {
content: 'Invalid build tool for Expo. Only "expo" and "react-native" are supported.',
contentType: "text/plain",
};
}
if (!packageManager) {
return {
content: "Missing packageManager parameter. Please specify npm, pnpm, or yarn.",
contentType: "text/plain",
};
}
// Determine package name
const packageName = "@react-native-reusables/cli";
// Generate installation guide based on build tool and package manager
const guides = {
expo: {
description: "Installation guide for Expo project",
steps: [
"Create an Expo project if you don't have one already:",
`${packageManager}${packageManager === "npm" ? " create" : ""} expo my-app`,
"",
"Navigate to your project directory:",
"cd my-app",
"",
"Install NativeWind (required for React Native Reusables):",
packageManager === "npm"
? `npm install nativewind`
: packageManager === "pnpm"
? `pnpm add nativewind`
: packageManager === "yarn"
? `yarn add nativewind`
: packageManager === "bun"
? `bun add nativewind`
: `npm install nativewind`,
"",
"Install React Native Reusables CLI:",
packageManager === "npm"
? `npx ${packageName}@latest init`
: packageManager === "pnpm"
? `pnpm dlx ${packageName}@latest init`
: packageManager === "yarn"
? `yarn dlx ${packageName}@latest init`
: packageManager === "bun"
? `bunx --bun ${packageName}@latest init`
: `npx ${packageName}@latest init`,
"",
"Follow the prompts to select your preferences",
"",
"Once initialized, you can add components:",
packageManager === "npm"
? `npx ${packageName}@latest add button`
: packageManager === "pnpm"
? `pnpm dlx ${packageName}@latest add button`
: packageManager === "yarn"
? `yarn dlx ${packageName}@latest add button`
: packageManager === "bun"
? `bunx --bun ${packageName}@latest add button`
: `npx ${packageName}@latest add button`,
"",
"Now you can use the component in your project!",
],
},
"react-native": {
description: "Installation guide for React Native project",
steps: [
"Create a React Native project if you don't have one already:",
`${packageManager === "npm"
? "npx"
: packageManager === "pnpm"
? "pnpm dlx"
: packageManager === "yarn"
? "yarn dlx"
: "bunx"} react-native@latest init my-app`,
"",
"Navigate to your project directory:",
"cd my-app",
"",
"Install NativeWind (required for React Native Reusables):",
packageManager === "npm"
? `npm install nativewind`
: packageManager === "pnpm"
? `pnpm add nativewind`
: packageManager === "yarn"
? `yarn add nativewind`
: packageManager === "bun"
? `bun add nativewind`
: `npm install nativewind`,
"",
"Install React Native Reusables CLI:",
packageManager === "npm"
? `npx ${packageName}@latest init`
: packageManager === "pnpm"
? `pnpm dlx ${packageName}@latest init`
: packageManager === "yarn"
? `yarn dlx ${packageName}@latest init`
: packageManager === "bun"
? `bunx --bun ${packageName}@latest init`
: `npx ${packageName}@latest init`,
"",
"Follow the prompts to select your preferences",
"",
"Once initialized, you can add components:",
packageManager === "npm"
? `npx ${packageName}@latest add button`
: packageManager === "pnpm"
? `pnpm dlx ${packageName}@latest add button`
: packageManager === "yarn"
? `yarn dlx ${packageName}@latest add button`
: packageManager === "bun"
? `bunx --bun ${packageName}@latest add button`
: `npx ${packageName}@latest add button`,
"",
"Now you can use the component in your project!",
],
},
default: {
description: "Generic installation guide for React Native",
steps: [
"Make sure you have a React Native or Expo project set up",
"",
"Install NativeWind (required for React Native Reusables):",
packageManager === "npm"
? `npm install nativewind`
: packageManager === "pnpm"
? `pnpm add nativewind`
: packageManager === "yarn"
? `yarn add nativewind`
: packageManager === "bun"
? `bun add nativewind`
: `npm install nativewind`,
"",
"Install React Native Reusables CLI:",
packageManager === "npm"
? `npx ${packageName}@latest init`
: packageManager === "pnpm"
? `pnpm dlx ${packageName}@latest init`
: packageManager === "yarn"
? `yarn dlx ${packageName}@latest init`
: packageManager === "bun"
? `bunx --bun ${packageName}@latest init`
: `npx ${packageName}@latest init`,
"",
"Follow the prompts to select your preferences",
"",
"Once initialized, you can add components:",
packageManager === "npm"
? `npx ${packageName}@latest add button`
: packageManager === "pnpm"
? `pnpm dlx ${packageName}@latest add button`
: packageManager === "yarn"
? `yarn dlx ${packageName}@latest add button`
: packageManager === "bun"
? `bunx --bun ${packageName}@latest add button`
: `npx ${packageName}@latest add button`,
"",
"Now you can use the component in your project!",
],
},
};
// Select appropriate guide based on build tool
const guide = guides[buildTool.toLowerCase()] ||
guides.default;
return {
content: `# ${guide.description} with ${packageManager}\n\n${guide.steps.join("\n")}`,
contentType: "text/plain",
};
}
catch (error) {
return {
content: `Error generating installation guide: ${error instanceof Error ? error.message : String(error)}`,
contentType: "text/plain",
};
}
};
}
return undefined;
};