Skip to main content
Glama

Jira MCP Server

by sespinosa
MIT License
15
2
  • Apple
  • Linux
users.ts8.08 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { Version3Client } from 'jira.js'; import { z } from 'zod'; import { rateLimiters, withRateLimit } from '../utils/rateLimiter.js'; import { auditLogger } from '../utils/auditLogger.js'; import { SecurityError, DANGEROUS_SCRIPT_PATTERNS } from '../utils/security.js'; export function registerUserTools(server: McpServer, jiraClient: Version3Client) { // Get User server.registerTool( 'get_user', { title: 'Get User', description: 'Get detailed information about a user', inputSchema: { accountId: z.string().describe('User account ID'), expand: z.array(z.string()).optional().describe('Fields to expand'), }, }, async (args) => { try { // Rate limiting and audit logging await withRateLimit( async () => { auditLogger.logOperation('get_user', 'user', { accountId: args.accountId }); return true; }, rateLimiters.standard, 'get_user' ); // Args are automatically validated by MCP SDK const validatedArgs = args; const user = await jiraClient.users.getUser({ accountId: validatedArgs.accountId, expand: validatedArgs.expand?.join(','), }); return { content: [ { type: 'text', text: JSON.stringify(user, null, 2), }, ], }; } catch (error) { // Audit failure auditLogger.logFailure( 'get_user', 'user', error instanceof Error ? error.message : 'Unknown error', { accountId: args.accountId } ); if (error instanceof SecurityError) { throw new Error(`Security violation: ${error.message}`); } throw error; } } ); // Get User Groups server.registerTool( 'get_user_groups', { title: 'Get User Groups', description: 'Get groups that a user belongs to', inputSchema: { accountId: z.string().describe('User account ID'), }, }, async (args) => { try { // Rate limiting and audit logging await withRateLimit( async () => { auditLogger.logOperation('get_user_groups', 'user', { accountId: args.accountId }); return true; }, rateLimiters.standard, 'get_user_groups' ); // Args are automatically validated by MCP SDK const validatedArgs = args; const groups = await jiraClient.users.getUserGroups({ accountId: validatedArgs.accountId, }); return { content: [ { type: 'text', text: JSON.stringify(groups, null, 2), }, ], }; } catch (error) { // Audit failure auditLogger.logFailure( 'get_user_groups', 'user', error instanceof Error ? error.message : 'Unknown error', { accountId: args.accountId } ); if (error instanceof SecurityError) { throw new Error(`Security violation: ${error.message}`); } throw error; } } ); // Find Users by Query server.registerTool( 'find_users', { title: 'Find Users', description: 'Find users by search query', inputSchema: { query: z.string().describe('Search query'), maxResults: z.number().default(50).describe('Maximum results'), startAt: z.number().default(0).describe('Starting index'), }, }, async (args) => { try { // Rate limiting and audit logging await withRateLimit( async () => { auditLogger.logOperation('find_users', 'user', { query: args.query, maxResults: args.maxResults, }); return true; }, rateLimiters.search, 'find_users' ); // Args are automatically validated by MCP SDK const validatedArgs = args; // Enhanced query validation if (validatedArgs.query.length > 100) { throw new Error('Search query too long (max 100 characters)'); } // Basic sanitization for search query - prevent dangerous patterns for (const pattern of DANGEROUS_SCRIPT_PATTERNS) { if (pattern.test(validatedArgs.query)) { throw new SecurityError( `Search query contains dangerous pattern: ${pattern}`, 'DANGEROUS_SEARCH_PATTERN' ); } } const users = await jiraClient.userSearch.findUsers({ query: validatedArgs.query, maxResults: validatedArgs.maxResults, startAt: validatedArgs.startAt, }); return { content: [ { type: 'text', text: JSON.stringify(users, null, 2), }, ], }; } catch (error) { // Audit failure auditLogger.logFailure( 'find_users', 'user', error instanceof Error ? error.message : 'Unknown error', { query: args.query } ); if (error instanceof SecurityError) { throw new Error(`Security violation: ${error.message}`); } throw error; } } ); // Find Assignable Users server.registerTool( 'find_assignable_users', { title: 'Find Assignable Users', description: 'Find users that can be assigned to issues', inputSchema: { query: z.string().optional().describe('Search query'), project: z.string().optional().describe('Project key'), issueKey: z.string().optional().describe('Issue key'), maxResults: z.number().default(50).describe('Maximum results'), startAt: z.number().default(0).describe('Starting index'), }, }, async (args) => { try { // Rate limiting and audit logging await withRateLimit( async () => { auditLogger.logOperation('find_assignable_users', 'user', { query: args.query, project: args.project, issueKey: args.issueKey, }); return true; }, rateLimiters.search, 'find_assignable_users' ); // Args are automatically validated by MCP SDK const validatedArgs = args; // Query validation if provided if (validatedArgs.query && validatedArgs.query.length > 100) { throw new Error('Search query too long (max 100 characters)'); } // Basic sanitization for search query if provided if (validatedArgs.query) { for (const pattern of DANGEROUS_SCRIPT_PATTERNS) { if (pattern.test(validatedArgs.query)) { throw new SecurityError( `Search query contains dangerous pattern: ${pattern}`, 'DANGEROUS_SEARCH_PATTERN' ); } } } const users = await jiraClient.userSearch.findAssignableUsers({ query: validatedArgs.query, project: validatedArgs.project, issueKey: validatedArgs.issueKey, maxResults: validatedArgs.maxResults, startAt: validatedArgs.startAt, }); return { content: [ { type: 'text', text: JSON.stringify(users, null, 2), }, ], }; } catch (error) { // Audit failure auditLogger.logFailure( 'find_assignable_users', 'user', error instanceof Error ? error.message : 'Unknown error', { query: args.query, project: args.project, issueKey: args.issueKey } ); if (error instanceof SecurityError) { throw new Error(`Security violation: ${error.message}`); } throw error; } } ); }

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/sespinosa/jira-mcp-server'

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