Skip to main content
Glama
tesla0225

MCP Create Server

by tesla0225

create-server-from-template

Generate a custom MCP server using predefined TypeScript or Python templates. Modify code, add dependencies, and tailor functionality to meet specific requirements for server implementation.

Instructions

Create a new MCP server from a template.

以下のテンプレートコードをベースに、ユーザーの要求に合わせたサーバーを実装してください。 言語に応じて適切なテンプレートを選択し、必要に応じて機能を追加・変更してください。

TypeScriptテンプレート:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { 
  CallToolRequestSchema, 
  ListToolsRequestSchema 
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server({
  name: "dynamic-test-server",
  version: "1.0.0"
}, {
  capabilities: {
    tools: {}
  }
});

// ここでツールを実装してください
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [{
      name: "echo",
      description: "Echo back a message",
      inputSchema: {
        type: "object",
        properties: {
          message: { type: "string" }
        },
        required: ["message"]
      }
    }]
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "echo") {
    // TypeScriptの型を適切に扱うため、型アサーションを使用
    const message = request.params.arguments.message as string;
    // または any を使う: const message: any = request.params.arguments.message;
    
    return {
      content: [
        {
          type: "text",
          text: `Echo: ${message}`
        }
      ]
    };
  }
  throw new Error("Tool not found");
});

// Server startup
const transport = new StdioServerTransport();
server.connect(transport);

Pythonテンプレート:

import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server

app = Server("dynamic-test-server")

@app.list_tools()
async def list_tools():
    return [
        {
            "name": "echo",
            "description": "Echo back a message",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "message": {"type": "string"}
                },
                "required": ["message"]
            }
        }
    ]

@app.call_tool()
async def call_tool(name, arguments):
    if name == "echo":
        return [{"type": "text", "text": f"Echo: {arguments.get('message')}"}]
    raise ValueError(f"Tool not found: {name}")

async def main():
    async with stdio_server() as streams:
        await app.run(
            streams[0],
            streams[1],
            app.create_initialization_options()
        )

if __name__ == "__main__":
    asyncio.run(main())

注意事項:

  • TypeScript実装時は、引数の型を適切に扱うために型アサーション(as string)を使用するか、 明示的に型を宣言してください(例:const value: string = request.params.arguments.someValue)。

  • 複雑な型を扱う場合は、interface や type を定義して型安全性を確保することをお勧めします。

ユーザーの要求に応じて上記のテンプレートを参考にカスタマイズしてください。その際、基本的な構造を維持しつつ、ツール名や機能を変更できます。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codeNoカスタマイズしたサーバーコード。テンプレートを元に変更したコードを入力してください。省略した場合はデフォルトのテンプレートが使用されます。
dependenciesNo使用するライブラリとそのバージョン(例: { "axios": "^1.0.0" })
languageYesThe programming language for the template

