MCP Tool Development Guide

This article describes how to develop MCP tools, covering the complete development workflow from defining functions and writing tool descriptions to registering and publishing tools.

1. Development Workflow

DolphinDB MCP tool development follows this workflow:

  1. Define functions: Implement the core business logic of the tool.
  2. Write the description: Provide detailed instructions for the large language model on how to call the tool.
  3. Register the tool: Use addMCPTool or updateMCPTool to register the tool with the MCP Server.
  4. Publish the tool: Use publishMCPTools to publish the tool so that clients can call it.

2. Define Functions

2.1 Supported Parameter Types

The large language model passes parameters to the MCP Server in JSON format. The following types are currently supported:

Table 1. Table 2-1 Supported Parameter Types
DolphinDB Type JSON Type Description
STRING string String
TEMPORAL (DATE, etc.) string Temporal type; pass it as a string and then convert it.
DOUBLE number Numeric type
BOOL boolean Boolean type
STRING[] array\ String array
TEMPORAL[] array\ Temporal array
DOUBLE[] array\ Numeric array
BOOL[] array\ Boolean array
Note:

You cannot pass a dictionary directly as a function parameter. Instead, pass it as a JSON string, and then use parseExpr().eval() in the function to parse it into a dictionary object.

2.2 Parameter Design

  • Intuitiveness: Parameter names must have clear natural-language meanings. For example, use stockCodes instead of codes.
  • Explicitness: If a parameter accepts only a limited set of values, list all possible values in the description.
  • Session management: If you need to save intermediate results from a tool call, include the sessionId and resultTableName parameters for shared in-memory table management.

2.3 Return Value Design

  • Return size: We recommend using toStdJson(t[0:min(10, t.size())]) to return the first 10 rows.
  • Status information: Return key information such as the operation result, shared table name, and data volume.
  • Conciseness: Avoid returning excessive data to prevent the context from becoming too long.

2.4 Sample Function Code

def get_stock_basic_info(stockCodes, resultTableName, sessionId){
    // 1. Load data and filter stock information
    t = select * from loadTable("dfs://basic_factor", "stock_basic") 
        where ts_code in stockCodes or symbol in stockCodes
    
    // 2. Session management
    if (trim(sessionId) != "") {
        if (trim(resultTableName) != "") {
            resultName = resultTableName + "_" + sessionId
            share(t, resultName)
            return "Query succeeded:shared table name " + resultName + 
                   "\nfirst 10 rows:\n" + toStdJson(t[0:min(10, t.size())])
        }
    }
    
    // 3. Return results
    return "Query succeeded:first 10 rows:\n" + toStdJson(t[0:min(10, t.size())])
}

3. Write Tool Descriptions

Tool descriptions are essential for helping the large language model understand and correctly call MCP tools. They must include the following sections.

3.1 Description Template

description_xxx = '
[Overview] - A one-sentence description of the tool’s core functionality.

Parameters:
- parameter1: Type, description
- parameter2: Type, description (if the parameter accepts only specific values, list all possible values)
- sessionId: STRING. A unique identifier for the current session, used to generate a unique shared table name. If empty, the in-memory table will not be shared and the query result will be returned directly.
- resultTableName: STRING. The name of the shared in-memory table used for subsequent analysis. It is recommended to use a meaningful name such as "xxx".

Returns:
- Operation result information, including the shared table name (if any) and sample data from the first 10 rows.

Example Code:

// Example 1 - Full usage with intermediate table management
functionName([parameter values], "table_name", "session123")

// Example 2 - Simplified usage without shared in-memory tables
functionName([parameter values], "", "")
'

3.2 Key Points for Writing Descriptions

Feature overview

  • State the tool's purpose directly in one sentence.
  • Example: "Load basic information for specified stock codes from the DolphinDB stock_basic table."

Parameter description

  • Each parameter must include a name, type, and detailed description.
  • Use STRING[], DATE[], and similar notation for list types.
  • For parameters that accept only a limited set of values, explicitly list all possible values.
  • Example:
    - stockCodes: STRING[], stock code list
    - dates: DATE[], date list

Return description

  • Clearly describe the format of the returned content and the information it contains.
  • Example: "Operation result information, including the shared table name (if any) and sample data from the first 10 rows."

Sample code

  • Provide at least two examples that cover the main use cases.
  • Use comments to describe the scenario for each example.

3.3 Complete Example

description_select_stocks_by_factors = '
Select stocks from the DolphinDB table day_factor based on user-specified factors and filtering conditions. The filtering is performed using data from the most recent trading day.

Parameters:
- factors: STRING[]. A list of factors specified by the user. Supported factors include existing indicators such as "pe" and "pb".
- conditions: STRING[]. A list of filtering conditions, where each condition is a string expression (e.g., "pe < 15", "pb > 1").
- resultTableName: STRING. The name of the shared in-memory table for subsequent analysis. It is recommended to use a meaningful name such as "selected_stocks".
- sessionId: STRING. A unique identifier for the current session, used to generate a unique shared table name. If empty, the in-memory table will not be shared and the query result will be returned directly.

Returns:
- Operation result information, including the shared table name (if any) and sample data from the first 10 rows.

Examples:

// Select stocks by the "pe" and "pb" indicators, using the filter conditions "pe < 15" and "pb > 1"
select_stocks_by_factors(["pe", "pb"], ["pe < 15", "pb > 1"], "selected_stocks", "session123")

// Simplified call without sharing the in-memory table
select_stocks_by_factors(["rev_yoy", "profit_yoy"], ["rev_yoy > 10", "profit_yoy > 5"], "", "")
'

4. Register and Publish Tools

After you develop an MCP tool, you must register it before publishing it for clients to use.

4.1 Register Tools

Use addMCPTool or updateMCPTool to register a function as an MCP tool.

We recommend using the following template to register tools:

if (`tool_name in (exec name from listMCPTools())) {
  updateMCPTool(`tool_name, tool_function, 
                `param1`param2`param3, 
                ["TYPE1", "TYPE2", "TYPE3"], 
                description_tool_name)
} else {
  addMCPTool(`tool_name, tool_function, 
             `param1`param2`param3, 
             ["TYPE1", "TYPE2", "TYPE3"], 
             description_tool_name)
}

To update an existing MCP tool, use updateMCPTool. Its parameters are similar to those of addMCPTool.

4.2 Publish Tools

Use publishMCPTools() to publish registered tools so that clients can call them.

After publishing, you can select and enable the tools from the tool list in clients.

publishMCPTools(`tool_name)