Get Issue Fields
get_issue_fieldsDiscover valid field names for querying MantisBT issues to ensure your API requests only reference existing server fields.
Instructions
Return all field names that are valid for the "select" parameter of list_issues and get_issue.
Fields are discovered by fetching a sample issue from MantisBT (which reflects the server's active configuration — e.g. whether eta, projection, or profile fields are enabled) and merging the result with fields that MantisBT omits when empty (notes, attachments, relationships, etc.). The result is cached with the same TTL as the metadata cache.
Use this tool before constructing a "select" string to ensure you only request fields that exist on this server.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | No | Optional project ID to scope the sample issue fetch |
Implementation Reference
- src/tools/metadata.ts:308-360 (handler)The implementation and registration of the "get_issue_fields" tool. It samples fields from issues or uses static defaults, and manages caching.
server.registerTool( 'get_issue_fields', { title: 'Get Issue Fields', description: `Return all field names that are valid for the "select" parameter of list_issues and get_issue. Fields are discovered by fetching a sample issue from MantisBT (which reflects the server's active configuration — e.g. whether eta, projection, or profile fields are enabled) and merging the result with fields that MantisBT omits when empty (notes, attachments, relationships, etc.). The result is cached with the same TTL as the metadata cache. Use this tool before constructing a "select" string to ensure you only request fields that exist on this server.`, inputSchema: z.object({ project_id: z.coerce.number().int().positive().optional().describe('Optional project ID to scope the sample issue fetch'), }), annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, }, }, async ({ project_id }) => { try { const cached = await cache.loadIssueFields(); if (cached) { return { content: [{ type: 'text', text: JSON.stringify({ fields: cached, source: 'cache' }, null, 2) }], }; } const params: Record<string, string | number | boolean | undefined> = { page: 1, page_size: 1, project_id, }; const result = await client.get<MantisPaginatedIssues>('issues', params); const issues = result.issues ?? []; let fields: string[]; if (issues.length === 0) { fields = STATIC_ISSUE_FIELDS; } else { const discovered = Object.keys(issues[0]); fields = Array.from(new Set([...discovered, ...EMPTY_STRIPPED_FIELDS])).sort(); } await cache.saveIssueFields(fields); return { content: [{ type: 'text', text: JSON.stringify({ fields, source: issues.length > 0 ? 'live' : 'static' }, null, 2) }], }; } catch (error) { const msg = error instanceof Error ? error.message : String(error); return { content: [{ type: 'text', text: errorText(msg) }], isError: true }; } } );