A template repository for creating Model Context Protocol (MCP) servers in the V programming language. This template provides a clean, minimal foundation that you can extend to build your own MCP servers.
This template includes:
- JSON-RPC 2.0 Protocol Implementation: Complete MCP protocol handling
- Modular Architecture: Clean separation of concerns (protocol, server, tools)
- Tool Registry System: Easy-to-extend tool handler registration
- Configuration Management: Environment variable-based configuration
- Build Scripts: Ready-to-use build scripts for Windows and Unix
- Example Tools: Sample tool implementations to guide your development
- V programming language installed and on PATH
-
Use this template to create your own repository:
- Click "Use this template" on GitHub, or
- Clone this repository and remove the
.gitdirectory
-
Customize the module name in
v.mod:Module { name: 'your_mcp_server' // Change this description: 'Your MCP server description' version: '0.1.0' dependencies: [] } -
Customize configuration in
src/server/config.v:- Add your server-specific configuration fields
- Update
from_env()to read your environment variables
-
Add your tools in
src/tools/tools.v:- Implement your tool handler functions
- Register them in
register_all()
-
Build and test:
# Linux/macOS ./build.sh # Windows build.bat
-
Run your server:
./mcp-server # or mcp-server.exe on Windows
.
├── src/
│ ├── main.v # Entry point and JSON-RPC message loop
│ ├── mcp/
│ │ └── mcp.v # JSON-RPC 2.0 protocol implementation
│ ├── server/
│ │ ├── config.v # Configuration management
│ │ └── server.v # Server state management
│ └── tools/
│ └── tools.v # Tool registry and handlers
├── build.sh # Linux/macOS build script
├── build.bat # Windows build script
├── v.mod # V module definition
└── README.md # This file
Add your server-specific configuration:
pub struct ServerConfig {
pub:
data_path string = ''
cache_ttl_seconds int = 300
max_results int = 50
log_level string = 'INFO'
}
pub fn from_env() ServerConfig {
data_path := os.getenv('DATA_PATH')
// ... your configuration logic
return ServerConfig{
data_path: data_path
// ...
}
}Add your server's state and methods:
pub struct ServerState {
pub mut:
config ServerConfig
cache map[string]CacheEntry
data map[string]string
}
pub fn new_server(config ServerConfig) ServerState {
return ServerState{
config: config
cache: map[string]CacheEntry{}
data: map[string]string{}
}
}Implement your tool handlers:
fn handle_my_tool(params mcp.JsonAny, mut server_state server.ServerState) string {
// Extract parameters
query := mcp.extract_string_param(params, 'query') or {
return 'Error: Query parameter is required'
}
// Implement your logic
result := server_state.process_query(query)
// Return result (markdown format recommended)
return '# Results\n\n${result}'
}
fn (mut r ToolRegistry) register_all() {
r.handlers['my_tool'] = handle_my_tool
// Add more handlers...
}Customize startup logging and initialization:
fn main() {
config := server.from_env()
mut server_state := server.new_server(config)
// Add your initialization logic here
server_state.initialize() or {
mcp.log('ERROR', 'Failed to initialize: ${err}')
return
}
mcp.log('INFO', 'Starting My MCP Server...')
// ... rest of the loop
}This template implements the JSON-RPC 2.0 protocol used by MCP. The protocol module (src/mcp/mcp.v) handles:
- Message reading/writing (stdio)
- Request/response parsing
- Error handling
- Parameter extraction utilities
You don't need to modify the protocol implementation unless you need custom transport (HTTP, WebSocket, etc.).
The template includes two example tools:
get_info: Returns server informationexample_tool: A template for creating new tools
Replace these with your own tool implementations.
Test your server by sending JSON-RPC requests via stdin:
echo '{"jsonrpc":"2.0","id":1,"method":"get_info","params":{}}' | ./mcp-serverAdd to .cursor/mcp.json:
{
"mcpServers": {
"my-server": {
"command": "/path/to/mcp-server",
"env": {
"LOG_LEVEL": "INFO"
}
}
}
}The server communicates via JSON-RPC 2.0 over stdio, which is compatible with all MCP clients.
-
Tool Naming: Use descriptive, action-oriented names (e.g.,
get_data,search_items,process_file) -
Error Handling: Always validate parameters and return clear error messages
-
Response Format: Use Markdown for tool responses to enable rich formatting in clients
-
Logging: Use
mcp.log()for important events and errors -
Configuration: Use environment variables for configuration to keep the server flexible
-
State Management: Keep server state in
ServerStateand make it thread-safe if needed
pub struct CacheEntry {
data string
timestamp int
}
pub fn (mut s ServerState) get_cached(key string) ?string {
entry := s.cache[key] or { return none }
if time.now().unix - entry.timestamp > s.config.cache_ttl_seconds {
s.cache.delete(key)
return none
}
return entry.data
}pub fn (mut s ServerState) load_data(path string) ! {
content := os.read_file(path)!
// Process content...
}pub fn (mut s ServerState) search(query string) []SearchResult {
// Implement search logic...
return results
}This template is provided as-is. Customize the license for your project.
If you improve this template, consider contributing back to help others!
For a complete example, see:
- v-vlang-mcp - V language MCP server
Happy Building! 🚀