MALDA™ Reference Manual

The AI-First Programming Language - Version 1.0.39

21. 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.

First-read stop. @MCPTool plus MCPServer.start() exposes functions to a host over STDIO. Smallest file: Examples/MCP/mcp_schema_tool.malda. Course: Learn MALDA — After the core path.

21.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"]
    }
  }
}
Do not print banners on stdout after 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.

21.2 @MCPTool and schemas

schema AddArgs {
    a: int;
    b: int;
}

@MCPTool("add", "Adds two numbers together", "AddArgs")
function add(a, b) {
    return int(a) + int(b);
}

If you omit a schema, MALDA builds JSON Schema from the parameter names: every property is type "string" and required. The optional third argument may be:

@MCPTool("get_weather", "Gets weather for a location", "{\"type\":\"object\",\"properties\":{\"location\":{\"type\":\"string\"},\"unit\":{\"type\":\"string\",\"enum\":[\"celsius\",\"fahrenheit\"]}},\"required\":[\"location\"]}")
function getWeather(location, unit) {
    // ...
}

When that third argument is present, the host validates incoming arguments against the schema before the function body (same rules as validate()). server.callTool("add", { a: 1, b: 2 }) returns { ok, data } or { ok: false, error } without starting STDIO. MCP tools/call returns isError: true on failure. Omitting the schema still advertises all-string properties and does not check args. Direct calls such as add(1, 2) are unchanged.

server.getTools() returns { name, description, inputSchema } for each @MCPTool without starting STDIO — useful to inspect the resolved schema. Same file: Examples/MCP/mcp_schema_tool.malda. @Tool accepts the same third argument and host-validates tool.execute / agent invoke (see the malda new agent scaffold).

21.3 MCPServer

var server = new MCPServer();                    // STDIO transport (default)
var server = new MCPServer("stdio");            // Explicit STDIO transport

JSON-RPC methods implemented: initialize, tools/list, tools/call, notifications/initialized.

21.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"});

21.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();

21.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 19. Agent Orchestration and compileMALDA in 13. Built-in Functions only when an agent should generate and compile MALDA.

See Also