Skip to main content
Glama
Tiberriver256

Azure DevOps MCP Server

get_project_details

Retrieve project details from Azure DevOps, including process information, work item types with their structure and fields, and associated teams with identity expansion.

Instructions

Get comprehensive details of a project including process, work item types, and teams

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectIdNoThe ID or name of the project (Default: MyProject)
organizationIdNoThe ID or name of the organization (Default: mycompany)
includeProcessNoInclude process information in the project result
includeWorkItemTypesNoInclude work item types and their structure
includeFieldsNoInclude field information for work item types
includeTeamsNoInclude associated teams in the project result
expandTeamIdentityNoExpand identity information in the team objects

Implementation Reference

  • The core handler function that implements the get_project_details tool logic. Fetches comprehensive project details including process info, work item types, fields, and teams using Azure DevOps Node API.
    export async function getProjectDetails(
      connection: WebApi,
      options: GetProjectDetailsOptions,
    ): Promise<ProjectDetails> {
      try {
        const {
          projectId,
          includeProcess = false,
          includeWorkItemTypes = false,
          includeFields = false,
          includeTeams = false,
          expandTeamIdentity = false,
        } = options;
    
        // Get the core API
        const coreApi = await connection.getCoreApi();
    
        // Get the basic project information
        const project = await coreApi.getProject(projectId);
    
        if (!project) {
          throw new AzureDevOpsResourceNotFoundError(
            `Project '${projectId}' not found`,
          );
        }
    
        // Initialize the result with the project information and ensure required properties
        const result: ProjectDetails = {
          ...project,
          // Ensure capabilities is always defined
          capabilities: project.capabilities || {
            versioncontrol: { sourceControlType: 'Git' },
            processTemplate: { templateName: 'Unknown', templateTypeId: 'unknown' },
          },
        };
    
        // If teams are requested, get them
        if (includeTeams) {
          const teams = await coreApi.getTeams(projectId, expandTeamIdentity);
          result.teams = teams;
        }
    
        // If process information is requested, get it
        if (includeProcess) {
          // Get the process template ID from the project capabilities
          const processTemplateId =
            project.capabilities?.processTemplate?.templateTypeId || 'unknown';
    
          // Always create a process object, even if we don't have a template ID
          // In a real implementation, we would use the Process API
          // Since it's not directly available in the WebApi type, we'll simulate it
          // This is a simplified version for the implementation
          // In a real implementation, you would need to use the appropriate API
    
          // Create the process info object directly
          const processInfo: ProcessInfo = {
            id: processTemplateId,
            name: project.capabilities?.processTemplate?.templateName || 'Unknown',
            description: 'Process template for the project',
            isDefault: true,
            type: 'system',
          };
    
          // If work item types are requested, get them
          if (includeWorkItemTypes) {
            // In a real implementation, we would get work item types from the API
            // For now, we'll use the work item tracking API to get basic types
            const workItemTrackingApi = await connection.getWorkItemTrackingApi();
            const workItemTypes =
              await workItemTrackingApi.getWorkItemTypes(projectId);
    
            // Map the work item types to our format
            const processWorkItemTypes: WorkItemTypeInfo[] = workItemTypes.map(
              (wit) => {
                // Create the work item type info object
                const workItemTypeInfo: WorkItemTypeInfo = {
                  name: wit.name || 'Unknown',
                  referenceName:
                    wit.referenceName || `System.Unknown.${Date.now()}`,
                  description: wit.description,
                  isDisabled: false,
                  states: [
                    { name: 'New', stateCategory: 'Proposed' },
                    { name: 'Active', stateCategory: 'InProgress' },
                    { name: 'Resolved', stateCategory: 'InProgress' },
                    { name: 'Closed', stateCategory: 'Completed' },
                  ],
                };
    
                // If fields are requested, don't add fields here - we'll add them after fetching from API
                return workItemTypeInfo;
              },
            );
    
            // If fields are requested, get the field definitions from the API
            if (includeFields) {
              try {
                // Instead of getting all fields and applying them to all work item types,
                // let's get the fields specific to each work item type
                for (const wit of processWorkItemTypes) {
                  try {
                    // Get fields specific to this work item type using the specialized method
                    const typeSpecificFields =
                      await workItemTrackingApi.getWorkItemTypeFieldsWithReferences(
                        projectId,
                        wit.name,
                      );
    
                    // Map the fields to our format
                    wit.fields = typeSpecificFields.map(
                      (field: WorkItemTypeField) => ({
                        name: field.name || 'Unknown',
                        referenceName: field.referenceName || 'Unknown',
                        type: field.type?.toString().toLowerCase() || 'string',
                        required: field.isRequired || false,
                        isIdentity: field.isIdentity || false,
                        isPicklist: field.isPicklist || false,
                        description: field.description,
                      }),
                    );
                  } catch (typeFieldError) {
                    console.error(
                      `Error fetching fields for work item type ${wit.name}:`,
                      typeFieldError,
                    );
    
                    // Fallback to basic fields
                    wit.fields = [
                      {
                        name: 'Title',
                        referenceName: 'System.Title',
                        type: 'string',
                        required: true,
                      },
                      {
                        name: 'Description',
                        referenceName: 'System.Description',
                        type: 'html',
                        required: false,
                      },
                    ];
                  }
                }
              } catch (fieldError) {
                console.error('Error in field processing:', fieldError);
    
                // Fallback to default fields if API call fails
                processWorkItemTypes.forEach((wit) => {
                  wit.fields = [
                    {
                      name: 'Title',
                      referenceName: 'System.Title',
                      type: 'string',
                      required: true,
                    },
                    {
                      name: 'Description',
                      referenceName: 'System.Description',
                      type: 'html',
                      required: false,
                    },
                  ];
                });
              }
            }
    
            processInfo.workItemTypes = processWorkItemTypes;
    
            // Add hierarchy information if available
            // This is a simplified version - in a real implementation, you would
            // need to get the backlog configuration and map it to the work item types
            processInfo.hierarchyInfo = {
              portfolioBacklogs: [
                {
                  name: 'Epics',
                  workItemTypes: processWorkItemTypes
                    .filter(
                      (wit: WorkItemTypeInfo) => wit.name.toLowerCase() === 'epic',
                    )
                    .map((wit: WorkItemTypeInfo) => wit.name),
                },
                {
                  name: 'Features',
                  workItemTypes: processWorkItemTypes
                    .filter(
                      (wit: WorkItemTypeInfo) =>
                        wit.name.toLowerCase() === 'feature',
                    )
                    .map((wit: WorkItemTypeInfo) => wit.name),
                },
              ],
              requirementBacklog: {
                name: 'Stories',
                workItemTypes: processWorkItemTypes
                  .filter(
                    (wit: WorkItemTypeInfo) =>
                      wit.name.toLowerCase() === 'user story' ||
                      wit.name.toLowerCase() === 'bug',
                  )
                  .map((wit: WorkItemTypeInfo) => wit.name),
              },
              taskBacklog: {
                name: 'Tasks',
                workItemTypes: processWorkItemTypes
                  .filter(
                    (wit: WorkItemTypeInfo) => wit.name.toLowerCase() === 'task',
                  )
                  .map((wit: WorkItemTypeInfo) => wit.name),
              },
            };
          }
    
          // Always set the process on the result
          result.process = processInfo;
        }
    
        return result;
      } catch (error) {
        if (error instanceof AzureDevOpsError) {
          throw error;
        }
        throw new Error(
          `Failed to get project details: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    }
  • Zod schema defining the input parameters for the get_project_details tool, including projectId and optional flags for additional details.
    export const GetProjectDetailsSchema = z.object({
      projectId: z
        .string()
        .optional()
        .describe(`The ID or name of the project (Default: ${defaultProject})`),
      organizationId: z
        .string()
        .optional()
        .describe(`The ID or name of the organization (Default: ${defaultOrg})`),
      includeProcess: z
        .boolean()
        .optional()
        .default(false)
        .describe('Include process information in the project result'),
      includeWorkItemTypes: z
        .boolean()
        .optional()
        .default(false)
        .describe('Include work item types and their structure'),
      includeFields: z
        .boolean()
        .optional()
        .default(false)
        .describe('Include field information for work item types'),
      includeTeams: z
        .boolean()
        .optional()
        .default(false)
        .describe('Include associated teams in the project result'),
      expandTeamIdentity: z
        .boolean()
        .optional()
        .default(false)
        .describe('Expand identity information in the team objects'),
    });
  • Tool registration definition specifying the name, description, and input schema for the get_project_details tool.
    {
      name: 'get_project_details',
      description:
        'Get comprehensive details of a project including process, work item types, and teams',
      inputSchema: zodToJsonSchema(GetProjectDetailsSchema),
    },
  • MCP request handler switch case that parses arguments and invokes the getProjectDetails handler function.
    case 'get_project_details': {
      const args = GetProjectDetailsSchema.parse(request.params.arguments);
      const result = await getProjectDetails(connection, {
        projectId: args.projectId ?? defaultProject,
        includeProcess: args.includeProcess,
        includeWorkItemTypes: args.includeWorkItemTypes,
        includeFields: args.includeFields,
        includeTeams: args.includeTeams,
        expandTeamIdentity: args.expandTeamIdentity,
      });
      return {
        content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
      };
    }
  • TypeScript interface defining the options parameter for the getProjectDetails handler function.
    export interface GetProjectDetailsOptions {
      projectId: string;
      includeProcess?: boolean;
      includeWorkItemTypes?: boolean;
      includeFields?: boolean;
      includeTeams?: boolean;
      expandTeamIdentity?: boolean;
    }

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/Tiberriver256/mcp-server-azure-devops'

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