Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/agent-toolkit/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"name": "@mondaydotcomorg/agent-toolkit",
"version": "5.12.0",


"version": "5.12.1",
"description": "monday.com agent toolkit",
"exports": {
"./mcp": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export const getItemBoard = gql`

// Create a new monday doc (works for both workspace and board/item locations via CreateDocInput)
export const createDoc = gql`
mutation createDoc($location: CreateDocInput!) {
create_doc(location: $location) {
mutation createDoc($location: CreateDocInput!, $docOwnerIds: [ID!]) {
create_doc(location: $location, doc_owner_ids: $docOwnerIds) {
id
object_id
url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,75 @@ describe('CreateDocTool', () => {
});
});

describe('docOwnerIds', () => {
it('includes docOwnerIds in variables when provided', async () => {
const createDocResponse = {
create_doc: { id: 'doc_owners', object_id: 'obj_owners', url: 'https://monday.com/docs/obj_owners', name: 'Owners Doc' },
};
const addContentResponse = { add_content_to_doc_from_markdown: { success: true, block_ids: [] } };

jest.spyOn(mocks, 'mockRequest').mockImplementation((query: string) => {
if (query.includes('mutation createDoc')) return Promise.resolve(createDocResponse);
if (query.includes('mutation addContentToDocFromMarkdown')) return Promise.resolve(addContentResponse);
return Promise.resolve({});
});

const args: inputType = {
location: 'workspace',
workspace_id: 12345,
doc_name: 'Owners Doc',
markdown: '# Test',
docOwnerIds: ['111', '222'],
};

await callToolByNameRawAsync('create_doc', args);

const createDocCall = mocks.getMockRequest().mock.calls.find((c) => c[0].includes('mutation createDoc'));
expect(createDocCall).toBeDefined();
expect(createDocCall[1]).toEqual(expect.objectContaining({ docOwnerIds: ['111', '222'] }));
});

it('does not include docOwnerIds in variables when not provided', async () => {
const createDocResponse = {
create_doc: { id: 'doc_no_owners', object_id: 'obj_no_owners', url: 'https://monday.com/docs/obj_no_owners', name: 'No Owners Doc' },
};
const addContentResponse = { add_content_to_doc_from_markdown: { success: true, block_ids: [] } };

jest.spyOn(mocks, 'mockRequest').mockImplementation((query: string) => {
if (query.includes('mutation createDoc')) return Promise.resolve(createDocResponse);
if (query.includes('mutation addContentToDocFromMarkdown')) return Promise.resolve(addContentResponse);
return Promise.resolve({});
});

const args: inputType = {
location: 'workspace',
workspace_id: 12345,
doc_name: 'No Owners Doc',
markdown: '# Test',
};

await callToolByNameRawAsync('create_doc', args);

const createDocCall = mocks.getMockRequest().mock.calls.find((c) => c[0].includes('mutation createDoc'));
expect(createDocCall).toBeDefined();
expect(createDocCall[1]).not.toHaveProperty('docOwnerIds');
});

it('rejects docOwnerIds as empty array (min 1 required)', async () => {
const args = {
location: 'workspace',
workspace_id: 12345,
doc_name: 'Empty Owners Doc',
markdown: '# Test',
docOwnerIds: [],
};

const result = await callToolByNameRawAsync('create_doc', args);
expect(result.content[0].text).toContain('Invalid arguments');
expect(mocks.getMockRequest()).not.toHaveBeenCalled();
});
});

describe('Validation Errors', () => {
it('should return error when workspace_id is missing', async () => {
const args: Partial<inputType> = {
Expand Down Expand Up @@ -583,6 +652,69 @@ describe('CreateDocTool', () => {
});
});

describe('docOwnerIds', () => {
it('includes docOwnerIds in item doc variables when provided', async () => {
Comment thread
Noa-Reuven marked this conversation as resolved.
const getItemBoardResponse = {
items: [{ id: 'item_99', board: { id: 'board_99', columns: [{ id: 'doc_col_99', type: NonDeprecatedColumnType.Doc }] } }],
};
const createDocResponse = { create_doc: { id: 'doc_owners_item', object_id: 'obj_owners_item', url: 'https://monday.com/docs/obj_owners_item', name: null } };
const addContentResponse = { add_content_to_doc_from_markdown: { success: true, block_ids: [] } };

jest.spyOn(mocks, 'mockRequest').mockImplementation((query: string) => {
if (query.includes('query getItemBoard')) return Promise.resolve(getItemBoardResponse);
if (query.includes('mutation createDoc')) return Promise.resolve(createDocResponse);
if (query.includes('mutation updateDocName')) return Promise.resolve({ update_doc_name: true });
if (query.includes('mutation addContentToDocFromMarkdown')) return Promise.resolve(addContentResponse);
return Promise.resolve({});
});

const args: inputType = {
location: 'item',
item_id: 99,
column_id: 'doc_col_99',
doc_name: 'Owners Item Doc',
markdown: '# Test',
docOwnerIds: ['555', '666'],
};

await callToolByNameRawAsync('create_doc', args);

const createDocCall = mocks.getMockRequest().mock.calls.find((c) => c[0].includes('mutation createDoc'));
expect(createDocCall).toBeDefined();
expect(createDocCall[1]).toEqual(expect.objectContaining({ docOwnerIds: ['555', '666'] }));
});

it('does not include docOwnerIds in item doc variables when not provided', async () => {
const getItemBoardResponse = {
items: [{ id: 'item_77', board: { id: 'board_77', columns: [{ id: 'doc_col_77', type: NonDeprecatedColumnType.Doc }] } }],
};
const createDocResponse = { create_doc: { id: 'doc_no_owners_item', object_id: 'obj_no_owners_item', url: 'https://monday.com/docs/obj_no_owners_item', name: null } };
const addContentResponse = { add_content_to_doc_from_markdown: { success: true, block_ids: [] } };

jest.spyOn(mocks, 'mockRequest').mockImplementation((query: string) => {
if (query.includes('query getItemBoard')) return Promise.resolve(getItemBoardResponse);
if (query.includes('mutation createDoc')) return Promise.resolve(createDocResponse);
if (query.includes('mutation updateDocName')) return Promise.resolve({ update_doc_name: true });
if (query.includes('mutation addContentToDocFromMarkdown')) return Promise.resolve(addContentResponse);
return Promise.resolve({});
});

const args: inputType = {
location: 'item',
item_id: 77,
column_id: 'doc_col_77',
doc_name: 'No Owners Item Doc',
markdown: '# Test',
};

await callToolByNameRawAsync('create_doc', args);

const createDocCall = mocks.getMockRequest().mock.calls.find((c) => c[0].includes('mutation createDoc'));
expect(createDocCall).toBeDefined();
expect(createDocCall[1]).not.toHaveProperty('docOwnerIds');
});
});

describe('Validation Errors', () => {
it('should return error when item_id is missing', async () => {
const args: Partial<inputType> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ export const createDocToolSchema = {
location: z
.enum(['workspace', 'item'])
.describe('Location where the document should be created - either in a workspace or attached to an item'),

docOwnerIds: z
Comment thread
Noa-Reuven marked this conversation as resolved.
Comment thread
Noa-Reuven marked this conversation as resolved.
.array(z.string())
.min(1)
.optional()
.describe(
'Optional list of user IDs to set as document owners at creation time. Use this to add the agent owner so they retain access to the document. Ownership is set inside the creation mutation itself, bypassing the permission checks that would block a subsequent add_subscribers_to_object call.',
),
workspace_id: z
.number()
.optional()
Expand Down Expand Up @@ -98,13 +104,14 @@ export class CreateDocTool extends BaseMondayApiTool<typeof createDocToolSchema>
return `Create a new monday.com doc either inside a workspace or attached to an item (via a doc column). After creation, the provided markdown will be appended to the document.

LOCATION TYPES:
- workspace: Creates a document in a workspace (requires workspace_id, optional doc_kind, optional folder_id)
- item: Creates a document attached to an item (requires item_id, optional column_id)
- workspace: Creates a document in a workspace (requires workspace_id, optional doc_kind, optional folder_id, optional docOwnerIds)
- item: Creates a document attached to an item (requires item_id, optional column_id, optional docOwnerIds)

USAGE EXAMPLES:
- Workspace doc: { location: "workspace", workspace_id: 123, doc_kind: "private" , markdown: "..." }
- Workspace doc in folder: { location: "workspace", workspace_id: 123, folder_id: 17264196 , markdown: "..." }
- Item doc: { location: "item", item_id: 456, column_id: "doc_col_1" , markdown: "..." }`;
- Workspace doc: { location: "workspace", workspace_id: 123, doc_name: "My Doc", doc_kind: "private" , markdown: "..." }
- Workspace doc in folder: { location: "workspace", workspace_id: 123, doc_name: "My Doc", folder_id: 17264196 , markdown: "..." }
- Item doc: { location: "item", item_id: 456, doc_name: "My Doc", column_id: "doc_col_1" , markdown: "..." }
- Workspace doc with agent owner: { location: "workspace", workspace_id: 123, doc_name: "My Doc", markdown: "...", docOwnerIds: ["<agent_owner_user_id>"] }`;
}

getInputSchema(): typeof createDocToolSchema {
Expand Down Expand Up @@ -139,6 +146,7 @@ USAGE EXAMPLES:
folder_id: parsedInput.folder_id?.toString(),
},
},
...(input.docOwnerIds !== undefined ? { docOwnerIds: input.docOwnerIds } : {}),
};

const res: CreateDocMutation = await this.mondayApi.request(createDocMutation, variables);
Expand Down Expand Up @@ -190,6 +198,7 @@ USAGE EXAMPLES:
column_id: columnId,
},
},
...(input.docOwnerIds !== undefined ? { docOwnerIds: input.docOwnerIds } : {}),
};

const res: CreateDocMutation = await this.mondayApi.request(createDocMutation, itemVariables);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9146,6 +9146,7 @@ export type MutationCreate_DepartmentArgs = {

/** Root mutation type for the Dependencies service */
export type MutationCreate_DocArgs = {
doc_owner_ids?: InputMaybe<Array<Scalars['ID']['input']>>;
location: CreateDocInput;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Documents = {
"\n query getDocById($docId: [ID!]) {\n docs(ids: $docId) {\n id\n name\n url\n }\n }\n": typeof types.GetDocByIdDocument,
"\n query aggregateBoardInsights($query: AggregateQueryInput!, $boardId: ID!) {\n boards(ids: [$boardId]) {\n name\n url\n }\n aggregate(query: $query) {\n results {\n entries {\n alias\n value {\n ... on AggregateBasicAggregationResult {\n result\n }\n ... on AggregateGroupByResult {\n value\n }\n }\n }\n }\n }\n }\n": typeof types.AggregateBoardInsightsDocument,
"\n query getItemBoard($itemId: ID!) {\n items(ids: [$itemId]) {\n id\n board {\n id\n columns {\n id\n type\n }\n }\n }\n }\n": typeof types.GetItemBoardDocument,
"\n mutation createDoc($location: CreateDocInput!) {\n create_doc(location: $location) {\n id\n object_id\n url\n name\n }\n }\n": typeof types.CreateDocDocument,
"\n mutation createDoc($location: CreateDocInput!, $docOwnerIds: [ID!]) {\n create_doc(location: $location, doc_owner_ids: $docOwnerIds) {\n id\n object_id\n url\n name\n }\n }\n": typeof types.CreateDocDocument,
"\n mutation updateDocName($docId: ID!, $name: String!) {\n update_doc_name(docId: $docId, name: $name)\n }\n": typeof types.UpdateDocNameDocument,
"\n mutation createFolder(\n $workspaceId: ID!\n $name: String!\n $color: FolderColor\n $fontWeight: FolderFontWeight\n $customIcon: FolderCustomIcon\n $parentFolderId: ID\n ) {\n create_folder(\n workspace_id: $workspaceId\n name: $name\n color: $color\n font_weight: $fontWeight\n custom_icon: $customIcon\n parent_folder_id: $parentFolderId\n ) {\n id\n name\n }\n }\n": typeof types.CreateFolderDocument,
"\n mutation createGroup(\n $boardId: ID!\n $groupName: String!\n $groupColor: String\n $relativeTo: String\n $positionRelativeMethod: PositionRelative\n ) {\n create_group(\n board_id: $boardId\n group_name: $groupName\n group_color: $groupColor\n relative_to: $relativeTo\n position_relative_method: $positionRelativeMethod\n ) {\n id\n title\n }\n }\n": typeof types.CreateGroupDocument,
Expand Down Expand Up @@ -152,7 +152,7 @@ const documents: Documents = {
"\n query getDocById($docId: [ID!]) {\n docs(ids: $docId) {\n id\n name\n url\n }\n }\n": types.GetDocByIdDocument,
"\n query aggregateBoardInsights($query: AggregateQueryInput!, $boardId: ID!) {\n boards(ids: [$boardId]) {\n name\n url\n }\n aggregate(query: $query) {\n results {\n entries {\n alias\n value {\n ... on AggregateBasicAggregationResult {\n result\n }\n ... on AggregateGroupByResult {\n value\n }\n }\n }\n }\n }\n }\n": types.AggregateBoardInsightsDocument,
"\n query getItemBoard($itemId: ID!) {\n items(ids: [$itemId]) {\n id\n board {\n id\n columns {\n id\n type\n }\n }\n }\n }\n": types.GetItemBoardDocument,
"\n mutation createDoc($location: CreateDocInput!) {\n create_doc(location: $location) {\n id\n object_id\n url\n name\n }\n }\n": types.CreateDocDocument,
"\n mutation createDoc($location: CreateDocInput!, $docOwnerIds: [ID!]) {\n create_doc(location: $location, doc_owner_ids: $docOwnerIds) {\n id\n object_id\n url\n name\n }\n }\n": types.CreateDocDocument,
"\n mutation updateDocName($docId: ID!, $name: String!) {\n update_doc_name(docId: $docId, name: $name)\n }\n": types.UpdateDocNameDocument,
"\n mutation createFolder(\n $workspaceId: ID!\n $name: String!\n $color: FolderColor\n $fontWeight: FolderFontWeight\n $customIcon: FolderCustomIcon\n $parentFolderId: ID\n ) {\n create_folder(\n workspace_id: $workspaceId\n name: $name\n color: $color\n font_weight: $fontWeight\n custom_icon: $customIcon\n parent_folder_id: $parentFolderId\n ) {\n id\n name\n }\n }\n": types.CreateFolderDocument,
"\n mutation createGroup(\n $boardId: ID!\n $groupName: String!\n $groupColor: String\n $relativeTo: String\n $positionRelativeMethod: PositionRelative\n ) {\n create_group(\n board_id: $boardId\n group_name: $groupName\n group_color: $groupColor\n relative_to: $relativeTo\n position_relative_method: $positionRelativeMethod\n ) {\n id\n title\n }\n }\n": types.CreateGroupDocument,
Expand Down Expand Up @@ -323,7 +323,7 @@ export function graphql(source: "\n query getItemBoard($itemId: ID!) {\n ite
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation createDoc($location: CreateDocInput!) {\n create_doc(location: $location) {\n id\n object_id\n url\n name\n }\n }\n"): (typeof documents)["\n mutation createDoc($location: CreateDocInput!) {\n create_doc(location: $location) {\n id\n object_id\n url\n name\n }\n }\n"];
export function graphql(source: "\n mutation createDoc($location: CreateDocInput!, $docOwnerIds: [ID!]) {\n create_doc(location: $location, doc_owner_ids: $docOwnerIds) {\n id\n object_id\n url\n name\n }\n }\n"): (typeof documents)["\n mutation createDoc($location: CreateDocInput!, $docOwnerIds: [ID!]) {\n create_doc(location: $location, doc_owner_ids: $docOwnerIds) {\n id\n object_id\n url\n name\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down
Loading
Loading