@nestr/mcp 0.1.35 → 0.1.36

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAiB,KAAK,WAAW,EAAkC,MAAM,kBAAkB,CAAC;AA+EnG,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2UnB,CAAC;AAGF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmxB3B,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAuBF,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,CAcrB"}
@@ -118,7 +118,7 @@ export const schemas = {
118
118
  labels: z.array(z.string()).optional().describe("Label IDs to set (e.g., ['project'] to convert an item into a project)"),
119
119
  fields: z.record(z.unknown()).optional().describe("Field updates (e.g., { 'project.status': 'Current' })"),
120
120
  users: z.array(z.string()).optional().describe("User IDs to assign"),
121
- data: z.record(z.unknown()).optional().describe("Data updates (e.g., { botContext: 'Key info...' }, plain text)"),
121
+ data: z.record(z.unknown()).optional().describe("Key-value data store shared with Nestr internals — never overwrite existing keys. Namespace your own data under 'mcp.' (e.g., { 'mcp.lastSync': '...' }). For AI knowledge persistence, use skills instead."),
122
122
  due: z.string().optional().describe("Due date (ISO format). For projects/tasks: deadline. For roles: re-election date. For meetings: start time."),
123
123
  completed: z.boolean().optional().describe("Mark task as completed (root-level field, not in fields). Note: Projects use fields['project.status'] = 'Done' instead."),
124
124
  }),
@@ -129,6 +129,13 @@ export const schemas = {
129
129
  nestId: z.string().describe("Nest ID to comment on"),
130
130
  body: z.string().describe("Comment text (supports HTML and @mentions)"),
131
131
  }),
