Skip to main content
Glama
Sheshiyer

Framer Plugin MCP Server

by Sheshiyer

create_plugin

Build a Framer plugin project with integrated web3 features like wallet connections, contract interactions, and NFT displays. Specify the plugin name, description, and output path to get started.

Instructions

Create a new Framer plugin project with web3 capabilities

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
descriptionYesPlugin description
nameYesPlugin name
outputPathYesOutput directory path
web3FeaturesNoWeb3 features to include

Implementation Reference

  • The main handler function for the 'create_plugin' tool. It generates a complete Framer plugin project structure, including package.json with dependencies (optionally web3), TypeScript configs, Vite config, and a basic React component in src/index.tsx, with web3 wallet integration if specified.
      private async handleCreatePlugin(args: CreatePluginArgs) {
        try {
          const pluginDir = path.resolve(args.outputPath);
          await fs.ensureDir(pluginDir);
    
          // Create package.json
          const packageJson: PackageJson = {
            name: args.name,
            version: '1.0.0',
            description: args.description,
            main: 'dist/index.js',
            scripts: {
              build: 'vite build',
              dev: 'vite'
            },
            dependencies: {
              '@framer/framer.motion': '^10.0.0',
              'react': '^18.2.0',
              'react-dom': '^18.2.0'
            },
            devDependencies: {
              '@types/react': '^18.2.0',
              'typescript': '^5.0.0',
              'vite': '^4.0.0',
              '@vitejs/plugin-react': '^4.0.0'
            }
          };
    
          // Add web3 dependencies if features are requested
          if (args.web3Features?.includes('wallet-connect')) {
            packageJson.dependencies = {
              ...packageJson.dependencies,
              '@web3-react/core': '^8.2.0',
              '@web3-react/injected-connector': '^6.0.7',
              'ethers': '^6.7.0'
            };
          }
    
          await fs.writeJSON(path.join(pluginDir, 'package.json'), packageJson, { spaces: 2 });
    
          // Create tsconfig.json
          const tsConfig = {
            compilerOptions: {
              target: 'ES2020',
              lib: ['DOM', 'DOM.Iterable', 'ESNext'],
              module: 'ESNext',
              skipLibCheck: true,
              moduleResolution: 'bundler',
              allowImportingTsExtensions: true,
              resolveJsonModule: true,
              isolatedModules: true,
              noEmit: true,
              jsx: 'react-jsx',
              strict: true,
              noUnusedLocals: true,
              noUnusedParameters: true,
              noFallthroughCasesInSwitch: true
            },
            include: ['src'],
            references: [{ path: './tsconfig.node.json' }]
          };
    
          await fs.writeJSON(path.join(pluginDir, 'tsconfig.json'), tsConfig, { spaces: 2 });
    
          // Create tsconfig.node.json
          const tsNodeConfig = {
            compilerOptions: {
              composite: true,
              skipLibCheck: true,
              module: 'ESNext',
              moduleResolution: 'bundler',
              allowSyntheticDefaultImports: true
            },
            include: ['vite.config.ts']
          };
    
          await fs.writeJSON(path.join(pluginDir, 'tsconfig.node.json'), tsNodeConfig, { spaces: 2 });
    
          // Create vite.config.ts
          const viteConfig = `
    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    
    export default defineConfig({
      plugins: [react()],
      build: {
        lib: {
          entry: 'src/index.tsx',
          name: '${args.name}',
          formats: ['es'],
          fileName: 'index'
        },
        rollupOptions: {
          external: ['react', 'react-dom'],
          output: {
            globals: {
              react: 'React',
              'react-dom': 'ReactDOM'
            }
          }
        }
      }
    });
    `;
    
          await fs.writeFile(path.join(pluginDir, 'vite.config.ts'), viteConfig);
    
          // Create src directory and base files
          const srcDir = path.join(pluginDir, 'src');
          await fs.ensureDir(srcDir);
    
          // Create index.tsx
          let indexContent = `
    import { addPropertyControls, ControlType } from 'framer';
    import { motion } from 'framer-motion';
    import React from 'react';
    
    export default function ${args.name.replace(/-/g, '_')}() {
      return (
        <motion.div
          style={{
            width: 200,
            height: 200,
            backgroundColor: '#09F',
            borderRadius: 20,
          }}
          whileHover={{ scale: 1.1 }}
          whileTap={{ scale: 0.9 }}
        />
      );
    }
    
    addPropertyControls(${args.name.replace(/-/g, '_')}, {
      text: {
        type: ControlType.String,
        title: 'Text',
        defaultValue: 'Hello World',
      },
    });
    `;
    
          if (args.web3Features?.includes('wallet-connect')) {
            indexContent = `
    import { addPropertyControls, ControlType } from 'framer';
    import { motion } from 'framer-motion';
    import React from 'react';
    import { Web3ReactProvider, useWeb3React } from '@web3-react/core';
    import { InjectedConnector } from '@web3-react/injected-connector';
    import { ethers } from 'ethers';
    
    const injected = new InjectedConnector({
      supportedChainIds: [1, 3, 4, 5, 42],
    });
    
    function Web3Button() {
      const { activate, active, account, library } = useWeb3React();
    
      const connect = async () => {
        try {
          await activate(injected);
        } catch (error) {
          console.error('Error connecting:', error);
        }
      };
    
      return (
        <motion.button
          onClick={connect}
          whileHover={{ scale: 1.1 }}
          whileTap={{ scale: 0.9 }}
          style={{
            padding: '10px 20px',
            borderRadius: 8,
            backgroundColor: active ? '#4CAF50' : '#09F',
            color: 'white',
            border: 'none',
            cursor: 'pointer',
          }}
        >
          {active ? \`Connected: \${account?.slice(0, 6)}...\${account?.slice(-4)}\` : 'Connect Wallet'}
        </motion.button>
      );
    }
    
    export default function ${args.name.replace(/-/g, '_')}() {
      return (
        <Web3ReactProvider getLibrary={(provider) => new ethers.BrowserProvider(provider)}>
          <Web3Button />
        </Web3ReactProvider>
      );
    }
    
    addPropertyControls(${args.name.replace(/-/g, '_')}, {
      text: {
        type: ControlType.String,
        title: 'Text',
        defaultValue: 'Connect Wallet',
      },
    });
    `;
          }
    
          await fs.writeFile(path.join(srcDir, 'index.tsx'), indexContent);
    
          return {
            content: [
              {
                type: 'text',
                text: `Successfully created Framer plugin project at ${pluginDir}`
              }
            ]
          };
        } catch (error) {
          throw new McpError(
            ErrorCode.InternalError,
            `Failed to create plugin: ${error instanceof Error ? error.message : String(error)}`
          );
        }
      }
  • TypeScript interface defining the input arguments for the create_plugin tool.
    interface CreatePluginArgs {
      name: string;
      description: string;
      outputPath: string;
      web3Features?: string[];
    }
  • JSON schema defining the input parameters for the 'create_plugin' tool, used in tool registration.
    inputSchema: {
      type: 'object',
      properties: {
        name: {
          type: 'string',
          description: 'Plugin name'
        },
        description: {
          type: 'string',
          description: 'Plugin description'
        },
        outputPath: {
          type: 'string',
          description: 'Output directory path'
        },
        web3Features: {
          type: 'array',
          items: {
            type: 'string',
            enum: ['wallet-connect', 'contract-interaction', 'nft-display']
          },
          description: 'Web3 features to include'
        }
      },
      required: ['name', 'description', 'outputPath']
    }
  • src/index.ts:63-92 (registration)
    Tool registration in the ListTools handler, defining name, description, and input schema for 'create_plugin'.
    {
      name: 'create_plugin',
      description: 'Create a new Framer plugin project with web3 capabilities',
      inputSchema: {
        type: 'object',
        properties: {
          name: {
            type: 'string',
            description: 'Plugin name'
          },
          description: {
            type: 'string',
            description: 'Plugin description'
          },
          outputPath: {
            type: 'string',
            description: 'Output directory path'
          },
          web3Features: {
            type: 'array',
            items: {
              type: 'string',
              enum: ['wallet-connect', 'contract-interaction', 'nft-display']
            },
            description: 'Web3 features to include'
          }
        },
        required: ['name', 'description', 'outputPath']
      }
    },
  • src/index.ts:112-113 (registration)
    Dispatcher in CallToolRequest handler that routes 'create_plugin' calls to the handleCreatePlugin method.
    case 'create_plugin':
      return this.handleCreatePlugin(request.params.arguments as unknown as CreatePluginArgs);
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It states the tool creates something but doesn't mention side effects (e.g., file system changes, dependencies installation), permissions required, or error handling. This is inadequate for a creation tool with potential system impacts.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that directly states the tool's purpose without unnecessary words. It is appropriately sized and front-loaded, making it easy to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool creates a project (a complex operation) with no annotations and no output schema, the description is insufficient. It doesn't cover what the output looks like, success/failure conditions, or system requirements, leaving significant gaps for an agent to use it effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 100%, so the schema already documents all parameters well. The description adds no additional parameter semantics beyond implying 'web3 capabilities' relates to the 'web3Features' parameter. This meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Create') and resource ('new Framer plugin project with web3 capabilities'), providing a specific purpose. However, it doesn't explicitly differentiate from the sibling tool 'build_plugin' (which likely builds existing plugins rather than creating new ones), preventing a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description offers no guidance on when to use this tool versus alternatives, such as the sibling 'build_plugin'. It lacks context about prerequisites, dependencies, or scenarios where this tool is appropriate, leaving the agent without usage direction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Sheshiyer/framer-plugin-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server