Skip to main content
Glama

claim

Claim a GitHub issue by posting a comment with your intent to work on it.

Instructions

Claim a GitHub issue by posting a comment expressing intent to work on it.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
issueUrlYesFull GitHub issue URL to claim
messageNoCustom claim message. If omitted, a default message is used.

Implementation Reference

  • The main handler function for the 'claim' tool. Posts a claim comment on a GitHub issue, enriches it with issue metadata, and records it in local state as 'claimed'.
    export async function runClaim(options: ClaimOptions): Promise<ClaimOutput> {
      validateUrl(options.issueUrl);
      validateGitHubUrl(options.issueUrl, ISSUE_URL_PATTERN, 'issue');
    
      const token = requireGitHubToken();
    
      // Default claim message or custom
      const message = options.message || "Hi! I'd like to work on this issue. Could you assign it to me?";
    
      validateMessage(message);
    
      // Parse URL
      const parsed = parseGitHubUrl(options.issueUrl);
      if (!parsed || parsed.type !== 'issues') {
        throw new ValidationError('Invalid issue URL format (must be an issue, not a PR)');
      }
    
      const { owner, repo, number } = parsed;
    
      const octokit = getOctokit(token);
    
      const { data: comment } = await octokit.issues.createComment({
        owner,
        repo,
        issue_number: number,
        body: message,
      });
    
      // Fetch the real issue title + labels so the tracked entry has useful metadata
      // rather than a permanent "(claimed)" placeholder that never gets backfilled
      // (#1056 M24). Best-effort: if the fetch fails, fall back to the placeholder
      // so state still records the claim.
      let issueTitle = '(claimed)';
      let issueLabels: string[] = [];
      let issueCreatedAt = new Date().toISOString();
      try {
        const { data: issue } = await octokit.issues.get({ owner, repo, issue_number: number });
        if (issue.title) issueTitle = issue.title;
        issueLabels = (issue.labels ?? [])
          .map((l) => (typeof l === 'string' ? l : (l.name ?? '')))
          .filter((name): name is string => Boolean(name));
        if (issue.created_at) issueCreatedAt = issue.created_at;
      } catch (error) {
        warn(
          MODULE,
          `Claimed ${options.issueUrl} but failed to enrich issue metadata (title/labels): ${error instanceof Error ? error.message : error}`,
        );
      }
    
      // Add to tracked issues — non-fatal if state save fails (comment already posted)
      try {
        const stateManager = getStateManager();
        stateManager.addIssue({
          id: number,
          url: options.issueUrl,
          repo: `${owner}/${repo}`,
          number,
          title: issueTitle,
          status: 'claimed',
          labels: issueLabels,
          createdAt: issueCreatedAt,
          updatedAt: new Date().toISOString(),
          vetted: false,
        });
        // Push state to Gist if in Gist mode. Best-effort — logs on failure
        // rather than silently swallowing, so operators see the degraded-sync
        // signal (#1036 audit H1).
        await maybeCheckpoint(stateManager, MODULE);
      } catch (error) {
        // Structured warning instead of bare console.error so the breadcrumb shows
        // up in the plugin's log pipeline (#1056 M24).
        warn(
          MODULE,
          `Comment posted on ${options.issueUrl} but failed to save to local state: ${error instanceof Error ? error.message : error}`,
        );
      }
    
      return {
        commentUrl: comment.html_url,
        issueUrl: options.issueUrl,
      };
    }
  • Input options interface for the claim command: issueUrl (required) and message (optional).
    interface ClaimOptions {
      issueUrl: string;
      message?: string;
    }
  • Output type definition for the claim command, containing commentUrl and issueUrl.
    export interface ClaimOutput {
      commentUrl: string;
      issueUrl: string;
    }
  • Zod schema for claim output validation: commentUrl (string) and issueUrl (string).
    export const ClaimOutputSchema = z.object({
      commentUrl: z.string(),
      issueUrl: z.string(),
    });
  • MCP tool registration for 'claim'. Registers with schema (issueUrl, message), marks as destructive/readOnlyHint=false, and wraps runClaim.
    // 10. claim — Claim an issue (#1053: destructive; posts under user's identity)
    server.registerTool(
      'claim',
      {
        description:
          "Claim a GitHub issue by posting a comment expressing intent to work on it. WARNING: posts a public comment under the authenticated user's identity. Irreversible. Do not call without explicit user confirmation.",
        inputSchema: {
          issueUrl: githubIssueUrlSchema.describe('Full GitHub issue URL to claim'),
          message: z.string().optional().describe('Custom claim message. If omitted, a default message is used.'),
        },
        annotations: { readOnlyHint: false, destructiveHint: true },
      },
      wrapTool(runClaim),
    );
Behavior4/5

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

Annotations indicate it is not read-only and not destructive. The description adds context that it posts a comment, which is a write operation. However, it does not disclose potential side effects like whether multiple claims are allowed or if it overrides existing claims.

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 a single, clear sentence with no redundancy. Every word contributes to understanding the tool's purpose.

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?

The description omits any mention of return values or error handling. Given the lack of an output schema, this information would help the agent interpret results. The tool is simple, but return behavior is not addressed.

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?

With 100% schema description coverage, the input schema already provides adequate parameter descriptions. The tool description adds no further semantic value beyond what the schema offers.

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 action ('claim'), the resource ('GitHub issue'), and the mechanism ('posting a comment expressing intent'). It effectively distinguishes from sibling tools like 'post' or 'startup' by specifying the intent-based claiming behavior.

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?

No explicit guidance on when to use this tool versus alternatives such as 'track' or 'post'. While the purpose implies usage for claiming, it does not mention prerequisites (e.g., needing a GitHub token) or scenarios to avoid.

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/costajohnt/oss-autopilot'

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