backlog-mcp-server 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +4 -4
- package/README.md +27 -25
- package/build/index.js +8 -4
- package/build/tools/getProjectUsers.js +30 -0
- package/build/tools/tools.js +2 -0
- package/package.json +47 -37
package/README.ja.md
CHANGED
|
@@ -101,8 +101,8 @@ docker pull ghcr.io/nulab/backlog-mcp-server:latest
|
|
|
101
101
|
```bash
|
|
102
102
|
git clone https://github.com/nulab/backlog-mcp-server.git
|
|
103
103
|
cd backlog-mcp-server
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
pnpm install
|
|
105
|
+
pnpm run build
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
2. テンプレートから `.env` を作成し、必須の環境変数を設定します:
|
|
@@ -119,7 +119,7 @@ cp .env.example .env
|
|
|
119
119
|
3. ローカルで起動します:
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
|
|
122
|
+
pnpm run dev
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
4. MCPとして使用するJSONを設定します:
|
|
@@ -529,7 +529,7 @@ MAX_TOKENS=10000
|
|
|
529
529
|
### テストの実行
|
|
530
530
|
|
|
531
531
|
```bash
|
|
532
|
-
|
|
532
|
+
pnpm test
|
|
533
533
|
```
|
|
534
534
|
|
|
535
535
|
### 新しいツールの追加
|
package/README.md
CHANGED
|
@@ -101,8 +101,8 @@ Replace `your-domain.backlog.com` with your Backlog domain and `your-api-key` wi
|
|
|
101
101
|
```bash
|
|
102
102
|
git clone https://github.com/nulab/backlog-mcp-server.git
|
|
103
103
|
cd backlog-mcp-server
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
pnpm install
|
|
105
|
+
pnpm run build
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
2. Create `.env` from template and set required variables:
|
|
@@ -119,7 +119,7 @@ Set the following values in `.env`:
|
|
|
119
119
|
3. Run locally:
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
|
|
122
|
+
pnpm run dev
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
4. Set your json to use as MCP
|
|
@@ -144,7 +144,7 @@ npm run dev
|
|
|
144
144
|
By default the server uses **stdio**. To run the [MCP Streamable HTTP](https://modelcontextprotocol.io/) transport instead (JSON-RPC over HTTP, same tools as stdio), start with `--transport http` or set `MCP_TRANSPORT=http`.
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
|
-
|
|
147
|
+
pnpm run build
|
|
148
148
|
MCP_TRANSPORT=http MCP_HTTP_PORT=3333 node build/index.js
|
|
149
149
|
```
|
|
150
150
|
|
|
@@ -154,13 +154,13 @@ MCP_TRANSPORT=http MCP_HTTP_PORT=3333 node build/index.js
|
|
|
154
154
|
|
|
155
155
|
Environment variables (CLI flags override when both are set):
|
|
156
156
|
|
|
157
|
-
| Variable
|
|
158
|
-
|
|
|
159
|
-
| `MCP_TRANSPORT`
|
|
160
|
-
| `MCP_HTTP_HOST`
|
|
161
|
-
| `MCP_HTTP_PORT`
|
|
162
|
-
| `MCP_HTTP_PATH`
|
|
163
|
-
| `MCP_HTTP_JSON_RESPONSE` | `true` to prefer JSON responses over SSE when supported
|
|
157
|
+
| Variable | Description |
|
|
158
|
+
| ------------------------ | ------------------------------------------------------------------------------------------ |
|
|
159
|
+
| `MCP_TRANSPORT` | `stdio` (default) or `http` |
|
|
160
|
+
| `MCP_HTTP_HOST` | Bind address (default `127.0.0.1`) |
|
|
161
|
+
| `MCP_HTTP_PORT` | Port (default `3333`) |
|
|
162
|
+
| `MCP_HTTP_PATH` | URL path (default `/mcp`) |
|
|
163
|
+
| `MCP_HTTP_JSON_RESPONSE` | `true` to prefer JSON responses over SSE when supported |
|
|
164
164
|
| `MCP_HTTP_ALLOWED_HOSTS` | Comma-separated allowed `Host` values when binding to `0.0.0.0` (DNS rebinding protection) |
|
|
165
165
|
|
|
166
166
|
### OAuth 2.0 Authentication (Remote MCP)
|
|
@@ -178,11 +178,11 @@ The server implements the [MCP Third-Party Authorization Flow](https://modelcont
|
|
|
178
178
|
|
|
179
179
|
2. Set the following environment variables (in addition to `BACKLOG_DOMAIN`):
|
|
180
180
|
|
|
181
|
-
| Variable
|
|
182
|
-
|
|
|
183
|
-
| `BACKLOG_OAUTH_CLIENT_ID`
|
|
184
|
-
| `BACKLOG_OAUTH_CLIENT_SECRET` | OAuth Client Secret from your Backlog application
|
|
185
|
-
| `MCP_SERVER_BASE_URL`
|
|
181
|
+
| Variable | Description |
|
|
182
|
+
| ----------------------------- | --------------------------------------------------------------- |
|
|
183
|
+
| `BACKLOG_OAUTH_CLIENT_ID` | OAuth Client ID from your Backlog application |
|
|
184
|
+
| `BACKLOG_OAUTH_CLIENT_SECRET` | OAuth Client Secret from your Backlog application |
|
|
185
|
+
| `MCP_SERVER_BASE_URL` | Public URL of your MCP server (e.g., `https://mcp.example.com`) |
|
|
186
186
|
|
|
187
187
|
> **Note:** `BACKLOG_API_KEY` is **not required** when OAuth is enabled — each user authenticates with their own Backlog account.
|
|
188
188
|
|
|
@@ -198,18 +198,19 @@ node build/index.js --transport http --http-host 0.0.0.0 --http-port 3333
|
|
|
198
198
|
|
|
199
199
|
The server automatically exposes the following OAuth endpoints when OAuth is enabled:
|
|
200
200
|
|
|
201
|
-
| Endpoint
|
|
202
|
-
|
|
|
203
|
-
| `GET /.well-known/oauth-authorization-server`
|
|
204
|
-
| `GET /.well-known/oauth-protected-resource/mcp` | OAuth Protected Resource Metadata ([RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728))
|
|
205
|
-
| `POST /register`
|
|
206
|
-
| `GET /authorize`
|
|
207
|
-
| `GET /callback`
|
|
208
|
-
| `POST /token`
|
|
201
|
+
| Endpoint | Description |
|
|
202
|
+
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
203
|
+
| `GET /.well-known/oauth-authorization-server` | OAuth Authorization Server Metadata ([RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414)) |
|
|
204
|
+
| `GET /.well-known/oauth-protected-resource/mcp` | OAuth Protected Resource Metadata ([RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728)) |
|
|
205
|
+
| `POST /register` | Dynamic Client Registration ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) |
|
|
206
|
+
| `GET /authorize` | Authorization endpoint (redirects to Backlog OAuth) |
|
|
207
|
+
| `GET /callback` | Backlog OAuth callback |
|
|
208
|
+
| `POST /token` | Token endpoint (authorization code & refresh token) |
|
|
209
209
|
|
|
210
210
|
MCP clients that support the MCP authorization specification will use these endpoints automatically.
|
|
211
211
|
|
|
212
212
|
> **Limitations:**
|
|
213
|
+
>
|
|
213
214
|
> - OAuth mode currently supports a single Backlog organization. It is not compatible with the multi-organization configuration.
|
|
214
215
|
> - Client registrations and tokens are stored in memory and will be lost on server restart.
|
|
215
216
|
|
|
@@ -288,6 +289,7 @@ Tools for managing projects, categories, custom fields, and issue types.
|
|
|
288
289
|
- `get_project_list`: Returns list of projects.
|
|
289
290
|
- `add_project`: Creates a new project.
|
|
290
291
|
- `get_project`: Returns information about a specific project.
|
|
292
|
+
- `get_project_users`: Returns list of users in a specific project.
|
|
291
293
|
- `update_project`: Updates an existing project.
|
|
292
294
|
- `delete_project`: Deletes a project.
|
|
293
295
|
|
|
@@ -633,7 +635,7 @@ This section demonstrates advanced configuration using multiple environment vari
|
|
|
633
635
|
### Running Tests
|
|
634
636
|
|
|
635
637
|
```bash
|
|
636
|
-
|
|
638
|
+
pnpm test
|
|
637
639
|
```
|
|
638
640
|
|
|
639
641
|
### Adding New Tools
|
package/build/index.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Copyright (c) 2025 Nulab inc.
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
-
import dotenv from 'dotenv';
|
|
6
5
|
import { default as env } from 'env-var';
|
|
7
6
|
import yargs from 'yargs';
|
|
8
7
|
import { hideBin } from 'yargs/helpers';
|
|
@@ -20,11 +19,11 @@ const { version } = packageJson;
|
|
|
20
19
|
// as an error event on stdout/stderr streams — both must be handled.
|
|
21
20
|
process.on('SIGPIPE', () => { });
|
|
22
21
|
process.stdout.on('error', (err) => {
|
|
23
|
-
if (err.code !== 'EPIPE')
|
|
22
|
+
if (!('code' in err) || err.code !== 'EPIPE')
|
|
24
23
|
throw err;
|
|
25
24
|
});
|
|
26
25
|
process.stderr.on('error', (err) => {
|
|
27
|
-
if (err.code !== 'EPIPE')
|
|
26
|
+
if (!('code' in err) || err.code !== 'EPIPE')
|
|
28
27
|
throw err;
|
|
29
28
|
});
|
|
30
29
|
process.on('uncaughtException', (error) => {
|
|
@@ -35,7 +34,12 @@ process.on('unhandledRejection', (reason) => {
|
|
|
35
34
|
logger.error({ err: reason }, 'Unhandled rejection');
|
|
36
35
|
process.exit(1);
|
|
37
36
|
});
|
|
38
|
-
|
|
37
|
+
try {
|
|
38
|
+
process.loadEnvFile();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// .env file is optional
|
|
42
|
+
}
|
|
39
43
|
const oauthConfig = getBacklogOAuthConfig();
|
|
40
44
|
const argv = yargs(hideBin(process.argv))
|
|
41
45
|
.option('transport', {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { buildToolSchema } from '../types/tool.js';
|
|
3
|
+
import { UserSchema } from '../types/zod/backlogOutputDefinition.js';
|
|
4
|
+
import { resolveIdOrKey } from '../utils/resolveIdOrKey.js';
|
|
5
|
+
const getProjectUsersSchema = buildToolSchema((t) => ({
|
|
6
|
+
projectId: z
|
|
7
|
+
.number()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe(t('TOOL_GET_PROJECT_USERS_PROJECT_ID', 'The numeric ID of the project (e.g., 12345)')),
|
|
10
|
+
projectKey: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe(t('TOOL_GET_PROJECT_USERS_PROJECT_KEY', "The key of the project (e.g., 'PROJECT')")),
|
|
14
|
+
}));
|
|
15
|
+
export const getProjectUsersTool = (backlog, { t }) => {
|
|
16
|
+
return {
|
|
17
|
+
name: 'get_project_users',
|
|
18
|
+
description: t('TOOL_GET_PROJECT_USERS_DESCRIPTION', 'Returns list of users in a specific project'),
|
|
19
|
+
schema: z.object(getProjectUsersSchema(t)),
|
|
20
|
+
outputSchema: UserSchema,
|
|
21
|
+
importantFields: ['userId', 'name', 'roleType', 'lang'],
|
|
22
|
+
handler: async ({ projectId, projectKey }) => {
|
|
23
|
+
const result = resolveIdOrKey('project', { id: projectId, key: projectKey }, t);
|
|
24
|
+
if (!result.ok) {
|
|
25
|
+
throw result.error;
|
|
26
|
+
}
|
|
27
|
+
return backlog.getProjectUsers(result.value);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
package/build/tools/tools.js
CHANGED
|
@@ -22,6 +22,7 @@ import { getNotificationsCountTool } from './getNotificationsCount.js';
|
|
|
22
22
|
import { getPrioritiesTool } from './getPriorities.js';
|
|
23
23
|
import { getProjectTool } from './getProject.js';
|
|
24
24
|
import { getProjectListTool } from './getProjectList.js';
|
|
25
|
+
import { getProjectUsersTool } from './getProjectUsers.js';
|
|
25
26
|
import { getPullRequestTool } from './getPullRequest.js';
|
|
26
27
|
import { getPullRequestCommentsTool } from './getPullRequestComments.js';
|
|
27
28
|
import { getPullRequestsTool } from './getPullRequests.js';
|
|
@@ -79,6 +80,7 @@ export const allTools = (backlog, helper) => {
|
|
|
79
80
|
getProjectListTool(backlog, helper),
|
|
80
81
|
addProjectTool(backlog, helper),
|
|
81
82
|
getProjectTool(backlog, helper),
|
|
83
|
+
getProjectUsersTool(backlog, helper),
|
|
82
84
|
updateProjectTool(backlog, helper),
|
|
83
85
|
deleteProjectTool(backlog, helper),
|
|
84
86
|
],
|
package/package.json
CHANGED
|
@@ -1,16 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backlog-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"backlog-mcp-server": "./build/index.js"
|
|
7
7
|
},
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22"
|
|
10
|
+
},
|
|
11
|
+
"devEngines": {
|
|
12
|
+
"runtime": {
|
|
13
|
+
"name": "node",
|
|
14
|
+
"version": ">=22",
|
|
15
|
+
"onFail": "warn"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
8
18
|
"license": "MIT",
|
|
9
19
|
"repository": {
|
|
10
20
|
"type": "git",
|
|
11
21
|
"url": "git+https://github.com/nulab/backlog-mcp-server.git"
|
|
12
22
|
},
|
|
23
|
+
"files": [
|
|
24
|
+
"build"
|
|
25
|
+
],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@hono/node-server": "^2.0.4",
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
+
"backlog-js": "^0.16.0",
|
|
30
|
+
"cosmiconfig": "^9.0.1",
|
|
31
|
+
"env-var": "^7.5.0",
|
|
32
|
+
"graphql": "^16.14.1",
|
|
33
|
+
"hono": "^4.12.25",
|
|
34
|
+
"pino": "^10.3.1",
|
|
35
|
+
"pino-pretty": "^13.1.3",
|
|
36
|
+
"yargs": "^18.0.0",
|
|
37
|
+
"zod": "^3.24.3"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@eslint/js": "^10.0.1",
|
|
41
|
+
"@release-it/conventional-changelog": "^11.0.1",
|
|
42
|
+
"@types/node": "^25.9.2",
|
|
43
|
+
"@types/yargs": "^17.0.35",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
|
45
|
+
"@typescript-eslint/parser": "^8.60.1",
|
|
46
|
+
"@typescript-eslint/utils": "^8.60.1",
|
|
47
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
48
|
+
"eslint": "^10.4.1",
|
|
49
|
+
"eslint-config-prettier": "^10.1.8",
|
|
50
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
51
|
+
"prettier": "^3.8.3",
|
|
52
|
+
"release-it": "^20.2.0",
|
|
53
|
+
"tsx": "^4.22.4",
|
|
54
|
+
"typescript": "^6.0.3",
|
|
55
|
+
"vitest": "^4.1.8"
|
|
56
|
+
},
|
|
13
57
|
"scripts": {
|
|
58
|
+
"preinstall": "npx only-allow pnpm",
|
|
14
59
|
"dev": "tsx src/index.ts",
|
|
15
60
|
"build": "tsc && chmod 755 build/index.js",
|
|
16
61
|
"test": "vitest run",
|
|
@@ -22,40 +67,5 @@
|
|
|
22
67
|
"format:fix": "prettier --write \"**/*.{ts,tsx}\"",
|
|
23
68
|
"typecheck": "tsc --noEmit",
|
|
24
69
|
"typecheck:all": "tsc --noEmit --project tsconfig.test.json"
|
|
25
|
-
},
|
|
26
|
-
"files": [
|
|
27
|
-
"build"
|
|
28
|
-
],
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"@hono/node-server": "^1.19.14",
|
|
31
|
-
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
32
|
-
"backlog-js": "^0.16.0",
|
|
33
|
-
"cosmiconfig": "^9.0.0",
|
|
34
|
-
"dotenv": "^16.5.0",
|
|
35
|
-
"env-var": "^7.5.0",
|
|
36
|
-
"graphql": "^16.11.0",
|
|
37
|
-
"hono": "^4.12.23",
|
|
38
|
-
"pino": "^9.9.0",
|
|
39
|
-
"pino-pretty": "^13.1.1",
|
|
40
|
-
"yargs": "^18.0.0",
|
|
41
|
-
"zod": "^3.24.3"
|
|
42
|
-
},
|
|
43
|
-
"devDependencies": {
|
|
44
|
-
"@eslint/js": "^9.24.0",
|
|
45
|
-
"@release-it/conventional-changelog": "^11.0.0",
|
|
46
|
-
"@types/node": "^22.14.1",
|
|
47
|
-
"@types/yargs": "^17.0.33",
|
|
48
|
-
"@typescript-eslint/eslint-plugin": "^8.30.1",
|
|
49
|
-
"@typescript-eslint/parser": "^8.30.1",
|
|
50
|
-
"@typescript-eslint/utils": "^8.30.1",
|
|
51
|
-
"@vitest/coverage-v8": "^4.0.0",
|
|
52
|
-
"eslint": "^9.24.0",
|
|
53
|
-
"eslint-config-prettier": "^10.1.2",
|
|
54
|
-
"eslint-plugin-prettier": "^5.2.6",
|
|
55
|
-
"prettier": "^3.5.3",
|
|
56
|
-
"release-it": "^20.0.1",
|
|
57
|
-
"tsx": "^4.20.6",
|
|
58
|
-
"typescript": "^5.8.3",
|
|
59
|
-
"vitest": "^4.0.0"
|
|
60
70
|
}
|
|
61
|
-
}
|
|
71
|
+
}
|