Skip to content

Server basics

Start with an McpServer, register the features it exposes, then attach a transport. The server accepts MCP requests such as server/discover, tools/list, and tools/call.

import nimwire
let server = newMcpServer(
"weather", "1.0.0",
instructions = "Use the weather tool for current conditions.")

The name and version are required. instructions is included in discovery so a client can understand the server’s purpose.

The mcpServer template is a shorter form when registration should stay next to construction:

let server = mcpServer("weather", "1.0.0"):
discard

Use mcpTool when the handler naturally works with JSON:

import std/[json, strutils]
server.addTool mcpTool("word_count", "Count words in text", %*{
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
"additionalProperties": false
}, proc (args: JsonNode, context: McpContext): McpToolResult =
textResult($args["text"].getStr.splitWhitespace.len))

The second handler parameter is request context. Name it ignoredContext when the handler does not need it. A handler can be synchronous or return Future[McpToolResult].

Tool names are 1 to 128 characters and may contain letters, numbers, _, -, and .. Names must be unique after registration.

Use the result that matches what the client should receive:

textResult("ready")
jsonResult(%*{"temperature": 16, "unit": "C"})
structuredResult(%*{"temperature": 16, "unit": "C"})

textResult creates a text content item. jsonResult and structuredResult include structured content as well as a readable text representation. Set isError = true when a tool completed but its result describes a tool failure.

For typed failures, return McpResult[T]:

proc lookup(code: string): McpResult[string] =
if code.len == 0:
return mcpResultError[string]("invalid_code", "A code is required")
mcpResult("result for " & code)

mcpFailure[T](message) is a shorthand for the tool_error code. Set retryable = true when retry middleware or a client may safely try again.

Namespaces make related tools easier to discover and prevent name collisions:

var admin = newMcpToolGroup("admin")
admin.addTool mcpTool("reload", "Reload configuration", %*{"type": "object"},
proc (args: JsonNode, context: McpContext): McpToolResult = textResult("ok"))
server.addToolGroup(admin)

The tool is exposed as admin.reload. You can also use server.addTools("admin", tools).

Discovery is sorted by final name, regardless of registration order. Set listPageSize in newMcpServer when a list should be paginated, for example listPageSize = 25. The client follows nextCursor values until it has the complete list.

listTtlMs and listCacheScope add cache hints to list and resource-read responses. listCacheScope must be "public" or "private".

Related: Typed tools, Resources, and the server API reference.