backlog-mcp-server 0.18.0 → 0.19.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 +16 -0
- package/README.md +17 -0
- package/build/auth/oauthRoutes.js +1 -1
- package/build/backlog/customFields.js +12 -9
- package/build/handlers/builders/composeDynamicToolHandler.d.ts +147 -0
- package/build/handlers/builders/composeDynamicToolHandler.js +55 -0
- package/build/httpMcpServer.js +8 -1
- package/build/lib.d.ts +2 -0
- package/build/lib.js +1 -0
- package/build/loadDescriptionOverrides.js +2 -2
- package/build/registerTools.js +18 -0
- package/build/tools/addDocument.d.ts +1 -1
- package/build/tools/addDocument.js +2 -1
- package/build/tools/addIssue.d.ts +1 -1
- package/build/tools/addIssueComment.d.ts +1 -1
- package/build/tools/addProject.d.ts +1 -1
- package/build/tools/addPullRequest.d.ts +1 -1
- package/build/tools/addPullRequestComment.d.ts +1 -1
- package/build/tools/addRelatedIssue.d.ts +1 -1
- package/build/tools/addVersionMilestone.d.ts +1 -1
- package/build/tools/addWatching.d.ts +1 -1
- package/build/tools/addWiki.d.ts +1 -1
- package/build/tools/countIssues.d.ts +1 -1
- package/build/tools/deleteIssue.d.ts +1 -1
- package/build/tools/deleteProject.d.ts +1 -1
- package/build/tools/deleteVersion.d.ts +1 -1
- package/build/tools/deleteWatching.d.ts +1 -1
- package/build/tools/getCategories.d.ts +1 -1
- package/build/tools/getCustomFields.d.ts +1 -1
- package/build/tools/getDocument.d.ts +1 -1
- package/build/tools/getDocument.js +1 -0
- package/build/tools/getDocumentTree.d.ts +1 -1
- package/build/tools/getDocuments.d.ts +1 -1
- package/build/tools/getDocuments.js +1 -0
- package/build/tools/getGitRepositories.d.ts +1 -1
- package/build/tools/getGitRepository.d.ts +1 -1
- package/build/tools/getIssue.d.ts +1 -1
- package/build/tools/getIssueAttachment.d.ts +16 -0
- package/build/tools/getIssueAttachment.js +345 -0
- package/build/tools/getIssueComments.d.ts +1 -1
- package/build/tools/getIssueTypes.d.ts +1 -1
- package/build/tools/getIssues.d.ts +15 -15
- package/build/tools/getMyself.d.ts +1 -1
- package/build/tools/getNotifications.d.ts +1 -1
- package/build/tools/getNotifications.js +3 -0
- package/build/tools/getNotificationsCount.d.ts +1 -1
- package/build/tools/getPriorities.d.ts +1 -1
- package/build/tools/getProject.d.ts +1 -1
- package/build/tools/getProjectList.d.ts +1 -1
- package/build/tools/getProjectUsers.d.ts +1 -1
- package/build/tools/getPullRequest.d.ts +1 -1
- package/build/tools/getPullRequestComments.d.ts +1 -1
- package/build/tools/getPullRequests.d.ts +1 -1
- package/build/tools/getPullRequestsCount.d.ts +1 -1
- package/build/tools/getRelatedIssues.d.ts +1 -1
- package/build/tools/getResolutions.d.ts +1 -1
- package/build/tools/getSpace.d.ts +1 -1
- package/build/tools/getSpaceActivities.d.ts +1 -1
- package/build/tools/getUserRecentUpdates.d.ts +1 -1
- package/build/tools/getUserStarsCount.d.ts +1 -1
- package/build/tools/getUsers.d.ts +1 -1
- package/build/tools/getVersionMilestoneList.d.ts +1 -1
- package/build/tools/getWatchingListCount.d.ts +1 -1
- package/build/tools/getWatchingListItems.d.ts +1 -1
- package/build/tools/getWiki.d.ts +1 -1
- package/build/tools/getWikiPages.d.ts +1 -1
- package/build/tools/getWikisCount.d.ts +1 -1
- package/build/tools/markNotificationAsRead.d.ts +1 -1
- package/build/tools/markWatchingAsRead.d.ts +1 -1
- package/build/tools/removeRelatedIssue.d.ts +1 -1
- package/build/tools/resetUnreadNotificationCount.d.ts +1 -1
- package/build/tools/shared/customFieldFiltersSchema.d.ts +1 -1
- package/build/tools/tools.js +2 -0
- package/build/tools/updateIssue.d.ts +1 -1
- package/build/tools/updateIssueComment.d.ts +1 -1
- package/build/tools/updateProject.d.ts +1 -1
- package/build/tools/updatePullRequest.d.ts +1 -1
- package/build/tools/updatePullRequestComment.d.ts +1 -1
- package/build/tools/updateVersionMilestone.d.ts +1 -1
- package/build/tools/updateWatching.d.ts +1 -1
- package/build/tools/updateWiki.d.ts +1 -1
- package/build/types/tool.d.ts +1 -1
- package/build/types/toolsets.d.ts +12 -1
- package/build/utils/logger.js +41 -3
- package/build/utils/resolveIdOrKey.d.ts +2 -2
- package/package.json +18 -25
package/README.ja.md
CHANGED
|
@@ -469,6 +469,22 @@ MAX_TOKENS=10000
|
|
|
469
469
|
|
|
470
470
|
> 注:これはベストエフォートの緩和策であり、保証された強制ではありません。
|
|
471
471
|
|
|
472
|
+
### ログ出力
|
|
473
|
+
|
|
474
|
+
ログは **stderr** に出力されます(stdio トランスポートでは stdout が JSON-RPC のストリームに使われるため)。
|
|
475
|
+
|
|
476
|
+
| 変数 | 説明 |
|
|
477
|
+
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
478
|
+
| `LOG_LEVEL` | `fatal` / `error` / `warn` / `info` / `debug` / `trace` / `silent`。既定は `NODE_ENV` が `production`(未設定時もこれに含まれる)のとき `error`、それ以外は `debug`。認識できない値は通知した上で既定値にフォールバックします。 |
|
|
479
|
+
|
|
480
|
+
出力**フォーマット**は引き続き `NODE_ENV` が決めます(`production` 以外では `pino-pretty` が利用可能なら人間向けの整形出力に切り替わります)。ログ量を変えたいときは `NODE_ENV` ではなく `LOG_LEVEL` を設定してください。デプロイ先で構造化 JSON のまま保てます。
|
|
481
|
+
|
|
482
|
+
`pino-pretty` は開発用の依存なので、公開されている npm パッケージにもコンテナイメージにも含まれていません。そのため、これらでは `NODE_ENV` の値に関わらず常に構造化 JSON が出力され、出力を変えられるのは `LOG_LEVEL` だけです。
|
|
483
|
+
|
|
484
|
+
```
|
|
485
|
+
LOG_LEVEL=info node build/index.js --transport http
|
|
486
|
+
```
|
|
487
|
+
|
|
472
488
|
### 完全なカスタム設定例
|
|
473
489
|
|
|
474
490
|
このセクションでは、複数の環境変数を使用した高度な設定を示します。これらは実験的な機能であり、すべてのMCPクライアントでサポートされているとは限りません。これはMCP標準仕様の一部ではなく、注意して使用する必要があります。
|
package/README.md
CHANGED
|
@@ -294,6 +294,7 @@ Tools for managing projects, categories, custom fields, and issue types.
|
|
|
294
294
|
Tools for managing issues, their comments, and related items like priorities, categories, custom fields, issue types, resolutions, and watching lists.
|
|
295
295
|
|
|
296
296
|
- `get_issue`: Returns information about a specific issue.
|
|
297
|
+
- `get_issue_attachment`: Downloads one attachment of an issue. Returns it as image or embedded resource content, or as base64 with `format: "base64"`.
|
|
297
298
|
- `get_issues`: Returns list of issues.
|
|
298
299
|
- `count_issues`: Returns count of issues.
|
|
299
300
|
- `add_issue`: Creates a new issue in the specified project.
|
|
@@ -586,6 +587,22 @@ If a response exceeds the limit, it will be truncated with a warning.
|
|
|
586
587
|
|
|
587
588
|
> Note: This is a best-effort mitigation, not a guaranteed enforcement.
|
|
588
589
|
|
|
590
|
+
### Logging
|
|
591
|
+
|
|
592
|
+
The server logs to **stderr** (stdout carries the JSON-RPC stream on the stdio transport).
|
|
593
|
+
|
|
594
|
+
| Variable | Description |
|
|
595
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
596
|
+
| `LOG_LEVEL` | `fatal`, `error`, `warn`, `info`, `debug`, `trace` or `silent`. Defaults to `error` when `NODE_ENV` is `production` — which is also the default when `NODE_ENV` is unset — and to `debug` otherwise. An unrecognised value is reported and the default is used. |
|
|
597
|
+
|
|
598
|
+
`NODE_ENV` still selects the output *format*: any value other than `production` switches to human-readable `pino-pretty` output when that package is available. Use `LOG_LEVEL`, not `NODE_ENV`, to change how much is logged, so that a deployment keeps structured JSON:
|
|
599
|
+
|
|
600
|
+
`pino-pretty` is a development dependency, so neither the published npm package nor the container image carries a copy. In those, logs are structured JSON whatever `NODE_ENV` says, and `LOG_LEVEL` is the only setting that changes the output.
|
|
601
|
+
|
|
602
|
+
```
|
|
603
|
+
LOG_LEVEL=info node build/index.js --transport http
|
|
604
|
+
```
|
|
605
|
+
|
|
589
606
|
### Full Custom Configuration Example
|
|
590
607
|
|
|
591
608
|
This section demonstrates advanced configuration using multiple environment variables. These are experimental features and may not be supported across all MCP clients. This is not part of the MCP standard specification and should be used with caution.
|
|
@@ -119,7 +119,7 @@ export function createOAuthRoutes(config, store, mcpPath) {
|
|
|
119
119
|
const declaredApplicationType = body.application_type ?? undefined;
|
|
120
120
|
if (declaredApplicationType !== undefined &&
|
|
121
121
|
!APPLICATION_TYPES.includes(declaredApplicationType)) {
|
|
122
|
-
return c.json(oauthError('invalid_client_metadata', `Unsupported application_type: ${
|
|
122
|
+
return c.json(oauthError('invalid_client_metadata', `Unsupported application_type: ${JSON.stringify(declaredApplicationType)}. Supported: ${APPLICATION_TYPES.join(', ')}`), 400);
|
|
123
123
|
}
|
|
124
124
|
const applicationType = resolveApplicationType(declaredApplicationType, redirectUris);
|
|
125
125
|
if (applicationType === 'web') {
|
|
@@ -49,20 +49,23 @@ export function customFieldFiltersToPayload(customFields) {
|
|
|
49
49
|
break;
|
|
50
50
|
}
|
|
51
51
|
case 'list': {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
// Always an array, single value included. Backlog matches a list custom
|
|
53
|
+
// field only on the indexed parameters `customField_1[0]=…`, which
|
|
54
|
+
// `Request.toQueryString` produces from an array under a `customField_`
|
|
55
|
+
// key. A bare `customField_1=…` is not matched, and neither is the
|
|
56
|
+
// `customField_1[][0]=…` that a `[]` suffix on this key would produce.
|
|
57
|
+
// Neither is rejected either — the filter is silently ignored and every
|
|
58
|
+
// issue comes back, so the caller cannot tell a filtered query from an
|
|
59
|
+
// unfiltered one.
|
|
60
|
+
const values = (Array.isArray(field.value) ? field.value : [field.value]).filter((value) => Number.isFinite(value));
|
|
61
|
+
if (values.length > 0) {
|
|
62
|
+
result[baseKey] = values;
|
|
60
63
|
}
|
|
61
64
|
break;
|
|
62
65
|
}
|
|
63
66
|
default: {
|
|
64
67
|
const exhaustiveCheck = field;
|
|
65
|
-
throw new Error(`Unsupported custom field filter type: ${exhaustiveCheck}`);
|
|
68
|
+
throw new Error(`Unsupported custom field filter type: ${JSON.stringify(exhaustiveCheck)}`);
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ErrorLike } from '../../types/result.js';
|
|
3
|
+
import { DynamicToolDefinition } from '../../types/tool.js';
|
|
4
|
+
export type ComposeDynamicOptions = {
|
|
5
|
+
errorHandler?: (err: unknown) => ErrorLike;
|
|
6
|
+
useOrganization?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type DynamicInput = {
|
|
9
|
+
organization?: string;
|
|
10
|
+
} & Record<string, unknown>;
|
|
11
|
+
/**
|
|
12
|
+
* Builds the schema and handler a dynamic tool is registered with.
|
|
13
|
+
*
|
|
14
|
+
* The counterpart of `composeToolHandler` for tools that produce a
|
|
15
|
+
* `CallToolResult` themselves. Those cannot go through the whole pipeline:
|
|
16
|
+
* field picking, the token limit and `wrapWithToolResult` all assume a JSON
|
|
17
|
+
* value they may reshape, and reshaping is exactly what a tool returning binary
|
|
18
|
+
* content must not allow — a base64 payload cut at the token limit is a corrupt
|
|
19
|
+
* file reported as a success.
|
|
20
|
+
*
|
|
21
|
+
* The two steps that are not about reshaping still apply, and are why this
|
|
22
|
+
* exists rather than registering the handler directly:
|
|
23
|
+
*
|
|
24
|
+
* - `wrapWithOrganizationContext`, without which a dynamic tool ignores
|
|
25
|
+
* `organization` and always talks to the default space;
|
|
26
|
+
* - `wrapWithErrorHandling`, without which a thrown Backlog error escapes as a
|
|
27
|
+
* protocol error rather than an `isError` result, and never reaches the
|
|
28
|
+
* handler that reacts to Backlog rejecting a credential.
|
|
29
|
+
*
|
|
30
|
+
* As in `composeToolHandler`, the returned schema is a fresh object: the tool
|
|
31
|
+
* definition is never mutated, because one toolset group is shared across
|
|
32
|
+
* per-request servers.
|
|
33
|
+
*/
|
|
34
|
+
export declare function composeDynamicToolHandler(tool: DynamicToolDefinition<any>, { errorHandler, useOrganization }?: ComposeDynamicOptions): {
|
|
35
|
+
schema: z.ZodObject<{
|
|
36
|
+
[x: string]: any;
|
|
37
|
+
organization: z.ZodOptional<z.ZodString>;
|
|
38
|
+
} | {
|
|
39
|
+
[x: string]: any;
|
|
40
|
+
organization?: undefined;
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
handler: (input: DynamicInput) => Promise<{
|
|
43
|
+
[x: string]: unknown;
|
|
44
|
+
_meta?: {
|
|
45
|
+
[x: string]: unknown;
|
|
46
|
+
"io.modelcontextprotocol/serverInfo"?: {
|
|
47
|
+
version: string;
|
|
48
|
+
websiteUrl?: string | undefined;
|
|
49
|
+
description?: string | undefined;
|
|
50
|
+
icons?: {
|
|
51
|
+
src: string;
|
|
52
|
+
mimeType?: string | undefined;
|
|
53
|
+
sizes?: string[] | undefined;
|
|
54
|
+
theme?: "dark" | "light" | undefined;
|
|
55
|
+
}[] | undefined;
|
|
56
|
+
name: string;
|
|
57
|
+
title?: string | undefined;
|
|
58
|
+
} | undefined;
|
|
59
|
+
} | undefined;
|
|
60
|
+
content: ({
|
|
61
|
+
type: "text";
|
|
62
|
+
text: string;
|
|
63
|
+
annotations?: {
|
|
64
|
+
audience?: ("assistant" | "user")[] | undefined;
|
|
65
|
+
priority?: number | undefined;
|
|
66
|
+
lastModified?: string | undefined;
|
|
67
|
+
} | undefined;
|
|
68
|
+
_meta?: {
|
|
69
|
+
[x: string]: unknown;
|
|
70
|
+
} | undefined;
|
|
71
|
+
} | {
|
|
72
|
+
type: "image";
|
|
73
|
+
data: string;
|
|
74
|
+
mimeType: string;
|
|
75
|
+
annotations?: {
|
|
76
|
+
audience?: ("assistant" | "user")[] | undefined;
|
|
77
|
+
priority?: number | undefined;
|
|
78
|
+
lastModified?: string | undefined;
|
|
79
|
+
} | undefined;
|
|
80
|
+
_meta?: {
|
|
81
|
+
[x: string]: unknown;
|
|
82
|
+
} | undefined;
|
|
83
|
+
} | {
|
|
84
|
+
type: "audio";
|
|
85
|
+
data: string;
|
|
86
|
+
mimeType: string;
|
|
87
|
+
annotations?: {
|
|
88
|
+
audience?: ("assistant" | "user")[] | undefined;
|
|
89
|
+
priority?: number | undefined;
|
|
90
|
+
lastModified?: string | undefined;
|
|
91
|
+
} | undefined;
|
|
92
|
+
_meta?: {
|
|
93
|
+
[x: string]: unknown;
|
|
94
|
+
} | undefined;
|
|
95
|
+
} | {
|
|
96
|
+
uri: string;
|
|
97
|
+
description?: string | undefined;
|
|
98
|
+
mimeType?: string | undefined;
|
|
99
|
+
size?: number | undefined;
|
|
100
|
+
annotations?: {
|
|
101
|
+
audience?: ("assistant" | "user")[] | undefined;
|
|
102
|
+
priority?: number | undefined;
|
|
103
|
+
lastModified?: string | undefined;
|
|
104
|
+
} | undefined;
|
|
105
|
+
_meta?: {
|
|
106
|
+
[x: string]: unknown;
|
|
107
|
+
} | undefined;
|
|
108
|
+
icons?: {
|
|
109
|
+
src: string;
|
|
110
|
+
mimeType?: string | undefined;
|
|
111
|
+
sizes?: string[] | undefined;
|
|
112
|
+
theme?: "dark" | "light" | undefined;
|
|
113
|
+
}[] | undefined;
|
|
114
|
+
name: string;
|
|
115
|
+
title?: string | undefined;
|
|
116
|
+
type: "resource_link";
|
|
117
|
+
} | {
|
|
118
|
+
type: "resource";
|
|
119
|
+
resource: {
|
|
120
|
+
uri: string;
|
|
121
|
+
mimeType?: string | undefined;
|
|
122
|
+
_meta?: {
|
|
123
|
+
[x: string]: unknown;
|
|
124
|
+
} | undefined;
|
|
125
|
+
text: string;
|
|
126
|
+
} | {
|
|
127
|
+
uri: string;
|
|
128
|
+
mimeType?: string | undefined;
|
|
129
|
+
_meta?: {
|
|
130
|
+
[x: string]: unknown;
|
|
131
|
+
} | undefined;
|
|
132
|
+
blob: string;
|
|
133
|
+
};
|
|
134
|
+
annotations?: {
|
|
135
|
+
audience?: ("assistant" | "user")[] | undefined;
|
|
136
|
+
priority?: number | undefined;
|
|
137
|
+
lastModified?: string | undefined;
|
|
138
|
+
} | undefined;
|
|
139
|
+
_meta?: {
|
|
140
|
+
[x: string]: unknown;
|
|
141
|
+
} | undefined;
|
|
142
|
+
})[];
|
|
143
|
+
structuredContent?: unknown;
|
|
144
|
+
isError?: boolean | undefined;
|
|
145
|
+
}>;
|
|
146
|
+
};
|
|
147
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { wrapWithErrorHandling } from '../transformers/wrapWithErrorHandling.js';
|
|
3
|
+
import { wrapWithOrganizationContext } from '../transformers/wrapWithOrganizationContext.js';
|
|
4
|
+
import { isErrorLike } from '../../types/result.js';
|
|
5
|
+
/**
|
|
6
|
+
* Builds the schema and handler a dynamic tool is registered with.
|
|
7
|
+
*
|
|
8
|
+
* The counterpart of `composeToolHandler` for tools that produce a
|
|
9
|
+
* `CallToolResult` themselves. Those cannot go through the whole pipeline:
|
|
10
|
+
* field picking, the token limit and `wrapWithToolResult` all assume a JSON
|
|
11
|
+
* value they may reshape, and reshaping is exactly what a tool returning binary
|
|
12
|
+
* content must not allow — a base64 payload cut at the token limit is a corrupt
|
|
13
|
+
* file reported as a success.
|
|
14
|
+
*
|
|
15
|
+
* The two steps that are not about reshaping still apply, and are why this
|
|
16
|
+
* exists rather than registering the handler directly:
|
|
17
|
+
*
|
|
18
|
+
* - `wrapWithOrganizationContext`, without which a dynamic tool ignores
|
|
19
|
+
* `organization` and always talks to the default space;
|
|
20
|
+
* - `wrapWithErrorHandling`, without which a thrown Backlog error escapes as a
|
|
21
|
+
* protocol error rather than an `isError` result, and never reaches the
|
|
22
|
+
* handler that reacts to Backlog rejecting a credential.
|
|
23
|
+
*
|
|
24
|
+
* As in `composeToolHandler`, the returned schema is a fresh object: the tool
|
|
25
|
+
* definition is never mutated, because one toolset group is shared across
|
|
26
|
+
* per-request servers.
|
|
27
|
+
*/
|
|
28
|
+
export function composeDynamicToolHandler(
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
tool, { errorHandler, useOrganization = false } = {}) {
|
|
31
|
+
// `extend` even with nothing to add, so the returned schema is always a copy.
|
|
32
|
+
// Handing back `tool.schema` itself would make the invariant above hold only
|
|
33
|
+
// when `useOrganization` is set.
|
|
34
|
+
const schema = tool.schema.extend(useOrganization
|
|
35
|
+
? {
|
|
36
|
+
organization: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Optional organization name. Use list_organizations to inspect available organizations.'),
|
|
40
|
+
}
|
|
41
|
+
: {});
|
|
42
|
+
const handler = wrapWithErrorHandling(wrapWithOrganizationContext(tool.handler), errorHandler);
|
|
43
|
+
return {
|
|
44
|
+
schema,
|
|
45
|
+
handler: async (input) => {
|
|
46
|
+
const result = await handler(input);
|
|
47
|
+
return isErrorLike(result)
|
|
48
|
+
? {
|
|
49
|
+
isError: true,
|
|
50
|
+
content: [{ type: 'text', text: result.message }],
|
|
51
|
+
}
|
|
52
|
+
: result.data;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
package/build/httpMcpServer.js
CHANGED
|
@@ -16,6 +16,14 @@ export const runHttpMcpServer = async (options) => {
|
|
|
16
16
|
const app = new Hono();
|
|
17
17
|
const isLocalhostBind = LOCALHOST_BINDS.includes(host);
|
|
18
18
|
const oauthEnabled = !!(oauthConfig && tokenStore);
|
|
19
|
+
// Registered before the Host and Origin guards so that it stays reachable
|
|
20
|
+
// under an allow list. A load balancer health check addresses the target
|
|
21
|
+
// directly and puts its address in `Host` — AWS ALB gives no way to override
|
|
22
|
+
// it — so a guarded `/health` can only ever answer 403, leaving an operator
|
|
23
|
+
// to choose between dropping the allow list and treating 403 as healthy.
|
|
24
|
+
// Exempting it costs nothing: the response is constant and reaches no state,
|
|
25
|
+
// so there is nothing here for a rebinding page to reach either.
|
|
26
|
+
app.get('/health', (c) => c.json({ status: 'healthy', timestamp: new Date().toISOString(), version }));
|
|
19
27
|
// DNS rebinding protection. `Host` is the actual defense: a rebinding page
|
|
20
28
|
// reaches us carrying its own hostname, which the allow list rejects.
|
|
21
29
|
if (allowedHosts?.length) {
|
|
@@ -36,7 +44,6 @@ export const runHttpMcpServer = async (options) => {
|
|
|
36
44
|
else if (isLocalhostBind && !allowedHosts?.length) {
|
|
37
45
|
app.use('*', localhostOriginValidation());
|
|
38
46
|
}
|
|
39
|
-
app.get('/health', (c) => c.json({ status: 'healthy', timestamp: new Date().toISOString(), version }));
|
|
40
47
|
if (oauthEnabled) {
|
|
41
48
|
const { createOAuthRoutes } = await import('./auth/oauthRoutes.js');
|
|
42
49
|
const { createBearerAuthMiddleware } = await import('./auth/bearerAuthMiddleware.js');
|
package/build/lib.d.ts
CHANGED
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export { allTools } from './tools/tools.js';
|
|
16
16
|
export { composeToolHandler } from './handlers/builders/composeToolHandler.js';
|
|
17
|
+
export { composeDynamicToolHandler } from './handlers/builders/composeDynamicToolHandler.js';
|
|
17
18
|
export { createDescriptionHelper } from './createDescriptionHelper.js';
|
|
18
19
|
export { backlogErrorHandler } from './backlog/backlogErrorHandler.js';
|
|
19
20
|
export { buildToolSchema } from './types/tool.js';
|
|
20
21
|
export { isErrorLike } from './types/result.js';
|
|
21
22
|
export type { ComposeOptions } from './handlers/builders/composeToolHandler.js';
|
|
23
|
+
export type { ComposeDynamicOptions } from './handlers/builders/composeDynamicToolHandler.js';
|
|
22
24
|
export type { DescriptionHelper } from './createDescriptionHelper.js';
|
|
23
25
|
export type { ToolDefinition, DynamicToolDefinition } from './types/tool.js';
|
|
24
26
|
export type { Toolset, ToolsetGroup, DynamicToolset, DynamicToolsetGroup, } from './types/toolsets.js';
|
package/build/lib.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export { allTools } from './tools/tools.js';
|
|
16
16
|
export { composeToolHandler } from './handlers/builders/composeToolHandler.js';
|
|
17
|
+
export { composeDynamicToolHandler } from './handlers/builders/composeDynamicToolHandler.js';
|
|
17
18
|
export { createDescriptionHelper } from './createDescriptionHelper.js';
|
|
18
19
|
export { backlogErrorHandler } from './backlog/backlogErrorHandler.js';
|
|
19
20
|
export { buildToolSchema } from './types/tool.js';
|
|
@@ -69,8 +69,8 @@ export function loadDescriptionOverrides(options) {
|
|
|
69
69
|
continue;
|
|
70
70
|
if (outcome.status === 'unreadable') {
|
|
71
71
|
// `logger.error`, not `warn`: the logger runs at level `error` unless
|
|
72
|
-
// NODE_ENV says otherwise, so a warning here would never
|
|
73
|
-
// this message exists for.
|
|
72
|
+
// LOG_LEVEL or NODE_ENV says otherwise, so a warning here would never
|
|
73
|
+
// reach the user this message exists for.
|
|
74
74
|
logger.error({ err: outcome.error, filePath }, 'Could not read the description override file; continuing with the built-in defaults');
|
|
75
75
|
return {};
|
|
76
76
|
}
|
package/build/registerTools.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { backlogErrorHandler } from './backlog/backlogErrorHandler.js';
|
|
2
|
+
import { composeDynamicToolHandler } from './handlers/builders/composeDynamicToolHandler.js';
|
|
2
3
|
import { composeToolHandler } from './handlers/builders/composeToolHandler.js';
|
|
3
4
|
export function registerTools(server, toolsetGroup, options) {
|
|
4
5
|
const { useFields, maxTokens, prefix, useOrganization } = options;
|
|
@@ -15,6 +16,23 @@ export function registerTools(server, toolsetGroup, options) {
|
|
|
15
16
|
useOrganization,
|
|
16
17
|
}),
|
|
17
18
|
});
|
|
19
|
+
// Tools that build their own result, registered from the same toolsets so
|
|
20
|
+
// that `--enable-toolsets` and the prefix cover them too.
|
|
21
|
+
registerToolsets({
|
|
22
|
+
server,
|
|
23
|
+
toolsetGroup: {
|
|
24
|
+
toolsets: toolsetGroup.toolsets.map((toolset) => ({
|
|
25
|
+
name: toolset.name,
|
|
26
|
+
description: toolset.description,
|
|
27
|
+
enabled: toolset.enabled,
|
|
28
|
+
tools: toolset.dynamicTools ?? [],
|
|
29
|
+
})),
|
|
30
|
+
},
|
|
31
|
+
prefix,
|
|
32
|
+
prepareTool: (tool) => composeDynamicToolHandler(
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
tool, { errorHandler: backlogErrorHandler, useOrganization }),
|
|
35
|
+
});
|
|
18
36
|
}
|
|
19
37
|
export function registerDynamicTools(server, dynamicToolsetGroup, prefix) {
|
|
20
38
|
registerToolsets({
|
|
@@ -3,7 +3,7 @@ import { Backlog } from 'backlog-js';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
5
5
|
import { ToolDefinition } from '../types/tool.js';
|
|
6
|
-
declare const addDocumentSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addDocumentSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodNumber;
|
|
8
8
|
title: z.ZodOptional<z.ZodString>;
|
|
9
9
|
content: z.ZodOptional<z.ZodString>;
|
|
@@ -28,7 +28,7 @@ const addDocumentSchema = buildToolSchema((t) => ({
|
|
|
28
28
|
}));
|
|
29
29
|
export const addDocumentTool = (backlog, { t }) => {
|
|
30
30
|
return {
|
|
31
|
-
name: '
|
|
31
|
+
name: 'add_document',
|
|
32
32
|
description: t('TOOL_ADD_DOCUMENT_DESCRIPTION', 'Adds a new document to the specified project.'),
|
|
33
33
|
schema: z.object(addDocumentSchema(t)),
|
|
34
34
|
returnsList: false,
|
|
@@ -46,6 +46,7 @@ export const addDocumentTool = (backlog, { t }) => {
|
|
|
46
46
|
'created',
|
|
47
47
|
'updatedUser',
|
|
48
48
|
'updated',
|
|
49
|
+
'childDocumentIds',
|
|
49
50
|
]),
|
|
50
51
|
importantFields: ['id', 'projectId', 'title', 'plain', 'createdUser'],
|
|
51
52
|
handler: async (params) => {
|
|
@@ -3,7 +3,7 @@ import { Backlog } from 'backlog-js';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
5
5
|
import { ToolDefinition } from '../types/tool.js';
|
|
6
|
-
declare const addIssueSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addIssueSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodNumber;
|
|
8
8
|
summary: z.ZodString;
|
|
9
9
|
issueTypeId: z.ZodNumber;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addIssueCommentSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addIssueCommentSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
issueId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
issueKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
content: z.ZodString;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addProjectSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addProjectSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
name: z.ZodString;
|
|
8
8
|
key: z.ZodString;
|
|
9
9
|
chartEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addPullRequestSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addPullRequestSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
projectKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
repoId: z.ZodOptional<z.ZodNumber>;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addPullRequestCommentSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addPullRequestCommentSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
projectKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
repoId: z.ZodOptional<z.ZodNumber>;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addRelatedIssueSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addRelatedIssueSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
issueId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
issueKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
targetIssueId: z.ZodNumber;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addVersionMilestoneSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addVersionMilestoneSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
projectKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
name: z.ZodString;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addWatchingSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addWatchingSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
issueIdOrKey: z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>;
|
|
8
8
|
note: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
9
9
|
};
|
package/build/tools/addWiki.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const addWikiSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const addWikiSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodNumber;
|
|
8
8
|
name: z.ZodString;
|
|
9
9
|
content: z.ZodString;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const countIssuesSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const countIssuesSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
8
8
|
issueTypeId: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
9
9
|
categoryId: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const deleteIssueSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const deleteIssueSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
issueId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
issueKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
};
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const deleteProjectSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const deleteProjectSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
projectKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
};
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const deleteVersionSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const deleteVersionSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
projectKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
id: z.ZodNumber;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const deleteWatchingSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const deleteWatchingSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
watchId: z.ZodNumber;
|
|
8
8
|
};
|
|
9
9
|
export declare const deleteWatchingTool: (backlog: Backlog, { t }: DescriptionHelper) => ToolDefinition<ReturnType<typeof deleteWatchingSchema>, Entity.WatchingList.WatchingListItem>;
|
|
@@ -3,7 +3,7 @@ import type { Entity } from 'backlog-js';
|
|
|
3
3
|
import { Backlog } from 'backlog-js';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const getCategoriesSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const getCategoriesSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
projectKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
};
|
|
@@ -3,7 +3,7 @@ import { Backlog } from 'backlog-js';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { ToolDefinition } from '../types/tool.js';
|
|
5
5
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
6
|
-
declare const getCustomFieldsInputSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const getCustomFieldsInputSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectId: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
projectKey: z.ZodOptional<z.ZodString>;
|
|
9
9
|
};
|
|
@@ -3,7 +3,7 @@ import { Backlog } from 'backlog-js';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
5
5
|
import { ToolDefinition } from '../types/tool.js';
|
|
6
|
-
declare const getDocumentSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const getDocumentSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
documentId: z.ZodString;
|
|
8
8
|
};
|
|
9
9
|
export declare const getDocumentTool: (backlog: Backlog, { t }: DescriptionHelper) => ToolDefinition<ReturnType<typeof getDocumentSchema>, Entity.Document.Document>;
|
|
@@ -3,7 +3,7 @@ import { Backlog } from 'backlog-js';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
5
5
|
import { ToolDefinition } from '../types/tool.js';
|
|
6
|
-
declare const getDocumentTreeSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const getDocumentTreeSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectIdOrKey: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
8
8
|
};
|
|
9
9
|
export declare const getDocumentTreeTool: (backlog: Backlog, { t }: DescriptionHelper) => ToolDefinition<ReturnType<typeof getDocumentTreeSchema>, Entity.Document.DocumentTree>;
|
|
@@ -3,7 +3,7 @@ import { Backlog } from 'backlog-js';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { DescriptionHelper } from '../createDescriptionHelper.js';
|
|
5
5
|
import { ToolDefinition } from '../types/tool.js';
|
|
6
|
-
declare const getDocumentsSchema: (t: DescriptionHelper[
|
|
6
|
+
declare const getDocumentsSchema: (t: DescriptionHelper['t']) => {
|
|
7
7
|
projectIds: z.ZodArray<z.ZodNumber>;
|
|
8
8
|
offset: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
9
9
|
};
|