132
+ updateComment: z.object({
133
+ commentId: z.string().describe("Comment ID to update"),
134
+ body: z.string().describe("Updated comment text (supports HTML and @mentions)"),
135
+ }),
136
+ deleteComment: z.object({
137
+ commentId: z.string().describe("Comment ID to delete"),
138
+ }),
132
139
  listCircles: z.object({
133
140
  workspaceId: z.string().describe("Workspace ID"),
134
141
  limit: z.number().optional().describe("Max results per page. Omit to see full count in meta.total."),
@@ -179,6 +186,12 @@ export const schemas = {
179
186
  workspaceId: z.string().describe("Workspace ID"),
180
187
  userId: z.string().describe("User ID"),
181
188
  }),
189
+ addWorkspaceUser: z.object({
190
+ workspaceId: z.string().describe("Workspace ID"),
191
+ username: z.string().describe("Email address of the user to add"),
192
+ fullName: z.string().optional().describe("Full name of the user (used when creating a new account)"),
193
+ language: z.string().optional().describe("Language preference (e.g., 'en', 'nl', 'de')"),
194
+ }),
182
195
  getLabel: z.object({
183
196
  workspaceId: z.string().describe("Workspace ID"),
184
197
  labelId: z.string().describe("Label ID"),
@@ -239,6 +252,98 @@ export const schemas = {
239
252
  }),
240
253
  // Daily plan (requires OAuth token)
241
254
  getDailyPlan: z.object({}),
255
+ // Current user identity (requires OAuth token)
256
+ getMe: z.object({}),
257
+ // User tension tools (requires OAuth token)
258
+ listMyTensions: z.object({
259
+ context: z.string().optional().describe("Optional context filter (e.g., workspace ID or circle ID)"),
260
+ }),
261
+ listTensionsAwaitingConsent: z.object({
262
+ context: z.string().optional().describe("Optional context filter (e.g., workspace ID or circle ID)"),
263
+ }),
264
+ // Tension tools
265
+ createTension: z.object({
266
+ nestId: z.string().describe("ID of the circle or role to create the tension on"),
267
+ title: z.string().describe("The gap you're sensing — what is the difference between current reality and desired state (plain text)"),
268
+ description: z.string().optional().describe("The observable facts — what you see/hear/experience that creates this tension (supports HTML)"),
269
+ feeling: z.string().optional().describe("The feeling this tension evokes in you — separated from the facts to keep the organizational response clean (plain text)"),
270
+ needs: z.string().optional().describe("The personal or organizational need that is alive — what need is not being met (plain text)"),
271
+ }),
272
+ getTension: z.object({
273
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
274
+ tensionId: z.string().describe("Tension ID"),
275
+ }),
276
+ listTensions: z.object({
277
+ nestId: z.string().describe("ID of the circle or role to list tensions for"),
278
+ search: z.string().optional().describe("Search query to filter tensions"),
279
+ limit: z.number().optional().describe("Max results to return"),
280
+ order: z.string().optional().describe("Sort order (e.g., 'createdAt', '-createdAt')"),
281
+ }),
282
+ updateTension: z.object({
283
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
284
+ tensionId: z.string().describe("Tension ID"),
285
+ title: z.string().optional().describe("Updated title — the gap being sensed (plain text)"),
286
+ description: z.string().optional().describe("Updated description — the observable facts (supports HTML)"),
287
+ feeling: z.string().optional().describe("Updated feeling this tension evokes (plain text)"),
288
+ needs: z.string().optional().describe("Updated need that is alive (plain text)"),
289
+ }),
290
+ deleteTension: z.object({
291
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
292
+ tensionId: z.string().describe("Tension ID to delete"),
293
+ }),
294
+ getTensionParts: z.object({
295
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
296
+ tensionId: z.string().describe("Tension ID"),
297
+ }),
298
+ addTensionPart: z.object({
299
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
300
+ tensionId: z.string().describe("Tension ID"),
301
+ _id: z.string().optional().describe("ID of an existing governance item to change or remove. Omit to propose a new item."),
302
+ title: z.string().optional().describe("Title for the governance item"),
303
+ labels: z.array(z.string()).optional().describe("Labels defining the item type (e.g., ['role'], ['circle'], ['policy'], ['accountability'], ['domain'])"),
304
+ purpose: z.string().optional().describe("Purpose of the item (supports HTML)"),
305
+ description: z.string().optional().describe("Description (supports HTML)"),
306
+ parentId: z.string().optional().describe("Parent ID — use to move/restructure items (e.g., move role to different circle)"),
307
+ users: z.array(z.string()).optional().describe("User IDs to assign (e.g., for role elections: assign the elected user to the role)"),
308
+ due: z.string().optional().describe("Due date / re-election date (ISO format)"),
309
+ accountabilities: z.array(z.string()).optional().describe("Accountability titles to set on a role (replaces existing)"),
310
+ domains: z.array(z.string()).optional().describe("Domain titles to set on a role (replaces existing)"),
311
+ removeNest: z.boolean().optional().describe("Set to true with _id to propose removal of the existing governance item"),
312
+ }),
313
+ modifyTensionPart: z.object({
314
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
315
+ tensionId: z.string().describe("Tension ID"),
316
+ partId: z.string().describe("Part ID to modify"),
317
+ title: z.string().optional().describe("Updated title"),
318
+ purpose: z.string().optional().describe("Updated purpose (supports HTML)"),
319
+ description: z.string().optional().describe("Updated description (supports HTML)"),
320
+ labels: z.array(z.string()).optional().describe("Updated labels"),
321
+ parentId: z.string().optional().describe("Updated parent ID"),
322
+ users: z.array(z.string()).optional().describe("Updated user assignments"),
323
+ due: z.string().optional().describe("Updated due date (ISO format)"),
324
+ removeNest: z.boolean().optional().describe("Change removal flag"),
325
+ accountabilities: z.array(z.string()).optional().describe("Updated accountabilities"),
326
+ domains: z.array(z.string()).optional().describe("Updated domains"),
327
+ }),
328
+ removeTensionPart: z.object({
329
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
330
+ tensionId: z.string().describe("Tension ID"),
331
+ partId: z.string().describe("Part ID to remove from the proposal"),
332
+ }),
333
+ getTensionChanges: z.object({
334
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
335
+ tensionId: z.string().describe("Tension ID"),
336
+ partId: z.string().describe("Part ID to get changes for"),
337
+ }),
338
+ getTensionStatus: z.object({
339
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
340
+ tensionId: z.string().describe("Tension ID"),
341
+ }),
342
+ updateTensionStatus: z.object({
343
+ nestId: z.string().describe("ID of the circle or role the tension belongs to"),
344
+ tensionId: z.string().describe("Tension ID"),
345
+ status: z.enum(["proposed", "draft"]).describe("'proposed' to submit for voting, 'draft' to retract back to draft"),
346
+ }),
242
347
  };
243
348
  // Tool definitions for MCP
244
349
  export const toolDefinitions = [
@@ -388,7 +493,7 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
388
493
  },
389
494
  {
390
495
  name: "nestr_update_nest",
391
- description: "Update properties of an existing nest. Use parentId to move a nest (e.g., inbox item to a project). Use data.botContext to store AI context (plain text) that persists across sessions.",
496
+ description: "Update properties of an existing nest. Use parentId to move a nest (e.g., inbox item to a project). For AI knowledge persistence, create skill-labeled nests under roles/circles instead of using data fields.",
392
497
  inputSchema: {
393
498
  type: "object",
394
499
  properties: {
@@ -413,7 +518,7 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
413
518
  },
414
519
  data: {
415
520
  type: "object",
416
- description: "Data updates (e.g., { botContext: 'Key info here...' } for AI memory, plain text)",
521
+ description: "Key-value data store shared with Nestr internals — never overwrite existing keys. Namespace your own data under 'mcp.' (e.g., { 'mcp.lastSync': '...' }). For AI knowledge persistence, use skills instead.",
417
522
  },
418
523
  due: {
419
524
  type: "string",
@@ -450,6 +555,29 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
450
555
  required: ["nestId", "body"],
451
556
  },
452
557
  },
558
+ {
559
+ name: "nestr_update_comment",
560
+ description: "Update an existing comment's text.",
561
+ inputSchema: {
562
+ type: "object",
563
+ properties: {
564
+ commentId: { type: "string", description: "Comment ID to update" },
565
+ body: { type: "string", description: "Updated comment text (supports HTML and @mentions)" },
566
+ },
567
+ required: ["commentId", "body"],
568
+ },
569
+ },
570
+ {
571
+ name: "nestr_delete_comment",
572
+ description: "Delete a comment (soft delete).",
573
+ inputSchema: {
574
+ type: "object",
575
+ properties: {
576
+ commentId: { type: "string", description: "Comment ID to delete" },
577
+ },
578
+ required: ["commentId"],
579
+ },
580
+ },
453
581
  {
454
582
  name: "nestr_list_circles",
455
583
  description: "List all circles (teams/departments) in a workspace. Response includes meta.total showing total matching count.",
@@ -586,6 +714,25 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
586
714
  required: ["workspaceId", "userId"],
587
715
  },
588
716
  },
717
+ {
718
+ name: "nestr_add_workspace_user",
719
+ description: `Add a user to a workspace by email address. If the user already has a Nestr account, they are added to the workspace. If not, a new account is created and they receive an invitation email.
720
+
721
+ **Requirements:**
722
+ - Caller must be a workspace admin (user-scoped key) or use a workspace API key
723
+ - If the user does not yet have a Nestr account, the email domain must be associated with and verified for the workspace — otherwise provisioning will fail with a 405 error
724
+ - If the user already exists in Nestr, they can be added regardless of domain`,
725
+ inputSchema: {
726
+ type: "object",
727
+ properties: {
728
+ workspaceId: { type: "string", description: "Workspace ID" },
729
+ username: { type: "string", description: "Email address of the user to add" },
730
+ fullName: { type: "string", description: "Full name (for new accounts)" },
731
+ language: { type: "string", description: "Language preference (e.g., 'en', 'nl')" },
732
+ },
733
+ required: ["workspaceId", "username"],
734
+ },
735
+ },
589
736
  {
590
737
  name: "nestr_get_label",
591
738
  description: "Get details of a specific label. Labels define what type a nest is (e.g., 'project', 'todo', 'role', 'circle', 'meeting').",
@@ -627,7 +774,7 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
627
774
  // Inbox tools (require OAuth token - won't work with workspace API keys)
628
775
  {
629
776
  name: "nestr_list_inbox",
630
- description: "List items in the user's inbox. The inbox is a collection point for 'stuff' that needs processing - ideas, tasks, notes captured quickly without organizing. Requires OAuth token (won't work with workspace API keys).",
777
+ description: "List items in the user's personal inbox. The inbox holds unprocessed 'stuff' sensed tensions, ideas, and captured items that haven't yet been differentiated into role work or personal projects. Spans all workspaces in scope. Requires OAuth token.",
631
778
  inputSchema: {
632
779
  type: "object",
633
780
  properties: {
@@ -639,7 +786,7 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
639
786
  },
640
787
  {
641
788
  name: "nestr_create_inbox_item",
642
- description: "Quick capture: add an item to the user's inbox for later processing. Use for capturing thoughts, ideas, or tasks without worrying about where they belong. Requires OAuth token.",
789
+ description: "Quick capture: add an item to the user's personal inbox for later processing. Use for capturing sensed tensions, thoughts, or ideas before deciding which workspace, role, or personal context they belong to. Requires OAuth token.",
643
790
  inputSchema: {
644
791
  type: "object",
645
792
  properties: {
@@ -760,7 +907,7 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
760
907
  // Daily plan (requires OAuth token)
761
908
  {
762
909
  name: "nestr_get_daily_plan",
763
- description: "Get the user's daily plan - items marked for 'today'. Returns todos and projects the user has added to their daily focus list by applying the 'now' label. Use this to help users plan their day or review what's on their plate. Note: Only includes items from inbox and in-scope workspaces (token scope may limit results). Requires OAuth token.",
910
+ description: "Get the user's personal daily plan - items marked for 'today'. Returns todos and projects across all contexts: role work from any workspace, personal projects, errands, or anything else the user has chosen to focus on today. Spans all workspaces in scope. Note: Token scope may limit which workspaces are included. Requires OAuth token.",
764
911
  inputSchema: {
765
912
  type: "object",
766
913
  properties: {
@@ -769,6 +916,221 @@ Requires user-scoped authentication (OAuth token or personal API key with user s
769
916
  },
770
917
  _meta: completableListUi,
771
918
  },
919
+ // Current user identity
920
+ {
921
+ name: "nestr_get_me",
922
+ description: "Get the current authenticated identity and operating mode. Returns user info including `bot: true` if the agent energizes roles directly (role-filler mode) or absent/false if assisting a human who energizes roles. Returns `authMode: 'api-key'` when using a workspace API key (no user identity, no user-scoped features). Call at session start to determine how to behave. Requires OAuth token for full user info; gracefully handles API key auth.",
923
+ inputSchema: {
924
+ type: "object",
925
+ properties: {},
926
+ },
927
+ },
928
+ // User tension tools (requires OAuth token)
929
+ {
930
+ name: "nestr_list_my_tensions",
931
+ description: "List tensions created by or assigned to the current user. Tensions are the primary communication mechanism between roles — check at natural breakpoints: session start, after completing work, when user asks what to do next. Returns both authored and assigned tensions across all workspaces. Requires OAuth token.",
932
+ inputSchema: {
933
+ type: "object",
934
+ properties: {
935
+ context: { type: "string", description: "Optional context filter (e.g., workspace ID or circle ID)" },
936
+ },
937
+ },
938
+ },
939
+ {
940
+ name: "nestr_list_tensions_awaiting_consent",
941
+ description: "List tensions awaiting the current user's consent vote. Returns governance proposals and other tensions that need the user's input. Check proactively — unprocessed tensions block organizational progress. Requires OAuth token.",
942
+ inputSchema: {
943
+ type: "object",
944
+ properties: {
945
+ context: { type: "string", description: "Optional context filter (e.g., workspace ID or circle ID)" },
946
+ },
947
+ },
948
+ },
949
+ // Tension tools
950
+ {
951
+ name: "nestr_create_tension",
952
+ description: "Create a new tension — the fundamental unit of inter-role communication. Tensions represent a gap between current reality and potential. Use for ALL cross-role communication: requesting information, sharing information, requesting outcomes/projects, requesting actions/tasks, or setting expectations (governance). The parent nest must be a role, circle, or anchor-circle.",
953
+ inputSchema: {
954
+ type: "object",
955
+ properties: {
956
+ nestId: { type: "string", description: "ID of the circle or role to create the tension on" },
957
+ title: { type: "string", description: "The gap — what is the difference between current reality and desired state (plain text)" },
958
+ description: { type: "string", description: "The observable facts — what you see/hear/experience (supports HTML)" },
959
+ feeling: { type: "string", description: "The feeling this tension evokes — separated to keep the organizational response clean (plain text)" },
960
+ needs: { type: "string", description: "The need that is alive — what personal or organizational need is not being met (plain text)" },
961
+ },
962
+ required: ["nestId", "title"],
963
+ },
964
+ },
965
+ {
966
+ name: "nestr_get_tension",
967
+ description: "Get a single tension including its current status (draft/proposed/accepted/objected). Use nestr_get_tension_status for detailed per-user voting responses.",
968
+ inputSchema: {
969
+ type: "object",
970
+ properties: {
971
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
972
+ tensionId: { type: "string", description: "Tension ID" },
973
+ },
974
+ required: ["nestId", "tensionId"],
975
+ },
976
+ },
977
+ {
978
+ name: "nestr_list_tensions",
979
+ description: "List tensions for a circle or role. Supports search query filtering. Use to find existing governance proposals or pending decisions.",
980
+ inputSchema: {
981
+ type: "object",
982
+ properties: {
983
+ nestId: { type: "string", description: "ID of the circle or role to list tensions for" },
984
+ search: { type: "string", description: "Search query to filter tensions" },
985
+ limit: { type: "number", description: "Max results to return" },
986
+ order: { type: "string", description: "Sort order (e.g., 'createdAt', '-createdAt')" },
987
+ },
988
+ required: ["nestId"],
989
+ },
990
+ },
991
+ {
992
+ name: "nestr_update_tension",
993
+ description: "Update a tension's title, description, feeling, or needs. Use to refine the tension statement or add personal context before adding proposal parts.",
994
+ inputSchema: {
995
+ type: "object",
996
+ properties: {
997
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
998
+ tensionId: { type: "string", description: "Tension ID" },
999
+ title: { type: "string", description: "Updated title — the gap being sensed (plain text)" },
1000
+ description: { type: "string", description: "Updated description — the observable facts (supports HTML)" },
1001
+ feeling: { type: "string", description: "Updated feeling this tension evokes (plain text)" },
1002
+ needs: { type: "string", description: "Updated need that is alive (plain text)" },
1003
+ },
1004
+ required: ["nestId", "tensionId"],
1005
+ },
1006
+ },
1007
+ {
1008
+ name: "nestr_delete_tension",
1009
+ description: "Delete a tension (soft delete). Use when a tension is no longer relevant or was created in error.",
1010
+ inputSchema: {
1011
+ type: "object",
1012
+ properties: {
1013
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1014
+ tensionId: { type: "string", description: "Tension ID to delete" },
1015
+ },
1016
+ required: ["nestId", "tensionId"],
1017
+ },
1018
+ },
1019
+ {
1020
+ name: "nestr_get_tension_parts",
1021
+ description: "Get all parts of a tension. Each part contains items representing proposed governance changes (with action: create/update/delete/role2circle/circle2role). Review parts to understand what a tension proposes before submitting.",
1022
+ inputSchema: {
1023
+ type: "object",
1024
+ properties: {
1025
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1026
+ tensionId: { type: "string", description: "Tension ID" },
1027
+ },
1028
+ required: ["nestId", "tensionId"],
1029
+ },
1030
+ },
1031
+ {
1032
+ name: "nestr_add_tension_part",
1033
+ description: `Add a governance change to a tension. Three modes based on input:
1034
+
1035
+ **New item** (no _id): Propose creating a new governance item. Provide title and labels (e.g., ["role"], ["circle"], ["policy"], ["accountability"], ["domain"]). For roles, include accountabilities and/or domains.
1036
+
1037
+ **Change existing item** (_id provided, no removeNest): Propose changes to an existing governance item. Provide the _id of the item plus fields to change. Supports title/purpose changes, restructuring (parentId to move between circles), conversions (labels to convert role↔circle), user assignment changes (for elections), and accountability/domain changes.
1038
+
1039
+ **Remove existing item** (_id + removeNest: true): Propose removal of an existing governance item.`,
1040
+ inputSchema: {
1041
+ type: "object",
1042
+ properties: {
1043
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1044
+ tensionId: { type: "string", description: "Tension ID" },
1045
+ _id: { type: "string", description: "ID of an existing governance item to change or remove. Omit to propose a new item." },
1046
+ title: { type: "string", description: "Title for the governance item" },
1047
+ labels: { type: "array", items: { type: "string" }, description: "Labels defining the item type (e.g., ['role'], ['circle'], ['policy'], ['accountability'], ['domain'])" },
1048
+ purpose: { type: "string", description: "Purpose of the item (supports HTML)" },
1049
+ description: { type: "string", description: "Description (supports HTML)" },
1050
+ parentId: { type: "string", description: "Parent ID — use to move/restructure items (e.g., move role to different circle)" },
1051
+ users: { type: "array", items: { type: "string" }, description: "User IDs to assign (e.g., for elections: assign elected user to the role)" },
1052
+ due: { type: "string", description: "Due date / re-election date (ISO format)" },
1053
+ accountabilities: { type: "array", items: { type: "string" }, description: "Accountability titles to set on a role (replaces existing)" },
1054
+ domains: { type: "array", items: { type: "string" }, description: "Domain titles to set on a role (replaces existing)" },
1055
+ removeNest: { type: "boolean", description: "Set to true with _id to propose removal of the existing governance item" },
1056
+ },
1057
+ required: ["nestId", "tensionId"],
1058
+ },
1059
+ },
1060
+ {
1061
+ name: "nestr_modify_tension_part",
1062
+ description: "Modify an existing proposal part. Use to refine proposed values after initial creation — e.g., adjust a role's title or add accountabilities to a proposed role.",
1063
+ inputSchema: {
1064
+ type: "object",
1065
+ properties: {
1066
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1067
+ tensionId: { type: "string", description: "Tension ID" },
1068
+ partId: { type: "string", description: "Part ID to modify" },
1069
+ title: { type: "string", description: "Updated title" },
1070
+ purpose: { type: "string", description: "Updated purpose (supports HTML)" },
1071
+ description: { type: "string", description: "Updated description (supports HTML)" },
1072
+ labels: { type: "array", items: { type: "string" }, description: "Updated labels" },
1073
+ parentId: { type: "string", description: "Updated parent ID" },
1074
+ users: { type: "array", items: { type: "string" }, description: "Updated user assignments" },
1075
+ due: { type: "string", description: "Updated due date (ISO format)" },
1076
+ removeNest: { type: "boolean", description: "Change removal flag" },
1077
+ accountabilities: { type: "array", items: { type: "string" }, description: "Updated accountabilities" },
1078
+ domains: { type: "array", items: { type: "string" }, description: "Updated domains" },
1079
+ },
1080
+ required: ["nestId", "tensionId", "partId"],
1081
+ },
1082
+ },
1083
+ {
1084
+ name: "nestr_remove_tension_part",
1085
+ description: "Remove a part from the proposal entirely. This does NOT propose deletion of a governance item — it removes the proposal part itself. Use nestr_add_tension_part with removeNest:true to propose deleting a governance item.",
1086
+ inputSchema: {
1087
+ type: "object",
1088
+ properties: {
1089
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1090
+ tensionId: { type: "string", description: "Tension ID" },
1091
+ partId: { type: "string", description: "Part ID to remove from the proposal" },
1092
+ },
1093
+ required: ["nestId", "tensionId", "partId"],
1094
+ },
1095
+ },
1096
+ {
1097
+ name: "nestr_get_tension_changes",
1098
+ description: "Get the namespaced diff for a proposal part. Returns { nestId, variable, newValue, oldValue } entries showing exactly what will change. Variables are namespaced: role.title, accountability.title, domain.title, policy.title, etc. For creates: oldValue is null. For deletes: newValue is null.",
1099
+ inputSchema: {
1100
+ type: "object",
1101
+ properties: {
1102
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1103
+ tensionId: { type: "string", description: "Tension ID" },
1104
+ partId: { type: "string", description: "Part ID to get changes for" },
1105
+ },
1106
+ required: ["nestId", "tensionId", "partId"],
1107
+ },
1108
+ },
1109
+ {
1110
+ name: "nestr_get_tension_status",
1111
+ description: "Get detailed status of a tension including per-user voting responses. Returns status (draft/proposed/accepted/objected), individual responses with timestamps, and auto-approval date if set. Use this to check who has voted and the current decision state.",
1112
+ inputSchema: {
1113
+ type: "object",
1114
+ properties: {
1115
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1116
+ tensionId: { type: "string", description: "Tension ID" },
1117
+ },
1118
+ required: ["nestId", "tensionId"],
1119
+ },
1120
+ },
1121
+ {
1122
+ name: "nestr_update_tension_status",
1123
+ description: "Submit a tension for voting (set to 'proposed') or retract it back to draft. Submitting triggers the async consent/voting process — circle members are notified and can accept or object. Retracting returns it to draft for further editing.",
1124
+ inputSchema: {
1125
+ type: "object",
1126
+ properties: {
1127
+ nestId: { type: "string", description: "ID of the circle or role the tension belongs to" },
1128
+ tensionId: { type: "string", description: "Tension ID" },
1129
+ status: { type: "string", enum: ["proposed", "draft"], description: "'proposed' to submit for voting, 'draft' to retract back to draft" },
1130
+ },
1131
+ required: ["nestId", "tensionId", "status"],
1132
+ },
1133
+ },
772
1134
  ];
773
1135
  // Strip description fields from nest objects in response data
774
1136
  function stripDescriptionFields(data) {
@@ -897,6 +1259,18 @@ async function _handleToolCall(client, name, args) {
897
1259
  const post = await client.createPost(parsed.nestId, parsed.body);
898
1260
  return formatResult({ message: "Comment added successfully", post });
899
1261
  }
1262
+ case "nestr_update_comment": {
1263
+ const parsed = schemas.updateComment.parse(args);
1264
+ const updated = await client.updateNest(parsed.commentId, {
1265
+ title: parsed.body,
1266
+ });
1267
+ return formatResult({ message: "Comment updated successfully", comment: updated });
1268
+ }
1269
+ case "nestr_delete_comment": {
1270
+ const parsed = schemas.deleteComment.parse(args);
1271
+ await client.deleteNest(parsed.commentId);
1272
+ return formatResult({ message: `Comment ${parsed.commentId} deleted successfully` });
1273
+ }
900
1274
  case "nestr_list_circles": {
901
1275
  const parsed = schemas.listCircles.parse(args);
902
1276
  const circles = await client.listCircles(parsed.workspaceId, {
@@ -971,6 +1345,15 @@ async function _handleToolCall(client, name, args) {
971
1345
  const user = await client.getUser(parsed.workspaceId, parsed.userId);
972
1346
  return formatResult(user);
973
1347
  }
1348
+ case "nestr_add_workspace_user": {
1349
+ const parsed = schemas.addWorkspaceUser.parse(args);
1350
+ const user = await client.addWorkspaceUser(parsed.workspaceId, {
1351
+ username: parsed.username,
1352
+ fullName: parsed.fullName,
1353
+ language: parsed.language,
1354
+ });
1355
+ return formatResult({ message: "User added to workspace successfully", user });
1356
+ }
974
1357
  case "nestr_get_label": {
975
1358
  const parsed = schemas.getLabel.parse(args);
976
1359
  const label = await client.getLabel(parsed.workspaceId, parsed.labelId);
@@ -1064,6 +1447,135 @@ async function _handleToolCall(client, name, args) {
1064
1447
  const items = await client.getDailyPlan();
1065
1448
  return formatResult(completableResponse(compactResponse(items), "daily-plan", "Daily Plan"));
1066
1449
  }
1450
+ // Current user identity
1451
+ case "nestr_get_me": {
1452
+ schemas.getMe.parse(args);
1453
+ try {
1454
+ const user = await client.getCurrentUser();
1455
+ return formatResult({
1456
+ authMode: "oauth",
1457
+ user,
1458
+ mode: user.bot ? "role-filler" : "assistant",
1459
+ hint: user.bot
1460
+ ? "You are a bot energizing roles. You have no authority as an agent — only through the roles you fill. Act autonomously within your roles' accountabilities. Process tensions proactively."
1461
+ : "You are assisting a human who energizes roles. Defer to them for decisions. Help them articulate tensions and navigate governance.",
1462
+ });
1463
+ }
1464
+ catch {
1465
+ // getCurrentUser fails for workspace API keys — no user identity
1466
+ return formatResult({
1467
+ authMode: "api-key",
1468
+ user: null,
1469
+ mode: "workspace",
1470
+ hint: "Using a workspace API key. No user identity — user-scoped features (inbox, daily plan, personal labels, my tensions) are unavailable. You are managing the workspace directly.",
1471
+ });
1472
+ }
1473
+ }
1474
+ // User tension tools (requires OAuth token)
1475
+ case "nestr_list_my_tensions": {
1476
+ const parsed = schemas.listMyTensions.parse(args);
1477
+ const tensions = await client.listMyTensions({ context: parsed.context });
1478
+ return formatResult(compactResponse(tensions));
1479
+ }
1480
+ case "nestr_list_tensions_awaiting_consent": {
1481
+ const parsed = schemas.listTensionsAwaitingConsent.parse(args);
1482
+ const tensions = await client.listTensionsAwaitingConsent({ context: parsed.context });
1483
+ return formatResult(compactResponse(tensions));
1484
+ }
1485
+ // Tension tools
1486
+ case "nestr_create_tension": {
1487
+ const parsed = schemas.createTension.parse(args);
1488
+ const fields = {};
1489
+ if (parsed.feeling)
1490
+ fields["tension.feeling"] = parsed.feeling;
1491
+ if (parsed.needs)
1492
+ fields["tension.needs"] = parsed.needs;
1493
+ const tension = await client.createTension(parsed.nestId, {
1494
+ title: parsed.title,
1495
+ description: parsed.description,
1496
+ ...(Object.keys(fields).length > 0 ? { fields } : {}),
1497
+ });
1498
+ return formatResult({ message: "Tension created successfully", tension });
1499
+ }
1500
+ case "nestr_get_tension": {
1501
+ const parsed = schemas.getTension.parse(args);
1502
+ const tension = await client.getTension(parsed.nestId, parsed.tensionId, { cleanText: true });
1503
+ return formatResult(tension);
1504
+ }
1505
+ case "nestr_list_tensions": {
1506
+ const parsed = schemas.listTensions.parse(args);
1507
+ const tensions = await client.listTensions(parsed.nestId, parsed.search, { limit: parsed.limit, order: parsed.order, cleanText: true });
1508
+ return formatResult(compactResponse(tensions));
1509
+ }
1510
+ case "nestr_update_tension": {
1511
+ const parsed = schemas.updateTension.parse(args);
1512
+ const fields = {};
1513
+ if (parsed.feeling !== undefined)
1514
+ fields["tension.feeling"] = parsed.feeling;
1515
+ if (parsed.needs !== undefined)
1516
+ fields["tension.needs"] = parsed.needs;
1517
+ const tension = await client.updateTension(parsed.nestId, parsed.tensionId, {
1518
+ title: parsed.title,
1519
+ description: parsed.description,
1520
+ ...(Object.keys(fields).length > 0 ? { fields } : {}),
1521
+ });
1522
+ return formatResult({ message: "Tension updated successfully", tension });
1523
+ }
1524
+ case "nestr_delete_tension": {
1525
+ const parsed = schemas.deleteTension.parse(args);
1526
+ await client.deleteTension(parsed.nestId, parsed.tensionId);
1527
+ return formatResult({ message: `Tension ${parsed.tensionId} deleted successfully` });
1528
+ }
1529
+ case "nestr_get_tension_parts": {
1530
+ const parsed = schemas.getTensionParts.parse(args);
1531
+ const parts = await client.getTensionParts(parsed.nestId, parsed.tensionId, { cleanText: true });
1532
+ return formatResult(parts);
1533
+ }
1534
+ case "nestr_add_tension_part": {
1535
+ const parsed = schemas.addTensionPart.parse(args);
1536
+ const { nestId, tensionId, removeNest, ...body } = parsed;
1537
+ if (body._id && removeNest) {
1538
+ // Propose removal of existing item
1539
+ const part = await client.proposeTensionRemoval(nestId, tensionId, { _id: body._id });
1540
+ return formatResult({ message: "Removal proposal added successfully", part });
1541
+ }
1542
+ else if (body._id) {
1543
+ // Propose change to existing item
1544
+ const part = await client.proposeTensionChange(nestId, tensionId, body);
1545
+ return formatResult({ message: "Change proposal added successfully", part });
1546
+ }
1547
+ else {
1548
+ // Propose new item
1549
+ const part = await client.createTensionPart(nestId, tensionId, body);
1550
+ return formatResult({ message: "New item proposal added successfully", part });
1551
+ }
1552
+ }
1553
+ case "nestr_modify_tension_part": {
1554
+ const parsed = schemas.modifyTensionPart.parse(args);
1555
+ const { nestId, tensionId, partId, ...data } = parsed;
1556
+ const part = await client.modifyTensionPart(nestId, tensionId, partId, data);
1557
+ return formatResult({ message: "Tension part modified successfully", part });
1558
+ }
1559
+ case "nestr_remove_tension_part": {
1560
+ const parsed = schemas.removeTensionPart.parse(args);
1561
+ await client.removeTensionPart(parsed.nestId, parsed.tensionId, parsed.partId);
1562
+ return formatResult({ message: `Tension part ${parsed.partId} removed successfully` });
1563
+ }
1564
+ case "nestr_get_tension_changes": {
1565
+ const parsed = schemas.getTensionChanges.parse(args);
1566
+ const changes = await client.getTensionPartChanges(parsed.nestId, parsed.tensionId, parsed.partId);
1567
+ return formatResult(changes);
1568
+ }
1569
+ case "nestr_get_tension_status": {
1570
+ const parsed = schemas.getTensionStatus.parse(args);
1571
+ const status = await client.getTensionStatus(parsed.nestId, parsed.tensionId);
1572
+ return formatResult(status);
1573
+ }
1574
+ case "nestr_update_tension_status": {
1575
+ const parsed = schemas.updateTensionStatus.parse(args);
1576
+ const status = await client.updateTensionStatus(parsed.nestId, parsed.tensionId, parsed.status);
1577
+ return formatResult({ message: `Tension status updated to '${parsed.status}'`, status });
1578
+ }
1067
1579
  default:
1068
1580
  return formatError({
1069
1581
  error: true,