Skip to content

MCP Server Templates

MCP Server Templates enable dynamic, context-aware server configuration. Instead of hardcoding server settings, you can define template configurations that automatically adapt based on runtime context like the current project, user, environment, or client connection.

Overview

Templates allow you to:

  • Dynamic server creation: Spawn different servers based on project context
  • Environment-aware configuration: Automatically adjust settings per environment
  • Context enrichment: Inject project-specific metadata into server configurations
  • Conditional enablement: Enable/disable servers based on runtime conditions

Templates vs. Static Servers

1MCP supports two types of server configurations:

FeatureStatic Servers (mcpServers)Template Servers (mcpTemplates)
ConfigurationFixed values at startupDynamic values based on context
Context awarenessNoneProject, user, transport, client
Multiple instancesSingle instance per configMultiple instances per context
LifecycleAlways runningCreated on-demand per connection
Use caseStable infrastructureDynamic, context-specific tools

Key Difference from Instruction Templates

MCP Server Templates (mcpTemplates) configure server instances with dynamic values like:

  • {{project.path}} - Project directory path
  • {{user.username}} - Current user

Instruction Templates customize LLM instructions with variables like:

  • {{serverCount}} - Number of connected servers
  • {{serverNames}} - List of server names

Quick Start

Basic Template Example

Add a template to your mcp.json:

json
{
  "mcpTemplates": {
    "project-context": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "{{project.path}}"],
      "tags": ["filesystem", "project"]
    }
  }
}

When a client connects, 1MCP:

  1. Collects context (project path, user, environment)
  2. Renders the template with actual values
  3. Creates a server instance with the rendered configuration
  4. Connects the client to the new instance

Environment-Specific Configuration

json
{
  "mcpTemplates": {
    "conditional-server": {
      "command": "node",
      "args": ["{{project.path}}/server.js"],
      "env": {
        "NODE_ENV": "{{project.environment}}",
        "DEBUG": "{{#if (eq project.environment 'development')}}true{{else}}false{{/if}}"
      },
      "disabled": "{{#if (eq project.environment 'production')}}true{{else}}false{{/if}}",
      "tags": ["development"]
    }
  }
}

Template Variables

Templates have access to four namespaces of context variables:

Project Variables (project.*)

VariableTypeDescriptionExample
project.pathstringAbsolute path to current project/Users/dev/myapp
project.namestringProject directory namemyapp
project.environmentstringEnvironment namedevelopment
project.git.branchstring?Git branch namemain
project.git.commitstring?Git commit hasha1b2c3d
project.git.repositorystring?Git remote URLhttps://github.com/user/repo
project.custom.*anyCustom values from .1mcprcUser-defined

User Variables (user.*)

VariableTypeDescriptionExample
user.usernamestring?System usernamedeveloper
user.namestring?User's full nameJane Developer
user.emailstring?User emailjane@example.com
user.homestring?Home directory path/Users/developer
user.uidstring?User ID501
user.gidstring?Group ID20
user.shellstring?Default shell/bin/zsh

Transport Variables (transport.*)

VariableTypeDescriptionExample
transport.typestringTransport protocolhttp, sse, stdio
transport.urlstring?Server URL (HTTP/SSE)http://localhost:3050
transport.connectionIdstring?Connection identifierconn_xyz789
transport.connectionTimestampstring?Connection time2025-01-25T10:30:00Z
transport.client.namestringClient application namecursor, claude-code
transport.client.versionstringClient version1.0.0
transport.client.titlestring?Client display nameCursor Editor

Template Syntax

1MCP uses Handlebars for template rendering. Variables use double curly braces: {{variable}}.

Variable Access

text
{{project.path}}              <!-- /Users/dev/project -->
{{user.username}}             <!-- developer -->
{{transport.client.name}}     <!-- cursor -->
{{project.custom.teamId}}     <!-- Custom value from .1mcprc -->

Conditionals

