nimcp
A Nim library to easily make MCP servers for use by LLMs
Documentation
NimCP - Easy Model Context Protocol (MCP) Servers in Nim
NimCP is a macro-based library for creating Model Context Protocol (MCP) servers in Nim. It leverages Nim's macro system to provide an incredibly easy-to-use API for building MCP servers that integrate seamlessly with LLM applications.
NOTE: 99.9% of this library was written using Claude Code!
Features
- Macro-driven API - Define servers, tools, resources, and prompts with simple, declarative syntax
- Full MCP 2024-11-05 Support - Complete implementation of MCP specification with JSON-RPC 2.0
- Multiple Transports - Supports stdio, SSE, HTTP, and WebSocket transports
- Enhanced Type System - Support for objects, unions, enums, optional types, and arrays
- Automatic Schema Generation - JSON schemas generated from Nim type signatures
- Request Context System - Progress tracking, cancellation, and request lifecycle management
- Resource URI Templates - Dynamic URI patterns with parameter extraction (`/users/{id}`)
- Server Composition - Compose multiple MCP servers into a single interface with prefixes and routing
- Pluggable Logging - Flexible logging system with multiple handlers, levels, and structured output
- Middleware Pipeline - Request/response transformation and processing hooks
- Fluent API - Method chaining patterns for elegant server configuration
- High Performance - Mummy based HTTP and WebSockets implementation
- Concurrent Processing - Uses the new taskpools library for stdio transport
- Minimal Dependencies - Uses only essential, well-maintained packages
Quick Start
Installation
nimble install nimcpSimple Example
import nimcp
import strformat
let server = mcpServer("my-server", "1.0.0"):
mcpTool:
proc echo(text: string): string =
## Echo back the input text
return "Echo: " & text
mcpTool:
proc add(a: float, b: float): string =
## Add two numbers together
return $fmt"Result: {a + b}"
when isMainModule:
# Use stdio transport (default):
let transport = newStdioTransport()
transport.serve(server)
# Or use HTTP transport:
# let transport = newMummyTransport(8080, "127.0.0.1")
# transport.serve(server)
# Or use WebSocket transport for real-time communication:
# let transport = newWebSocketTransport(8080, "127.0.0.1")
# transport.serve(server)That's it! Your MCP server is ready to run.
Core Concepts
Tools
Tools are functions that LLM applications can call. Define them with the `mcpTool` macro that plucks out the tool name, description, and JSON schema from your procedure signature and doc comments:
mcpTool:
proc calculate(expression: string): string =
## Perform mathematical calculations
## - expression: Mathematical expression to evaluate
# Your calculation logic here
return "Result: 42"Context-Aware vs Regular Tools
NimCP also supports context aware tools that also receive server context for accessing server state and request information:
# Context aware tools need to have first parameter being an McpRequestContext
mcpTool:
proc notifyTool(ctx: McpRequestContext, args: JsonNode): McpToolResult =
## Log request and track processing
ctx.info("Processing notification request")
# Your notification logic here
let message = args.getOrDefault("message", %"").getStr()
ctx.info("Notification processing complete")
return McpToolResult(content: @[createTextContent("Notification: " & message)])When to use Context-Aware Tools:
- Server-initiated events
- Access to server configuration or transport-specific features
- Custom logging or middleware integration
- Request-specific state management
Manual Registration Methods:
- `server.registerTool(tool, handler)` - Regular tools
- `server.registerToolWithContext(tool, handler)` - Context-aware tools
- Same pattern applies to resources and prompts
Resources
Resources provide data that can be read by LLM applications:
mcpResource("data://config", "Configuration", "Application configuration"):
proc get_config(uri: string): string =
return readFile("config.json")Prompts
Prompts are reusable templates for LLM interactions:
mcpPrompt("code_review", "Code review prompt", @[
McpPromptArgument(name: "language", description: some("Programming language")),
McpPromptArgument(name: "code", description: some("Code to review"))
]):
proc review_prompt(name: string, args: Table[string, JsonNode]): seq[McpPromptMessage] =
let language = args.getOrDefault("language", %"unknown").getStr()
let code = args.getOrDefault("code", %"").getStr()
return @[
McpPromptMessage(
role: System,
content: createTextContent(&"Review this {language} code for best practices and potential issues.")
),
McpPromptMessage(
role: User,
content: createTextContent(code)
)
]Manual Server Creation
For more control, you can create servers manually:
import nimcp
let server = newMcpServer("advanced-server", "2.0.0")
# Register tools manually
let tool = McpTool(
name: "custom_tool",
description: some("A custom tool"),
inputSchema: %*{"type": "object"}
)
proc customHandler(args: JsonNode): McpToolResult =
return McpToolResult(content: @[createTextContent("Custom result")])
server.registerTool(tool, customHandler)
# Run the server
try:
let transport = newStdioTransport()
transport.serve(server)
finally:
server.shutdown()Server Composition
NimCP supports composing multiple servers into a single interface - perfect for API gateways:
import nimcp, nimcp/composed_server
# Create individual servers using macro API
let calculatorServer = mcpServer("calculator-service", "1.0.0"):
mcpTool:
proc add(a: float, b: float): string =
## Add two numbers together
return fmt"Result: {a + b}"
let fileServer = mcpServer("file-service", "1.0.0"):
mcpTool:
proc readFile(path: string): string =
## Read contents of a file
try:
return readFile(path)
except IOError as e:
return fmt"Error reading file: {e.msg}"
# Compose them into a single gateway
let apiGateway = newComposedServer("api-gateway", "1.0.0")
# Mount each service with prefixes for namespacing
apiGateway.mountServerAt("/calc", calculatorServer, some("calc_"))
apiGateway.mountServerAt("/files", fileServer, some("file_"))
# Run the composed server
let transport = newStdioTransport()
transport.serve(apiGateway)
# Tools are now available as: calc_add, file_readFileError Handling
NimCP automatically handles JSON-RPC errors, but you can throw exceptions in your handlers:
mcpTool:
proc validate(data: string): string =
## Validate input data
if data.len == 0:
raise newException(ValueError, "Empty data parameter")
return "Valid!"Examples
Check out the `examples/` directory for comprehensive examples and see the examples README for some more info.
Just from command line you can test and list tools with for example:
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | ./examples/calculator_serverIf you are using Claude Code, this is how you can add it as an MCP server:
1. Add the MCP server to Claude Code:
claude mcp add basic_calculator --transport stdio $PWD/examples/basic_calculator1. Verify it was added:
claude mcp list3. Test the server from within Claude Code:
Once added, you should be able to use the calculator tools directly in Claude Code conversations:
Example usage in Claude Code:
If the CLI method doesn't work, you can manually edit your MCP configuration file (usually at ~/.claude.json). Just change the path to what you have:
{
"mcpServers": {
"calculator_server": {
"type": "stdio",
"command": "/path/to/examples/calculator_server",
"args": [],
"env": {}
}
}
}
Testing
Run the test suite:
nimble testContributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License. See LICENSE for details.
MCP Resources
Frequently asked questions
What is nimcp?
nimcp is A Nim library to easily make MCP servers for use by LLMs
How do I install nimcp?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is nimcp open source?
Yes — it is hosted on GitHub at https://github.com/gokr/nimcp and has 24 stars.
Related MCP tools
Model Context Protocol Servers
Pre-indexed code knowledge graph, auto syncs on code changes, for Claude Code, Codex, Gemini, Cursor, OpenCode, AntiGravity, Kiro, CoPilot, and Hermes Agent — fewer tokens, fewer tool calls, 100% local
an open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM
The easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:
The Open-Source Multimodal AI Agent Stack: Connecting Cutting-Edge AI Models and Agent Infra
Cognee is the open-source AI memory platform for agents. Give your AI agents persistent long-term memory across sessions with a self-hosted knowledge graph engine.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP