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:
| Feature | Static Servers (mcpServers) | Template Servers (mcpTemplates) |
|---|---|---|
| Configuration | Fixed values at startup | Dynamic values based on context |
| Context awareness | None | Project, user, transport, client |
| Multiple instances | Single instance per config | Multiple instances per context |
| Lifecycle | Always running | Created on-demand per connection |
| Use case | Stable infrastructure | Dynamic, 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:
{
"mcpTemplates": {
"project-context": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "{{project.path}}"],
"tags": ["filesystem", "project"]
}
}
}When a client connects, 1MCP:
- Collects context (project path, user, environment)
- Renders the template with actual values
- Creates a server instance with the rendered configuration
- Connects the client to the new instance
Environment-Specific Configuration
{
"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.*)
| Variable | Type | Description | Example |
|---|---|---|---|
project.path | string | Absolute path to current project | /Users/dev/myapp |
project.name | string | Project directory name | myapp |
project.environment | string | Environment name | development |
project.git.branch | string? | Git branch name | main |
project.git.commit | string? | Git commit hash | a1b2c3d |
project.git.repository | string? | Git remote URL | https://github.com/user/repo |
project.custom.* | any | Custom values from .1mcprc | User-defined |
User Variables (user.*)
| Variable | Type | Description | Example |
|---|---|---|---|
user.username | string? | System username | developer |
user.name | string? | User's full name | Jane Developer |
user.email | string? | User email | jane@example.com |
user.home | string? | Home directory path | /Users/developer |
user.uid | string? | User ID | 501 |
user.gid | string? | Group ID | 20 |
user.shell | string? | Default shell | /bin/zsh |
Transport Variables (transport.*)
| Variable | Type | Description | Example |
|---|---|---|---|
transport.type | string | Transport protocol | http, sse, stdio |
transport.url | string? | Server URL (HTTP/SSE) | http://localhost:3050 |
transport.connectionId | string? | Connection identifier | conn_xyz789 |
transport.connectionTimestamp | string? | Connection time | 2025-01-25T10:30:00Z |
transport.client.name | string | Client application name | cursor, claude-code |
transport.client.version | string | Client version | 1.0.0 |
transport.client.title | string? | Client display name | Cursor Editor |
Template Syntax
1MCP uses Handlebars for template rendering. Variables use double curly braces: {{variable}}.
Variable Access
{{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:
{{#if (eq project.environment 'production')}}
<!-- Production configuration -->
{{else}}
<!-- Development configuration -->
{{/if}}Comparisons
Use built-in helpers for comparisons:
{{#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:
{{#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
{{#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:
{
"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
| Field | Type | Description |
|---|---|---|
preset | string | Default preset to use |
tags | string|string[] | Default tags for filtering |
context.projectId | string | Project identifier |
context.environment | string | Environment name (development, staging, production) |
context.team | string | Team name |
context.custom | object | Custom key-value pairs |
context.envPrefixes | string[] | Environment variable prefixes to include |
context.includeGit | boolean | Include Git information |
context.sanitizePaths | boolean | Sanitize file paths for security |
Accessing Custom Context
Custom values are available as {{project.custom.*}}:
{
"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:
{
"$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:
{
"templateSettings": {
"validateOnReload": true,
"failureMode": "graceful",
"cacheContext": true
}
}| Setting | Type | Default | Description |
|---|---|---|---|
validateOnReload | boolean | false | Reserved for future use; currently has no effect |
failureMode | 'strict'|'graceful' | 'strict' | How to handle template errors |
cacheContext | boolean | true | Cache 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:
{
"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
{{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
{{eq a b}} <!-- Equal -->
{{ne a b}} <!-- Not equal -->
{{gt a b}} <!-- Greater than -->
{{lt a b}} <!-- Less than -->Logical Helpers
{{and a b c}} <!-- All truthy -->
{{or a b c}} <!-- Any truthy -->String Helpers
{{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
{{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):
{
"context": {
"projectId": "myapp-api",
"team": "platform",
"custom": {
"apiEndpoint": "https://api.example.com"
}
}
}Avoid (hardcoded):
{
"mcpTemplates": {
"api-server": {
"env": {
"API_ENDPOINT": "https://api.example.com"
}
}
}
}2. Make Templates Environment-Aware
Use project.environment for environment-specific behavior:
{
"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:
{
"templateSettings": {
"validateOnReload": true,
"failureMode": "strict"
}
}4. Use Graceful Failure in Production
Prevent template errors from breaking production:
{
"templateSettings": {
"validateOnReload": false,
"failureMode": "graceful"
}
}5. Tag Templates Appropriately
Use static tags to enable proper filtering with presets:
{
"mcpTemplates": {
"team-server": {
"tags": ["filesystem", "search", "team"]
}
}
}Note: Template expressions inside
tagsarrays (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:
- Ensure templates are in
mcpTemplates, notmcpServers - Check that context is being collected (enable debug logging)
- Verify variable names match the context structure
Custom Context Missing
Symptom: {{project.custom.*}} variables are undefined
Solutions:
- Check
.1mcprcfile exists in project root - Validate JSON syntax in
.1mcprc - Ensure
context.customobject is properly structured
Server Not Starting
Symptom: Template server fails to start
Solutions:
- Check rendered configuration in logs
- Verify command path after template rendering
- Ensure environment variables are properly quoted
Conditional Logic Not Working
Symptom: {{#if}} conditions not evaluating as expected
Solutions:
- Use comparison helpers:
{{#if (eq var 'value')}} - Check for whitespace in values
- Enable debug logging to see actual values
See Also
- Template Syntax Reference - Complete syntax and helper reference
- Custom Instructions Template - Customize LLM instructions (different feature)
- Context Collection - How context is collected
- Server Filtering - Tag-based filtering
