@freelancercom/phabricator-mcp 2.0.12 → 2.0.14

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.
@@ -20,12 +20,14 @@ export function registerConpherenceTools(server, client) {
20
20
  });
21
21
  // Read messages in a thread
22
22
  server.tool('phabricator_conpherence_read', 'Read messages from a Conpherence chat room/thread (returned in reverse chronological order). Uses conpherence.querytransaction (the only Conduit method that returns message content).', {
23
- roomID: z.coerce.number().describe('Numeric room ID (use phabricator_conpherence_search to find it)'),
23
+ roomID: z.coerce.number().optional().describe('Numeric room ID (provide this or roomPHID)'),
24
+ roomPHID: z.string().optional().describe('Room PHID (provide this or roomID)'),
24
25
  limit: z.coerce.number().max(100).optional().describe('Maximum messages to return'),
25
26
  offset: z.coerce.number().optional().describe('Result offset for pagination'),
26
27
  }, async (params) => {
27
28
  const result = await client.call('conpherence.querytransaction', {
28
29
  roomID: params.roomID,
30
+ roomPHID: params.roomPHID,
29
31
  limit: params.limit,
30
32
  offset: params.offset,
31
33
  });
@@ -46,10 +46,17 @@ export function registerDifferentialTools(server, client) {
46
46
  addProjectPHIDs: z.array(z.string()).optional().describe('Add projects'),
47
47
  removeProjectPHIDs: z.array(z.string()).optional().describe('Remove projects'),
48
48
  comment: z.string().optional().describe('Add a comment'),
49
- action: z.enum(['accept', 'reject', 'abandon', 'reclaim', 'reopen', 'request-review', 'resign', 'commandeer', 'plan-changes', 'close', 'draft']).optional().describe('Revision action to take'),
49
+ action: z.enum(['accept', 'reject', 'abandon', 'reclaim', 'reopen', 'request-review', 'resign', 'commandeer', 'plan-changes', 'close']).optional().describe('Revision action to take. Each action is sent as its own transaction type with value true.'),
50
+ draft: z.boolean().optional().describe('Hold revision as draft (true) or release from draft (false)'),
50
51
  addSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to add'),
51
52
  removeSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to remove'),
52
53
  repositoryPHID: z.string().optional().describe('Repository PHID to associate with the revision'),
54
+ addTaskPHIDs: z.array(z.string()).optional().describe('Maniphest task PHIDs to associate'),
55
+ removeTaskPHIDs: z.array(z.string()).optional().describe('Maniphest task PHIDs to remove'),
56
+ addParentPHIDs: z.array(z.string()).optional().describe('Parent revision PHIDs to add (dependencies)'),
57
+ removeParentPHIDs: z.array(z.string()).optional().describe('Parent revision PHIDs to remove'),
58
+ addChildPHIDs: z.array(z.string()).optional().describe('Child revision PHIDs to add (dependents)'),
59
+ removeChildPHIDs: z.array(z.string()).optional().describe('Child revision PHIDs to remove'),
53
60
  }, async (params) => {
54
61
  const transactions = [];
55
62
  if (params.title !== undefined) {
@@ -80,7 +87,10 @@ export function registerDifferentialTools(server, client) {
80
87
  transactions.push({ type: 'comment', value: params.comment });
81
88
  }
82
89
  if (params.action !== undefined) {
83
- transactions.push({ type: 'action', value: params.action });
90
+ transactions.push({ type: params.action, value: true });
91
+ }
92
+ if (params.draft !== undefined) {
93
+ transactions.push({ type: 'draft', value: params.draft });
84
94
  }
85
95
  if (params.addSubscriberPHIDs !== undefined) {
86
96
  transactions.push({ type: 'subscribers.add', value: params.addSubscriberPHIDs });
@@ -89,7 +99,25 @@ export function registerDifferentialTools(server, client) {
89
99
  transactions.push({ type: 'subscribers.remove', value: params.removeSubscriberPHIDs });
90
100
  }
91
101
  if (params.repositoryPHID !== undefined) {
92
- transactions.push({ type: 'repository', value: params.repositoryPHID });
102
+ transactions.push({ type: 'repositoryPHID', value: params.repositoryPHID });
103
+ }
104
+ if (params.addTaskPHIDs !== undefined) {
105
+ transactions.push({ type: 'tasks.add', value: params.addTaskPHIDs });
106
+ }
107
+ if (params.removeTaskPHIDs !== undefined) {
108
+ transactions.push({ type: 'tasks.remove', value: params.removeTaskPHIDs });
109
+ }
110
+ if (params.addParentPHIDs !== undefined) {
111
+ transactions.push({ type: 'parents.add', value: params.addParentPHIDs });
112
+ }
113
+ if (params.removeParentPHIDs !== undefined) {
114
+ transactions.push({ type: 'parents.remove', value: params.removeParentPHIDs });
115
+ }
116
+ if (params.addChildPHIDs !== undefined) {
117
+ transactions.push({ type: 'children.add', value: params.addChildPHIDs });
118
+ }
119
+ if (params.removeChildPHIDs !== undefined) {
120
+ transactions.push({ type: 'children.remove', value: params.removeChildPHIDs });
93
121
  }
94
122
  if (transactions.length === 0) {
95
123
  return { content: [{ type: 'text', text: 'No changes specified' }] };
@@ -11,6 +11,8 @@ export function registerDiffusionTools(server, client) {
11
11
  shortNames: z.array(z.string()).optional().describe('Repository short names'),
12
12
  types: z.array(z.string()).optional().describe('VCS types: git, hg, svn'),
13
13
  uris: z.array(z.string()).optional().describe('Repository URIs'),
14
+ status: z.string().optional().describe('Repository status: "open" (active) or "closed" (inactive)'),
15
+ hosted: z.string().optional().describe('Hosting: "phabricator" (hosted) or "remote"'),
14
16
  projects: z.array(z.string()).optional().describe('Project PHIDs'),
15
17
  spaces: z.array(z.string()).optional().describe('Space PHIDs (for multi-space installations)'),
16
18
  query: z.string().optional().describe('Full-text search query'),
@@ -30,7 +32,7 @@ export function registerDiffusionTools(server, client) {
30
32
  });
31
33
  // Search commits
32
34
  server.tool('phabricator_commit_search', 'Search Diffusion commits', {
33
- queryKey: z.string().optional().describe('Built-in query: "all", "authored"'),
35
+ queryKey: z.string().optional().describe('Built-in query: "all", "active", "authored", "audited"'),
34
36
  constraints: jsonCoerce(z.object({
35
37
  ids: z.array(z.coerce.number()).optional().describe('Commit IDs'),
36
38
  phids: z.array(z.string()).optional().describe('Commit PHIDs'),
@@ -178,8 +180,6 @@ export function registerDiffusionTools(server, client) {
178
180
  status: z.enum(['active', 'inactive']).optional().describe('Repository status'),
179
181
  addProjectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to add'),
180
182
  removeProjectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to remove'),
181
- addSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to add'),
182
- removeSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to remove'),
183
183
  space: z.string().optional().describe('Space PHID (for multi-space installations)'),
184
184
  }, async (params) => {
185
185
  const transactions = [];
@@ -210,12 +210,6 @@ export function registerDiffusionTools(server, client) {
210
210
  if (params.removeProjectPHIDs !== undefined) {
211
211
  transactions.push({ type: 'projects.remove', value: params.removeProjectPHIDs });
212
212
  }
213
- if (params.addSubscriberPHIDs !== undefined) {
214
- transactions.push({ type: 'subscribers.add', value: params.addSubscriberPHIDs });
215
- }
216
- if (params.removeSubscriberPHIDs !== undefined) {
217
- transactions.push({ type: 'subscribers.remove', value: params.removeSubscriberPHIDs });
218
- }
219
213
  if (params.space !== undefined) {
220
214
  transactions.push({ type: 'space', value: params.space });
221
215
  }
@@ -3,15 +3,17 @@ import { jsonCoerce } from './coerce.js';
3
3
  export function registerFileTools(server, client) {
4
4
  // Upload a file
5
5
  server.tool('phabricator_file_upload', 'Upload a file to Phabricator. Returns a file PHID that can be used with phabricator_file_info to get the file ID for embedding in Remarkup via {F<id>}.', {
6
- name: z.string().describe('Filename with extension (e.g. "screenshot.png")'),
6
+ name: z.string().optional().describe('Filename with extension (e.g. "screenshot.png")'),
7
7
  data_base64: z.string().describe('Base64-encoded file content'),
8
8
  viewPolicy: z.string().optional().describe('File visibility policy (e.g., "public", "users", or a custom policy PHID)'),
9
9
  canCDN: z.boolean().optional().describe('Whether the file can be served over CDN (for public assets)'),
10
10
  }, async (params) => {
11
11
  const apiParams = {
12
- name: params.name,
13
12
  data_base64: params.data_base64,
14
13
  };
14
+ if (params.name !== undefined) {
15
+ apiParams.name = params.name;
16
+ }
15
17
  if (params.viewPolicy !== undefined) {
16
18
  apiParams.viewPolicy = params.viewPolicy;
17
19
  }
@@ -22,7 +22,7 @@ export function registerHarbormasterTools(server, client) {
22
22
  });
23
23
  // Search builds
24
24
  server.tool('phabricator_build_search', 'Search Harbormaster builds (CI/build results)', {
25
- queryKey: z.string().optional().describe('Built-in query: "all"'),
25
+ queryKey: z.string().optional().describe('Built-in query: "all", "initiated", "waiting", "active", "completed"'),
26
26
  constraints: jsonCoerce(z.object({
27
27
  ids: z.array(z.coerce.number()).optional().describe('Build IDs'),
28
28
  phids: z.array(z.string()).optional().describe('Build PHIDs'),
@@ -31,6 +31,9 @@ export function registerHarbormasterTools(server, client) {
31
31
  statuses: z.array(z.string()).optional().describe('Build statuses: building, passed, failed, aborted, error, paused'),
32
32
  initiators: z.array(z.string()).optional().describe('PHIDs of users/objects that initiated the build'),
33
33
  })).optional().describe('Search constraints'),
34
+ attachments: jsonCoerce(z.object({
35
+ querybuilds: z.boolean().optional().describe('Include build query data'),
36
+ })).optional().describe('Data attachments'),
34
37
  order: z.string().optional().describe('Result order'),
35
38
  limit: z.coerce.number().max(100).optional().describe('Maximum results (max 100)'),
36
39
  after: z.string().optional().describe('Cursor for next-page pagination'),
@@ -90,13 +93,14 @@ export function registerHarbormasterTools(server, client) {
90
93
  duration: z.coerce.number().optional().describe('Duration in seconds'),
91
94
  path: z.string().optional().describe('File path related to the test'),
92
95
  coverage: z.record(z.string(), z.string()).optional().describe('Coverage data as {path: "NNCUUUC..."} where N=not executable, C=covered, U=uncovered'),
96
+ format: z.string().optional().describe('Format for details field: "text" (default) or "remarkup"'),
93
97
  details: z.string().optional().describe('Additional details or failure message'),
94
98
  }))).optional().describe('Unit test results to report'),
95
99
  lint: jsonCoerce(z.array(z.object({
96
100
  name: z.string().describe('Lint message name'),
97
101
  code: z.string().describe('Lint rule code'),
98
102
  severity: z.string().describe('Severity: "advice", "autofix", "warning", "error", "disabled"'),
99
- path: z.string().optional().describe('File path'),
103
+ path: z.string().describe('File path'),
100
104
  line: z.coerce.number().optional().describe('Line number'),
101
105
  char: z.coerce.number().optional().describe('Character offset'),
102
106
  description: z.string().optional().describe('Lint message description'),
@@ -3,7 +3,7 @@ import { jsonCoerce } from './coerce.js';
3
3
  export function registerManiphestTools(server, client) {
4
4
  // Search tasks
5
5
  server.tool('phabricator_task_search', 'Search Maniphest tasks with optional filters', {
6
- queryKey: z.string().optional().describe('Built-in query: "all", "open", "authored", "assigned"'),
6
+ queryKey: z.string().optional().describe('Built-in query: "all", "open", "authored", "assigned", "subscribed"'),
7
7
  constraints: jsonCoerce(z.object({
8
8
  ids: z.array(z.coerce.number()).optional().describe('Task IDs to search for'),
9
9
  phids: z.array(z.string()).optional().describe('Task PHIDs to search for'),
@@ -23,6 +23,7 @@ export function registerManiphestTools(server, client) {
23
23
  subtaskIDs: z.array(z.coerce.number()).optional().describe('Subtask IDs'),
24
24
  hasParents: z.boolean().optional().describe('true: only tasks with open parent tasks. false: only tasks without. Omit to show all.'),
25
25
  hasSubtasks: z.boolean().optional().describe('true: only tasks with open subtasks. false: only tasks without. Omit to show all.'),
26
+ subscribers: z.array(z.string()).optional().describe('Subscriber user/project PHIDs'),
26
27
  spaces: z.array(z.string()).optional().describe('Filter by Space PHIDs (for multi-space installations)'),
27
28
  closedStart: z.coerce.number().optional().describe('Closed after (epoch timestamp)'),
28
29
  closedEnd: z.coerce.number().optional().describe('Closed before (epoch timestamp)'),
@@ -33,7 +34,7 @@ export function registerManiphestTools(server, client) {
33
34
  projects: z.boolean().optional().describe('Include project info'),
34
35
  subscribers: z.boolean().optional().describe('Include subscriber info'),
35
36
  })).optional().describe('Data attachments to include'),
36
- order: z.string().optional().describe('Result order: "priority", "updated", "newest", "oldest", "title", "relevance"'),
37
+ order: z.string().optional().describe('Result order: "priority", "updated", "outdated", "newest", "oldest", "closed", "title", "relevance"'),
37
38
  limit: z.coerce.number().max(100).optional().describe('Maximum results (max 100)'),
38
39
  after: z.string().optional().describe('Cursor for next-page pagination'),
39
40
  before: z.string().optional().describe('Cursor for previous-page pagination'),
@@ -53,6 +54,8 @@ export function registerManiphestTools(server, client) {
53
54
  subtype: z.string().optional().describe('Task subtype (e.g. "default", "incident")'),
54
55
  parentPHIDs: z.array(z.string()).optional().describe('Parent task PHIDs'),
55
56
  subtaskPHIDs: z.array(z.string()).optional().describe('Subtask PHIDs'),
57
+ commitPHIDs: z.array(z.string()).optional().describe('Commit PHIDs to associate'),
58
+ points: z.coerce.number().nullable().optional().describe('Story points value (if points are enabled on this instance)'),
56
59
  space: z.string().optional().describe('Space PHID to place the task in (for multi-space installations)'),
57
60
  comment: z.string().optional().describe('Initial comment on the task (supports Remarkup)'),
58
61
  customFields: jsonCoerce(z.record(z.string(), z.unknown())).optional().describe('Custom field transactions. Keys are transaction types (e.g. "custom.my-field"), values are the field values. Check your Phabricator Conduit console (conduit/method/maniphest.edit/) for available fields.'),
@@ -87,6 +90,12 @@ export function registerManiphestTools(server, client) {
87
90
  if (params.subtaskPHIDs !== undefined) {
88
91
  transactions.push({ type: 'subtasks.set', value: params.subtaskPHIDs });
89
92
  }
93
+ if (params.commitPHIDs !== undefined) {
94
+ transactions.push({ type: 'commits.set', value: params.commitPHIDs });
95
+ }
96
+ if (params.points !== undefined) {
97
+ transactions.push({ type: 'points', value: params.points });
98
+ }
90
99
  if (params.space !== undefined) {
91
100
  transactions.push({ type: 'space', value: params.space });
92
101
  }
@@ -118,6 +127,9 @@ export function registerManiphestTools(server, client) {
118
127
  removeParentPHIDs: z.array(z.string()).optional().describe('Parent task PHIDs to remove'),
119
128
  addSubtaskPHIDs: z.array(z.string()).optional().describe('Subtask PHIDs to add'),
120
129
  removeSubtaskPHIDs: z.array(z.string()).optional().describe('Subtask PHIDs to remove'),
130
+ addCommitPHIDs: z.array(z.string()).optional().describe('Commit PHIDs to associate'),
131
+ removeCommitPHIDs: z.array(z.string()).optional().describe('Commit PHIDs to disassociate'),
132
+ points: z.coerce.number().nullable().optional().describe('Story points value (null to clear)'),
121
133
  columnPHID: z.string().optional().describe('Move to workboard column'),
122
134
  space: z.string().optional().describe('Space PHID to move the task to (for multi-space installations)'),
123
135
  comment: z.string().optional().describe('Add a comment alongside the edit (supports Remarkup)'),
@@ -166,6 +178,15 @@ export function registerManiphestTools(server, client) {
166
178
  if (params.removeSubtaskPHIDs !== undefined) {
167
179
  transactions.push({ type: 'subtasks.remove', value: params.removeSubtaskPHIDs });
168
180
  }
181
+ if (params.addCommitPHIDs !== undefined) {
182
+ transactions.push({ type: 'commits.add', value: params.addCommitPHIDs });
183
+ }
184
+ if (params.removeCommitPHIDs !== undefined) {
185
+ transactions.push({ type: 'commits.remove', value: params.removeCommitPHIDs });
186
+ }
187
+ if (params.points !== undefined) {
188
+ transactions.push({ type: 'points', value: params.points });
189
+ }
169
190
  if (params.columnPHID !== undefined) {
170
191
  transactions.push({ type: 'column', value: [{ columnPHID: params.columnPHID }] });
171
192
  }
@@ -3,7 +3,7 @@ import { jsonCoerce } from './coerce.js';
3
3
  export function registerOwnersTools(server, client) {
4
4
  // Search code ownership packages
5
5
  server.tool('phabricator_owners_search', 'Search Owners packages (code ownership). Find who owns a code path or list ownership packages.', {
6
- queryKey: z.string().optional().describe('Built-in query: "all", "active"'),
6
+ queryKey: z.string().optional().describe('Built-in query: "all", "active", "authority"'),
7
7
  constraints: jsonCoerce(z.object({
8
8
  ids: z.array(z.coerce.number()).optional().describe('Package IDs'),
9
9
  phids: z.array(z.string()).optional().describe('Package PHIDs'),
@@ -3,7 +3,7 @@ import { jsonCoerce } from './coerce.js';
3
3
  export function registerPasteTools(server, client) {
4
4
  // Search pastes
5
5
  server.tool('phabricator_paste_search', 'Search Phabricator pastes', {
6
- queryKey: z.string().optional().describe('Built-in query: "all", "authored"'),
6
+ queryKey: z.string().optional().describe('Built-in query: "all", "active", "authored"'),
7
7
  constraints: jsonCoerce(z.object({
8
8
  ids: z.array(z.coerce.number()).optional().describe('Paste IDs'),
9
9
  phids: z.array(z.string()).optional().describe('Paste PHIDs'),
@@ -37,6 +37,7 @@ export function registerPasteTools(server, client) {
37
37
  language: z.string().optional().describe('Syntax highlighting language'),
38
38
  status: z.string().optional().describe('Status: active or archived'),
39
39
  addSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to add'),
40
+ addProjectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to tag'),
40
41
  }, async (params) => {
41
42
  const transactions = [
42
43
  { type: 'text', value: params.content },
@@ -53,6 +54,9 @@ export function registerPasteTools(server, client) {
53
54
  if (params.addSubscriberPHIDs !== undefined) {
54
55
  transactions.push({ type: 'subscribers.add', value: params.addSubscriberPHIDs });
55
56
  }
57
+ if (params.addProjectPHIDs !== undefined) {
58
+ transactions.push({ type: 'projects.add', value: params.addProjectPHIDs });
59
+ }
56
60
  const result = await client.call('paste.edit', { transactions });
57
61
  return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
58
62
  });
@@ -65,6 +69,8 @@ export function registerPasteTools(server, client) {
65
69
  status: z.string().optional().describe('Status: active or archived'),
66
70
  addSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to add'),
67
71
  removeSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to remove'),
72
+ addProjectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to add'),
73
+ removeProjectPHIDs: z.array(z.string()).optional().describe('Project PHIDs to remove'),
68
74
  comment: z.string().optional().describe('Add a comment alongside the edit (supports Remarkup)'),
69
75
  }, async (params) => {
70
76
  const transactions = [];
@@ -86,6 +92,12 @@ export function registerPasteTools(server, client) {
86
92
  if (params.removeSubscriberPHIDs !== undefined) {
87
93
  transactions.push({ type: 'subscribers.remove', value: params.removeSubscriberPHIDs });
88
94
  }
95
+ if (params.addProjectPHIDs !== undefined) {
96
+ transactions.push({ type: 'projects.add', value: params.addProjectPHIDs });
97
+ }
98
+ if (params.removeProjectPHIDs !== undefined) {
99
+ transactions.push({ type: 'projects.remove', value: params.removeProjectPHIDs });
100
+ }
89
101
  if (params.comment !== undefined) {
90
102
  transactions.push({ type: 'comment', value: params.comment });
91
103
  }
@@ -3,11 +3,10 @@ import { jsonCoerce } from './coerce.js';
3
3
  export function registerPhameTools(server, client) {
4
4
  // Search blogs
5
5
  server.tool('phabricator_blog_search', 'Search Phame blogs', {
6
- queryKey: z.string().optional().describe('Built-in query: "all", "active"'),
6
+ queryKey: z.string().optional().describe('Built-in query: "all", "active", "archived"'),
7
7
  constraints: jsonCoerce(z.object({
8
8
  ids: z.array(z.coerce.number()).optional().describe('Blog IDs'),
9
9
  phids: z.array(z.string()).optional().describe('Blog PHIDs'),
10
- statuses: z.array(z.string()).optional().describe('Blog statuses (may not be supported on all instances)'),
11
10
  subscribers: z.array(z.string()).optional().describe('Subscriber user/project PHIDs'),
12
11
  projects: z.array(z.string()).optional().describe('Project PHIDs'),
13
12
  query: z.string().optional().describe('Full-text search query'),
@@ -30,7 +29,7 @@ export function registerPhameTools(server, client) {
30
29
  name: z.string().optional().describe('Blog name'),
31
30
  subtitle: z.string().optional().describe('Blog subtitle'),
32
31
  description: z.string().optional().describe('Blog description (Remarkup)'),
33
- fullDomain: z.string().optional().describe('Custom full domain for the blog'),
32
+ domainFullURI: z.string().optional().describe('Custom full domain URI for the blog'),
34
33
  parentSite: z.string().optional().describe('Parent site name'),
35
34
  parentDomain: z.string().optional().describe('Parent domain URL'),
36
35
  status: z.string().optional().describe('Blog status'),
@@ -48,8 +47,8 @@ export function registerPhameTools(server, client) {
48
47
  if (params.description !== undefined) {
49
48
  transactions.push({ type: 'description', value: params.description });
50
49
  }
51
- if (params.fullDomain !== undefined) {
52
- transactions.push({ type: 'fullDomain', value: params.fullDomain });
50
+ if (params.domainFullURI !== undefined) {
51
+ transactions.push({ type: 'domainFullURI', value: params.domainFullURI });
53
52
  }
54
53
  if (params.parentSite !== undefined) {
55
54
  transactions.push({ type: 'parentSite', value: params.parentSite });
@@ -81,12 +80,12 @@ export function registerPhameTools(server, client) {
81
80
  });
82
81
  // Search blog posts
83
82
  server.tool('phabricator_blog_post_search', 'Search Phame blog posts', {
84
- queryKey: z.string().optional().describe('Built-in query: "all", "live"'),
83
+ queryKey: z.string().optional().describe('Built-in query: "all", "live", "draft", "archived"'),
85
84
  constraints: jsonCoerce(z.object({
86
85
  ids: z.array(z.coerce.number()).optional().describe('Post IDs'),
87
86
  phids: z.array(z.string()).optional().describe('Post PHIDs'),
88
87
  blogPHIDs: z.array(z.string()).optional().describe('Filter by blog PHIDs'),
89
- visibility: z.array(z.coerce.number()).optional().describe('Visibility values: 0 (draft), 1 (published), 2 (archived)'),
88
+ visibility: z.array(z.string()).optional().describe('Visibility values: "0" (draft), "1" (published), "2" (archived)'),
90
89
  subscribers: z.array(z.string()).optional().describe('Subscriber user/project PHIDs'),
91
90
  projects: z.array(z.string()).optional().describe('Project PHIDs'),
92
91
  query: z.string().optional().describe('Full-text search query'),
@@ -3,7 +3,7 @@ import { jsonCoerce } from './coerce.js';
3
3
  export function registerProjectTools(server, client) {
4
4
  // Search projects
5
5
  server.tool('phabricator_project_search', 'Search Phabricator projects', {
6
- queryKey: z.string().optional().describe('Built-in query: "all", "active", "joined"'),
6
+ queryKey: z.string().optional().describe('Built-in query: "all", "active", "joined", "watching"'),
7
7
  constraints: jsonCoerce(z.object({
8
8
  ids: z.array(z.coerce.number()).optional().describe('Project IDs'),
9
9
  phids: z.array(z.string()).optional().describe('Project PHIDs'),
@@ -13,6 +13,7 @@ export function registerProjectTools(server, client) {
13
13
  watchers: z.array(z.string()).optional().describe('Watcher user PHIDs'),
14
14
  ancestors: z.array(z.string()).optional().describe('Ancestor project PHIDs'),
15
15
  parents: z.array(z.string()).optional().describe('Parent project PHIDs (find subprojects)'),
16
+ status: z.string().optional().describe('Project status: "active" (default), "archived"'),
16
17
  icons: z.array(z.string()).optional().describe('Filter by project icon'),
17
18
  isMilestone: z.boolean().optional().describe('Filter milestones'),
18
19
  isRoot: z.boolean().optional().describe('Filter root projects'),
@@ -40,13 +41,10 @@ export function registerProjectTools(server, client) {
40
41
  server.tool('phabricator_project_edit', 'Create or edit a Phabricator project. Omit objectIdentifier to create a new project (name is required for creation).', {
41
42
  objectIdentifier: z.string().optional().describe('Project PHID or ID. Omit to create a new project.'),
42
43
  name: z.string().optional().describe('New name'),
43
- description: z.string().optional().describe('New description'),
44
44
  icon: z.string().optional().describe('New icon'),
45
45
  color: z.string().optional().describe('New color'),
46
46
  addMemberPHIDs: z.array(z.string()).optional().describe('Add members'),
47
47
  removeMemberPHIDs: z.array(z.string()).optional().describe('Remove members'),
48
- addSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to add'),
49
- removeSubscriberPHIDs: z.array(z.string()).optional().describe('Subscriber PHIDs to remove'),
50
48
  space: z.string().optional().describe('Space PHID (for multi-space installations)'),
51
49
  parent: z.string().optional().describe('Parent project PHID (to create as a subproject)'),
52
50
  milestone: z.string().optional().describe('Parent project PHID (to create as a milestone of that project)'),
@@ -69,9 +67,6 @@ export function registerProjectTools(server, client) {
69
67
  if (params.slug !== undefined) {
70
68
  transactions.push({ type: 'slugs', value: [params.slug] });
71
69
  }
72
- if (params.description !== undefined) {
73
- transactions.push({ type: 'description', value: params.description });
74
- }
75
70
  if (params.icon !== undefined) {
76
71
  transactions.push({ type: 'icon', value: params.icon });
77
72
  }
@@ -84,12 +79,6 @@ export function registerProjectTools(server, client) {
84
79
  if (params.removeMemberPHIDs !== undefined) {
85
80
  transactions.push({ type: 'members.remove', value: params.removeMemberPHIDs });
86
81
  }
87
- if (params.addSubscriberPHIDs !== undefined) {
88
- transactions.push({ type: 'subscribers.add', value: params.addSubscriberPHIDs });
89
- }
90
- if (params.removeSubscriberPHIDs !== undefined) {
91
- transactions.push({ type: 'subscribers.remove', value: params.removeSubscriberPHIDs });
92
- }
93
82
  if (params.comment !== undefined) {
94
83
  transactions.push({ type: 'comment', value: params.comment });
95
84
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freelancercom/phabricator-mcp",
3
- "version": "2.0.12",
3
+ "version": "2.0.14",
4
4
  "description": "MCP server for Phabricator Conduit API - manage tasks, code reviews, repositories, and more",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",