mcp-server-bitbucket 0.11.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/Dockerfile +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2976 -0
- package/docker-entrypoint.sh +6 -0
- package/package.json +57 -0
- package/smithery.yaml +47 -0
- package/src/client.ts +1102 -0
- package/src/index.ts +149 -0
- package/src/prompts.ts +208 -0
- package/src/resources.ts +160 -0
- package/src/settings.ts +63 -0
- package/src/tools/branches.ts +69 -0
- package/src/tools/commits.ts +186 -0
- package/src/tools/deployments.ts +100 -0
- package/src/tools/index.ts +112 -0
- package/src/tools/permissions.ts +205 -0
- package/src/tools/pipelines.ts +301 -0
- package/src/tools/projects.ts +63 -0
- package/src/tools/pull-requests.ts +321 -0
- package/src/tools/repositories.ts +208 -0
- package/src/tools/restrictions.ts +94 -0
- package/src/tools/source.ts +78 -0
- package/src/tools/tags.ts +88 -0
- package/src/tools/webhooks.ts +121 -0
- package/src/types.ts +369 -0
- package/src/utils.ts +83 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commit tools for Bitbucket MCP Server
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { getClient } from '../client.js';
|
|
7
|
+
import { validateLimit, notFoundResponse, truncateHash } from '../utils.js';
|
|
8
|
+
import { CommitStatusState } from '../types.js';
|
|
9
|
+
|
|
10
|
+
export const definitions: Tool[] = [
|
|
11
|
+
{
|
|
12
|
+
name: 'list_commits',
|
|
13
|
+
description: 'List commits in a repository.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
18
|
+
branch: { type: 'string', description: 'Filter by branch name (optional)' },
|
|
19
|
+
path: { type: 'string', description: 'Filter by file path - only commits that modified this path (optional)' },
|
|
20
|
+
limit: { type: 'number', description: 'Maximum results (default: 20)', default: 20 },
|
|
21
|
+
},
|
|
22
|
+
required: ['repo_slug'],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'get_commit',
|
|
27
|
+
description: 'Get detailed information about a specific commit.',
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
32
|
+
commit: { type: 'string', description: 'Commit hash (full or short)' },
|
|
33
|
+
},
|
|
34
|
+
required: ['repo_slug', 'commit'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'compare_commits',
|
|
39
|
+
description: 'Compare two commits or branches and see files changed.',
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
44
|
+
base: { type: 'string', description: 'Base commit hash or branch name' },
|
|
45
|
+
head: { type: 'string', description: 'Head commit hash or branch name' },
|
|
46
|
+
},
|
|
47
|
+
required: ['repo_slug', 'base', 'head'],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'get_commit_statuses',
|
|
52
|
+
description: 'Get build/CI statuses for a commit.',
|
|
53
|
+
inputSchema: {
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
57
|
+
commit: { type: 'string', description: 'Commit hash' },
|
|
58
|
+
limit: { type: 'number', description: 'Maximum results (default: 20)', default: 20 },
|
|
59
|
+
},
|
|
60
|
+
required: ['repo_slug', 'commit'],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'create_commit_status',
|
|
65
|
+
description: 'Create a build status for a commit. Use this to report CI/CD status from external systems.',
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties: {
|
|
69
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
70
|
+
commit: { type: 'string', description: 'Commit hash' },
|
|
71
|
+
state: { type: 'string', description: 'Status state: SUCCESSFUL, FAILED, INPROGRESS, STOPPED' },
|
|
72
|
+
key: { type: 'string', description: 'Unique identifier for this status' },
|
|
73
|
+
url: { type: 'string', description: 'URL to the build details (optional)' },
|
|
74
|
+
name: { type: 'string', description: 'Display name for the status (optional)' },
|
|
75
|
+
description: { type: 'string', description: 'Status description (optional)' },
|
|
76
|
+
},
|
|
77
|
+
required: ['repo_slug', 'commit', 'state', 'key'],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
export const handlers: Record<string, (args: Record<string, unknown>) => Promise<Record<string, unknown>>> = {
|
|
83
|
+
list_commits: async (args) => {
|
|
84
|
+
const client = getClient();
|
|
85
|
+
const commits = await client.listCommits(args.repo_slug as string, {
|
|
86
|
+
branch: args.branch as string,
|
|
87
|
+
path: args.path as string,
|
|
88
|
+
limit: validateLimit((args.limit as number) || 20),
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
commits: commits.map(c => ({
|
|
92
|
+
hash: truncateHash(c.hash),
|
|
93
|
+
message: c.message,
|
|
94
|
+
author: c.author?.raw,
|
|
95
|
+
date: c.date,
|
|
96
|
+
})),
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
get_commit: async (args) => {
|
|
101
|
+
const client = getClient();
|
|
102
|
+
const result = await client.getCommit(args.repo_slug as string, args.commit as string);
|
|
103
|
+
if (!result) {
|
|
104
|
+
return notFoundResponse('Commit', args.commit as string);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
hash: result.hash,
|
|
108
|
+
message: result.message,
|
|
109
|
+
author: result.author?.raw,
|
|
110
|
+
date: result.date,
|
|
111
|
+
parents: result.parents?.map(p => truncateHash(p.hash)),
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
compare_commits: async (args) => {
|
|
116
|
+
const client = getClient();
|
|
117
|
+
const result = await client.compareCommits(
|
|
118
|
+
args.repo_slug as string,
|
|
119
|
+
args.base as string,
|
|
120
|
+
args.head as string
|
|
121
|
+
);
|
|
122
|
+
if (!result) {
|
|
123
|
+
return { error: `Could not compare ${args.base}..${args.head}` };
|
|
124
|
+
}
|
|
125
|
+
const files = (result.values as Array<{
|
|
126
|
+
new?: { path?: string };
|
|
127
|
+
old?: { path?: string };
|
|
128
|
+
status?: string;
|
|
129
|
+
lines_added?: number;
|
|
130
|
+
lines_removed?: number;
|
|
131
|
+
}>) || [];
|
|
132
|
+
return {
|
|
133
|
+
files: files.slice(0, 50).map(f => ({
|
|
134
|
+
path: f.new?.path || f.old?.path,
|
|
135
|
+
status: f.status,
|
|
136
|
+
'+': f.lines_added || 0,
|
|
137
|
+
'-': f.lines_removed || 0,
|
|
138
|
+
})),
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
get_commit_statuses: async (args) => {
|
|
143
|
+
const client = getClient();
|
|
144
|
+
const statuses = await client.getCommitStatuses(args.repo_slug as string, args.commit as string, {
|
|
145
|
+
limit: validateLimit((args.limit as number) || 20),
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
commit: truncateHash(args.commit as string),
|
|
149
|
+
statuses: statuses.map(s => ({
|
|
150
|
+
key: s.key,
|
|
151
|
+
state: s.state,
|
|
152
|
+
name: s.name,
|
|
153
|
+
description: s.description,
|
|
154
|
+
url: s.url,
|
|
155
|
+
created: s.created_on,
|
|
156
|
+
})),
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
create_commit_status: async (args) => {
|
|
161
|
+
const state = (args.state as string).toUpperCase();
|
|
162
|
+
const validStates = Object.values(CommitStatusState);
|
|
163
|
+
if (!validStates.includes(state as CommitStatusState)) {
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
error: `Invalid state '${args.state}'. Must be one of: ${validStates.join(', ')}`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const client = getClient();
|
|
171
|
+
const result = await client.createCommitStatus(args.repo_slug as string, args.commit as string, {
|
|
172
|
+
state,
|
|
173
|
+
key: args.key as string,
|
|
174
|
+
url: args.url as string,
|
|
175
|
+
name: args.name as string,
|
|
176
|
+
description: args.description as string,
|
|
177
|
+
});
|
|
178
|
+
return {
|
|
179
|
+
key: result.key,
|
|
180
|
+
state: result.state,
|
|
181
|
+
name: result.name,
|
|
182
|
+
url: result.url,
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment tools for Bitbucket MCP Server
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { getClient } from '../client.js';
|
|
7
|
+
import { validateLimit, notFoundResponse } from '../utils.js';
|
|
8
|
+
|
|
9
|
+
export const definitions: Tool[] = [
|
|
10
|
+
{
|
|
11
|
+
name: 'list_environments',
|
|
12
|
+
description: 'List deployment environments for a repository.',
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
17
|
+
limit: { type: 'number', description: 'Maximum results (default: 20)', default: 20 },
|
|
18
|
+
},
|
|
19
|
+
required: ['repo_slug'],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'get_environment',
|
|
24
|
+
description: 'Get details about a specific deployment environment.',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
29
|
+
environment_uuid: { type: 'string', description: 'Environment UUID' },
|
|
30
|
+
},
|
|
31
|
+
required: ['repo_slug', 'environment_uuid'],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'list_deployment_history',
|
|
36
|
+
description: 'Get deployment history for a specific environment.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
41
|
+
environment_uuid: { type: 'string', description: 'Environment UUID' },
|
|
42
|
+
limit: { type: 'number', description: 'Maximum results (default: 20)', default: 20 },
|
|
43
|
+
},
|
|
44
|
+
required: ['repo_slug', 'environment_uuid'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
export const handlers: Record<string, (args: Record<string, unknown>) => Promise<Record<string, unknown>>> = {
|
|
50
|
+
list_environments: async (args) => {
|
|
51
|
+
const client = getClient();
|
|
52
|
+
const environments = await client.listEnvironments(args.repo_slug as string, {
|
|
53
|
+
limit: validateLimit((args.limit as number) || 20),
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
environments: environments.map(e => ({
|
|
57
|
+
uuid: e.uuid,
|
|
58
|
+
name: e.name,
|
|
59
|
+
type: e.environment_type?.name,
|
|
60
|
+
rank: e.rank,
|
|
61
|
+
})),
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
get_environment: async (args) => {
|
|
66
|
+
const client = getClient();
|
|
67
|
+
const result = await client.getEnvironment(args.repo_slug as string, args.environment_uuid as string);
|
|
68
|
+
if (!result) {
|
|
69
|
+
return notFoundResponse('Environment', args.environment_uuid as string);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
uuid: result.uuid,
|
|
73
|
+
name: result.name,
|
|
74
|
+
environment_type: result.environment_type?.name,
|
|
75
|
+
rank: result.rank,
|
|
76
|
+
restrictions: result.restrictions,
|
|
77
|
+
lock: result.lock,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
list_deployment_history: async (args) => {
|
|
82
|
+
const client = getClient();
|
|
83
|
+
const deployments = await client.listDeploymentHistory(
|
|
84
|
+
args.repo_slug as string,
|
|
85
|
+
args.environment_uuid as string,
|
|
86
|
+
{ limit: validateLimit((args.limit as number) || 20) }
|
|
87
|
+
);
|
|
88
|
+
return {
|
|
89
|
+
deployments: deployments.map(d => ({
|
|
90
|
+
uuid: d.uuid,
|
|
91
|
+
state: d.state?.name,
|
|
92
|
+
started: d.state?.started_on,
|
|
93
|
+
completed: d.state?.completed_on,
|
|
94
|
+
commit: d.release?.commit?.hash?.substring(0, 7),
|
|
95
|
+
pipeline_uuid: d.release?.pipeline?.uuid,
|
|
96
|
+
})),
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool definitions and handlers for Bitbucket MCP Server
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { getClient } from '../client.js';
|
|
7
|
+
import { validateLimit, notFoundResponse, truncateHash, sanitizeSearchTerm } from '../utils.js';
|
|
8
|
+
import { PRState, MergeStrategy, CommitStatusState } from '../types.js';
|
|
9
|
+
|
|
10
|
+
// Import tool handlers from separate files
|
|
11
|
+
import * as repositoryTools from './repositories.js';
|
|
12
|
+
import * as pullRequestTools from './pull-requests.js';
|
|
13
|
+
import * as pipelineTools from './pipelines.js';
|
|
14
|
+
import * as branchTools from './branches.js';
|
|
15
|
+
import * as commitTools from './commits.js';
|
|
16
|
+
import * as deploymentTools from './deployments.js';
|
|
17
|
+
import * as webhookTools from './webhooks.js';
|
|
18
|
+
import * as tagTools from './tags.js';
|
|
19
|
+
import * as restrictionTools from './restrictions.js';
|
|
20
|
+
import * as sourceTools from './source.js';
|
|
21
|
+
import * as permissionTools from './permissions.js';
|
|
22
|
+
import * as projectTools from './projects.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* All tool definitions for the MCP server
|
|
26
|
+
*/
|
|
27
|
+
export const toolDefinitions: Tool[] = [
|
|
28
|
+
// Repository tools
|
|
29
|
+
...repositoryTools.definitions,
|
|
30
|
+
// Pull request tools
|
|
31
|
+
...pullRequestTools.definitions,
|
|
32
|
+
// Pipeline tools
|
|
33
|
+
...pipelineTools.definitions,
|
|
34
|
+
// Branch tools
|
|
35
|
+
...branchTools.definitions,
|
|
36
|
+
// Commit tools
|
|
37
|
+
...commitTools.definitions,
|
|
38
|
+
// Deployment tools
|
|
39
|
+
...deploymentTools.definitions,
|
|
40
|
+
// Webhook tools
|
|
41
|
+
...webhookTools.definitions,
|
|
42
|
+
// Tag tools
|
|
43
|
+
...tagTools.definitions,
|
|
44
|
+
// Branch restriction tools
|
|
45
|
+
...restrictionTools.definitions,
|
|
46
|
+
// Source browsing tools
|
|
47
|
+
...sourceTools.definitions,
|
|
48
|
+
// Permission tools
|
|
49
|
+
...permissionTools.definitions,
|
|
50
|
+
// Project tools
|
|
51
|
+
...projectTools.definitions,
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Handle tool calls by routing to the appropriate handler
|
|
56
|
+
*/
|
|
57
|
+
export async function handleToolCall(
|
|
58
|
+
name: string,
|
|
59
|
+
args: Record<string, unknown>
|
|
60
|
+
): Promise<Record<string, unknown>> {
|
|
61
|
+
// Repository tools
|
|
62
|
+
if (name in repositoryTools.handlers) {
|
|
63
|
+
return await repositoryTools.handlers[name as keyof typeof repositoryTools.handlers](args);
|
|
64
|
+
}
|
|
65
|
+
// Pull request tools
|
|
66
|
+
if (name in pullRequestTools.handlers) {
|
|
67
|
+
return await pullRequestTools.handlers[name as keyof typeof pullRequestTools.handlers](args);
|
|
68
|
+
}
|
|
69
|
+
// Pipeline tools
|
|
70
|
+
if (name in pipelineTools.handlers) {
|
|
71
|
+
return await pipelineTools.handlers[name as keyof typeof pipelineTools.handlers](args);
|
|
72
|
+
}
|
|
73
|
+
// Branch tools
|
|
74
|
+
if (name in branchTools.handlers) {
|
|
75
|
+
return await branchTools.handlers[name as keyof typeof branchTools.handlers](args);
|
|
76
|
+
}
|
|
77
|
+
// Commit tools
|
|
78
|
+
if (name in commitTools.handlers) {
|
|
79
|
+
return await commitTools.handlers[name as keyof typeof commitTools.handlers](args);
|
|
80
|
+
}
|
|
81
|
+
// Deployment tools
|
|
82
|
+
if (name in deploymentTools.handlers) {
|
|
83
|
+
return await deploymentTools.handlers[name as keyof typeof deploymentTools.handlers](args);
|
|
84
|
+
}
|
|
85
|
+
// Webhook tools
|
|
86
|
+
if (name in webhookTools.handlers) {
|
|
87
|
+
return await webhookTools.handlers[name as keyof typeof webhookTools.handlers](args);
|
|
88
|
+
}
|
|
89
|
+
// Tag tools
|
|
90
|
+
if (name in tagTools.handlers) {
|
|
91
|
+
return await tagTools.handlers[name as keyof typeof tagTools.handlers](args);
|
|
92
|
+
}
|
|
93
|
+
// Branch restriction tools
|
|
94
|
+
if (name in restrictionTools.handlers) {
|
|
95
|
+
return await restrictionTools.handlers[name as keyof typeof restrictionTools.handlers](args);
|
|
96
|
+
}
|
|
97
|
+
// Source browsing tools
|
|
98
|
+
if (name in sourceTools.handlers) {
|
|
99
|
+
return await sourceTools.handlers[name as keyof typeof sourceTools.handlers](args);
|
|
100
|
+
}
|
|
101
|
+
// Permission tools
|
|
102
|
+
if (name in permissionTools.handlers) {
|
|
103
|
+
return await permissionTools.handlers[name as keyof typeof permissionTools.handlers](args);
|
|
104
|
+
}
|
|
105
|
+
// Project tools
|
|
106
|
+
if (name in projectTools.handlers) {
|
|
107
|
+
return await projectTools.handlers[name as keyof typeof projectTools.handlers](args);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission tools for Bitbucket MCP Server
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { getClient } from '../client.js';
|
|
7
|
+
import { validateLimit, notFoundResponse } from '../utils.js';
|
|
8
|
+
|
|
9
|
+
export const definitions: Tool[] = [
|
|
10
|
+
// User permissions
|
|
11
|
+
{
|
|
12
|
+
name: 'list_user_permissions',
|
|
13
|
+
description: 'List user permissions for a repository.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
18
|
+
limit: { type: 'number', description: 'Maximum results (default: 50)', default: 50 },
|
|
19
|
+
},
|
|
20
|
+
required: ['repo_slug'],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'get_user_permission',
|
|
25
|
+
description: "Get a specific user's permission for a repository.",
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {
|
|
29
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
30
|
+
selected_user: { type: 'string', description: "User's account_id or UUID" },
|
|
31
|
+
},
|
|
32
|
+
required: ['repo_slug', 'selected_user'],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'update_user_permission',
|
|
37
|
+
description: "Update or add a user's permission for a repository.",
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
42
|
+
selected_user: { type: 'string', description: "User's account_id or UUID" },
|
|
43
|
+
permission: { type: 'string', description: 'Permission level: "read", "write", or "admin"' },
|
|
44
|
+
},
|
|
45
|
+
required: ['repo_slug', 'selected_user', 'permission'],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'delete_user_permission',
|
|
50
|
+
description: "Remove a user's explicit permission from a repository.",
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
55
|
+
selected_user: { type: 'string', description: "User's account_id or UUID" },
|
|
56
|
+
},
|
|
57
|
+
required: ['repo_slug', 'selected_user'],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
// Group permissions
|
|
61
|
+
{
|
|
62
|
+
name: 'list_group_permissions',
|
|
63
|
+
description: 'List group permissions for a repository.',
|
|
64
|
+
inputSchema: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
68
|
+
limit: { type: 'number', description: 'Maximum results (default: 50)', default: 50 },
|
|
69
|
+
},
|
|
70
|
+
required: ['repo_slug'],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'get_group_permission',
|
|
75
|
+
description: "Get a specific group's permission for a repository.",
|
|
76
|
+
inputSchema: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
properties: {
|
|
79
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
80
|
+
group_slug: { type: 'string', description: 'Group slug' },
|
|
81
|
+
},
|
|
82
|
+
required: ['repo_slug', 'group_slug'],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'update_group_permission',
|
|
87
|
+
description: "Update or add a group's permission for a repository.",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {
|
|
91
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
92
|
+
group_slug: { type: 'string', description: 'Group slug' },
|
|
93
|
+
permission: { type: 'string', description: 'Permission level: "read", "write", or "admin"' },
|
|
94
|
+
},
|
|
95
|
+
required: ['repo_slug', 'group_slug', 'permission'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'delete_group_permission',
|
|
100
|
+
description: "Remove a group's explicit permission from a repository.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
repo_slug: { type: 'string', description: 'Repository slug' },
|
|
105
|
+
group_slug: { type: 'string', description: 'Group slug' },
|
|
106
|
+
},
|
|
107
|
+
required: ['repo_slug', 'group_slug'],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
export const handlers: Record<string, (args: Record<string, unknown>) => Promise<Record<string, unknown>>> = {
|
|
113
|
+
list_user_permissions: async (args) => {
|
|
114
|
+
const client = getClient();
|
|
115
|
+
const permissions = await client.listUserPermissions(args.repo_slug as string, {
|
|
116
|
+
limit: validateLimit((args.limit as number) || 50),
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
users: permissions.map(p => ({
|
|
120
|
+
user: p.user?.display_name,
|
|
121
|
+
account_id: p.user?.account_id,
|
|
122
|
+
permission: p.permission,
|
|
123
|
+
})),
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
get_user_permission: async (args) => {
|
|
128
|
+
const client = getClient();
|
|
129
|
+
const result = await client.getUserPermission(args.repo_slug as string, args.selected_user as string);
|
|
130
|
+
if (!result) {
|
|
131
|
+
return notFoundResponse('User permission', args.selected_user as string);
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
user: result.user?.display_name,
|
|
135
|
+
account_id: result.user?.account_id,
|
|
136
|
+
permission: result.permission,
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
update_user_permission: async (args) => {
|
|
141
|
+
const client = getClient();
|
|
142
|
+
const result = await client.updateUserPermission(
|
|
143
|
+
args.repo_slug as string,
|
|
144
|
+
args.selected_user as string,
|
|
145
|
+
args.permission as string
|
|
146
|
+
);
|
|
147
|
+
return {
|
|
148
|
+
user: result.user?.display_name,
|
|
149
|
+
permission: result.permission,
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
delete_user_permission: async (args) => {
|
|
154
|
+
const client = getClient();
|
|
155
|
+
await client.deleteUserPermission(args.repo_slug as string, args.selected_user as string);
|
|
156
|
+
return {};
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
list_group_permissions: async (args) => {
|
|
160
|
+
const client = getClient();
|
|
161
|
+
const permissions = await client.listGroupPermissions(args.repo_slug as string, {
|
|
162
|
+
limit: validateLimit((args.limit as number) || 50),
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
groups: permissions.map(p => ({
|
|
166
|
+
group: p.group?.name,
|
|
167
|
+
slug: p.group?.slug,
|
|
168
|
+
permission: p.permission,
|
|
169
|
+
})),
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
get_group_permission: async (args) => {
|
|
174
|
+
const client = getClient();
|
|
175
|
+
const result = await client.getGroupPermission(args.repo_slug as string, args.group_slug as string);
|
|
176
|
+
if (!result) {
|
|
177
|
+
return notFoundResponse('Group permission', args.group_slug as string);
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
group: result.group?.name,
|
|
181
|
+
slug: result.group?.slug,
|
|
182
|
+
permission: result.permission,
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
update_group_permission: async (args) => {
|
|
187
|
+
const client = getClient();
|
|
188
|
+
const result = await client.updateGroupPermission(
|
|
189
|
+
args.repo_slug as string,
|
|
190
|
+
args.group_slug as string,
|
|
191
|
+
args.permission as string
|
|
192
|
+
);
|
|
193
|
+
return {
|
|
194
|
+
group: result.group?.name,
|
|
195
|
+
permission: result.permission,
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
delete_group_permission: async (args) => {
|
|
200
|
+
const client = getClient();
|
|
201
|
+
await client.deleteGroupPermission(args.repo_slug as string, args.group_slug as string);
|
|
202
|
+
return {};
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
|