Skip to main content
Glama

MCP Atlassian Server

by phuc-nt
pages.ts15 kB
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; import { Logger } from '../../utils/logger.js'; import { pagesListSchema, pageSchema, commentsListSchema, attachmentListSchema, versionListSchema, labelListSchema } from '../../schemas/confluence.js'; import { getConfluencePagesV2, getConfluencePageV2, getConfluencePageBodyV2, getConfluencePageAncestorsV2, getConfluencePageChildrenV2, getConfluencePageLabelsV2, getConfluencePageAttachmentsV2, getConfluencePageVersionsV2, getConfluencePagesWithFilters } from '../../utils/confluence-resource-api.js'; import { getConfluencePageFooterCommentsV2, getConfluencePageInlineCommentsV2 } from '../../utils/confluence-resource-api.js'; import { Config, Resources } from '../../utils/mcp-helpers.js'; const logger = Logger.getLogger('ConfluenceResource:Pages'); export function registerPageResources(server: McpServer) { logger.info('Registering Confluence page resources...'); // Resource: Page details (API v2, tách call metadata và body) server.resource( 'confluence-page-details-v2', new ResourceTemplate('confluence://pages/{pageId}', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages/{pageId}', name: 'Confluence Page Details', description: 'Get details for a specific Confluence page by ID. Replace {pageId} with the page ID.', mimeType: 'application/json' } ] }) }), async (uri, { pageId }, extra) => { let normalizedPageId = Array.isArray(pageId) ? pageId[0] : pageId; try { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); if (!normalizedPageId) { throw new Error('Missing pageId in URI'); } logger.info(`Getting details for Confluence page (v2): ${normalizedPageId}`); const page = await getConfluencePageV2(config, normalizedPageId); let body = {}; try { body = await getConfluencePageBodyV2(config, normalizedPageId); } catch (e) { body = {}; } const formattedPage = { ...page, body: (body && typeof body === 'object' && 'value' in body) ? body.value : '', bodyType: (body && typeof body === 'object' && 'representation' in body) ? body.representation : 'storage', }; const uriString = typeof uri === 'string' ? uri : uri.href; return Resources.createStandardResource( uriString, [formattedPage], 'page', pageSchema, 1, 1, 0, `${config.baseUrl}/wiki/pages/${normalizedPageId}` ); } catch (error) { logger.error(`Error getting Confluence page details (v2) for ${normalizedPageId}:`, error); throw error; } } ); // Resource: List of children pages server.resource( 'confluence-page-children', new ResourceTemplate('confluence://pages/{pageId}/children', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages/{pageId}/children', name: 'Confluence Page Children', description: 'List all children for a Confluence page. Replace {pageId} với ID trang.', mimeType: 'application/json' } ] }) }), async (uri, { pageId }, extra) => { let normalizedPageId = Array.isArray(pageId) ? pageId[0] : pageId; try { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); if (!normalizedPageId) { throw new Error('Missing pageId in URI'); } logger.info(`Getting children for Confluence page (v2): ${normalizedPageId}`); const data = await getConfluencePageChildrenV2(config, normalizedPageId); const formattedChildren = (data.results || []).map((child: any) => ({ id: child.id, title: child.title, status: child.status, url: `${config.baseUrl}/wiki/pages/${child.id}` })); const childrenSchema = { type: 'array', items: pageSchema }; return Resources.createStandardResource( typeof uri === 'string' ? uri : uri.href, formattedChildren, 'children', childrenSchema, formattedChildren.length, formattedChildren.length, 0, `${config.baseUrl}/wiki/pages/${normalizedPageId}` ); } catch (error) { logger.error(`Error getting Confluence page children for ${normalizedPageId}:`, error); throw error; } } ); // Resource: List of comments for a page (API v2, gộp cả footer và inline) server.resource( 'confluence-page-comments', new ResourceTemplate('confluence://pages/{pageId}/comments', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages/{pageId}/comments', name: 'Confluence Page Comments', description: 'List comments for a Confluence page. Replace {pageId} with the page ID.', mimeType: 'application/json' } ] }) }), async (uri, { pageId }, extra) => { let normalizedPageId = Array.isArray(pageId) ? pageId[0] : pageId; try { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); if (!normalizedPageId) { throw new Error('Missing pageId in URI'); } logger.info(`Getting comments for Confluence page (v2): ${normalizedPageId}`); const footerComments = await getConfluencePageFooterCommentsV2(config, normalizedPageId); const inlineComments = await getConfluencePageInlineCommentsV2(config, normalizedPageId); const allComments = [...(footerComments.results || []), ...(inlineComments.results || [])]; return Resources.createStandardResource( typeof uri === 'string' ? uri : uri.href, allComments, 'comments', commentsListSchema, allComments.length, allComments.length, 0, `${config.baseUrl}/wiki/pages/${normalizedPageId}` ); } catch (error) { logger.error(`Error getting Confluence page comments for ${normalizedPageId}:`, error); throw error; } } ); // Resource: List of ancestors for a page server.resource( 'confluence-page-ancestors', new ResourceTemplate('confluence://pages/{pageId}/ancestors', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages/{pageId}/ancestors', name: 'Confluence Page Ancestors', description: 'List all ancestors for a Confluence page. Replace {pageId} with the page ID.', mimeType: 'application/json' } ] }) }), async (uri, { pageId }, extra) => { let normalizedPageId = Array.isArray(pageId) ? pageId[0] : pageId; try { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); if (!normalizedPageId) { throw new Error('Missing pageId in URI'); } logger.info(`Getting ancestors for Confluence page (v2): ${normalizedPageId}`); const data = await getConfluencePageAncestorsV2(config, normalizedPageId); const ancestors = Array.isArray(data?.results) ? data.results : []; return Resources.createStandardResource( typeof uri === 'string' ? uri : uri.href, ancestors, 'ancestors', { type: 'array', items: pageSchema }, ancestors.length, ancestors.length, 0, `${config.baseUrl}/wiki/pages/${normalizedPageId}` ); } catch (error) { logger.error(`Error getting Confluence page ancestors for ${normalizedPageId}:`, error); throw error; } } ); // Resource: List of attachments for a page server.resource( 'confluence-page-attachments', new ResourceTemplate('confluence://pages/{pageId}/attachments', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages/{pageId}/attachments', name: 'Confluence Page Attachments', description: 'List all attachments for a Confluence page. Replace {pageId} with the page ID.', mimeType: 'application/json' } ] }) }), async (uri, params, extra) => { let normalizedPageId = Array.isArray(params.pageId) ? params.pageId[0] : params.pageId; try { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); if (!normalizedPageId) { throw new Error('Missing pageId in URI'); } logger.info(`Getting attachments for Confluence page (v2): ${normalizedPageId}`); const data = await getConfluencePageAttachmentsV2(config, normalizedPageId); return Resources.createStandardResource( typeof uri === 'string' ? uri : uri.href, data.results || [], 'attachments', attachmentListSchema, data.size || (data.results || []).length, data.limit || (data.results || []).length, 0, undefined ); } catch (error) { logger.error(`Error getting Confluence page attachments for ${normalizedPageId}:`, error); throw error; } } ); // Resource: List of versions for a page server.resource( 'confluence-page-versions', new ResourceTemplate('confluence://pages/{pageId}/versions', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages/{pageId}/versions', name: 'Confluence Page Versions', description: 'List all versions for a Confluence page. Replace {pageId} with the page ID.', mimeType: 'application/json' } ] }) }), async (uri, params, extra) => { let normalizedPageId = Array.isArray(params.pageId) ? params.pageId[0] : params.pageId; try { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); if (!normalizedPageId) { throw new Error('Missing pageId in URI'); } logger.info(`Getting versions for Confluence page (v2): ${normalizedPageId}`); const data = await getConfluencePageVersionsV2(config, normalizedPageId); return Resources.createStandardResource( typeof uri === 'string' ? uri : uri.href, data.results || [], 'versions', versionListSchema, data.size || (data.results || []).length, data.limit || (data.results || []).length, 0, undefined ); } catch (error) { logger.error(`Error getting Confluence page versions for ${normalizedPageId}:`, error); throw error; } } ); // Resource: List of pages (search/filter) server.resource( 'confluence-pages-list', new ResourceTemplate('confluence://pages', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages', name: 'Confluence Pages', description: 'List and search all Confluence pages', mimeType: 'application/json' } ] }) }), async (uri, params, extra) => { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); const filterParams = { ...params }; const data = await getConfluencePagesWithFilters(config, filterParams); const formattedPages = (data.results || []).map((page: any) => ({ id: page.id, title: page.title, status: page.status, url: `${config.baseUrl}/wiki/pages/${page.id}` })); const uriString = typeof uri === 'string' ? uri : uri.href; return Resources.createStandardResource( uriString, formattedPages, 'pages', pagesListSchema, data.size || formattedPages.length, filterParams.limit || formattedPages.length, 0, undefined ); } ); // Resource: List of labels for a page server.resource( 'confluence-page-labels', new ResourceTemplate('confluence://pages/{pageId}/labels', { list: async (_extra) => ({ resources: [ { uri: 'confluence://pages/{pageId}/labels', name: 'Confluence Page Labels', description: 'List all labels for a Confluence page. Replace {pageId} with the page ID.', mimeType: 'application/json' } ] }) }), async (uri, { pageId }, extra) => { let normalizedPageId = Array.isArray(pageId) ? pageId[0] : pageId; try { let config = (extra && typeof extra === 'object' && 'context' in extra && extra.context && (extra.context as any).atlassianConfig) ? (extra.context as any).atlassianConfig : Config.getAtlassianConfigFromEnv(); if (!normalizedPageId) { throw new Error('Missing pageId in URI'); } logger.info(`Getting labels for Confluence page (v2): ${normalizedPageId}`); const data = await getConfluencePageLabelsV2(config, normalizedPageId); const formattedLabels = (data.results || []).map((label: any) => ({ id: label.id, name: label.name, prefix: label.prefix })); return Resources.createStandardResource( typeof uri === 'string' ? uri : uri.href, formattedLabels, 'labels', labelListSchema, data.size || formattedLabels.length, data.limit || formattedLabels.length, 0, undefined ); } catch (error) { logger.error(`Error getting Confluence page labels for ${normalizedPageId}:`, error); 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/phuc-nt/mcp-atlassian-server'

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