20. MCP Server
MCP (Model Context Protocol) lets an AI host — Claude Desktop, Cursor, ChatGPT, or a MALDA MCPClient — launch your process and talk JSON-RPC 2.0 over STDIO (stdin/stdout). Decorate ordinary functions with @MCPTool, call new MCPServer().start(), and the host can list and call them. Same file: Examples/MCP/mcp_tools_server.malda.
20.1 A minimal server
@MCPTool("add", "Adds two numbers together")
function add(a, b) {
return int(a) + int(b);
}
@MCPTool("reverse_string", "Reverses a string")
function reverseString(text) {
var reversed = "";
var i = length(text) - 1;
while (i >= 0) {
reversed = reversed + substring(text, i, 1);
i = i - 1;
}
return reversed;
}
var server = new MCPServer();
server.start();
while (server.isRunning) {
sleep(1000);
}
Run it as a normal MALDA program. The host, not you, should start that process when it wants the tools:
malda Examples/MCP/mcp_tools_server.malda
An MCP host config (Claude Desktop claude_desktop_config.json, Cursor mcp.json) looks like this — point command at a malda executable on PATH, or a full path:
{
"mcpServers": {
"malda-tools": {
"command": "malda",
"args": ["C:/path/to/Examples/MCP/mcp_tools_server.malda"]
}
}
}
start() if a host is connected: STDIO is the protocol. Log to stderr or a file. The example server in Examples/MCP/ prints before the host handshake in a demo loop; a production server should stay quiet on stdout.
20.2 @MCPTool and schemas
@MCPTool("tool_name", "Tool description")
function myTool(param1, param2) {
return param1 + param2;
}
If you omit a schema, MALDA builds JSON Schema from the parameter names: every property is type "string" and required. Pass a JSON schema string as the third argument when you need enums, numbers, or optional fields:
@MCPTool("tool_name", "Tool description", "{\"type\":\"object\",\"properties\":{...}}")
function myTool(param1) {
// ...
}
20.3 MCPServer
var server = new MCPServer(); // STDIO transport (default)
var server = new MCPServer("stdio"); // Explicit STDIO transport
start(): discover@MCPToolfunctions and serve JSON-RPCstop(): stop the servergetTools(): list registered toolsisRunning: loop until the host disconnects
JSON-RPC methods implemented: initialize, tools/list, tools/call, notifications/initialized.
20.4 MCPClient: call another server
MCPClient starts a child process and speaks the same STDIO protocol. Same file: Examples/MCP/mcp_client_example.malda. Run the client from the repo root so malda can find the server script.
var client = new MCPClient("example-server");
var connected = client.connect("malda", ["Examples/MCP/mcp_tools_server.malda"]);
if (!connected) {
print("Failed to connect");
return;
}
var tools = client.getTools();
print("Tool count: " + string(tools.length));
var sum = client.callTool("add", {"a": 5, "b": 3});
print(string(sum));
client.disconnect();
connect(command, args?, env?) returns true on success. callTool(name, arguments?) converts the JSON result to MALDA values. Each tool from getTools() has name, description, and schema.
var client = new MCPClient("my-server");
var connected = client.connect("python", ["-m", "mcp_server"], {"API_KEY": "secret"});
createTool(toolName, registeredName?, register?)wraps one tool as anMCPToolInstanceyou canagent.addTool(...)(see 18. Agent Orchestration)refreshTools()rediscovers tools after the server has changedserverName/isConnectedare properties
20.5 Wrapper agent (optional)
createWrapperAgent builds an Agent with every tool from the connected server already attached. If you omit llmClient, MALDA uses a local GGUF model (downloaded on first use). Prefer the callTool example above until you need an LLM in the loop.
var mcpClient = new MCPClient("example-server");
mcpClient.connect("malda", ["Examples/MCP/mcp_tools_server.malda"]);
var agent = mcpClient.createWrapperAgent(
"Helper",
"assistant",
"You use MCP tools to answer questions."
);
var response = agent.think("Add 5 and 3");
print(response.content);
mcpClient.disconnect();
20.6 Advanced: generate a script
createMcpAgentScript(agentName, agentRole, agentInstructions, tools, outputPath, model?) writes a .malda file that exposes an agent as MCP tools. That is a code generator, not a live STDIO session — prefer callTool or createWrapperAgent until you need to emit a file. Pair it with MALDACodingAgent in 18. Agent Orchestration and compileMALDA in 13. Built-in Functions only when an agent should generate and compile MALDA.
See Also
- 9. Functions - Function decorators
- 18. Agent Orchestration - Agents, tools, and
agent.think - 21. ACP (Agent Communication Protocol) - Agent-to-agent, not tools