Skip to main content
Glama
WonderCV

ClawHire MCP

by WonderCV

request_outreach

Send job invitations to potential candidates in the WonderCV database. Candidates receive branded messages and can choose to join ClawHire to share their profile with you.

Instructions

向数据库候选人(未入驻 ClawHire 的 WonderCV 用户)发送职位邀请。

工作原理

  1. ClawHire 代表您发送一封品牌化的邮件/微信消息

  2. 候选人收到:"【公司名】对您的简历感兴趣,邀请您了解 [职位名称]"

  3. 候选人可选择:感兴趣(加入 ClawHire 并开放档案)或不感兴趣

  4. 如候选人感兴趣,将自动出现在您的候选人列表中

限制

  • 每日限额(Alpha: 10次/天, Free: 5次/天)

  • 同一候选人90天内只能联系一次

  • 候选人可随时退订

提示

  • 建议配合职位使用,说明具体职位而非泛泛邀请

  • 简短的个性化消息可提高回复率

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idYes会话 ID,从 register_company 获取
candidate_refYes候选人引用ID(从 search_candidates 的 database_candidates 获取)
job_tokenYes关联的职位token,用于在邀请邮件中展示职位信息
messageNo自定义邀请消息(可选),将附在标准模板后

Implementation Reference

  • The main handler function that executes the request_outreach tool logic - validates session, checks quota, calls backend API, and returns response
    async execute(input: Input) {
      // Validate session
      const session = getSession(input.session_id);
      if (!session) {
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                error: {
                  code: 'INVALID_SESSION',
                  message: '会话已过期或无效,请重新调用 register_company',
                },
              }, null, 2),
            },
          ],
          isError: true,
        };
      }
    
      // Check outreach quota (preview only)
      // TODO: Fix race condition under concurrent load (KnownIssues.md #1)
      const remainingBefore = getRemainingQuota(session, 'outreach_sent');
      if (remainingBefore <= 0) {
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                error: {
                  code: 'QUOTA_EXCEEDED',
                  message: `今日 outreach 额度已用完`,
                },
                access: {
                  tier: session.tier,
                  remaining_outreach_today: 0,
                  reset_at: '次日零点',
                },
              }, null, 2),
            },
          ],
          isError: true,
        };
      }
    
      try {
        const response = await requestOutreach({
          session_id: input.session_id,
          candidate_ref: input.candidate_ref,
          job_token: input.job_token,
          message: input.message,
        });
    
        const { data } = response;
    
        // Consume quota only after successful outreach
        checkAndIncrementUsage(session, 'outreach_sent');
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                data: {
                  outreach_id: data.outreach_id,
                  status: data.status,
                  message: data.message,
                  note: '候选人尚未加入ClawHire平台。如果候选人感兴趣,将自动出现在您的候选人列表中。',
                },
                access: {
                  tier: session.tier,
                  remaining_outreach_today: getRemainingQuota(session, 'outreach_sent'),
                },
                meta: {
                  session_id: session.session_id,
                },
                next_steps: [
                  '继续浏览其他数据库候选人',
                  '使用 search_candidates 查看市场候选人(已入驻,可直接查看档案)',
                  '候选人回复后将收到通知',
                ],
              }, null, 2),
            },
          ],
          isError: false,
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : '发送邀请失败';
        const isRateLimit = errorMessage.includes('rate limit') || errorMessage.includes('cooldown');
        
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                error: {
                  code: isRateLimit ? 'OUTREACH_COOLDOWN' : 'OUTREACH_FAILED',
                  message: isRateLimit 
                    ? '该候选人近期已收到过邀请,请90天后再试'
                    : errorMessage,
                },
                hint: isRateLimit 
                  ? '每位候选人90天内只能收到一次邀请,请尊重候选人隐私'
                  : '请检查 candidate_ref 和 job_token 是否正确',
              }, null, 2),
            },
          ],
          isError: true,
        };
      }
    },
  • Zod input schema defining validation for session_id, candidate_ref, job_token, and optional message fields
    const inputSchema = z.object({
      session_id: z.string()
        .describe('会话 ID,从 register_company 获取'),
      
      candidate_ref: z.string()
        .describe('候选人引用ID(从 search_candidates 的 database_candidates 获取)'),
      
      job_token: z.string()
        .describe('关联的职位token,用于在邀请邮件中展示职位信息'),
      
      message: z.string()
        .max(500, '自定义消息不能超过500字')
        .optional()
        .describe('自定义邀请消息(可选),将附在标准模板后'),
    });
    
    type Input = z.infer<typeof inputSchema>;
  • TypeScript interfaces (RequestOutreachInput, RequestOutreachOutput) and API function for the backend request
    export interface RequestOutreachInput {
      session_id: string;
      candidate_ref: string;
      job_token: string;
      message?: string;
    }
    
    export interface RequestOutreachOutput {
      outreach_id: string;
      status: string;
      message: string;
    }
    
    export async function requestOutreach(
      input: RequestOutreachInput
    ): Promise<ApiResponse<RequestOutreachOutput>> {
      return apiRequest('/candidates/outreach', {
        method: 'POST',
        body: input,
        sessionId: input.session_id,
      });
    }
  • Tool registration - imports requestOutreachTool and exports it in allTools array for server initialization
    import { requestOutreachTool } from './request_outreach.js';
    
    // Export all tools
    export {
      registerCompanyTool,
      postJobTool,
      listJobsTool,
      searchCandidatesTool,
      viewCandidateTool,
      listApplicationsTool,
      requestOutreachTool,
    };
    
    // Tool registry for server initialization
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    export const allTools: Tool<any>[] = [
      registerCompanyTool,
      postJobTool,
      listJobsTool,
      searchCandidatesTool,
      viewCandidateTool,
      listApplicationsTool,
      requestOutreachTool,
    ];

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/WonderCV/clawhire-mcp'

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