Skip to main content
Glama

Backlog MCP Server

index.ts4.44 kB
#!/usr/bin/env node // Copyright (c) 2025 Nulab inc. // Licensed under the MIT License. import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import * as backlogjs from 'backlog-js'; import dotenv from 'dotenv'; import { default as env } from 'env-var'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import { createTranslationHelper } from './createTranslationHelper.js'; import { registerDyamicTools, registerTools } from './registerTools.js'; import { dynamicTools } from './tools/dynamicTools/toolsets.js'; import { logger } from './utils/logger.js'; import { createToolRegistrar } from './utils/toolRegistrar.js'; import { buildToolsetGroup } from './utils/toolsetUtils.js'; import { wrapServerWithToolRegistry } from './utils/wrapServerWithToolRegistry.js'; import { VERSION } from './version.js'; dotenv.config(); const domain = env.get('BACKLOG_DOMAIN').required().asString(); const apiKey = env.get('BACKLOG_API_KEY').required().asString(); const backlog = new backlogjs.Backlog({ host: domain, apiKey: apiKey }); const argv = yargs(hideBin(process.argv)) .option('max-tokens', { type: 'number', describe: 'Maximum number of tokens allowed in the response', default: env.get('MAX_TOKENS').default('50000').asIntPositive(), }) .option('optimize-response', { type: 'boolean', describe: 'Enable GraphQL-style response optimization to include only requested fields', default: env.get('OPTIMIZE_RESPONSE').default('false').asBool(), }) .option('prefix', { type: 'string', describe: 'Optional string prefix to prepend to all generated outputs', default: env.get('PREFIX').default('').asString(), }) .option('export-translations', { type: 'boolean', describe: 'Export translations and exit', default: false, }) .option('enable-toolsets', { type: 'array', describe: `Specify which toolsets to enable. Defaults to 'all'. Available toolsets: - space: Tools for managing Backlog space settings and general information - project: Tools for managing projects, categories, custom fields, and issue types - issue: Tools for managing issues and their comments - wiki: Tools for managing wiki pages - git: Tools for managing Git repositories and pull requests - notifications: Tools for managing user notifications`, default: env.get('ENABLE_TOOLSETS').default('all').asArray(','), }) .option('dynamic-toolsets', { type: 'boolean', describe: 'Enable dynamic toolsets such as enable_toolset, list_available_toolsets, etc.', default: env.get('ENABLE_DYNAMIC_TOOLSETS').default('false').asBool(), }) .parseSync(); const useFields = argv.optimizeResponse; const server = wrapServerWithToolRegistry( new McpServer({ name: 'backlog', description: useFields ? `You can include only the fields you need using GraphQL-style syntax. Start with the example above and customize freely.` : undefined, version: VERSION, }) ); const transHelper = createTranslationHelper(); const maxTokens = argv.maxTokens; const prefix = argv.prefix; let enabledToolsets = argv.enableToolsets as string[]; // If dynamic toolsets are enabled, remove "all" to allow for selective enabling via commands if (argv.dynamicToolsets) { enabledToolsets = enabledToolsets.filter((a) => a != 'all'); } const mcpOption = { useFields: useFields, maxTokens, prefix }; const toolsetGroup = buildToolsetGroup(backlog, transHelper, enabledToolsets); // Register all tools registerTools(server, toolsetGroup, mcpOption); // Register dynamic tool management tools if enabled if (argv.dynamicToolsets) { const registrar = createToolRegistrar(server, toolsetGroup, mcpOption); const dynamicToolsetGroup = dynamicTools( registrar, transHelper, toolsetGroup ); registerDyamicTools(server, dynamicToolsetGroup, prefix); } if (argv.exportTranslations) { const data = transHelper.dump(); // eslint-disable-next-line no-console console.log(JSON.stringify(data, null, 2)); process.exit(0); } async function main() { const transport = new StdioServerTransport(); await server.connect(transport); logger.info('Backlog MCP Server running on stdio'); } main().catch((error) => { logger.error({ err: error }, 'Fatal error in main()'); process.exit(1); });

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/nulab/backlog-mcp-server'

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