Skip to main content
Glama
WonderCV

ClawHire MCP

by WonderCV

list_applications

View and filter job applications with candidate details, match scores, and AI-agent proficiency badges to identify suitable talent.

Instructions

查看收到的职位申请。

返回信息:

  • 候选人基本信息和匹配度评分

  • AI-Agent 熟练度徽章(MCP用户自动标识)

  • 申请状态和申请时间

  • 候选人的求职信/备注

匹配度评分说明:

  • 90-100: 非常匹配

  • 70-89: 较好匹配

  • 50-69: 一般匹配

  • <50: 可能不匹配

注意:此工具仅查看申请列表,如需处理申请(通过/拒绝)将在 v2 实现。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idYes会话 ID,从 register_company 获取
job_tokenNo按职位过滤(可选),不提供则显示所有职位的申请
statusNo按状态过滤:submitted=新申请, viewed=已查看, shortlisted=已筛选, rejected=已拒绝
pageNo页码
page_sizeNo每页数量

Implementation Reference

  • The main handler (execute function) for list_applications tool. Validates session, calls backend API, formats application data with match scores and AI fluency badges, groups results by status, and returns paginated results with next step suggestions.
    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,
        };
      }
    
      try {
        const response = await listApplications({
          session_id: input.session_id,
          job_token: input.job_token,
          status: input.status,
          page: input.page,
          page_size: input.page_size,
        });
    
        const { data } = response;
    
        // Format applications
        const formattedApplications = data.applications.map(app => ({
          application_id: app.application_id,
          job: {
            token: app.job_token,
            post: app.job_post,
          },
          candidate: {
            id: app.candidate_id,
            headline: app.candidate_headline,
            source: app.candidate_source,
            source_badge: sourceBadgeMap[app.candidate_source] || app.candidate_source,
          },
          match: {
            score: app.match_score,
            reasons: app.match_reasons,
          },
          ai_fluency: {
            badge: app.ai_fluency_badge,
            label: app.ai_fluency_badge === 'ai_power_user' ? 'AI高级用户'
              : app.ai_fluency_badge === 'verified_mcp_user' ? 'MCP用户'
              : app.ai_fluency_badge === 'ai_aware' ? 'AI了解者'
              : '未标识',
          },
          application: {
            status: app.status,
            status_text: statusTextMap[app.status] || app.status,
            applied_at: app.applied_at,
            cover_note: app.cover_note,
          },
        }));
    
        // Group by status for summary
        const statusCounts = data.applications.reduce((acc, app) => {
          acc[app.status] = (acc[app.status] || 0) + 1;
          return acc;
        }, {} as Record<string, number>);
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                data: {
                  applications: formattedApplications,
                  summary: {
                    total: data.total,
                    by_status: statusCounts,
                    ai_fluent_candidates: data.applications.filter(
                      a => a.ai_fluency_badge === 'ai_power_user' || a.ai_fluency_badge === 'verified_mcp_user'
                    ).length,
                  },
                },
                pagination: {
                  page: data.page,
                  page_size: data.page_size,
                },
                meta: {
                  session_id: session.session_id,
                },
                next_steps: formattedApplications.length > 0
                  ? [
                      '调用 view_candidate 查看感兴趣的候选人详细档案',
                      '高匹配度候选人建议优先联系',
                    ]
                  : [
                      '暂无新申请,调用 search_candidates 主动寻找候选人',
                      '调用 list_jobs 查看职位状态',
                    ],
              }, null, 2),
            },
          ],
          isError: false,
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : '获取申请列表失败';
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                error: {
                  code: 'LIST_APPLICATIONS_FAILED',
                  message: errorMessage,
                },
              }, null, 2),
            },
          ],
          isError: true,
        };
      }
    },
  • Zod input schema definition for list_applications tool. Defines validation for session_id (required), job_token (optional), status enum, page and page_size parameters with appropriate constraints.
    const inputSchema = z.object({
      session_id: z.string()
        .describe('会话 ID,从 register_company 获取'),
      
      job_token: z.string()
        .optional()
        .describe('按职位过滤(可选),不提供则显示所有职位的申请'),
      
      status: z.enum(['submitted', 'viewed', 'shortlisted', 'rejected'])
        .optional()
        .describe('按状态过滤:submitted=新申请, viewed=已查看, shortlisted=已筛选, rejected=已拒绝'),
      
      page: z.number()
        .int()
        .positive()
        .optional()
        .describe('页码'),
      
      page_size: z.number()
        .int()
        .positive()
        .max(50)
        .optional()
        .describe('每页数量'),
    });
  • Registration of listApplicationsTool - imported from list_applications.ts, exported, and added to the allTools registry array for MCP server initialization.
    import { listApplicationsTool } from './list_applications.js';
    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,
    ];
  • Backend API helper for list_applications. Defines ListApplicationsInput/Output interfaces and the listApplications function that makes GET requests to /applications endpoint with query parameters.
    export interface ListApplicationsInput {
      session_id: string;
      job_token?: string;
      status?: string;
      page?: number;
      page_size?: number;
    }
    
    export interface ListApplicationsOutput {
      applications: Application[];
      total: number;
      page: number;
      page_size: number;
    }
    
    export async function listApplications(
      input: ListApplicationsInput
    ): Promise<ApiResponse<ListApplicationsOutput>> {
      const params = new URLSearchParams();
      params.append('session_id', input.session_id);
      if (input.job_token) params.append('job_token', input.job_token);
      if (input.status) params.append('status', input.status);
      if (input.page !== undefined) params.append('page', input.page.toString());
      if (input.page_size !== undefined) params.append('page_size', input.page_size.toString());
    
      return apiRequest(`/applications?${params.toString()}`, {
        method: 'GET',
        sessionId: input.session_id,
      });
    }
Behavior3/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. It discloses key behavioral traits: it's a read-only operation (implied by '查看' - view), returns specific data fields (candidate info, match scores, badges, status, cover letters), includes match score interpretation guidelines, and notes pagination support (via page/page_size parameters). However, it lacks details on authentication needs, rate limits, error handling, or data freshness.

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 well-structured and appropriately sized. It front-loads the core purpose, then lists return information, explains match scores, and adds a note about limitations. Most sentences earn their place by providing useful context, though the match score breakdown could be slightly condensed.

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 no annotations and no output schema, the description does a fair job covering the tool's behavior, return data, and limitations. It explains what data is returned and how to interpret match scores, which compensates for the lack of output schema. However, for a tool with 5 parameters and no annotations, it could benefit from more details on error cases, authentication, or performance characteristics.

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 documents all parameters thoroughly. The description doesn't add any parameter-specific semantics beyond what's in the schema (e.g., it doesn't explain 'job_token' or 'status' enums further). However, it implicitly references pagination via 'page' and 'page_size' by listing them as returned data, which slightly reinforces their purpose. Baseline 3 is appropriate given high schema coverage.

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: '查看收到的职位申请' (view received job applications). It specifies the verb (view) and resource (job applications), making the intent unambiguous. However, it doesn't explicitly differentiate from sibling tools like 'view_candidate' or 'search_candidates', which might also involve viewing candidate-related data.

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

Usage Guidelines3/5

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

The description implies usage context by stating it's for viewing applications and noting that processing applications (approve/reject) will be in v2, suggesting this is for read-only inspection. However, it doesn't provide explicit guidance on when to use this tool versus alternatives like 'search_candidates' or 'view_candidate', nor does it mention prerequisites (e.g., needing a session_id from 'register_company').

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

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