Skip to main content
Glama
BobGod

WeChat Publisher MCP

by BobGod

wechat_query_status

Check WeChat Official Account article publishing status and view statistics using message ID and account credentials.

Instructions

查询文章发布状态和统计数据

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
msgIdYes消息ID
appIdYes微信公众号AppID
appSecretYes微信公众号AppSecret

Implementation Reference

  • src/server.js:74-108 (registration)
    Registration of the wechat_query_status tool, including input schema definition and thin wrapper handler that delegates to WeChatStatus.query
    server.registerTool(
      "wechat_query_status",
      {
        description: "查询文章发布状态和统计数据",
        inputSchema: {
          msgId: z.string().describe("消息ID"),
          appId: z.string().describe("微信公众号AppID"),
          appSecret: z.string().describe("微信公众号AppSecret")
        }
      },
      async (params) => {
        const { msgId, appId, appSecret } = params;
        logger.info(`Querying status for message: ${msgId}`);
        
        try {
          // 调用实际的查询逻辑
          const result = await WeChatStatus.query({
            msgId,
            appId,
            appSecret
          });
          
          return result;
        } catch (error) {
          logger.error(`查询失败: ${error.message}`);
          return {
            content: [{
              type: "text",
              text: `❌ 查询失败: ${error.message}`
            }],
            isError: true
          };
        }
      }
    );
  • Core handler implementation for wechat_query_status: performs parameter validation, initializes WeChatAPI, queries publish status, formats detailed response with stats, handles errors.
    static async query(params) {
      const startTime = Date.now();
      
      try {
        logger.info('开始查询状态', { msgId: params.msgId });
        
        // 1. 参数验证
        const validation = validateStatusParams(params);
        if (!validation.valid) {
          throw new Error(`参数验证失败: ${validation.errors.join(', ')}`);
        }
    
        const { msgId, appId, appSecret } = params;
    
        // 2. 初始化微信API
        logger.debug('初始化微信API');
        const wechatAPI = new WeChatAPI(appId, appSecret);
    
        // 3. 查询发布状态
        logger.debug('查询发布状态', { msgId });
        const statusData = await wechatAPI.getPublishStatus(msgId);
    
        const executionTime = Date.now() - startTime;
        logger.info('状态查询成功', { 
          msgId,
          status: statusData.publish_status,
          executionTime: `${executionTime}ms` 
        });
    
        // 4. 构建成功响应
        const successMessage = this.buildStatusMessage(statusData, executionTime, msgId);
    
        return {
          content: [{
            type: "text",
            text: successMessage
          }]
        };
    
      } catch (error) {
        const executionTime = Date.now() - startTime;
        logger.error('状态查询失败', {
          msgId: params.msgId,
          error: error.message,
          executionTime: `${executionTime}ms`,
          stack: error.stack
        });
        
        return {
          content: [{
            type: "text",
            text: this.buildErrorMessage(error)
          }],
          isError: true
        };
      }
    }
  • Low-level helper that performs the actual HTTP request to WeChat API endpoint /cgi-bin/freepublish/get to retrieve publish status and article stats.
    async getPublishStatus(msgId) {
      logger.info('开始查询发布状态', { msgId, appId: this.appId });
      
      // 检查是否为明确的测试模式(只有以test_开头的msgId才使用模拟数据)
      if (msgId && msgId.toString().startsWith('test_')) {
        logger.info('测试模式:返回模拟状态数据', { msgId });
        return {
          errcode: 0,
          errmsg: 'ok',
          publish_status: 1, // 发布成功
          article_detail: {
            count: 1,
            item: [{
              article_id: msgId,
              title: '测试文章标题',
              author: '测试作者',
              digest: '这是一篇测试文章',
              content: '',
              content_source_url: '',
              url: `https://mp.weixin.qq.com/s/test_${msgId}`,
              publish_time: Math.floor(Date.now() / 1000),
              stat_info: {
                read_num: 0,  // 测试模式不显示虚假阅读量
                like_num: 0,
                comment_num: 0,
                share_num: 0
              }
            }]
          }
        };
      }
      
      // 对于真实的msgId,始终调用真实的微信API
      const accessToken = await this.getAccessToken();
      logger.debug('获取到access_token,准备查询状态', { tokenLength: accessToken.length });
      
      try {
        logger.debug('调用微信API查询发布状态', { 
          msgId, 
          api: 'freepublish/get' 
        });
        
        const response = await axios.post(
          `https://api.weixin.qq.com/cgi-bin/freepublish/get?access_token=${accessToken}`,
          { publish_id: msgId },
          { timeout: 15000 }
        );
    
        logger.debug('微信API响应', { 
          errcode: response.data.errcode,
          errmsg: response.data.errmsg,
          hasArticleDetail: !!response.data.article_detail
        });
    
        if (response.data.errcode === 0) {
          logger.info('状态查询成功', { 
            msgId,
            status: response.data.publish_status,
            articleCount: response.data.article_detail?.count || 0
          });
          return response.data;
        } else {
          // 如果是文章不存在或权限问题,返回更友好的错误信息
          if (response.data.errcode === 40007) {
            throw new Error(`文章不存在或已被删除 (错误码: ${response.data.errcode})`);
          } else if (response.data.errcode === 40001) {
            throw new Error(`access_token无效,请检查AppID和AppSecret (错误码: ${response.data.errcode})`);
          } else {
            throw new Error(`查询发布状态失败: ${response.data.errmsg} (错误码: ${response.data.errcode})`);
          }
        }
      } catch (error) {
        logger.error('状态查询失败', { 
          msgId,
          error: error.message,
          isAxiosError: !!error.response
        });
        
        if (error.response) {
          const errorData = error.response.data;
          throw new Error(`微信API调用失败: ${errorData.errmsg || error.message} (HTTP状态: ${error.response.status})`);
        } else if (error.code === 'ECONNABORTED') {
          throw new Error('请求超时,请检查网络连接后重试');
        } else {
          throw new Error(`网络请求失败: ${error.message}`);
        }
      }
    }
  • Runtime input schema validation for wechat_query_status parameters: checks required fields, formats, lengths for msgId, appId, appSecret.
    function validateStatusParams(params) {
      const errors = [];
      
      // 必需参数检查
      if (!params.msgId || typeof params.msgId !== 'string' || params.msgId.trim() === '') {
        errors.push('msgId参数是必需的,且不能为空字符串');
      }
      
      if (!params.appId || typeof params.appId !== 'string' || params.appId.trim() === '') {
        errors.push('appId参数是必需的,且不能为空字符串');
      }
      
      if (!params.appSecret || typeof params.appSecret !== 'string' || params.appSecret.trim() === '') {
        errors.push('appSecret参数是必需的,且不能为空字符串');
      }
      
      // 格式验证
      if (params.msgId && !isValidMsgId(params.msgId)) {
        errors.push('msgId格式不正确,应该是数字字符串');
      }
      
      // AppID格式验证
      if (params.appId && !params.appId.startsWith('wx')) {
        errors.push('AppID格式错误,应该以"wx"开头');
      }
      
      if (params.appId && params.appId.length !== 18) {
        errors.push('AppID长度应该为18个字符');
      }
      
      // AppSecret格式验证
      if (params.appSecret && params.appSecret.length !== 32) {
        errors.push('AppSecret长度应该为32个字符');
      }
      
      return {
        valid: errors.length === 0,
        errors
      };
    }
  • Zod-based input schema definition for the tool registration, specifying required string parameters.
    description: "查询文章发布状态和统计数据",
    inputSchema: {
      msgId: z.string().describe("消息ID"),
      appId: z.string().describe("微信公众号AppID"),
      appSecret: z.string().describe("微信公众号AppSecret")
    }
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool queries status and statistics, implying a read-only operation, but doesn't clarify aspects like authentication needs (though parameters suggest it), rate limits, error handling, or what specific data is returned. This leaves gaps in understanding the tool's behavior.

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