Use {{#if}} for conditional logic:

text

{{#if (eq project.environment 'production')}}
  <!-- Production configuration -->
{{else}}
  <!-- Development configuration -->
{{/if}}

Comparisons

Use built-in helpers for comparisons:

text
{{#if (eq project.environment 'development')}}{{/if}}
{{#if (ne user.username 'root')}}{{/if}}
{{#if (gt project.custom.count 5)}}{{/if}}
{{#if (lt transport.client.version '2.0')}}{{/if}}

Logical Operators

Combine conditions with and/or:

text
{{#if (and (eq project.environment 'production') (eq project.custom.region 'us'))}}
{{/if}}

{{#if (or (eq project.custom.team 'backend') (eq project.custom.team 'devops'))}}
{{/if}}

String Operations

text
{{#if (contains project.name 'admin')}}
{{/if}}

{{#if (startsWith project.git.branch 'feature/')}}
{{/if}}

{{#if (endsWith project.name '-test')}}
{{/if}}

Context Enrichment (.1mcprc)

Project-level context enrichment allows you to inject custom metadata into templates. Create a .1mcprc file in your project root:

json
{
  "preset": "my-team-preset",
  "tags": ["team-a", "backend"],
  "context": {
    "projectId": "myapp-backend",
    "environment": "development",
    "team": "platform",
    "custom": {
      "teamId": "team-a",
      "region": "us-west",
      "debugMode": true,
      "apiEndpoint": "https://dev-api.example.com"
    },
    "envPrefixes": ["MYAPP_*", "TEAM_*"],
    "includeGit": true,
    "sanitizePaths": true
  }
}

Context Fields

FieldTypeDescription
presetstringDefault preset to use
tagsstring|string[]Default tags for filtering
context.projectIdstringProject identifier
context.environmentstringEnvironment name (development, staging, production)
context.teamstringTeam name
context.customobjectCustom key-value pairs
context.envPrefixesstring[]Environment variable prefixes to include
context.includeGitbooleanInclude Git information
context.sanitizePathsbooleanSanitize file paths for security

Accessing Custom Context

Custom values are available as {{project.custom.*}}:

json
{
  "mcpTemplates": {
    "team-server": {
      "command": "npx",
      "args": ["-y", "serena", "{{project.path}}"],
      "env": {
        "TEAM_ID": "{{project.custom.teamId}}",
        "REGION": "{{project.custom.region}}",
        "API_ENDPOINT": "{{project.custom.apiEndpoint}}",
        "DEBUG": "{{#if project.custom.debugMode}}true{{else}}false{{/if}}"
      },
      "tags": ["{{project.custom.team}}"]
    }
  }
}

Complete Example

Here's a comprehensive template configuration:

json
{
  "$schema": "https://docs.1mcp.app/schemas/v1.0.0/mcp-config.json",
  "version": "1.0.0",
  "templateSettings": {
    "validateOnReload": true,
    "failureMode": "graceful",
    "cacheContext": true
  },
  "mcpTemplates": {
    "project-filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "{{project.path}}"],
      "tags": ["filesystem", "project-local"],
      "disabled": "{{#if (eq transport.client.name 'claude-code')}}false{{else}}true{{/if}}"
    },
    "team-serena": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/oraios/serena",
        "serena",
        "start-mcp-server",
        "--project",
        "{{project.path}}",
        "--team",
        "{{project.custom.team}}",
        "--env",
        "{{project.environment}}"
      ],
      "env": {
        "PROJECT_ID": "{{project.custom.projectId}}",
        "GIT_BRANCH": "{{project.git.branch}}",
        "API_ENDPOINT": "{{project.custom.apiEndpoint}}"
      },
      "cwd": "{{project.path}}",
      "tags": ["filesystem", "search"]
    },
    "conditional-debug-server": {
      "command": "node",
      "args": ["{{project.path}}/debug-server.js"],
      "cwd": "{{project.path}}",
      "env": {
        "NODE_ENV": "{{project.environment}}",
        "DEBUG": "{{#if (eq project.environment 'development')}}true{{else}}false{{/if}}",
        "LOG_LEVEL": "{{#if (eq project.environment 'production')}}warn{{else}}debug{{/if}}"
      },
      "disabled": "{{#if (eq project.environment 'production')}}true{{else}}false{{/if}}",
      "tags": ["debug", "development"]
    },
    "client-aware-server": {
      "command": "npx",
      "args": [
        "-y",
        "my-custom-server",
        "--client",
        "{{transport.client.name}}",
        "--version",
        "{{transport.client.version}}"
      ],
      "env": {
        "CLIENT_NAME": "{{transport.client.name}}",
        "CLIENT_VERSION": "{{transport.client.version}}",
        "CONNECTION_ID": "{{transport.connectionId}}",
        "USER": "{{user.username}}"
      },
      "tags": ["client-aware", "custom"]
    }
  }
}

Template Settings

Control template processing behavior with templateSettings:

json
{
  "templateSettings": {
    "validateOnReload": true,
    "failureMode": "graceful",
    "cacheContext": true
  }
}
SettingTypeDefaultDescription
validateOnReloadbooleanfalseReserved for future use; currently has no effect
failureMode'strict'|'graceful''strict'How to handle template errors
cacheContextbooleantrueCache rendered templates by context hash

Failure Modes

  • strict: Template errors cause the affected template server to be skipped; the error is logged. Other servers continue normally.
  • graceful: Template errors are logged, original template used as fallback

Conditional Disable

Templates can be conditionally disabled using the disabled field:

json
{
  "mcpTemplates": {
    "dev-only-server": {
      "command": "node",
      "args": ["dev-tools.js"],
      "disabled": "{{#if (eq project.environment 'production')}}true{{else}}false{{/if}}",
      "tags": ["development"]
    },
    "client-specific": {
      "command": "npx",
      "args": ["-y", "special-server"],
      "disabled": "{{#if (eq transport.client.name 'cursor')}}false{{else}}true{{/if}}",
      "tags": ["cursor-only"]
    },
    "user-restricted": {
      "command": "npx",
      "args": ["-y", "admin-tools"],
      "disabled": "{{#if (contains user.username 'admin')}}false{{else}}true{{/if}}",
      "tags": ["admin"]
    }
  }
}

The disabled field evaluates the template and converts the result to a boolean:

  • "true", "1", "yes"true (disabled)
  • "false", "0", "no" or empty → false (enabled)

Handlebars Helpers

1MCP includes several built-in Handlebars helpers:

Math Helpers

text
{{math value1 '+' value2}}           <!-- Addition -->
{{math value1 '-' value2}}           <!-- Subtraction -->
{{math value1 '*' value2}}           <!-- Multiplication -->
{{math value1 '/' value2}}           <!-- Division -->
{{math value1 '%' value2}}           <!-- Modulo -->
{{math value1 '**' value2}}          <!-- Exponentiation -->
{{math value '/' 100 '*' 100}}       <!-- Chained operations (all results rounded) -->

Comparison Helpers

text
{{eq a b}}     <!-- Equal -->
{{ne a b}}     <!-- Not equal -->
{{gt a b}}     <!-- Greater than -->
{{lt a b}}     <!-- Less than -->

Logical Helpers

text
{{and a b c}}  <!-- All truthy -->
{{or a b c}}   <!-- Any truthy -->

String Helpers

text
{{contains str substring}}     <!-- Contains substring -->
{{startsWith str prefix}}      <!-- Starts with prefix -->
{{endsWith str suffix}}        <!-- Ends with suffix -->
{{len str}}                    <!-- String length -->
{{substring str start end}}    <!-- Extract substring -->

Math Operation Helpers

text
{{subtract a b}}    <!-- a - b with null safety -->
{{div a b}}         <!-- a / b with zero safety -->

Best Practices

1. Use .1mcprc for Project Context

Store project-specific metadata in .1mcprc rather than hardcoding in templates:

Good (.1mcprc):

json
{
  "context": {
    "projectId": "myapp-api",
    "team": "platform",
    "custom": {
      "apiEndpoint": "https://api.example.com"
    }
  }
}

Avoid (hardcoded):

json
{
  "mcpTemplates": {
    "api-server": {
      "env": {
        "API_ENDPOINT": "https://api.example.com"
      }
    }
  }
}

2. Make Templates Environment-Aware

Use project.environment for environment-specific behavior:

json
{
  "mcpTemplates": {
    "smart-server": {
      "env": {
        "LOG_LEVEL": "{{#if (eq project.environment 'production')}}warn{{else}}debug{{/if}}",
        "CACHE_ENABLED": "{{#if (eq project.environment 'production')}}true{{else}}false{{/if}}"
      }
    }
  }
}

3. Validate with validateOnReload

Enable template validation during development:

json
{
  "templateSettings": {
    "validateOnReload": true,
    "failureMode": "strict"
  }
}

4. Use Graceful Failure in Production

Prevent template errors from breaking production:

json
{
  "templateSettings": {
    "validateOnReload": false,
    "failureMode": "graceful"
  }
}

5. Tag Templates Appropriately

Use static tags to enable proper filtering with presets:

json
{
  "mcpTemplates": {
    "team-server": {
      "tags": ["filesystem", "search", "team"]
    }
  }
}

Note: Template expressions inside tags arrays (e.g. "team-{{project.custom.team}}") are not rendered — they will be used as literal tag strings. Use static tag values only.

Troubleshooting

Template Not Rendering

Symptom: Template variables appear as literal {{variable}} strings

Solutions:

  1. Ensure templates are in mcpTemplates, not mcpServers
  2. Check that context is being collected (enable debug logging)
  3. Verify variable names match the context structure

Custom Context Missing

Symptom: {{project.custom.*}} variables are undefined

Solutions:

  1. Check .1mcprc file exists in project root
  2. Validate JSON syntax in .1mcprc
  3. Ensure context.custom object is properly structured

Server Not Starting

Symptom: Template server fails to start

Solutions:

  1. Check rendered configuration in logs
  2. Verify command path after template rendering
  3. Ensure environment variables are properly quoted

Conditional Logic Not Working

Symptom: {{#if}} conditions not evaluating as expected

Solutions:

  1. Use comparison helpers: {{#if (eq var 'value')}}
  2. Check for whitespace in values
  3. Enable debug logging to see actual values

See Also

Released under the Apache 2.0 License.