Skip to main content
Glama

deploy-template

Search for Railway templates using fuzzy search and deploy selected templates to your current project and environment.

Instructions

Search and deploy Railway templates. This tool will search for templates using fuzzy search and automatically deploy the selected template to the current Railway project and environment.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
workspacePathYesThe path to the workspace to deploy the template to
searchQueryYesSearch query to filter templates by name, description, or category
templateIndexNoIndex of the template to deploy (required if multiple templates found)
teamIdNoThe ID of the team (optional)

Implementation Reference

  • The complete MCP tool object definition for 'deploy-template', including name, title, description, Zod inputSchema, and the async handler function that orchestrates template search, selection, project linking, and deployment using API helpers.
    export const deployTemplateTool = { name: "deploy-template", title: "Deploy Railway Template", description: "Search and deploy Railway templates. This tool will search for templates using fuzzy search and automatically deploy the selected template to the current Railway project and environment.", inputSchema: { workspacePath: z .string() .describe("The path to the workspace to deploy the template to"), searchQuery: z .string() .describe( "Search query to filter templates by name, description, or category", ), templateIndex: z .number() .optional() .describe( "Index of the template to deploy (required if multiple templates found)", ), teamId: z.string().optional().describe("The ID of the team (optional)"), }, handler: async ({ workspacePath, searchQuery, templateIndex, teamId, }: DeployTemplateOptions) => { try { // Search and list templates const { templates, filteredCount, totalCount } = await searchAndListTemplates({ searchQuery }); if (templates.length === 0) { return createToolResponse( `🔍 No templates found matching "${searchQuery}".\n\n` + `**Total templates available:** ${totalCount}\n\n` + `**Suggestions:**\n` + `• Try a different search term\n` + `• Use broader keywords\n` + `• Check your internet connection`, ); } // If multiple templates found and no index specified, show the list if (templates.length > 1 && templateIndex === undefined) { const templateList = templates .map((template: Template, index: number) => { const verifiedBadge = template.isVerified ? "verified" : "unverified"; return ( `${index + 1}. **${template.name}** - (${verifiedBadge})\n` + ` ID: \`${template.id}\`\n` + ` Description: ${template.description || "No description available"}\n` + ` Category: ${template.category}\n` + ` Active Projects: ${template.activeProjects} | Health: ${template.health} | Payout: ${template.totalPayout}` ); }) .join("\n\n"); return createToolResponse( `🔍 Multiple templates found matching "${searchQuery}":\n\n` + `**Showing ${filteredCount} of ${totalCount} templates:**\n\n` + templateList + `\n\n**Please specify which template to deploy by providing:**\n` + `• templateIndex: [1-${templates.length}]`, ); } // Get the template to deploy let templateToDeploy: Template; if (templates.length === 1) { templateToDeploy = templates[0]; } else if (templateIndex !== undefined) { if (templateIndex < 1 || templateIndex > templates.length) { return createToolResponse( `❌ Invalid template index: ${templateIndex}\n\n` + `**Valid range:** 1-${templates.length}\n\n` + `Please provide a valid template index.`, ); } templateToDeploy = templates[templateIndex - 1]; } else { // This shouldn't happen, but just in case return createToolResponse( "❌ Unexpected error: Multiple templates found but no index specified.", ); } // Get current project and environment IDs from Railway context const projectResult = await getLinkedProjectInfo({ workspacePath }); if (!projectResult.success || !projectResult.project) { return createToolResponse( "❌ No Railway project is linked to this workspace.\n\n" + "**Next Steps:**\n" + "• Run `railway link` to connect to a project\n" + "• Or use the `create-project-and-link` tool to create a new project", ); } const currentProjectId = projectResult.project.id; const currentEnvironmentId = await getCurrentEnvironmentId({ workspacePath, }); // Deploy the template const result = await deployTemplate({ environmentId: currentEnvironmentId, projectId: currentProjectId, serializedConfig: templateToDeploy.serializedConfig, templateId: templateToDeploy.id, teamId, }); return createToolResponse( `✅ Successfully deployed Railway template:\n\n` + `**Template:** ${templateToDeploy.name}\n` + `**Template ID:** ${templateToDeploy.id}\n` + `**Project:** ${projectResult.project.name} (${currentProjectId})\n` + `**Environment:** ${currentEnvironmentId}\n` + `**Workflow ID:** ${result.workflowId}\n\n` + `The template has been deployed successfully to the current Railway project and environment.`, ); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; return createToolResponse( "❌ Failed to search/deploy Railway template\n\n" + `**Error:** ${errorMessage}\n\n` + "**Next Steps:**\n" + "• Check your internet connection\n" + "• Verify that Railway's API is accessible\n" + "• Make sure you're authenticated with Railway (`railway login`)", ); } }, };
  • Zod-based input schema defining the parameters for the deploy-template tool: workspacePath, searchQuery, optional templateIndex and teamId.
    inputSchema: { workspacePath: z .string() .describe("The path to the workspace to deploy the template to"), searchQuery: z .string() .describe( "Search query to filter templates by name, description, or category", ), templateIndex: z .number() .optional() .describe( "Index of the template to deploy (required if multiple templates found)", ), teamId: z.string().optional().describe("The ID of the team (optional)"), },
  • src/tools/index.ts:5-5 (registration)
    Registration/export of the deployTemplateTool in the tools index, making it available for the MCP server.
    export { deployTemplateTool } from "./deploy-template";
  • Helper function that performs the actual template deployment via Railway GraphQL API mutation templateDeployV2.
    export const deployTemplate = async ({ environmentId, projectId, serializedConfig, templateId, teamId, }: { environmentId: string; projectId: string; serializedConfig: SerializedTemplateConfig; templateId: string; teamId?: string; }): Promise<TemplateDeployResponse> => { const query = ` mutation deployTemplate($environmentId: String, $projectId: String, $templateId: String!, $teamId: String, $serializedConfig: SerializedTemplateConfig!) { templateDeployV2(input: { environmentId: $environmentId, projectId: $projectId, templateId: $templateId, teamId: $teamId, serializedConfig: $serializedConfig }) { projectId workflowId } } `; try { const token = getRailwayAuthToken(); const client = new GraphQLClient( "https://backboard.railway.com/graphql/v2", { headers: { Authorization: `Bearer ${token}`, "x-source": "railway-mcp-server", }, }, ); const data = await client.request<{ templateDeployV2: TemplateDeployResponse; }>(query, { environmentId, projectId, templateId, teamId, serializedConfig, }); return data.templateDeployV2; } catch (error: unknown) { if (error instanceof Error) { throw new Error(`Failed to deploy template: ${error.message}`); } throw new Error("Failed to deploy template: Unknown error"); } };
  • Helper function to fetch, sort (verified/payout/active/health), and fuzzy search Railway templates.
    export const searchAndListTemplates = async ({ searchQuery, }: { searchQuery?: string; }): Promise<{ templates: Template[]; filteredCount: number; totalCount: number; }> => { const query = ` query { templates { edges { node { id name description category serializedConfig activeProjects health totalPayout isVerified } } } } `; try { const client = new GraphQLClient( "https://backboard.railway.com/graphql/v2", { headers: { "x-source": "railway-mcp-server", }, }, ); const data = await client.request<{ templates: { edges: Array<{ node: Template; }>; }; }>(query); const templates = data.templates.edges.map( (edge) => edge.node, ) as Template[]; const totalCount = templates.length; // Sort templates based on the specified criteria (verified templates first, then by totalPayout, then by activeProjects, then by health) const sortedTemplates = templates.sort((a: Template, b: Template) => { if (a.isVerified && !b.isVerified) return -1; if (!a.isVerified && b.isVerified) return 1; if (a.totalPayout !== b.totalPayout) { return (b.totalPayout || 0) - (a.totalPayout || 0); } if (a.activeProjects !== b.activeProjects) { return (b.activeProjects || 0) - (a.activeProjects || 0); } if (a.health !== b.health) { return (b.health || 0) - (a.health || 0); } // If all criteria are equal, maintain original order return 0; }); // If no search query provided, return all sorted templates if (!searchQuery || searchQuery.trim() === "") { return { templates: sortedTemplates, filteredCount: totalCount, totalCount, }; } // Configure Fuse.js for fuzzy search const fuse = new Fuse(sortedTemplates, { keys: ["name", "description", "category"], threshold: 0.3, // Lower threshold = more strict matching includeScore: true, includeMatches: true, }); // Perform fuzzy search const searchResults = fuse.search(searchQuery.trim()); const filteredTemplates = searchResults.map((result) => result.item); return { templates: filteredTemplates, filteredCount: filteredTemplates.length, totalCount, }; } catch (error: unknown) { if (error instanceof Error) { throw new Error(`Failed to search Railway templates: ${error.message}`); } throw new Error("Failed to search Railway templates: Unknown error"); } };

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/railwayapp/railway-mcp-server'

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