Create Issue
create_issueCreate a new bug report or feature request in MantisBT with required details like summary, description, project ID, and category to track software issues.
Instructions
Create a new MantisBT issue. Returns the created issue including its assigned ID.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| summary | Yes | Issue summary/title | |
| description | Yes | Detailed issue description. Required — do not create issues without a description. Plain text or Markdown. | |
| project_id | Yes | Project ID the issue belongs to | |
| category | Yes | Category name (use get_project_categories to list available categories) | |
| priority | No | Priority: canonical English name (none, low, normal, high, urgent, immediate) or localized label. Default: "normal". Use get_issue_enums to see all available values. | normal |
| severity | No | Severity: canonical English name (feature, trivial, text, tweak, minor, major, crash, block) or localized label. Default: "minor". Use get_issue_enums to see all available values. | minor |
| handler_id | No | User ID of the person to assign the issue to | |
| handler | No | Username (login name) of the person to assign the issue to. Alternative to handler_id — the server resolves the name to a user ID from the project members. Use get_project_users to see available users. | |
| version | No | Affected product version name (use get_project_versions to list available versions) | |
| target_version | No | Target version name — version in which the issue is planned to be fixed (use get_project_versions to list available versions) | |
| fixed_in_version | No | Version name in which the issue was fixed (use get_project_versions to list available versions) | |
| steps_to_reproduce | No | Steps to reproduce the issue. Plain text or Markdown. | |
| additional_information | No | Additional information about the issue. Plain text or Markdown. | |
| reproducibility | No | Reproducibility: canonical English name or localized label (always, sometimes, random, have not tried, unable to reproduce, N/A). Use get_issue_enums to see all available values. | |
| view_state | No | Visibility of the issue: "public" (default) or "private" |
Implementation Reference
- src/tools/issues.ts:280-382 (handler)The implementation of the create_issue tool, including schema definition and handler logic.
server.registerTool( 'create_issue', { title: 'Create Issue', description: 'Create a new MantisBT issue. Returns the created issue including its assigned ID.', inputSchema: z.object({ summary: z.string().min(1).describe('Issue summary/title'), description: z.string().min(1).describe('Detailed issue description. Required — do not create issues without a description. Plain text or Markdown.'), project_id: z.coerce.number().int().positive().describe('Project ID the issue belongs to'), category: z.string().min(1).describe('Category name (use get_project_categories to list available categories)'), priority: z.string().default('normal').describe('Priority: canonical English name (none, low, normal, high, urgent, immediate) or localized label. Default: "normal". Use get_issue_enums to see all available values.'), severity: z.string().default('minor').describe('Severity: canonical English name (feature, trivial, text, tweak, minor, major, crash, block) or localized label. Default: "minor". Use get_issue_enums to see all available values.'), handler_id: z.coerce.number().int().positive().optional().describe('User ID of the person to assign the issue to'), handler: z.string().optional().describe('Username (login name) of the person to assign the issue to. Alternative to handler_id — the server resolves the name to a user ID from the project members. Use get_project_users to see available users.'), version: z.string().optional().describe('Affected product version name (use get_project_versions to list available versions)'), target_version: z.string().optional().describe('Target version name — version in which the issue is planned to be fixed (use get_project_versions to list available versions)'), fixed_in_version: z.string().optional().describe('Version name in which the issue was fixed (use get_project_versions to list available versions)'), steps_to_reproduce: z.string().optional().describe('Steps to reproduce the issue. Plain text or Markdown.'), additional_information: z.string().optional().describe('Additional information about the issue. Plain text or Markdown.'), reproducibility: z.string().optional().describe('Reproducibility: canonical English name or localized label (always, sometimes, random, have not tried, unable to reproduce, N/A). Use get_issue_enums to see all available values.'), view_state: z.enum(['public', 'private']).optional().describe('Visibility of the issue: "public" (default) or "private"'), }), annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, }, }, async ({ summary, description, project_id, category, priority, severity, handler_id, handler, version, target_version, fixed_in_version, steps_to_reproduce, additional_information, reproducibility, view_state }) => { // Resolve handler username to handler_id when only a name is given let resolvedHandlerId = handler_id; if (resolvedHandlerId === undefined && handler !== undefined) { const metadata = await cache.loadIfValid(); let users: MantisUser[] = metadata?.byProject[project_id]?.users ?? []; if (users.length === 0) { try { const usersResult = await client.get<{ users: MantisUser[] }>(`projects/${project_id}/users`); users = usersResult.users ?? []; } catch { users = []; } } const user = users.find(u => u.name === handler || u.real_name === handler); if (!user) { const names = users.map(u => u.name).join(', '); return { content: [{ type: 'text', text: errorText(`User "${handler}" not found in project ${project_id}. Available users: ${names || 'none (run sync_metadata or check project_id)'}`) }], isError: true, }; } resolvedHandlerId = user.id; } try { const body: Record<string, unknown> = { summary, description, project: { id: project_id }, category: { name: category }, }; const priorityResolved = await resolveEnum('priority', priority, client); if (typeof priorityResolved === 'string') return { content: [{ type: 'text', text: errorText(priorityResolved) }], isError: true }; body.priority = priorityResolved; const severityResolved = await resolveEnum('severity', severity, client); if (typeof severityResolved === 'string') return { content: [{ type: 'text', text: errorText(severityResolved) }], isError: true }; body.severity = severityResolved; if (resolvedHandlerId) body.handler = { id: resolvedHandlerId }; if (version !== undefined) body.version = { name: version }; if (target_version !== undefined) body.target_version = { name: target_version }; if (fixed_in_version !== undefined) body.fixed_in_version = { name: fixed_in_version }; if (steps_to_reproduce !== undefined) body.steps_to_reproduce = steps_to_reproduce; if (additional_information !== undefined) body.additional_information = additional_information; if (reproducibility !== undefined) { const reproducibilityResolved = await resolveEnum('reproducibility', reproducibility, client); if (typeof reproducibilityResolved === 'string') return { content: [{ type: 'text', text: errorText(reproducibilityResolved) }], isError: true }; body.reproducibility = reproducibilityResolved; } if (view_state !== undefined) body.view_state = { name: view_state }; const raw = await client.post<Record<string, unknown>>('issues', body); const partial = ('issue' in raw && typeof raw['issue'] === 'object' && raw['issue'] !== null) ? raw['issue'] as MantisIssue : raw as unknown as MantisIssue; let issue: MantisIssue = partial; if (!('summary' in (partial as unknown as Record<string, unknown>))) { // Older MantisBT returned only { id: N } — fetch the full issue. // Suppress GET errors: the issue was already created. try { const fetched = await client.get<{ issues: MantisIssue[] }>(`issues/${partial.id}`); issue = fetched.issues?.[0] ?? partial; } catch { // unable to fetch details — return minimal object } } return { content: [{ type: 'text', text: JSON.stringify(issue, null, 2) }], }; } catch (error) { const msg = error instanceof Error ? error.message : String(error); return { content: [{ type: 'text', text: errorText(msg) }], isError: true }; } } );