This document explains how MCP tools work in AgentTools and how to add new tools.
MCP tools allow servers to expose callable functions to language models. Clients can discover available tools, view their parameter specifications, and invoke them with arguments. This follows the MCP tools specification.
Tools are designed to be model-controlled, meaning the LLM decides when and how to use them based on the conversation context and user requests.
The tools system provides:
$DefaultMCPTools- An association of predefined tool definitions- Tools are specified via the
"Tools"LLMEvaluator property - Tools can be referenced by name (string) or defined inline (association)
- Client requests tool list (
tools/list): Server returns available tools with names, descriptions, and JSON schemas for parameters - Client invokes tool (
tools/call): Server executes the tool function with provided arguments - Result returned: The generated content is returned as a string to the LLM
| Property | Type | Required | Description |
|---|---|---|---|
"Name" |
String | Yes | Unique identifier for the tool |
"DisplayName" |
String | No | Human-readable display name |
"Description" |
String | Yes | Detailed description of what the tool does |
"Function" |
Symbol | Yes | The Wolfram Language function to call |
"Parameters" |
List | Yes | Parameter specifications (see below) |
"Options" |
List | No | Tool options |
"LLMKit" |
String | No | Dependency: "Suggested", "Required", or Automatic |
"Initialization" |
Delayed | No | Optional initialization code run before first use |
"Overrides" |
Association or Delayed | No | Environment-specific property overrides merged in when the server state is built (see Environment-Specific Overrides) |
The paclet provides $DefaultMCPTools, an association of predefined tool definitions:
$DefaultMCPTools = <|
"WolframLanguageEvaluator" -> LLMTool[ ... ],
"WolframContext" -> LLMTool[ ... ],
"WolframAlpha" -> LLMTool[ ... ],
...
|>| Tool | Description | Server |
|---|---|---|
WolframContext |
Semantic search across Wolfram resources (documentation, Wolfram Alpha, repositories, and more) | Wolfram |
WolframAlphaContext |
Semantic search for Wolfram Alpha results | WolframAlpha |
WolframLanguageContext |
Semantic search across Wolfram Language resources (documentation, function repository, data repository, neural net repository, and more) | WolframLanguage, WolframPacletDevelopment |
| Tool | Description | Server |
|---|---|---|
WolframLanguageEvaluator |
Evaluates Wolfram Language code with time constraints | Wolfram, WolframLanguage, WolframPacletDevelopment |
WolframAlpha |
Natural language queries to Wolfram Alpha | Wolfram, WolframAlpha |
SymbolDefinition |
Retrieves symbol definitions in readable markdown format | WolframLanguage, WolframPacletDevelopment |
| Tool | Description | Server |
|---|---|---|
ReadNotebook |
Reads Wolfram notebooks (.nb) as markdown text | WolframLanguage, WolframPacletDevelopment |
WriteNotebook |
Converts markdown to Wolfram notebooks | WolframLanguage, WolframPacletDevelopment |
| Tool | Description | Server |
|---|---|---|
TestReport |
Runs Wolfram Language test files (.wlt) and returns a report | WolframLanguage, WolframPacletDevelopment |
| Tool | Description | Server |
|---|---|---|
CodeInspector |
Inspects Wolfram Language code and returns a formatted report of issues | WolframLanguage, WolframPacletDevelopment |
| Tool | Description | Server |
|---|---|---|
CreateSymbolDoc |
Creates new symbol documentation pages for paclets | WolframPacletDevelopment |
EditSymbolDoc |
Edits existing symbol documentation pages | WolframPacletDevelopment |
EditSymbolDocExamples |
Edits example sections of symbol documentation | WolframPacletDevelopment |
| Tool | Description | Server |
|---|---|---|
CheckPaclet |
Checks a paclet for issues before building or submission | WolframPacletDevelopment |
BuildPaclet |
Builds a .paclet archive for distribution |
WolframPacletDevelopment |
SubmitPaclet |
Submits a paclet to the Wolfram Language Paclet Repository | WolframPacletDevelopment |
| Tool | Description | Server |
|---|---|---|
NotebookViewer |
Embeds interactive Wolfram Cloud notebooks inline | (available, not in default servers) |
MCPAppsTest |
Diagnostic tool for testing the MCP Apps pipeline | (available, not in default servers) |
Note: When a client supports the
io.modelcontextprotocol/uiextension, theWolframAlphaandWolframLanguageEvaluatortools are automatically enhanced with UI capabilities (e.g., deploying cloud notebooks and returning_metawithnotebookUrl). See mcp-apps.md for details.
$defaultMCPTools[ "ToolName" ] := LLMTool @ <|
"Name" -> "ToolName",
"DisplayName" -> "Human Readable Name",
"Description" -> "Detailed tool description...",
"Function" -> toolFunction,
"Options" -> { },
"Parameters" -> { ... },
"LLMKit" -> "Suggested", (* Optional *)
"Initialization" :> initFunction[ ] (* Optional *)
|>Parameters are specified as a list of rules, where each parameter is defined as:
"paramName" -> <|
"Interpreter" -> "String" | "Integer" | "Boolean",
"Help" -> "Parameter description",
"Required" -> True | False
|>Example from WolframLanguageEvaluator:
"Parameters" -> {
"code" -> <|
"Interpreter" -> "String",
"Help" -> "The Wolfram Language code to evaluate.",
"Required" -> True
|>,
"timeConstraint" -> <|
"Interpreter" -> "Integer",
"Help" -> "The time constraint for the evaluation (default is 60 seconds).",
"Required" -> False
|>
}Create a new file in Kernel/Tools/ following this pattern:
(* ::Section::Closed:: *)
(*Package Header*)
BeginPackage[ "Wolfram`AgentTools`Tools`YourTool`" ];
Begin[ "`Private`" ];
Needs[ "Wolfram`AgentTools`" ];
Needs[ "Wolfram`AgentTools`Common`" ];
Needs[ "Wolfram`AgentTools`Tools`" ];
(* ::Section::Closed:: *)
(*Prompts*)
$yourToolDescription = "\
Description of what your tool does.
Include usage guidance for the LLM.";
(* ::Section::Closed:: *)
(*Tool Definition*)
$defaultMCPTools[ "YourTool" ] := LLMTool @ <|
"Name" -> "YourTool",
"DisplayName" -> "Your Tool Name",
"Description" -> $yourToolDescription,
"Function" -> yourToolFunction,
"Options" -> { },
"Parameters" -> {
"param1" -> <|
"Interpreter" -> "String",
"Help" -> "Description of parameter",
"Required" -> True
|>
}
|>;
(* ::Section::Closed:: *)
(*Definitions*)
yourToolFunction // beginDefinition;
yourToolFunction[ KeyValuePattern[ "param1" -> value_ ] ] :=
yourToolFunction @ value;
yourToolFunction[ value_String ] := Enclose[
Module[ { result },
result = ConfirmBy[ yourComputation @ value, StringQ, "Result" ];
(* Tools must return a string *)
result
],
throwInternalFailure
];
yourToolFunction // endDefinition;
(* ::Section::Closed:: *)
(*Package Footer*)
End[ ];
EndPackage[ ];Add your new subcontext to Kernel/Tools/Tools.wl:
$subcontexts = {
"Wolfram`AgentTools`Tools`Context`",
"Wolfram`AgentTools`Tools`Notebooks`",
(* ... existing subcontexts ... *)
"Wolfram`AgentTools`Tools`YourTool`" (* Add your new subcontext *)
};If you want the tool to be included in default servers, update Kernel/DefaultServers.wl:
$defaultMCPServers[ "ServerName" ] := <|
"Name" -> "ServerName",
"Location" -> "BuiltIn",
"Transport" -> "StandardInputOutput",
"ServerVersion" -> $pacletVersion,
"ObjectVersion" -> $objectVersion,
"LLMEvaluator" -> <|
"Tools" -> {
(* ... existing tools ... *)
"YourTool" (* Add your tool *)
},
"MCPPrompts" -> { ... }
|>
|>Add tests to Tests/Tools.wlt:
VerificationTest[
$DefaultMCPTools[ "YourTool" ][ "Name" ],
"YourTool",
TestID -> "YourTool-Name"
]
VerificationTest[
StringQ @ $DefaultMCPTools[ "YourTool" ][ "Description" ],
True,
TestID -> "YourTool-Description"
]CreateMCPServer[ "MyServer", <|
"Tools" -> { "WolframLanguageEvaluator", "WolframAlpha" }
|> ]Tools contributed by third-party paclets can be referenced using paclet-qualified names:
CreateMCPServer[ "MyServer", <|
"Tools" -> {
"WolframLanguageEvaluator",
"PublisherID/MyPaclet/CustomTool"
}
|> ]See paclet-extensions.md for details on how paclets declare tools.
CreateMCPServer[ "MyServer", <|
"Tools" -> {
LLMTool @ <|
"Name" -> "CustomTool",
"Description" -> "Does something custom",
"Function" -> myFunction,
"Parameters" -> {
"input" -> <| "Interpreter" -> "String", "Required" -> True |>
}
|>
}
|> ]Tools receive parameters as an association. Use KeyValuePattern to extract values:
toolFunction[ KeyValuePattern @ {
"param1" -> value1_,
"param2" -> value2_
} ] := toolFunction[ value1, value2 ];Optional parameters may have value Missing["NoInput"]:
toolFunction[ KeyValuePattern @ {
"required" -> value_,
"optional" -> optional_
} ] := Module[ { opt },
opt = Replace[ optional, Except[ _Integer ] -> 60 ]; (* Default value *)
(* ... *)
];For tools that need to access definitions from the evaluator kernel (when using external evaluation):
toolFunction[ args_ ] := useEvaluatorKernel @ toolFunction0 @ args;When the client advertises the roots capability, AgentTools selects a project directory and stores it in $mcpRoot (see mcp-roots.md). The main server kernel and the local evaluator kernel are automatically SetDirectory'd to that path, so tools that evaluate Wolfram Language code or read files via Import etc. inherit the project root with no extra work.
Tools that spawn external processes via RunProcess should pass ProcessDirectory -> $mcpRoot (with a None fallback) so the child process also starts in the project root:
RunProcess[
processArgs,
ProcessDirectory -> If[ StringQ @ $mcpRoot, $mcpRoot, Inherited ]
]$mcpRoot is exported from WolframAgentToolsCommon``. Tools must tolerate $mcpRoot === None` (no client root, capability not advertised, etc.) and fall back to the kernel's working directory.
Use the "Initialization" property for lazy setup (e.g., loading vector databases):
$defaultMCPTools[ "MyTool" ] := LLMTool @ <|
(* ... *)
"Initialization" :> initializeResources[ ]
|>A tool can behave differently depending on where the MCP server is running. Two exported symbols describe the host and are bound by each transport before the server's tool tables are built (both are None outside a server session):
| Symbol | Values |
|---|---|
$MCPEvaluationEnvironment |
"Local" for the stdio server started by StartMCPServer; "Cloud" for a cloud-deployed server |
$MCPTransport |
"StandardInputOutput" for the stdio transport; "StreamableHTTP" for the cloud (Streamable HTTP) transport |
The "Overrides" property is a (typically delayed) association of tool properties that is merged into the tool definition at that point, so one tool name can present a different description, parameter set, and implementation per environment:
$defaultMCPTools[ "WriteNotebook" ] := LLMTool @ <|
"Name" -> "WriteNotebook",
"Description" -> "Converts markdown text to a Wolfram notebook and saves it to a file.",
"Function" -> writeNotebook,
"Parameters" -> { (* file, overwrite, markdown *) },
"Overrides" :> If[ $MCPEvaluationEnvironment === "Cloud", $writeNotebookCloudOverrides, <| |> ]
|>;
$writeNotebookCloudOverrides = <|
"Description" -> "Converts markdown text to a Wolfram notebook and deploys it to a cloud object.",
"Function" -> writeCloudNotebook,
"Parameters" -> { (* path, permissions, overwrite, markdown *) }
|>;Overrides replace whole properties (e.g. the entire "Parameters" list); <| |> or None leaves the tool unchanged. They are applied by initializeServerState (both transports) and by serverToolListData (the cloud landing page's /api/info), not when a tool is evaluated directly, so $DefaultMCPTools["WriteNotebook"] always holds the local definition.
Two further exported symbols describe the product rather than the transport: $StandaloneMCPServer is True when the kernel is the standalone MCP server product (a kernel that only runs the MCP server, without a full Mathematica installation), and $StandaloneMCPServerInformation holds the information that product publishes about itself. Both are set by the standalone application and are False and <| |> everywhere else; see usage-data.md.
Tools must return strings. For structured output, use consistent formats:
"# Result\n\n## Section\n\n```wl\ncode\n```"Return error information as part of the string:
"Error: Invalid input \"" <> input <> "\""Images can be exported to cloud and returned as markdown links:
""Tools should handle errors gracefully using the standard error handling pattern:
toolFunction[ args_ ] := Enclose[
Module[ { result },
result = ConfirmBy[ computation[ args ], StringQ, "Result" ];
result
],
throwInternalFailure
];The server wraps tool calls with error handling that converts failures to error messages rather than MCP protocol errors.
Tools can specify their LLMKit dependency:
| Value | Meaning |
|---|---|
"Required" |
Tool will fail without LLMKit subscription |
"Suggested" |
Tool works better with LLMKit but has fallback |
Automatic |
No special dependency |
Example:
$defaultMCPTools[ "WolframAlphaContext" ] := LLMTool @ <|
(* ... *)
"LLMKit" -> "Required"
|>Tools can define configurable options that users can customize at install time via the "ToolOptions" option on InstallMCPServer. This allows controlling tool behavior without modifying source code.
- Default values are defined per-tool in
$defaultToolOptions(alongside tool definitions inKernel/Tools/) - User overrides are passed via
"ToolOptions"when callingInstallMCPServer - At install time, options are serialized to the
MCP_TOOL_OPTIONSenvironment variable in the server configuration - At runtime,
$toolOptionsis populated from this environment variable at server startup - Tool code reads options via
toolOptionValue[toolName, optionName], which falls back from user override to default
Default options are defined alongside the tool definition using $defaultToolOptions:
$defaultToolOptions[ "YourTool" ] = <|
"OptionName" -> defaultValue
|>;Use toolOptionValue to read an option with automatic fallback:
toolOptionValue[ "YourTool", "OptionName" ]The lookup priority is:
$toolOptions(user-specified viaMCP_TOOL_OPTIONS) — highest priority$defaultToolOptions— lowest priorityMissing["ToolOption", ...]if not found
A common pattern is to define a file-scoped variable that reads the option lazily:
$myOption := toolOptionValue[ "YourTool", "OptionName" ];| Option | Type | Default | Description |
|---|---|---|---|
"Method" |
String | Automatic |
Evaluation method. "Session" uses the server kernel; "Local" spawns a separate sandboxed kernel; "Cloud" runs each evaluation in a fresh Wolfram Cloud kernel. Automatic means "Cloud" when the server itself runs in the cloud (see cloud-deployment.md) and "Session" otherwise. |
"ImageExportMethod" |
String | None |
How to export graphics. None, "Local", "Cloud", or "CloudPublic". |
"TimeConstraint" |
Integer | 60 |
Default time limit (seconds) when the LLM doesn't specify timeConstraint. The LLM can still override this per-call. |
"MaxSessionCount" |
Integer | 100 |
Maximum number of saved evaluator sessions to keep (oldest pruned first; the current session is always kept). |
"MaxSessionBytes" |
Integer | 1073741824 |
Total byte budget for saved evaluator sessions. |
"MaxSessionAge" |
Quantity | Quantity[1, "Months"] |
Saved evaluator sessions older than this are pruned. |
The evaluator's optional session parameter gives each conversation an isolated, resumable session
(its definitions, line numbers, and In/Out history). Sessions are saved under
$UserBaseDirectory/ApplicationData/Wolfram/AgentTools/Sessions/ after every call, so they survive
server restarts, and every result ends with a reminder of the session ID to pass on subsequent calls.
With Chatbook 2.7.28+, each top-level input of the code gets its own line number, as in an interactive
kernel session (1 + 1 and 2 + 2 on separate lines give Out[1]= 2 and Out[2]= 4), so one call can
use up several lines. Chatbook reports the line number for the next input (the "Line" property of
WolframLanguageToolEvaluate), and the session continues from there. Session bookkeeping in the "Local"
eval kernel is evaluated with "Line" -> None, so it uses no line number and stays out of the In/Out
history. Older Chatbook versions evaluate the code as a single input, so the line number advances by one
per call.
Under the "Cloud" method each call runs in a fresh, non-persistent cloud kernel, so only a session's
global definitions persist: Chatbook 2.7.11+ returns the evaluator kernel's Global` definitions
after each call as an MX byte array (WolframChatbook$CloudSessionMX), which AgentTools stores in
the session file and hands back before the next call. Loaded packages, In/Out history, %, and any
other kernel state are lost between calls, and each result's session reminder says so (with an older
Chatbook on the server it says that definitions cannot be restored at all).
| Option | Type | Default | Description |
|---|---|---|---|
"MaxItems" |
Integer | 10 |
Number of documentation results to return. |
| Option | Type | Default | Description |
|---|---|---|---|
"MaxItems" |
Integer or Automatic |
Automatic |
Maximum number of Wolfram|Alpha results. Automatic uses internal defaults. |
"IncludeWolframLanguageResults" |
Boolean or Automatic |
Automatic |
Whether to include Wolfram Language code results. |
| Option | Type | Default | Description |
|---|---|---|---|
"WolframLanguageMaxItems" |
Integer | 10 |
Max documentation results (independent of WolframLanguageContext options). |
"WolframAlphaMaxItems" |
Integer or Automatic |
Automatic |
Max Wolfram|Alpha results (independent of WolframAlphaContext options). |
Because the combined tool provides documentation results alongside the Wolfram|Alpha results, it also passes "DocumentationProvided" -> True to RelatedWolframAlphaResults so that queries better answered by documentation are skipped. The option only exists in newer Chatbook versions (2.7.2+), so it is passed only when the loaded Chatbook actually supports it (detected via documentationProvidedAvailableQ in Kernel/Tools/Context.wl).
Users customize tool options when installing an MCP server:
InstallMCPServer[
"ClaudeCode",
"WolframLanguage",
"ToolOptions" -> <|
"WolframLanguageEvaluator" -> <|"Method" -> "Local", "TimeConstraint" -> 120|>,
"WolframLanguageContext" -> <|"MaxItems" -> 20|>
|>
]Kernel/Tools/Tools.wl- Main tools module, defines$DefaultMCPToolsKernel/Tools/Context.wl- Context tools (WolframContext, WolframAlphaContext, WolframLanguageContext)Kernel/Tools/WolframLanguageEvaluator.wl- Code evaluation tool (with UI-enhanced mode)Kernel/Tools/WolframAlpha.wl- Wolfram Alpha query tool (with UI-enhanced mode)Kernel/Tools/NotebookViewer.wl- Embedded notebook viewer tool (MCP Apps)Kernel/Tools/MCPAppsTest.wl- MCP Apps diagnostic toolKernel/Tools/SymbolDefinition.wl- Symbol definition lookup toolKernel/Tools/Notebooks.wl- ReadNotebook and WriteNotebook toolsKernel/Tools/TestReport.wl- Test runner toolKernel/Tools/CodeInspector/- Code inspection toolKernel/Tools/PacletDocumentation/- Documentation editing toolsKernel/Tools/PacletTools/- Paclet check/build/submit toolsKernel/UIResources.wl- UI resource registry for MCP AppsKernel/MCPServerObject.wl- Tool validation and normalizationKernel/Server/Shared.wl- Protocol handling fortools/listandtools/call(includingtoolSchema, which sanitizes tool schema"pattern"fields for JSON Schema consumers)Kernel/Utilities.wl-toJSRegex, the ICU/PCRE → ECMA 262 regex conversion used bytoolSchemaKernel/DefaultServers.wl- Server configurations with"Tools"settingsAssets/Apps/- HTML and JSON files for MCP Apps UI resourcesKernel/PacletExtension.wl- Paclet-qualified tool resolution (see paclet-extensions.md)Kernel/MCPRoots.wl- Project-root handshake ($mcpRoot); see mcp-roots.mdTests/Tools.wlt- Tests for tool functionalityTests/PacletTools.wlt- Tests for CheckPaclet, BuildPaclet, and SubmitPacletTests/ToolOptions.wlt- Tests for tool options systemSpecs/ToolOptions.md- Design specification for tool optionsAgentSkills/Manifest.wl- Maps tools to distributable agent skills (see agent-skills.md)Scripts/BuildAgentSkills.wls- Generates standalone.wlsscripts from tool definitions and writes the built skills toAssets/AgentSkills/(rebuild and commit after changing a tool that a skill uses;Tests/AgentSkillsBuild.wltfails when the built skills are stale)