@freelancercom/phabricator-mcp 1.0.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.md +303 -0
- package/dist/client/conduit.d.ts +11 -0
- package/dist/client/conduit.js +41 -0
- package/dist/client/conduit.test.d.ts +1 -0
- package/dist/client/conduit.test.js +97 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.js +53 -0
- package/dist/config.test.d.ts +1 -0
- package/dist/config.test.js +54 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +21 -0
- package/dist/tools/differential.d.ts +3 -0
- package/dist/tools/differential.js +97 -0
- package/dist/tools/diffusion.d.ts +3 -0
- package/dist/tools/diffusion.js +48 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +22 -0
- package/dist/tools/maniphest.d.ts +3 -0
- package/dist/tools/maniphest.js +129 -0
- package/dist/tools/paste.d.ts +3 -0
- package/dist/tools/paste.js +45 -0
- package/dist/tools/phame.d.ts +3 -0
- package/dist/tools/phame.js +102 -0
- package/dist/tools/phid.d.ts +3 -0
- package/dist/tools/phid.js +17 -0
- package/dist/tools/phriction.d.ts +3 -0
- package/dist/tools/phriction.js +46 -0
- package/dist/tools/project.d.ts +3 -0
- package/dist/tools/project.js +82 -0
- package/dist/tools/transaction.d.ts +3 -0
- package/dist/tools/transaction.js +19 -0
- package/dist/tools/user.d.ts +3 -0
- package/dist/tools/user.js +32 -0
- package/package.json +51 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerDifferentialTools(server, client) {
|
|
3
|
+
// Search revisions
|
|
4
|
+
server.tool('phabricator_revision_search', 'Search Differential revisions (code reviews)', {
|
|
5
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "active", "authored", "waiting"'),
|
|
6
|
+
constraints: z.object({
|
|
7
|
+
ids: z.array(z.number()).optional().describe('Revision IDs'),
|
|
8
|
+
phids: z.array(z.string()).optional().describe('Revision PHIDs'),
|
|
9
|
+
authorPHIDs: z.array(z.string()).optional().describe('Author PHIDs'),
|
|
10
|
+
reviewerPHIDs: z.array(z.string()).optional().describe('Reviewer PHIDs'),
|
|
11
|
+
repositoryPHIDs: z.array(z.string()).optional().describe('Repository PHIDs'),
|
|
12
|
+
statuses: z.array(z.string()).optional().describe('Statuses: needs-review, needs-revision, accepted, published, abandoned, changes-planned'),
|
|
13
|
+
}).optional().describe('Search constraints'),
|
|
14
|
+
attachments: z.object({
|
|
15
|
+
reviewers: z.boolean().optional().describe('Include reviewers'),
|
|
16
|
+
subscribers: z.boolean().optional().describe('Include subscribers'),
|
|
17
|
+
projects: z.boolean().optional().describe('Include projects'),
|
|
18
|
+
}).optional().describe('Data attachments'),
|
|
19
|
+
order: z.string().optional().describe('Result order'),
|
|
20
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
21
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
22
|
+
}, async (params) => {
|
|
23
|
+
const result = await client.call('differential.revision.search', params);
|
|
24
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
25
|
+
});
|
|
26
|
+
// Edit revision
|
|
27
|
+
server.tool('phabricator_revision_edit', 'Edit a Differential revision', {
|
|
28
|
+
objectIdentifier: z.string().describe('Revision PHID or ID (e.g., "D123")'),
|
|
29
|
+
title: z.string().optional().describe('New title'),
|
|
30
|
+
summary: z.string().optional().describe('New summary'),
|
|
31
|
+
testPlan: z.string().optional().describe('New test plan'),
|
|
32
|
+
addReviewerPHIDs: z.array(z.string()).optional().describe('Add reviewers'),
|
|
33
|
+
removeReviewerPHIDs: z.array(z.string()).optional().describe('Remove reviewers'),
|
|
34
|
+
addProjectPHIDs: z.array(z.string()).optional().describe('Add projects'),
|
|
35
|
+
removeProjectPHIDs: z.array(z.string()).optional().describe('Remove projects'),
|
|
36
|
+
comment: z.string().optional().describe('Add a comment'),
|
|
37
|
+
}, async (params) => {
|
|
38
|
+
const transactions = [];
|
|
39
|
+
if (params.title !== undefined) {
|
|
40
|
+
transactions.push({ type: 'title', value: params.title });
|
|
41
|
+
}
|
|
42
|
+
if (params.summary !== undefined) {
|
|
43
|
+
transactions.push({ type: 'summary', value: params.summary });
|
|
44
|
+
}
|
|
45
|
+
if (params.testPlan !== undefined) {
|
|
46
|
+
transactions.push({ type: 'testPlan', value: params.testPlan });
|
|
47
|
+
}
|
|
48
|
+
if (params.addReviewerPHIDs !== undefined) {
|
|
49
|
+
transactions.push({ type: 'reviewers.add', value: params.addReviewerPHIDs });
|
|
50
|
+
}
|
|
51
|
+
if (params.removeReviewerPHIDs !== undefined) {
|
|
52
|
+
transactions.push({ type: 'reviewers.remove', value: params.removeReviewerPHIDs });
|
|
53
|
+
}
|
|
54
|
+
if (params.addProjectPHIDs !== undefined) {
|
|
55
|
+
transactions.push({ type: 'projects.add', value: params.addProjectPHIDs });
|
|
56
|
+
}
|
|
57
|
+
if (params.removeProjectPHIDs !== undefined) {
|
|
58
|
+
transactions.push({ type: 'projects.remove', value: params.removeProjectPHIDs });
|
|
59
|
+
}
|
|
60
|
+
if (params.comment !== undefined) {
|
|
61
|
+
transactions.push({ type: 'comment', value: params.comment });
|
|
62
|
+
}
|
|
63
|
+
if (transactions.length === 0) {
|
|
64
|
+
return { content: [{ type: 'text', text: 'No changes specified' }] };
|
|
65
|
+
}
|
|
66
|
+
const result = await client.call('differential.revision.edit', {
|
|
67
|
+
objectIdentifier: params.objectIdentifier,
|
|
68
|
+
transactions,
|
|
69
|
+
});
|
|
70
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
71
|
+
});
|
|
72
|
+
// Get raw diff content
|
|
73
|
+
server.tool('phabricator_get_raw_diff', 'Get the raw diff/patch content for a Differential diff by diff ID. Use phabricator_diff_search to find the diff ID from a revision PHID first.', {
|
|
74
|
+
diffID: z.number().describe('The diff ID (numeric, e.g., 1392561). Use phabricator_diff_search to find this from a revision.'),
|
|
75
|
+
}, async (params) => {
|
|
76
|
+
const result = await client.call('differential.getrawdiff', {
|
|
77
|
+
diffID: params.diffID,
|
|
78
|
+
});
|
|
79
|
+
return { content: [{ type: 'text', text: result }] };
|
|
80
|
+
});
|
|
81
|
+
// Search diffs
|
|
82
|
+
server.tool('phabricator_diff_search', 'Search Differential diffs', {
|
|
83
|
+
constraints: z.object({
|
|
84
|
+
ids: z.array(z.number()).optional().describe('Diff IDs'),
|
|
85
|
+
phids: z.array(z.string()).optional().describe('Diff PHIDs'),
|
|
86
|
+
revisionPHIDs: z.array(z.string()).optional().describe('Revision PHIDs'),
|
|
87
|
+
}).optional().describe('Search constraints'),
|
|
88
|
+
attachments: z.object({
|
|
89
|
+
commits: z.boolean().optional().describe('Include commit info'),
|
|
90
|
+
}).optional().describe('Data attachments'),
|
|
91
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
92
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
93
|
+
}, async (params) => {
|
|
94
|
+
const result = await client.call('differential.diff.search', params);
|
|
95
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerDiffusionTools(server, client) {
|
|
3
|
+
// Search repositories
|
|
4
|
+
server.tool('phabricator_repository_search', 'Search Diffusion repositories', {
|
|
5
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "active"'),
|
|
6
|
+
constraints: z.object({
|
|
7
|
+
ids: z.array(z.number()).optional().describe('Repository IDs'),
|
|
8
|
+
phids: z.array(z.string()).optional().describe('Repository PHIDs'),
|
|
9
|
+
callsigns: z.array(z.string()).optional().describe('Repository callsigns'),
|
|
10
|
+
shortNames: z.array(z.string()).optional().describe('Repository short names'),
|
|
11
|
+
types: z.array(z.string()).optional().describe('VCS types: git, hg, svn'),
|
|
12
|
+
uris: z.array(z.string()).optional().describe('Repository URIs'),
|
|
13
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
14
|
+
}).optional().describe('Search constraints'),
|
|
15
|
+
attachments: z.object({
|
|
16
|
+
uris: z.boolean().optional().describe('Include repository URIs'),
|
|
17
|
+
metrics: z.boolean().optional().describe('Include metrics'),
|
|
18
|
+
projects: z.boolean().optional().describe('Include projects'),
|
|
19
|
+
}).optional().describe('Data attachments'),
|
|
20
|
+
order: z.string().optional().describe('Result order'),
|
|
21
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
22
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
23
|
+
}, async (params) => {
|
|
24
|
+
const result = await client.call('diffusion.repository.search', params);
|
|
25
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
26
|
+
});
|
|
27
|
+
// Search commits
|
|
28
|
+
server.tool('phabricator_commit_search', 'Search Diffusion commits', {
|
|
29
|
+
constraints: z.object({
|
|
30
|
+
ids: z.array(z.number()).optional().describe('Commit IDs'),
|
|
31
|
+
phids: z.array(z.string()).optional().describe('Commit PHIDs'),
|
|
32
|
+
repositoryPHIDs: z.array(z.string()).optional().describe('Repository PHIDs'),
|
|
33
|
+
identifiers: z.array(z.string()).optional().describe('Commit identifiers (hashes)'),
|
|
34
|
+
authorPHIDs: z.array(z.string()).optional().describe('Author PHIDs'),
|
|
35
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
36
|
+
}).optional().describe('Search constraints'),
|
|
37
|
+
attachments: z.object({
|
|
38
|
+
projects: z.boolean().optional().describe('Include projects'),
|
|
39
|
+
subscribers: z.boolean().optional().describe('Include subscribers'),
|
|
40
|
+
}).optional().describe('Data attachments'),
|
|
41
|
+
order: z.string().optional().describe('Result order'),
|
|
42
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
43
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
44
|
+
}, async (params) => {
|
|
45
|
+
const result = await client.call('diffusion.commit.search', params);
|
|
46
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { registerManiphestTools } from './maniphest.js';
|
|
2
|
+
import { registerDifferentialTools } from './differential.js';
|
|
3
|
+
import { registerDiffusionTools } from './diffusion.js';
|
|
4
|
+
import { registerUserTools } from './user.js';
|
|
5
|
+
import { registerProjectTools } from './project.js';
|
|
6
|
+
import { registerPasteTools } from './paste.js';
|
|
7
|
+
import { registerPhrictionTools } from './phriction.js';
|
|
8
|
+
import { registerPhidTools } from './phid.js';
|
|
9
|
+
import { registerPhameTools } from './phame.js';
|
|
10
|
+
import { registerTransactionTools } from './transaction.js';
|
|
11
|
+
export function registerAllTools(server, client) {
|
|
12
|
+
registerManiphestTools(server, client);
|
|
13
|
+
registerDifferentialTools(server, client);
|
|
14
|
+
registerDiffusionTools(server, client);
|
|
15
|
+
registerUserTools(server, client);
|
|
16
|
+
registerProjectTools(server, client);
|
|
17
|
+
registerPasteTools(server, client);
|
|
18
|
+
registerPhrictionTools(server, client);
|
|
19
|
+
registerPhidTools(server, client);
|
|
20
|
+
registerPhameTools(server, client);
|
|
21
|
+
registerTransactionTools(server, client);
|
|
22
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerManiphestTools(server, client) {
|
|
3
|
+
// Search tasks
|
|
4
|
+
server.tool('phabricator_task_search', 'Search Maniphest tasks with optional filters', {
|
|
5
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "open", "authored", "assigned"'),
|
|
6
|
+
constraints: z.object({
|
|
7
|
+
ids: z.array(z.number()).optional().describe('Task IDs to search for'),
|
|
8
|
+
phids: z.array(z.string()).optional().describe('Task PHIDs to search for'),
|
|
9
|
+
assigned: z.array(z.string()).optional().describe('Assigned user PHIDs'),
|
|
10
|
+
authorPHIDs: z.array(z.string()).optional().describe('Author PHIDs'),
|
|
11
|
+
statuses: z.array(z.string()).optional().describe('Task statuses: open, resolved, wontfix, invalid, spite, duplicate'),
|
|
12
|
+
priorities: z.array(z.number()).optional().describe('Priority levels'),
|
|
13
|
+
subtypes: z.array(z.string()).optional().describe('Task subtypes'),
|
|
14
|
+
columnPHIDs: z.array(z.string()).optional().describe('Workboard column PHIDs'),
|
|
15
|
+
projectPHIDs: z.array(z.string()).optional().describe('Project PHIDs (tasks tagged with these projects)'),
|
|
16
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
17
|
+
}).optional().describe('Search constraints'),
|
|
18
|
+
attachments: z.object({
|
|
19
|
+
columns: z.boolean().optional().describe('Include workboard column info'),
|
|
20
|
+
projects: z.boolean().optional().describe('Include project info'),
|
|
21
|
+
subscribers: z.boolean().optional().describe('Include subscriber info'),
|
|
22
|
+
}).optional().describe('Data attachments to include'),
|
|
23
|
+
order: z.string().optional().describe('Result order: "priority", "updated", "newest", "oldest"'),
|
|
24
|
+
limit: z.number().max(100).optional().describe('Maximum results (max 100)'),
|
|
25
|
+
after: z.string().optional().describe('Cursor for pagination'),
|
|
26
|
+
}, async (params) => {
|
|
27
|
+
const result = await client.call('maniphest.search', params);
|
|
28
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
29
|
+
});
|
|
30
|
+
// Create task
|
|
31
|
+
server.tool('phabricator_task_create', 'Create a new Maniphest task', {
|
|
32
|
+
title: z.string().describe('Task title'),
|
|
33
|
+
description: z.string().optional().describe('Task description (supports Remarkup)'),
|
|
34
|
+
ownerPHID: z.string().optional().describe('Assigned owner PHID'),
|
|
35
|
+
priority: z.string().optional().describe('Priority: unbreak, triage, high, normal, low, wish'),
|
|
36
|
+
projectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to tag'),
|
|
37
|
+
subscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs'),
|
|
38
|
+
status: z.string().optional().describe('Initial status'),
|
|
39
|
+
}, async (params) => {
|
|
40
|
+
const transactions = [
|
|
41
|
+
{ type: 'title', value: params.title },
|
|
42
|
+
];
|
|
43
|
+
if (params.description !== undefined) {
|
|
44
|
+
transactions.push({ type: 'description', value: params.description });
|
|
45
|
+
}
|
|
46
|
+
if (params.ownerPHID !== undefined) {
|
|
47
|
+
transactions.push({ type: 'owner', value: params.ownerPHID });
|
|
48
|
+
}
|
|
49
|
+
if (params.priority !== undefined) {
|
|
50
|
+
transactions.push({ type: 'priority', value: params.priority });
|
|
51
|
+
}
|
|
52
|
+
if (params.projectPHIDs !== undefined) {
|
|
53
|
+
transactions.push({ type: 'projects.set', value: params.projectPHIDs });
|
|
54
|
+
}
|
|
55
|
+
if (params.subscriberPHIDs !== undefined) {
|
|
56
|
+
transactions.push({ type: 'subscribers.set', value: params.subscriberPHIDs });
|
|
57
|
+
}
|
|
58
|
+
if (params.status !== undefined) {
|
|
59
|
+
transactions.push({ type: 'status', value: params.status });
|
|
60
|
+
}
|
|
61
|
+
const result = await client.call('maniphest.edit', { transactions });
|
|
62
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
63
|
+
});
|
|
64
|
+
// Edit task
|
|
65
|
+
server.tool('phabricator_task_edit', 'Edit an existing Maniphest task', {
|
|
66
|
+
objectIdentifier: z.string().describe('Task PHID or ID (e.g., "T123" or PHID)'),
|
|
67
|
+
title: z.string().optional().describe('New title'),
|
|
68
|
+
description: z.string().optional().describe('New description'),
|
|
69
|
+
ownerPHID: z.string().nullable().optional().describe('New owner PHID (null to unassign)'),
|
|
70
|
+
priority: z.string().optional().describe('New priority'),
|
|
71
|
+
status: z.string().optional().describe('New status: open, resolved, wontfix, invalid, spite, duplicate'),
|
|
72
|
+
addProjectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to add'),
|
|
73
|
+
removeProjectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to remove'),
|
|
74
|
+
addSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to add'),
|
|
75
|
+
removeSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to remove'),
|
|
76
|
+
columnPHID: z.string().optional().describe('Move to workboard column'),
|
|
77
|
+
}, async (params) => {
|
|
78
|
+
const transactions = [];
|
|
79
|
+
if (params.title !== undefined) {
|
|
80
|
+
transactions.push({ type: 'title', value: params.title });
|
|
81
|
+
}
|
|
82
|
+
if (params.description !== undefined) {
|
|
83
|
+
transactions.push({ type: 'description', value: params.description });
|
|
84
|
+
}
|
|
85
|
+
if (params.ownerPHID !== undefined) {
|
|
86
|
+
transactions.push({ type: 'owner', value: params.ownerPHID });
|
|
87
|
+
}
|
|
88
|
+
if (params.priority !== undefined) {
|
|
89
|
+
transactions.push({ type: 'priority', value: params.priority });
|
|
90
|
+
}
|
|
91
|
+
if (params.status !== undefined) {
|
|
92
|
+
transactions.push({ type: 'status', value: params.status });
|
|
93
|
+
}
|
|
94
|
+
if (params.addProjectPHIDs !== undefined) {
|
|
95
|
+
transactions.push({ type: 'projects.add', value: params.addProjectPHIDs });
|
|
96
|
+
}
|
|
97
|
+
if (params.removeProjectPHIDs !== undefined) {
|
|
98
|
+
transactions.push({ type: 'projects.remove', value: params.removeProjectPHIDs });
|
|
99
|
+
}
|
|
100
|
+
if (params.addSubscriberPHIDs !== undefined) {
|
|
101
|
+
transactions.push({ type: 'subscribers.add', value: params.addSubscriberPHIDs });
|
|
102
|
+
}
|
|
103
|
+
if (params.removeSubscriberPHIDs !== undefined) {
|
|
104
|
+
transactions.push({ type: 'subscribers.remove', value: params.removeSubscriberPHIDs });
|
|
105
|
+
}
|
|
106
|
+
if (params.columnPHID !== undefined) {
|
|
107
|
+
transactions.push({ type: 'column', value: [params.columnPHID] });
|
|
108
|
+
}
|
|
109
|
+
if (transactions.length === 0) {
|
|
110
|
+
return { content: [{ type: 'text', text: 'No changes specified' }] };
|
|
111
|
+
}
|
|
112
|
+
const result = await client.call('maniphest.edit', {
|
|
113
|
+
objectIdentifier: params.objectIdentifier,
|
|
114
|
+
transactions,
|
|
115
|
+
});
|
|
116
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
117
|
+
});
|
|
118
|
+
// Add comment to task
|
|
119
|
+
server.tool('phabricator_task_add_comment', 'Add a comment to a Maniphest task', {
|
|
120
|
+
objectIdentifier: z.string().describe('Task PHID or ID (e.g., "T123")'),
|
|
121
|
+
comment: z.string().describe('Comment text (supports Remarkup)'),
|
|
122
|
+
}, async (params) => {
|
|
123
|
+
const result = await client.call('maniphest.edit', {
|
|
124
|
+
objectIdentifier: params.objectIdentifier,
|
|
125
|
+
transactions: [{ type: 'comment', value: params.comment }],
|
|
126
|
+
});
|
|
127
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
128
|
+
});
|
|
129
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerPasteTools(server, client) {
|
|
3
|
+
// Search pastes
|
|
4
|
+
server.tool('phabricator_paste_search', 'Search Phabricator pastes', {
|
|
5
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "authored"'),
|
|
6
|
+
constraints: z.object({
|
|
7
|
+
ids: z.array(z.number()).optional().describe('Paste IDs'),
|
|
8
|
+
phids: z.array(z.string()).optional().describe('Paste PHIDs'),
|
|
9
|
+
authorPHIDs: z.array(z.string()).optional().describe('Author PHIDs'),
|
|
10
|
+
languages: z.array(z.string()).optional().describe('Languages'),
|
|
11
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
12
|
+
}).optional().describe('Search constraints'),
|
|
13
|
+
attachments: z.object({
|
|
14
|
+
content: z.boolean().optional().describe('Include paste content'),
|
|
15
|
+
}).optional().describe('Data attachments'),
|
|
16
|
+
order: z.string().optional().describe('Result order'),
|
|
17
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
18
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
19
|
+
}, async (params) => {
|
|
20
|
+
const result = await client.call('paste.search', params);
|
|
21
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
22
|
+
});
|
|
23
|
+
// Create paste
|
|
24
|
+
server.tool('phabricator_paste_create', 'Create a new Phabricator paste', {
|
|
25
|
+
title: z.string().optional().describe('Paste title'),
|
|
26
|
+
content: z.string().describe('Paste content'),
|
|
27
|
+
language: z.string().optional().describe('Syntax highlighting language'),
|
|
28
|
+
status: z.string().optional().describe('Status: active or archived'),
|
|
29
|
+
}, async (params) => {
|
|
30
|
+
const transactions = [
|
|
31
|
+
{ type: 'text', value: params.content },
|
|
32
|
+
];
|
|
33
|
+
if (params.title !== undefined) {
|
|
34
|
+
transactions.push({ type: 'title', value: params.title });
|
|
35
|
+
}
|
|
36
|
+
if (params.language !== undefined) {
|
|
37
|
+
transactions.push({ type: 'language', value: params.language });
|
|
38
|
+
}
|
|
39
|
+
if (params.status !== undefined) {
|
|
40
|
+
transactions.push({ type: 'status', value: params.status });
|
|
41
|
+
}
|
|
42
|
+
const result = await client.call('paste.edit', { transactions });
|
|
43
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerPhameTools(server, client) {
|
|
3
|
+
// Search blogs
|
|
4
|
+
server.tool('phabricator_blog_search', 'Search Phame blogs', {
|
|
5
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "active"'),
|
|
6
|
+
constraints: z.object({
|
|
7
|
+
ids: z.array(z.number()).optional().describe('Blog IDs'),
|
|
8
|
+
phids: z.array(z.string()).optional().describe('Blog PHIDs'),
|
|
9
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
10
|
+
}).optional().describe('Search constraints'),
|
|
11
|
+
order: z.string().optional().describe('Result order'),
|
|
12
|
+
limit: z.number().max(100).optional().describe('Maximum results (max 100)'),
|
|
13
|
+
after: z.string().optional().describe('Cursor for pagination'),
|
|
14
|
+
}, async (params) => {
|
|
15
|
+
const result = await client.call('phame.blog.search', params);
|
|
16
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
17
|
+
});
|
|
18
|
+
// Search blog posts
|
|
19
|
+
server.tool('phabricator_blog_post_search', 'Search Phame blog posts', {
|
|
20
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "live"'),
|
|
21
|
+
constraints: z.object({
|
|
22
|
+
ids: z.array(z.number()).optional().describe('Post IDs'),
|
|
23
|
+
phids: z.array(z.string()).optional().describe('Post PHIDs'),
|
|
24
|
+
blogPHIDs: z.array(z.string()).optional().describe('Filter by blog PHIDs'),
|
|
25
|
+
visibility: z.array(z.string()).optional().describe('Visibility: "published", "draft", "archived"'),
|
|
26
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
27
|
+
}).optional().describe('Search constraints'),
|
|
28
|
+
order: z.string().optional().describe('Result order'),
|
|
29
|
+
limit: z.number().max(100).optional().describe('Maximum results (max 100)'),
|
|
30
|
+
after: z.string().optional().describe('Cursor for pagination'),
|
|
31
|
+
}, async (params) => {
|
|
32
|
+
const result = await client.call('phame.post.search', params);
|
|
33
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
34
|
+
});
|
|
35
|
+
// Create blog post
|
|
36
|
+
server.tool('phabricator_blog_post_create', 'Create a new Phame blog post', {
|
|
37
|
+
title: z.string().describe('Post title'),
|
|
38
|
+
body: z.string().describe('Post body content (supports Remarkup)'),
|
|
39
|
+
blogPHID: z.string().describe('PHID of the blog to post to'),
|
|
40
|
+
subtitle: z.string().optional().describe('Post subtitle'),
|
|
41
|
+
visibility: z.string().optional().describe('Visibility: "published", "draft", "archived" (default: draft)'),
|
|
42
|
+
}, async (params) => {
|
|
43
|
+
const transactions = [
|
|
44
|
+
{ type: 'title', value: params.title },
|
|
45
|
+
{ type: 'body', value: params.body },
|
|
46
|
+
{ type: 'blog', value: params.blogPHID },
|
|
47
|
+
];
|
|
48
|
+
if (params.subtitle !== undefined) {
|
|
49
|
+
transactions.push({ type: 'subtitle', value: params.subtitle });
|
|
50
|
+
}
|
|
51
|
+
if (params.visibility !== undefined) {
|
|
52
|
+
transactions.push({ type: 'visibility', value: params.visibility });
|
|
53
|
+
}
|
|
54
|
+
const result = await client.call('phame.post.edit', { transactions });
|
|
55
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
56
|
+
});
|
|
57
|
+
// Edit blog post
|
|
58
|
+
server.tool('phabricator_blog_post_edit', 'Edit an existing Phame blog post', {
|
|
59
|
+
objectIdentifier: z.string().describe('Post PHID or ID'),
|
|
60
|
+
title: z.string().optional().describe('New post title'),
|
|
61
|
+
subtitle: z.string().optional().describe('New post subtitle'),
|
|
62
|
+
body: z.string().optional().describe('New post body content (supports Remarkup)'),
|
|
63
|
+
visibility: z.string().optional().describe('Visibility: "published", "draft", "archived"'),
|
|
64
|
+
blogPHID: z.string().optional().describe('Move post to a different blog (PHID)'),
|
|
65
|
+
}, async (params) => {
|
|
66
|
+
const transactions = [];
|
|
67
|
+
if (params.title !== undefined) {
|
|
68
|
+
transactions.push({ type: 'title', value: params.title });
|
|
69
|
+
}
|
|
70
|
+
if (params.subtitle !== undefined) {
|
|
71
|
+
transactions.push({ type: 'subtitle', value: params.subtitle });
|
|
72
|
+
}
|
|
73
|
+
if (params.body !== undefined) {
|
|
74
|
+
transactions.push({ type: 'body', value: params.body });
|
|
75
|
+
}
|
|
76
|
+
if (params.visibility !== undefined) {
|
|
77
|
+
transactions.push({ type: 'visibility', value: params.visibility });
|
|
78
|
+
}
|
|
79
|
+
if (params.blogPHID !== undefined) {
|
|
80
|
+
transactions.push({ type: 'blog', value: params.blogPHID });
|
|
81
|
+
}
|
|
82
|
+
if (transactions.length === 0) {
|
|
83
|
+
return { content: [{ type: 'text', text: 'No changes specified' }] };
|
|
84
|
+
}
|
|
85
|
+
const result = await client.call('phame.post.edit', {
|
|
86
|
+
objectIdentifier: params.objectIdentifier,
|
|
87
|
+
transactions,
|
|
88
|
+
});
|
|
89
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
90
|
+
});
|
|
91
|
+
// Add comment to blog post
|
|
92
|
+
server.tool('phabricator_blog_post_add_comment', 'Add a comment to a Phame blog post', {
|
|
93
|
+
objectIdentifier: z.string().describe('Post PHID or ID'),
|
|
94
|
+
comment: z.string().describe('Comment text (supports Remarkup)'),
|
|
95
|
+
}, async (params) => {
|
|
96
|
+
const result = await client.call('phame.post.edit', {
|
|
97
|
+
objectIdentifier: params.objectIdentifier,
|
|
98
|
+
transactions: [{ type: 'comment', value: params.comment }],
|
|
99
|
+
});
|
|
100
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
101
|
+
});
|
|
102
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerPhidTools(server, client) {
|
|
3
|
+
// Lookup PHIDs by name
|
|
4
|
+
server.tool('phabricator_phid_lookup', 'Look up PHIDs by human-readable names (e.g., "T123", "D456", "@username")', {
|
|
5
|
+
names: z.array(z.string()).describe('Names to look up (e.g., ["T123", "D456", "@john"])'),
|
|
6
|
+
}, async (params) => {
|
|
7
|
+
const result = await client.call('phid.lookup', { names: params.names });
|
|
8
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
9
|
+
});
|
|
10
|
+
// Query PHID details
|
|
11
|
+
server.tool('phabricator_phid_query', 'Get detailed information about PHIDs', {
|
|
12
|
+
phids: z.array(z.string()).describe('PHIDs to query'),
|
|
13
|
+
}, async (params) => {
|
|
14
|
+
const result = await client.call('phid.query', { phids: params.phids });
|
|
15
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerPhrictionTools(server, client) {
|
|
3
|
+
// Search wiki documents
|
|
4
|
+
server.tool('phabricator_document_search', 'Search Phriction wiki documents', {
|
|
5
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "active"'),
|
|
6
|
+
constraints: z.object({
|
|
7
|
+
ids: z.array(z.number()).optional().describe('Document IDs'),
|
|
8
|
+
phids: z.array(z.string()).optional().describe('Document PHIDs'),
|
|
9
|
+
paths: z.array(z.string()).optional().describe('Document paths'),
|
|
10
|
+
ancestorPaths: z.array(z.string()).optional().describe('Ancestor paths to search under'),
|
|
11
|
+
statuses: z.array(z.string()).optional().describe('Document statuses'),
|
|
12
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
13
|
+
}).optional().describe('Search constraints'),
|
|
14
|
+
attachments: z.object({
|
|
15
|
+
content: z.boolean().optional().describe('Include document content'),
|
|
16
|
+
}).optional().describe('Data attachments'),
|
|
17
|
+
order: z.string().optional().describe('Result order'),
|
|
18
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
19
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
20
|
+
}, async (params) => {
|
|
21
|
+
const result = await client.call('phriction.document.search', params);
|
|
22
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
23
|
+
});
|
|
24
|
+
// Edit wiki document
|
|
25
|
+
server.tool('phabricator_document_edit', 'Edit a Phriction wiki document', {
|
|
26
|
+
slug: z.string().describe('Document path/slug (e.g., "projects/myproject/")'),
|
|
27
|
+
title: z.string().optional().describe('Document title'),
|
|
28
|
+
content: z.string().optional().describe('Document content (Remarkup)'),
|
|
29
|
+
}, async (params) => {
|
|
30
|
+
const transactions = [];
|
|
31
|
+
if (params.title !== undefined) {
|
|
32
|
+
transactions.push({ type: 'title', value: params.title });
|
|
33
|
+
}
|
|
34
|
+
if (params.content !== undefined) {
|
|
35
|
+
transactions.push({ type: 'content', value: params.content });
|
|
36
|
+
}
|
|
37
|
+
if (transactions.length === 0) {
|
|
38
|
+
return { content: [{ type: 'text', text: 'No changes specified' }] };
|
|
39
|
+
}
|
|
40
|
+
const result = await client.call('phriction.document.edit', {
|
|
41
|
+
objectIdentifier: params.slug,
|
|
42
|
+
transactions,
|
|
43
|
+
});
|
|
44
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerProjectTools(server, client) {
|
|
3
|
+
// Search projects
|
|
4
|
+
server.tool('phabricator_project_search', 'Search Phabricator projects', {
|
|
5
|
+
queryKey: z.string().optional().describe('Built-in query: "all", "active", "joined"'),
|
|
6
|
+
constraints: z.object({
|
|
7
|
+
ids: z.array(z.number()).optional().describe('Project IDs'),
|
|
8
|
+
phids: z.array(z.string()).optional().describe('Project PHIDs'),
|
|
9
|
+
slugs: z.array(z.string()).optional().describe('Project slugs'),
|
|
10
|
+
name: z.string().optional().describe('Exact name match'),
|
|
11
|
+
members: z.array(z.string()).optional().describe('Member user PHIDs'),
|
|
12
|
+
watchers: z.array(z.string()).optional().describe('Watcher user PHIDs'),
|
|
13
|
+
ancestors: z.array(z.string()).optional().describe('Ancestor project PHIDs'),
|
|
14
|
+
isMilestone: z.boolean().optional().describe('Filter milestones'),
|
|
15
|
+
isRoot: z.boolean().optional().describe('Filter root projects'),
|
|
16
|
+
query: z.string().optional().describe('Full-text search query'),
|
|
17
|
+
}).optional().describe('Search constraints'),
|
|
18
|
+
attachments: z.object({
|
|
19
|
+
members: z.boolean().optional().describe('Include members'),
|
|
20
|
+
watchers: z.boolean().optional().describe('Include watchers'),
|
|
21
|
+
ancestors: z.boolean().optional().describe('Include ancestors'),
|
|
22
|
+
}).optional().describe('Data attachments'),
|
|
23
|
+
order: z.string().optional().describe('Result order'),
|
|
24
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
25
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
26
|
+
}, async (params) => {
|
|
27
|
+
const result = await client.call('project.search', params);
|
|
28
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
29
|
+
});
|
|
30
|
+
// Edit project
|
|
31
|
+
server.tool('phabricator_project_edit', 'Edit a Phabricator project', {
|
|
32
|
+
objectIdentifier: z.string().describe('Project PHID or ID'),
|
|
33
|
+
name: z.string().optional().describe('New name'),
|
|
34
|
+
description: z.string().optional().describe('New description'),
|
|
35
|
+
icon: z.string().optional().describe('New icon'),
|
|
36
|
+
color: z.string().optional().describe('New color'),
|
|
37
|
+
addMemberPHIDs: z.array(z.string()).optional().describe('Add members'),
|
|
38
|
+
removeMemberPHIDs: z.array(z.string()).optional().describe('Remove members'),
|
|
39
|
+
}, async (params) => {
|
|
40
|
+
const transactions = [];
|
|
41
|
+
if (params.name !== undefined) {
|
|
42
|
+
transactions.push({ type: 'name', value: params.name });
|
|
43
|
+
}
|
|
44
|
+
if (params.description !== undefined) {
|
|
45
|
+
transactions.push({ type: 'description', value: params.description });
|
|
46
|
+
}
|
|
47
|
+
if (params.icon !== undefined) {
|
|
48
|
+
transactions.push({ type: 'icon', value: params.icon });
|
|
49
|
+
}
|
|
50
|
+
if (params.color !== undefined) {
|
|
51
|
+
transactions.push({ type: 'color', value: params.color });
|
|
52
|
+
}
|
|
53
|
+
if (params.addMemberPHIDs !== undefined) {
|
|
54
|
+
transactions.push({ type: 'members.add', value: params.addMemberPHIDs });
|
|
55
|
+
}
|
|
56
|
+
if (params.removeMemberPHIDs !== undefined) {
|
|
57
|
+
transactions.push({ type: 'members.remove', value: params.removeMemberPHIDs });
|
|
58
|
+
}
|
|
59
|
+
if (transactions.length === 0) {
|
|
60
|
+
return { content: [{ type: 'text', text: 'No changes specified' }] };
|
|
61
|
+
}
|
|
62
|
+
const result = await client.call('project.edit', {
|
|
63
|
+
objectIdentifier: params.objectIdentifier,
|
|
64
|
+
transactions,
|
|
65
|
+
});
|
|
66
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
67
|
+
});
|
|
68
|
+
// Search workboard columns
|
|
69
|
+
server.tool('phabricator_column_search', 'Search project workboard columns', {
|
|
70
|
+
constraints: z.object({
|
|
71
|
+
ids: z.array(z.number()).optional().describe('Column IDs'),
|
|
72
|
+
phids: z.array(z.string()).optional().describe('Column PHIDs'),
|
|
73
|
+
projects: z.array(z.string()).optional().describe('Project PHIDs'),
|
|
74
|
+
}).optional().describe('Search constraints'),
|
|
75
|
+
order: z.string().optional().describe('Result order'),
|
|
76
|
+
limit: z.number().max(100).optional().describe('Maximum results'),
|
|
77
|
+
after: z.string().optional().describe('Pagination cursor'),
|
|
78
|
+
}, async (params) => {
|
|
79
|
+
const result = await client.call('project.column.search', params);
|
|
80
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
81
|
+
});
|
|
82
|
+
}
|