Conciseness4/5

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

The description is a single, concise sentence in Chinese that directly states the tool's purpose. It's front-loaded with no unnecessary words, making it efficient. However, it could be slightly improved by adding brief context or usage hints without losing conciseness.

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

Completeness3/5

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

Given the tool's moderate complexity (3 required parameters, no output schema, no annotations), the description is minimally adequate. It covers the basic purpose but lacks details on behavioral traits, usage guidelines, and output expectations. With no annotations or output schema, more context would be helpful for an AI agent to use it 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?

The input schema has 100% description coverage, with clear parameter descriptions in Chinese (e.g., '消息ID' for msgId). The description doesn't add any additional meaning beyond the schema, such as explaining parameter relationships or usage examples. Since schema coverage is high, the baseline score of 3 is appropriate.

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

Purpose4/5

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

The description clearly states the tool's purpose: '查询文章发布状态和统计数据' translates to 'query article publishing status and statistical data.' This specifies the verb (query) and resource (article publishing status/statistics). However, it doesn't explicitly differentiate from the sibling tool 'wechat_publish_article,' which appears to be for publishing rather than querying.

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. It doesn't mention the sibling tool 'wechat_publish_article' or any other tools, nor does it specify prerequisites, contexts, or exclusions for usage.

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/BobGod/wechat-publisher-mcp'

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