Skip to main content
Glama
esign-cn-open-source

e签宝 MCP Server

Official

create_sign_flow

Create electronic signature workflows for documents in multiple formats including PDF, Word, Excel, and images, with automatic PDF conversion and SMS notifications for signers.

Instructions

创建签署流程,支持多种文件格式,包括:PDF、Word、Excel、PPT、WPS、图片等。非PDF格式会自动转换为PDF。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filePathYes文件路径,支持本地文件路径或 HTTP(S) 远程文件下载链接。支持的格式:PDF(.pdf)、Word(.docx/.doc/.rtf)、Excel(.xlsx/.xls)、PPT(.pptx/.ppt)、WPS(.wps/.et/.dps)、图片(.jpg/.png/.bmp等)、HTML(.html/.htm)
fileNameYes文件名,必须包含文件扩展名(例如:合同.pdf、文档.docx),扩展名要与实际文件格式一致
receiverPhoneYes签署人手机号,用于接收签署通知短信
usernameNo签署人姓名,非必填,默认为空字符串,如果对方没有在e签宝注册过, 则必须提供姓名; 如果对应用户已存在个人信息,则不需要添加姓名

Implementation Reference

  • Primary handler logic for the 'create_sign_flow' tool in the CallToolRequestSchema handler. Orchestrates file upload, waits for file processing, creates the sign flow, generates sign URL, and returns success/error response.
    case "create_sign_flow": {
        try {
            const args = request.params.arguments as unknown as SignRequest;
            const {filePath, fileName, receiverPhone, username} = args;
    
            logToFile(`uploadFile filePath: ${filePath} fileName: ${fileName}`);
    
            const fileId = await uploadFile(filePath, fileName);
            // 等待文件处理完成
            await waitForFileProcessing(fileId);
    
            const flowId = await createSignFlow(fileId, receiverPhone, fileName, username);
            const signUrl = await getSignUrl(flowId, receiverPhone);
    
            return {
                content: [{
                    type: "text",
                    text: `Success!\nFlow ID: ${flowId}\nSign URL: ${signUrl}`
                }]
            };
        } catch (err: any) {
            return {
                content: [{
                    type: "text",
                    text: `Error: ${err.message}`
                }]
            };
        }
    }
  • Input schema definition for the 'create_sign_flow' tool, specifying parameters: filePath, fileName, receiverPhone, username.
    inputSchema: {
        type: "object",
        properties: {
            filePath: {
                type: "string",
                description: "文件路径,支持本地文件路径或 HTTP(S) 远程文件下载链接。支持的格式:PDF(.pdf)、Word(.docx/.doc/.rtf)、Excel(.xlsx/.xls)、PPT(.pptx/.ppt)、WPS(.wps/.et/.dps)、图片(.jpg/.png/.bmp等)、HTML(.html/.htm)"
            },
            fileName: {
                type: "string",
                description: "文件名,必须包含文件扩展名(例如:合同.pdf、文档.docx),扩展名要与实际文件格式一致"
            },
            receiverPhone: {
                type: "string",
                description: "签署人手机号,用于接收签署通知短信"
            },
            username: {
                type: "string",
                description: "签署人姓名,非必填,默认为空字符串,如果对方没有在e签宝注册过, 则必须提供姓名; 如果对应用户已存在个人信息,则不需要添加姓名"
            }
        },
        required: ["filePath", "fileName", "receiverPhone"]
    }
  • src/index.ts:163-187 (registration)
    Tool registration in the ListTools response, defining name, description, and input schema for 'create_sign_flow'.
        name: "create_sign_flow",
        description: "创建签署流程,支持多种文件格式,包括:PDF、Word、Excel、PPT、WPS、图片等。非PDF格式会自动转换为PDF。",
        inputSchema: {
            type: "object",
            properties: {
                filePath: {
                    type: "string",
                    description: "文件路径,支持本地文件路径或 HTTP(S) 远程文件下载链接。支持的格式:PDF(.pdf)、Word(.docx/.doc/.rtf)、Excel(.xlsx/.xls)、PPT(.pptx/.ppt)、WPS(.wps/.et/.dps)、图片(.jpg/.png/.bmp等)、HTML(.html/.htm)"
                },
                fileName: {
                    type: "string",
                    description: "文件名,必须包含文件扩展名(例如:合同.pdf、文档.docx),扩展名要与实际文件格式一致"
                },
                receiverPhone: {
                    type: "string",
                    description: "签署人手机号,用于接收签署通知短信"
                },
                username: {
                    type: "string",
                    description: "签署人姓名,非必填,默认为空字符串,如果对方没有在e签宝注册过, 则必须提供姓名; 如果对应用户已存在个人信息,则不需要添加姓名"
                }
            },
            required: ["filePath", "fileName", "receiverPhone"]
        }
    },
  • Core helper function that performs the actual API call to create the signing flow with predefined sign field positions.
    async function createSignFlow(fileId: string, receiverPhone: string, fileName: string, username : string): Promise<string> {
        const requestPath = '/v3/sign-flow/create-by-file';
        const requestBody = JSON.stringify({
            docs: [{
                fileId: fileId,
                fileName: fileName
            }],
            signFlowConfig: {
                signFlowTitle: "待签署文件",
                signFlowDesc: "请签署文件",
                signFlowEffectiveTime: Date.now(),
                signFlowExpireTime: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7天后过期
                signOrder: false, // 无序签署
                notifyType: "1", // 短信通知
                redirectUrl: "", // 可以为空
                autoFinish: true
            },
            signers: [{
                signConfig: {
                    signOrder: 1,
                    forcedReadingTime: "10" // 强制阅读时间10秒
                },
                noticeConfig: {
                    noticeTypes: "1" // 短信通知
                },
                signerType: 0, // 个人签署
                psnSignerInfo: {
                    psnAccount: receiverPhone,
                    psnInfo: username === "" || username === undefined ? undefined : {
                        psnName: username === "" ? undefined : username
                    }
                },
                signFields: [{
                    fileId: fileId,
                    signFieldType: 0,
                    normalSignFieldConfig: {
                        autoSign: false,
                        freeMode: false,
                        movableSignField: false,
                        signFieldStyle: 1,
                        signFieldSize: "96",
                        signFieldPosition: {
                            positionPage: "1",
                            positionX: 100,
                            positionY: 100
                        }
                    },
                    signDateConfig: {
                        dateFormat: "yyyy-MM-dd",
                        showSignDate: 1,
                        signDatePositionX: 100,
                        signDatePositionY: 150
                    }
                }]
            }],
            autoStart: true
        });
    
        debugger
        const headers = getCommonHeaders('POST', requestPath, requestBody);
    
        const response = await fetch(`${config.host}${requestPath}`, {
            method: 'POST',
            headers: headers,
            body: requestBody
        });
    
        const result = await response.json() as ApiResponse<SignFlowResponse>;
        if (result.code === 0) {
            return result.data.signFlowId;
        }
        throw new Error(`Sign flow creation failed: ${result.message}`);
    }
  • Helper function for uploading files (local paths or HTTP URLs) to the eSign service, handling format checks, remote downloads, upload URL acquisition, and file upload, returning the fileId.
    async function uploadFile(filePath: string, fileName: string): Promise<string> {
        // 检查文件格式是否支持
        if (!isFileSupported(fileName)) {
            throw new Error(`不支持的文件格式。支持的格式包括:${SUPPORTED_FILE_EXTENSIONS.join(', ')}`);
        }
    
        let actualFilePath = filePath;
        let cleanup: (() => void) | undefined;
    
        try {
            // 检查是否是远程文件
            if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
                logToFile(`检测到远程文件链接: ${filePath}`);
                const downloadResult = await downloadFile(filePath);
                actualFilePath = downloadResult.filePath;
                cleanup = downloadResult.cleanup;
                logToFile(`远程文件已下载到本地: ${actualFilePath}`);
            }
    
            // 步骤一:获取文件上传地址
            const fileSize = fs.statSync(actualFilePath).size;
            const fileBuffer = fs.readFileSync(actualFilePath);
            const contentMd5 = calculateContentMd5(fileBuffer);
            const isPDF = fileName.toLowerCase().endsWith('.pdf');
            const isHTML = fileName.toLowerCase().match(/\.(html|htm)$/);
    
            const requestPath = '/v3/files/file-upload-url';
            const requestBody = JSON.stringify({
                contentMd5,
                contentType: isPDF ? 'application/pdf' : 'application/octet-stream',
                fileName,
                fileSize,
                convertToPDF: !isPDF,
                convertToHTML: isHTML ? false : undefined
            });
    
            logToFile(`上传文件请求参数:\ncontentMd5=${contentMd5}\nfileSize=${fileSize}`);
    
            const headers = getCommonHeaders('POST', requestPath, requestBody, 'application/json; charset=UTF-8');
    
            logToFile("headers " + JSON.stringify(headers))
            const response = await fetch(`${config.host}${requestPath}`, {
                method: 'POST',
                headers: headers,
                body: requestBody
            });
    
            const responseText = await response.text();
            logToFile(`上传文件响应:\n${responseText}`);
    
            const result = JSON.parse(responseText) as ApiResponse<{
                fileId: string;
                fileUploadUrl: string;
            }>;
    
            if (result.code !== 0) {
                throw new Error(`Failed to get upload URL: ${result.message}`);
            }
    
            // 步骤二:上传文件流
            const uploadResponse = await fetch(result.data.fileUploadUrl, {
                method: 'PUT',
                headers: {
                    'Content-Type': isPDF ? 'application/pdf' : 'application/octet-stream',
                    'Content-MD5': contentMd5
                },
                body: fileBuffer
            });
    
            if (!uploadResponse.ok) {
                throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
            }
    
            // 返回文件ID
            return result.data.fileId;
        } finally {
            // 如果是远程文件,清理临时文件
            if (cleanup) {
                cleanup();
            }
        }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. While it mentions automatic PDF conversion for non-PDF files, it doesn't cover critical behavioral aspects like authentication requirements, rate limits, error conditions, what happens after creation, or whether this is a destructive/mutative operation. The description is insufficient for a tool that creates resources.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with just two sentences that efficiently convey key information about format support and PDF conversion. Every word earns its place, and it's front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a creation tool with no annotations and no output schema, the description is incomplete. It doesn't explain what the tool returns, what happens after creation, error handling, or important behavioral constraints. The agent would be missing critical context needed to use this tool effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents all parameters. The description adds no additional parameter semantics beyond what's in the schema descriptions. It mentions format support generally but doesn't provide parameter-specific insights. Baseline 3 is appropriate when schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('创建签署流程' - create signing flow) and resource (files with multiple formats), distinguishing it from the sibling tool 'query_sign_flow' which presumably queries rather than creates. It specifies the verb and resource precisely.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives, nor any context about prerequisites or exclusions. It mentions format support but doesn't explain when to choose this over other tools or what scenarios it's designed for.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/esign-cn-open-source/mcp-server-esign'

If you have feedback or need assistance with the MCP directory API, please join our Discord server