@sutraspaces/mcp-server 1.0.1 → 1.1.2
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 +69 -8
- package/package.json +5 -5
- package/src/client.js +4 -0
- package/src/index.js +18 -2
- package/src/resources/admin-api.js +136 -0
- package/src/resources/design.js +77 -0
- package/src/tools/automations.js +89 -0
- package/src/tools/blog.js +204 -0
- package/src/tools/design.js +136 -0
- package/src/tools/documents.js +108 -0
- package/src/tools/help-center.js +498 -0
- package/src/tools/media.js +86 -0
- package/src/tools/members.js +71 -3
- package/src/tools/properties.js +69 -0
- package/src/tools/spaces.js +95 -3
package/src/tools/properties.js
CHANGED
|
@@ -89,6 +89,75 @@ export function registerPropertyTools(server, client) {
|
|
|
89
89
|
}
|
|
90
90
|
);
|
|
91
91
|
|
|
92
|
+
server.tool(
|
|
93
|
+
"bulk_update_member_property_values",
|
|
94
|
+
"Set property values for up to 100 members. Requires an Idempotency-Key. Use null to clear a value.",
|
|
95
|
+
{
|
|
96
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
97
|
+
idempotency_key: z.string().describe("Unique key for this batch operation"),
|
|
98
|
+
items: z.array(z.object({
|
|
99
|
+
member_id: z.string().describe("Member ID (mem_...)"),
|
|
100
|
+
properties: z.record(z.any()).describe("Object keyed by property key or mprop_ ID, values to set (null to clear)"),
|
|
101
|
+
})).describe("Array of member property updates (max 100)"),
|
|
102
|
+
},
|
|
103
|
+
async ({ space_id, idempotency_key, items }) => {
|
|
104
|
+
const data = await client.patch(
|
|
105
|
+
`/spaces/${space_id}/members/properties/bulk`,
|
|
106
|
+
{ items },
|
|
107
|
+
{ "Idempotency-Key": idempotency_key }
|
|
108
|
+
);
|
|
109
|
+
return json(data);
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
server.tool(
|
|
114
|
+
"get_contact_property_values",
|
|
115
|
+
"Get all property values for a specific contact in a space. Contacts use the same member property definitions as members.",
|
|
116
|
+
{
|
|
117
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
118
|
+
contact_id: z.string().describe("Contact ID (contact_...)"),
|
|
119
|
+
},
|
|
120
|
+
async ({ space_id, contact_id }) => {
|
|
121
|
+
const data = await client.get(`/spaces/${space_id}/contacts/${contact_id}/properties`);
|
|
122
|
+
return json(data);
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
server.tool(
|
|
127
|
+
"update_contact_property_values",
|
|
128
|
+
"Set property values for a contact. Use null to clear a value. Keys can be property keys or mprop_ IDs.",
|
|
129
|
+
{
|
|
130
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
131
|
+
contact_id: z.string().describe("Contact ID (contact_...)"),
|
|
132
|
+
properties: z.record(z.any()).describe("Object keyed by property key or mprop_ ID, values to set (null to clear)"),
|
|
133
|
+
},
|
|
134
|
+
async ({ space_id, contact_id, properties }) => {
|
|
135
|
+
const data = await client.patch(`/spaces/${space_id}/contacts/${contact_id}/properties`, { properties });
|
|
136
|
+
return json(data);
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
server.tool(
|
|
141
|
+
"bulk_update_contact_property_values",
|
|
142
|
+
"Set property values for up to 100 contacts. Requires an Idempotency-Key. Use null to clear a value.",
|
|
143
|
+
{
|
|
144
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
145
|
+
idempotency_key: z.string().describe("Unique key for this batch operation"),
|
|
146
|
+
items: z.array(z.object({
|
|
147
|
+
contact_id: z.string().describe("Contact ID (contact_...)"),
|
|
148
|
+
properties: z.record(z.any()).describe("Object keyed by property key or mprop_ ID, values to set (null to clear)"),
|
|
149
|
+
})).describe("Array of contact property updates (max 100)"),
|
|
150
|
+
},
|
|
151
|
+
async ({ space_id, idempotency_key, items }) => {
|
|
152
|
+
const data = await client.patch(
|
|
153
|
+
`/spaces/${space_id}/contacts/properties/bulk`,
|
|
154
|
+
{ items },
|
|
155
|
+
{ "Idempotency-Key": idempotency_key }
|
|
156
|
+
);
|
|
157
|
+
return json(data);
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
|
|
92
161
|
// --- Space Properties ---
|
|
93
162
|
|
|
94
163
|
server.tool(
|
package/src/tools/spaces.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
+
const placementSchema = z.object({
|
|
4
|
+
surface: z.enum(["auto", "collection", "document"]).optional().describe("Where the child appears. Use auto for normal course/section placement."),
|
|
5
|
+
position: z.number().int().nonnegative().optional().describe("Zero-based order in the resolved surface."),
|
|
6
|
+
view_as: z.enum(["list", "hcard", "vcard", "button", "link"]).optional().describe("Document card render mode. Ignored for collection placement."),
|
|
7
|
+
insert: z.enum(["append", "before", "after", "inside"]).optional().describe("Document insertion mode."),
|
|
8
|
+
anchor_node_uid: z.string().optional().describe("Tiptap node UID used with before/after/inside."),
|
|
9
|
+
set_parent_ordering: z.enum(["custom_order"]).optional().describe("Set parent list ordering so collection position is visually effective."),
|
|
10
|
+
}).optional();
|
|
11
|
+
|
|
3
12
|
export function registerSpaceTools(server, client) {
|
|
4
13
|
server.tool(
|
|
5
14
|
"list_spaces",
|
|
@@ -18,6 +27,19 @@ export function registerSpaceTools(server, client) {
|
|
|
18
27
|
}
|
|
19
28
|
);
|
|
20
29
|
|
|
30
|
+
server.tool(
|
|
31
|
+
"list_membership_spaces",
|
|
32
|
+
"List basic information about spaces where the API token owner is a member. This is read-only membership inventory, not admin access to space subresources.",
|
|
33
|
+
{
|
|
34
|
+
limit: z.number().optional().describe("Max results per page (default 25, max 100)"),
|
|
35
|
+
cursor: z.string().optional().describe("Pagination cursor from a previous response"),
|
|
36
|
+
},
|
|
37
|
+
async ({ limit, cursor }) => {
|
|
38
|
+
const data = await client.get("/me/membership_spaces", { limit, cursor });
|
|
39
|
+
return json(data);
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
21
43
|
server.tool(
|
|
22
44
|
"get_space",
|
|
23
45
|
"Get details for a single space by its ID (sp_...).",
|
|
@@ -46,7 +68,7 @@ export function registerSpaceTools(server, client) {
|
|
|
46
68
|
|
|
47
69
|
server.tool(
|
|
48
70
|
"create_space",
|
|
49
|
-
"Create a new space. Omit parent_id for a top-level space, or include
|
|
71
|
+
"Create a new space. Omit parent_id for a top-level space, or include a parent sp_ ID to create a child. Use sp_ IDs, not slugs.",
|
|
50
72
|
{
|
|
51
73
|
name: z.string().describe("Space name"),
|
|
52
74
|
description: z.string().optional().describe("Space description"),
|
|
@@ -54,14 +76,84 @@ export function registerSpaceTools(server, client) {
|
|
|
54
76
|
privacy: z.string().optional().describe("Privacy level (default: open)"),
|
|
55
77
|
pod_type: z.enum(["standard", "readonly"]).optional().describe("Pod type (default: standard)"),
|
|
56
78
|
parent_id: z.string().optional().describe("Parent space ID (sp_...) to create as a child"),
|
|
79
|
+
content_scaffold: z.enum(["none", "ui_default"]).optional().describe("Use none when document content will be written through document tools."),
|
|
80
|
+
placement: placementSchema,
|
|
57
81
|
},
|
|
58
|
-
async ({ name, description, type, privacy, pod_type, parent_id }) => {
|
|
59
|
-
const body = { name, description, type, privacy, pod_type, parent_id };
|
|
82
|
+
async ({ name, description, type, privacy, pod_type, parent_id, content_scaffold, placement }) => {
|
|
83
|
+
const body = { name, description, type, privacy, pod_type, parent_id, content_scaffold, placement };
|
|
60
84
|
const data = await client.post("/spaces", body);
|
|
61
85
|
return json(data);
|
|
62
86
|
}
|
|
63
87
|
);
|
|
64
88
|
|
|
89
|
+
server.tool(
|
|
90
|
+
"create_child_space",
|
|
91
|
+
"Create a child space under a parent sp_ ID and make it visible through placement. For courses and sections use placement.surface = auto.",
|
|
92
|
+
{
|
|
93
|
+
parent_id: z.string().describe("Parent space ID (sp_...). Do not use a slug."),
|
|
94
|
+
name: z.string().describe("Child space name"),
|
|
95
|
+
description: z.string().optional(),
|
|
96
|
+
type: z.string().optional().describe("Space type (default: content)"),
|
|
97
|
+
privacy: z.string().optional(),
|
|
98
|
+
pod_type: z.enum(["standard", "readonly"]).optional(),
|
|
99
|
+
content_scaffold: z.enum(["none", "ui_default"]).optional().describe("Use none when document content will be written through document tools."),
|
|
100
|
+
placement: placementSchema,
|
|
101
|
+
idempotency_key: z.string().optional().describe("Idempotency-Key header for safe retries"),
|
|
102
|
+
},
|
|
103
|
+
async ({ parent_id, idempotency_key, ...body }) => {
|
|
104
|
+
const headers = idempotency_key ? { "Idempotency-Key": idempotency_key } : undefined;
|
|
105
|
+
const data = await client.post(`/spaces/${parent_id}/children`, body, headers);
|
|
106
|
+
return json(data);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
server.tool(
|
|
111
|
+
"attach_child_space",
|
|
112
|
+
"Attach an existing child sp_ ID to a parent sp_ ID and make it visible. Use this when a space already exists but is not showing in the course/section/page.",
|
|
113
|
+
{
|
|
114
|
+
parent_id: z.string().describe("Parent space ID (sp_...). Do not use a slug."),
|
|
115
|
+
child_id: z.string().describe("Existing child space ID (sp_...). Do not use a slug."),
|
|
116
|
+
placement: placementSchema,
|
|
117
|
+
idempotency_key: z.string().optional().describe("Idempotency-Key header for safe retries"),
|
|
118
|
+
},
|
|
119
|
+
async ({ parent_id, child_id, placement, idempotency_key }) => {
|
|
120
|
+
const headers = idempotency_key ? { "Idempotency-Key": idempotency_key } : undefined;
|
|
121
|
+
const data = await client.put(`/spaces/${parent_id}/children/${child_id}`, { placement }, headers);
|
|
122
|
+
return json(data);
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
server.tool(
|
|
127
|
+
"update_child_space_placement",
|
|
128
|
+
"Move or repair a child space display under a parent. Use auto for normal course/section placement; use document for a card in a content page.",
|
|
129
|
+
{
|
|
130
|
+
parent_id: z.string().describe("Parent space ID (sp_...). Do not use a slug."),
|
|
131
|
+
child_id: z.string().describe("Child space ID (sp_...). Do not use a slug."),
|
|
132
|
+
placement: placementSchema,
|
|
133
|
+
idempotency_key: z.string().optional().describe("Idempotency-Key header for safe retries"),
|
|
134
|
+
},
|
|
135
|
+
async ({ parent_id, child_id, placement, idempotency_key }) => {
|
|
136
|
+
const headers = idempotency_key ? { "Idempotency-Key": idempotency_key } : undefined;
|
|
137
|
+
const data = await client.patch(`/spaces/${parent_id}/children/${child_id}/placement`, { placement }, headers);
|
|
138
|
+
return json(data);
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
server.tool(
|
|
143
|
+
"detach_child_space",
|
|
144
|
+
"Detach a child space from one parent without deleting the child space.",
|
|
145
|
+
{
|
|
146
|
+
parent_id: z.string().describe("Parent space ID (sp_...). Do not use a slug."),
|
|
147
|
+
child_id: z.string().describe("Child space ID (sp_...). Do not use a slug."),
|
|
148
|
+
idempotency_key: z.string().optional().describe("Idempotency-Key header for safe retries"),
|
|
149
|
+
},
|
|
150
|
+
async ({ parent_id, child_id, idempotency_key }) => {
|
|
151
|
+
const headers = idempotency_key ? { "Idempotency-Key": idempotency_key } : undefined;
|
|
152
|
+
const data = await client.delete(`/spaces/${parent_id}/children/${child_id}`, headers);
|
|
153
|
+
return json(data);
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
|
|
65
157
|
server.tool(
|
|
66
158
|
"update_space",
|
|
67
159
|
"Update an existing space's name, description, type, privacy, or state.",
|