Skip to main content
Glama

MCP Atlassian Server

by phuc-nt
spaces.ts5.71 kB
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; import { Logger } from '../../utils/logger.js'; import { getConfluenceSpacesV2, getConfluenceSpaceV2, getConfluencePagesWithFilters } from '../../utils/confluence-resource-api.js'; import { spacesListSchema, spaceSchema, pagesListSchema } from '../../schemas/confluence.js'; import { Config, Resources } from '../../utils/mcp-helpers.js'; const logger = Logger.getLogger('ConfluenceResource:Spaces'); /** * Register Confluence space-related resources * @param server MCP Server instance */ export function registerSpaceResources(server: McpServer) { logger.info('Registering Confluence space resources...'); // Resource: List of spaces (API v2, cursor-based) server.resource( 'confluence-spaces-list', new ResourceTemplate('confluence://spaces', { list: async (_extra) => { return { resources: [ { uri: 'confluence://spaces', name: 'Confluence Spaces', description: 'List and search all Confluence spaces', mimeType: 'application/json' } ] }; } }), async (uri, params, _extra) => { const config = Config.getAtlassianConfigFromEnv(); const limit = params?.limit ? parseInt(Array.isArray(params.limit) ? params.limit[0] : params.limit, 10) : 25; const cursor = params?.cursor ? (Array.isArray(params.cursor) ? params.cursor[0] : params.cursor) : undefined; logger.info(`Getting Confluence spaces list (v2): cursor=${cursor}, limit=${limit}`); const data = await getConfluenceSpacesV2(config, cursor, limit); const uriString = typeof uri === 'string' ? uri : uri.href; // Chuẩn hóa metadata cho cursor-based const total = data.size ?? (data.results?.length || 0); const hasMore = !!(data._links && data._links.next); const nextCursor = hasMore ? (new URL(data._links.next, 'http://dummy').searchParams.get('cursor') || '') : undefined; const metadata = { total, limit, hasMore, links: { self: uriString, next: hasMore && nextCursor ? `${uriString}?cursor=${encodeURIComponent(nextCursor)}&limit=${limit}` : undefined } }; // Chuẩn hóa trả về return Resources.createStandardResource( uriString, data.results, 'spaces', spacesListSchema, total, limit, 0, undefined ); } ); // Resource: Space details (API v2, mapping id) server.resource( 'confluence-space-details', new ResourceTemplate('confluence://spaces/{spaceId}', { list: async (_extra) => ({ resources: [ { uri: 'confluence://spaces/{spaceId}', name: 'Confluence Space Details', description: 'Get details for a specific Confluence space by id. Replace {spaceId} với id số của space (ví dụ: 19464200).', mimeType: 'application/json' } ] }) }), async (uri, params, _extra) => { const config = Config.getAtlassianConfigFromEnv(); let normalizedSpaceId = Array.isArray(params.spaceId) ? params.spaceId[0] : params.spaceId; if (!normalizedSpaceId) throw new Error('Missing spaceId in URI'); if (!/^\d+$/.test(normalizedSpaceId)) throw new Error('spaceId must be a number'); logger.info(`Getting details for Confluence space (v2) by id: ${normalizedSpaceId}`); // Lấy thông tin space qua API helper (giả sử getConfluenceSpaceV2 hỗ trợ lookup theo id) const space = await getConfluenceSpaceV2(config, normalizedSpaceId); const uriString = typeof uri === 'string' ? uri : uri.href; return Resources.createStandardResource( uriString, [space], 'space', spaceSchema, 1, 1, 0, undefined ); } ); // Resource: List of pages in a space server.resource( 'confluence-space-pages', new ResourceTemplate('confluence://spaces/{spaceId}/pages', { list: async (_extra) => ({ resources: [ { uri: 'confluence://spaces/{spaceId}/pages', name: 'Confluence Space Pages', description: 'List all pages in a specific Confluence space. Replace {spaceId} với id số của space.', mimeType: 'application/json' } ] }) }), async (uri, params, _extra) => { const config = Config.getAtlassianConfigFromEnv(); let normalizedSpaceId = Array.isArray(params.spaceId) ? params.spaceId[0] : params.spaceId; if (!normalizedSpaceId) throw new Error('Missing spaceId in URI'); if (!/^\d+$/.test(normalizedSpaceId)) throw new Error('spaceId must be a number'); // Không lookup theo key nữa, dùng trực tiếp id const filterParams = { 'space-id': normalizedSpaceId, limit: params.limit ? parseInt(Array.isArray(params.limit) ? params.limit[0] : params.limit, 10) : 25 }; 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, 0, undefined ); } ); }

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