Implementation Reference

  • Handler logic for the 'create-server-from-template' tool. Parses arguments, determines server code (custom or default template based on language), and calls serverManager.createServer to instantiate the MCP server with optional dependencies.
    case "create-server-from-template": {
      const args = request.params
        .arguments as unknown as CreateServerFromTemplateArgs;
      if (!args.language) {
        throw new Error("Missing required argument: language");
      }
    
      // LLMから提供されたカスタムコードがあればそれを使用し、なければデフォルトのテンプレートを使用
      let serverCode = args.code;
    
      // コードが提供されていない場合はデフォルトテンプレートを使用
      if (!serverCode) {
        // 既存のテンプレート選択ロジック
        switch (args.language) {
          case "typescript":
            serverCode = `/* TypeScriptテンプレート */`;
            break;
          case "python":
            serverCode = `# Pythonテンプレート`;
            break;
          default:
            throw new Error(
              `Unsupported template language: ${args.language}`
            );
        }
      }
    
      const result = await serverManager.createServer(
        serverCode,
        args.language,
        args.dependencies
      );
    
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify({
              serverId: result,
              message: args.code
                ? `Created server from custom code in ${args.language}`
                : `Created server from ${args.language} template`,
            }),
          },
        ],
      };
    }
  • Tool definition including name, detailed description with embedded templates for TypeScript and Python, and inputSchema defining parameters: language (required, enum), optional code, and dependencies.
    const createServerFromTemplateTool: Tool = {
      name: "create-server-from-template",
      description: `Create a new MCP server from a template.
      
      以下のテンプレートコードをベースに、ユーザーの要求に合わせたサーバーを実装してください。
      言語に応じて適切なテンプレートを選択し、必要に応じて機能を追加・変更してください。
      
      TypeScriptテンプレート:
      \`\`\`typescript
      import { Server } from "@modelcontextprotocol/sdk/server/index.js";
      import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
      import { 
        CallToolRequestSchema, 
        ListToolsRequestSchema 
      } from "@modelcontextprotocol/sdk/types.js";
    
      const server = new Server({
        name: "dynamic-test-server",
        version: "1.0.0"
      }, {
        capabilities: {
          tools: {}
        }
      });
    
      // ここでツールを実装してください
      server.setRequestHandler(ListToolsRequestSchema, async () => {
        return {
          tools: [{
            name: "echo",
            description: "Echo back a message",
            inputSchema: {
              type: "object",
              properties: {
                message: { type: "string" }
              },
              required: ["message"]
            }
          }]
        };
      });
    
      server.setRequestHandler(CallToolRequestSchema, async (request) => {
        if (request.params.name === "echo") {
          // TypeScriptの型を適切に扱うため、型アサーションを使用
          const message = request.params.arguments.message as string;
          // または any を使う: const message: any = request.params.arguments.message;
          
          return {
            content: [
              {
                type: "text",
                text: \`Echo: \${message}\`
              }
            ]
          };
        }
        throw new Error("Tool not found");
      });
    
      // Server startup
      const transport = new StdioServerTransport();
      server.connect(transport);
      \`\`\`
      
      Pythonテンプレート:
      \`\`\`python
      import asyncio
      from mcp.server import Server
      from mcp.server.stdio import stdio_server
    
      app = Server("dynamic-test-server")
    
      @app.list_tools()
      async def list_tools():
          return [
              {
                  "name": "echo",
                  "description": "Echo back a message",
                  "inputSchema": {
                      "type": "object",
                      "properties": {
                          "message": {"type": "string"}
                      },
                      "required": ["message"]
                  }
              }
          ]
    
      @app.call_tool()
      async def call_tool(name, arguments):
          if name == "echo":
              return [{"type": "text", "text": f"Echo: {arguments.get('message')}"}]
          raise ValueError(f"Tool not found: {name}")
    
      async def main():
          async with stdio_server() as streams:
              await app.run(
                  streams[0],
                  streams[1],
                  app.create_initialization_options()
              )
    
      if __name__ == "__main__":
          asyncio.run(main())
      \`\`\`
      
      注意事項:
      - TypeScript実装時は、引数の型を適切に扱うために型アサーション(as string)を使用するか、
        明示的に型を宣言してください(例:const value: string = request.params.arguments.someValue)。
      - 複雑な型を扱う場合は、interface や type を定義して型安全性を確保することをお勧めします。
      
      ユーザーの要求に応じて上記のテンプレートを参考にカスタマイズしてください。その際、基本的な構造を維持しつつ、ツール名や機能を変更できます。`,
      inputSchema: {
        type: "object",
        properties: {
          language: {
            type: "string",
            enum: ["typescript", "python"],
            description: "The programming language for the template",
          },
          code: {
            type: "string",
            description:
              "カスタマイズしたサーバーコード。テンプレートを元に変更したコードを入力してください。省略した場合はデフォルトのテンプレートが使用されます。",
          },
          dependencies: {
            type: "object",
            description: "使用するライブラリとそのバージョン(例: { \"axios\": \"^1.0.0\" })",
          },
        },
        required: ["language"],
      },
    };
  • index.ts:1011-1022 (registration)
    Registration of the tool in the ListToolsRequest handler, where createServerFromTemplateTool is included in the returned tools list.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      console.error("Received ListToolsRequest");
      return {
        tools: [
          createServerFromTemplateTool,
          executeToolTool,
          getServerToolsTool,
          deleteServerTool,
          listServersTool,
        ],
      };
    });
  • Core helper method in ServerManager class that implements the actual server creation logic called by the tool handler. Handles temp dir setup, deps install (npm/pip), code compilation (TS), process spawn, and MCP client connection.
    async createServer(
      code: string, 
      language: string,
      dependencies?: Record<string, string>
    ): Promise<string> {
      const serverId = uuidv4();
      const serverDir = path.join(this.serversDir, serverId);
    
      try {
        // Create server directory
        await fs.mkdir(serverDir, { recursive: true });
        await fs.chmod(serverDir, 0o777); // 権限を追加
    
        // 依存関係がある場合はインストール(シンボリックリンクは作成しない)
        if (dependencies && Object.keys(dependencies).length > 0) {
          await this.installDependencies(serverDir, dependencies, language);
        } else {
          // 依存関係がない場合のみシンボリックリンクを作成
          try {
            await fs.symlink(
              "/app/node_modules",
              path.join(serverDir, "node_modules")
            );
            console.error(`Created symlink to node_modules in ${serverDir}`);
          } catch (error) {
            console.error(`Error creating symlink: ${error}`);
            // エラーがあっても続行する
          }
        }
    
        // Write server code to file
        let filePath: string;
        let command: string;
        let args: string[] = [];
    
        // 共通の環境変数設定
        const appNodeModules = path.resolve("/app/node_modules");
        const commonEnv = {
          ...process.env,
          PATH: process.env.PATH || "/usr/local/bin:/usr/bin:/bin",
          NODE_PATH: appNodeModules,
        };
    
        console.error(`Current PATH: ${process.env.PATH}`);
        console.error(`Current NODE_PATH: ${process.env.NODE_PATH}`);
    
        switch (language) {
          case "typescript":
            filePath = path.join(serverDir, "index.ts");
            const jsFilePath = path.join(serverDir, "index.js");
            const tsConfigPath = path.join(__dirname, "tsconfig.json");
    
            await fs.writeFile(filePath, code);
    
            // 絶対パスを取得して出力
            command = await getCommandPath("npx");
            console.error(`Using command path for npx: ${command}`);
    
            // TypeScriptをコンパイルする方法に変更
            await new Promise<void>((resolve, reject) => {
              const tscCommand = "npx";
              const tscArgs = [
                "tsc",
                "--allowJs",
                filePath,
                "--outDir",
                serverDir,
                "--target",
                "ES2020",
                "--module",
                "NodeNext",
                "--moduleResolution",
                "NodeNext",
                "--esModuleInterop",
                "--skipLibCheck",
                "--resolveJsonModule",
              ];
    
    
              console.error(
                `Compiling TypeScript: ${tscCommand} ${tscArgs.join(" ")}`
              );
    
              const compileProcess = spawn(tscCommand, tscArgs, {
                stdio: ["ignore", "pipe", "pipe"],
                shell: true,
                env: commonEnv,
                cwd: "/app", // アプリケーションのルートディレクトリを指定
              });
    
              compileProcess.stdout.on("data", (data) => {
                console.error(`TSC stdout: ${data}`);
              });
    
              compileProcess.stderr.on("data", (data) => {
                console.error(`TSC stderr: ${data}`);
              });
    
              compileProcess.on("exit", (code) => {
                if (code === 0) {
                  console.error(`TypeScript compilation successful`);
                  resolve();
                } else {
                  console.error(
                    `TypeScript compilation failed with code ${code}`
                  );
                  reject(
                    new Error(`TypeScript compilation failed with code ${code}`)
                  );
                }
              });
            });
    
            // コンパイルされたJavaScriptを実行
            command = await getCommandPath("node");
            args = [jsFilePath];
            break;
    
          case "javascript":
            filePath = path.join(serverDir, "index.js");
            await fs.writeFile(filePath, code);
            command = await getCommandPath("node");
            args = [filePath];
            break;
    
          case "python":
            filePath = path.join(serverDir, "server.py");
            await fs.writeFile(filePath, code);
            command = await getCommandPath("python");
            args = [filePath];
            break;
    
          default:
            throw new Error(`Unsupported language: ${language}`);
        }
    
        console.error(`Spawning process: ${command} ${args.join(" ")}`);
    
        // サーバープロセスを起動(パイプに変更)
        const childProcess = spawn(command, args, {
          stdio: ["pipe", "pipe", "pipe"], // inheritではなくpipeを使用
          shell: true,
          env: commonEnv,
          cwd: process.cwd(),
        });
    
        // 標準エラー出力のログ取得
        childProcess.stderr.on("data", (data) => {
          console.error(`Child process stderr: ${data}`);
        });
    
        // 標準出力のログ取得
        childProcess.stdout.on("data", (data) => {
          console.error(`Child process stdout: ${data}`);
        });
    
        // Create MCP client to communicate with the server
        const transport = new StdioClientTransport({
          command,
          args,
          env: commonEnv, // 同じ環境変数を使用
        });
    
        const client = new Client(
          {
            name: "mcp-create-client",
            version: "1.0.0",
          },
          {
            capabilities: {
              tools: {},
            },
          }
        );
    
        try {
          await client.connect(transport);
          console.error(`Connected to server ${serverId}`);
        } catch (error) {
          console.error(`Error connecting to server ${serverId}:`, error);
          childProcess.kill();
          throw error;
        }
    
        // Store server info
        this.servers.set(serverId, {
          process: childProcess,
          client,
          transport,
          language,
          filePath,
        });
    
        // Handle process exit
        childProcess.on("exit", (code) => {
          console.error(`Server ${serverId} exited with code ${code}`);
          this.servers.delete(serverId);
        });
    
        return serverId;
      } catch (error) {
        // Clean up on error
        console.error(`Error creating server:`, error);
        try {
          await fs.rm(serverDir, { recursive: true, force: true });
        } catch (cleanupError) {
          console.error(`Error cleaning up server directory: ${cleanupError}`);
        }
    
        throw error;
      }
    }
  • TypeScript interface defining the expected arguments for the create-server-from-template tool, used for type casting in the handler.
    interface CreateServerFromTemplateArgs {
      language: "typescript" | "python";
      code?: string;
      dependencies?: Record<string, string>; // 例: { "axios": "^1.0.0" }
    }
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/tesla0225/mcp-create'

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