Skip to main content
Glama

JoeMCP

migration.md11.6 kB
# TypeScript with Smithery CLI > Migrate your TypeScript MCP servers to Streamable HTTP, with STDIO support for backwards compatibility ## When to Use This Approach Choose TypeScript with Smithery CLI when you: * Want the simplest migration path from STDIO to HTTP * Are using the official MCP SDK and don't need custom middleware * Want Smithery to handle containerization and deployment * Want to maintain backward compatibility with STDIO transport * Need a fully featured interactive development playground for testing <Card title="Show me the repo" icon="github" href="https://github.com/smithery-ai/smithery-cookbook/tree/main/servers/typescript/migrate_stdio_to_http/server_with_smithery_cli"> View the fully runnable GitHub repo for this example </Card> ## What We're Building We'll build a simple MCP server with a `count_characters` tool that: * Takes text input and counts occurrences of a specific character * Validates an API key from Smithery configuration to demonstrate configuration handling * Uses Smithery CLI for building the server and containerization * Supports both HTTP and STDIO transport ## Code Migration ### Let's say you start with this... Here's a typical STDIO-based MCP server that you might be starting with: ```typescript theme={null} // src/index.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create STDIO server const server = new McpServer({ name: "Character Counter", version: "1.0.0" }); // Get case sensitivity from environment variable const caseSensitive = process.env.CASE_SENSITIVE === 'true'; // Register tool server.registerTool("count_characters", { description: "Count occurrences of a specific character in text", inputSchema: { text: { type: "string", description: "The text to search in" }, character: { type: "string", description: "The character to count" } } }, async ({ text, character }) => { // Tool implementation with API key validation, etc. // ... }); // Run with STDIO transport const transport = new StdioServerTransport(); await server.server.connect(transport); ``` ### Step 1: Update Imports and Configuration Schema Now let's migrate this to work with Smithery CLI. First, update your imports and define your configuration schema: ```typescript theme={null} // src/index.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Define session configuration schema export const configSchema = z.object({ caseSensitive: z.boolean().optional().default(false).describe("Whether character matching should be case sensitive"), }); ``` <Note> **Configuration is Optional**: If your MCP server doesn't need any configuration (API keys, settings, etc.), you can remove all the config schema and validation code. The server will work perfectly fine without it. </Note> ### Step 2: Create Server Function and Register Tools Create the exported server function that Smithery CLI will use: ```typescript theme={null} // src/index.ts export default function createServer({ config, }: { config: z.infer<typeof configSchema>; }) { const server = new McpServer({ name: "Character Counter", version: "1.0.0", }); server.registerTool("count_characters", { title: "Count Characters", description: "Count occurrences of a specific character in text", inputSchema: { text: z.string().describe("The text to search in"), character: z.string().describe("The character to count (single character)"), }, }, async ({ text, character }) => { // Apply user preferences from config const searchText = config.caseSensitive ? text : text.toLowerCase(); const searchChar = config.caseSensitive ? character : character.toLowerCase(); // Count occurrences of the specific character const count = searchText.split(searchChar).length - 1; return { content: [ { type: "text", text: `The character "${character}" appears ${count} times in the text.` } ], }; } ); return server.server; } ``` ### Step 3: Maintaining STDIO Compatibility (Optional) Now that we have our `createServer` function ready for Smithery CLI, we can optionally add STDIO support for backward compatibility. This gives you the best of both worlds: * **HTTP deployment**: Smithery CLI uses your exported `createServer` function for scalable HTTP deployment * **Local development**: Keep the familiar STDIO transport for backwards compatibility * **NPM distribution**: Publish your server so others can install and run it locally To enable STDIO support, add a `main()` function at the bottom of your file: ```typescript theme={null} // src/index.ts async function main() { // Check if case sensitivity is enabled const caseSensitive = process.env.CASE_SENSITIVE === 'true'; // Create server with configuration const server = createServer({ config: { caseSensitive, }, }); const transport = new StdioServerTransport(); await server.connect(transport); console.error("MCP Server running in stdio mode"); } // By default run the server with stdio transport main().catch((error) => { console.error("Server error:", error); process.exit(1); }); ``` <Note> **How it works**: When you deploy with Smithery CLI, it imports and uses your exported `createServer` function for HTTP transport. The `main()` function only runs when you execute the file directly (like `node dist/index.js`), giving you STDIO support for local development. </Note> ## Configuration Changes ### Step 4: Update package.json Configure `package.json` so Smithery CLI can find your exported server and add scripts for both HTTP and STDIO workflows: ```json theme={null} { "name": "my-mcp-server", "version": "1.0.0", "type": "module", "module": "src/index.ts", // [!code highlight] "scripts": { "dev": "smithery dev", "build": "npm run build:http", "build:stdio": "tsc", "build:http": "smithery build", // [!code highlight] "start": "npm run start:http", "start:http": "node .smithery/index.cjs", "start:stdio": "node dist/index.js", "prepublishOnly": "npm run build:stdio" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.18.2", "@smithery/sdk": "^1.6.4", "zod": "^3.25.46" }, "devDependencies": { "@smithery/cli": "^1.4.0" } } ``` **Important**: The `module` field tells Smithery CLI where to find your exported server function. **Script explanations:** * `dev`: Start development server with interactive playground * `build`: Build for production (defaults to HTTP) * `build:stdio`: Compile TypeScript for STDIO usage * `build:http`: Build for Smithery HTTP deployment * `start`: Start production server (defaults to HTTP) * `start:http`: Run the Smithery-built HTTP server * `start:stdio`: Run the compiled STDIO version locally * `prepublishOnly`: Ensure STDIO build before publishing to npm ### Step 5: Update smithery.yaml <CodeGroup> ```yaml Before (STDIO) theme={null} startCommand: type: stdio commandFunction: | (config) => ({ command: 'npx', args: ['tsx', 'src/index.ts'], env: { CASE_SENSITIVE: config.caseSensitive } }) configSchema: type: object properties: caseSensitive: type: boolean description: Whether character matching should be case sensitive default: false exampleConfig: caseSensitive: false ``` ```yaml After (HTTP) theme={null} runtime: "typescript" ``` </CodeGroup> That's it! The Smithery CLI handles the HTTP transport automatically. <Note> **No Dockerfile needed**: Unlike custom container deployments, TypeScript projects using Smithery CLI don't require a Dockerfile. The CLI handles containerization automatically. </Note> <Tip> Install the CLI locally with: ```bash theme={null} npm i -D @smithery/cli ``` Add your SDK dependency explicitly: ```bash theme={null} npm i @modelcontextprotocol/sdk @smithery/sdk ``` </Tip> ## Local Testing 1. **Using Smithery Interactive Playground:** ```bash theme={null} # Start development server with interactive playground npm run dev ``` The `npm run dev` command opens the **Smithery interactive playground** where you can: * Test your MCP server tools in real-time * See tool responses and debug issues * Validate your configuration schema * Experiment with different inputs <img src="https://mintcdn.com/smithery/VM0SEWDjb0U0Bzut/images/smithery_playground.png?fit=max&auto=format&n=VM0SEWDjb0U0Bzut&q=85&s=3c78c452c84004d16526e7db38804ee7" alt="Smithery Interactive Playground" className="rounded-lg shadow-sm" data-og-width="2834" width="2834" data-og-height="1550" height="1550" data-path="images/smithery_playground.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/smithery/VM0SEWDjb0U0Bzut/images/smithery_playground.png?w=280&fit=max&auto=format&n=VM0SEWDjb0U0Bzut&q=85&s=7211d8414733b79c937e055e0828948b 280w, https://mintcdn.com/smithery/VM0SEWDjb0U0Bzut/images/smithery_playground.png?w=560&fit=max&auto=format&n=VM0SEWDjb0U0Bzut&q=85&s=9500535816ca56ddba79940f0ffd8aab 560w, https://mintcdn.com/smithery/VM0SEWDjb0U0Bzut/images/smithery_playground.png?w=840&fit=max&auto=format&n=VM0SEWDjb0U0Bzut&q=85&s=e21c3731eb81e819130d20e4b944481b 840w, https://mintcdn.com/smithery/VM0SEWDjb0U0Bzut/images/smithery_playground.png?w=1100&fit=max&auto=format&n=VM0SEWDjb0U0Bzut&q=85&s=ae91295d266f5d674ca99f4103fac2df 1100w, https://mintcdn.com/smithery/VM0SEWDjb0U0Bzut/images/smithery_playground.png?w=1650&fit=max&auto=format&n=VM0SEWDjb0U0Bzut&q=85&s=2ebcd4ce7e6c94228bc2725b08d24c6a 1650w, https://mintcdn.com/smithery/VM0SEWDjb0U0Bzut/images/smithery_playground.png?w=2500&fit=max&auto=format&n=VM0SEWDjb0U0Bzut&q=85&s=4532e4de8d07ff12ad7f88ec78a92abd 2500w" /> 2. **Building for Production:** ```bash theme={null} # Build your server for deployment npm run build ``` This compiles your TypeScript code and prepares it for deployment on Smithery. 3. **Testing STDIO mode locally:** ```bash theme={null} # Build TypeScript code npm run build:stdio # Run in STDIO mode CASE_SENSITIVE=true npm run start:stdio ``` ## Deployment 1. **Push Code**: Push your updated code (including updated `package.json` and `smithery.yaml`) to GitHub 2. **Deploy**: Go to [smithery.ai/new](https://smithery.ai/new) and connect your GitHub repository 3. **Verify**: Test your deployed server through the Smithery interface The TypeScript runtime handles HTTP transport automatically - no additional configuration needed. ## Summary This guide showed how to migrate a TypeScript MCP server from STDIO to HTTP transport using Smithery CLI. We transformed a traditional STDIO server into an exported `createServer` function using the official `McpServer` from the SDK, configured session handling with Zod, and updated `package.json` and `smithery.yaml` for automatic containerization. This approach provides the simplest migration path while supporting both HTTP deployment through Smithery CLI and optional STDIO backward compatibility. *** **Need help?** Join our [Discord](https://discord.gg/Afd38S5p9A) or email [support@smithery.ai](mailto:support@smithery.ai) for assistance.

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/lumberjack-so/joeMCP'

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