@vantageos/vantage-crm-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +260 -0
- package/dist/convex/crm/_helpers.js +24 -0
- package/dist/convex/crm/activities.js +220 -0
- package/dist/convex/crm/briefing.js +198 -0
- package/dist/convex/crm/calendarCron.js +92 -0
- package/dist/convex/crm/calendarCronDispatch.js +83 -0
- package/dist/convex/crm/calendarSync.js +294 -0
- package/dist/convex/crm/companies.js +323 -0
- package/dist/convex/crm/contacts.js +346 -0
- package/dist/convex/crm/deals.js +481 -0
- package/dist/convex/crm/emailActions.js +158 -0
- package/dist/convex/crm/emailCron.js +210 -0
- package/dist/convex/crm/emailCronDispatch.js +76 -0
- package/dist/convex/crm/emailSync.js +260 -0
- package/dist/convex/crm/onboarding.js +185 -0
- package/dist/convex/crm/stats.js +75 -0
- package/dist/convex/crm/tasks.js +109 -0
- package/dist/convex/crons.js +25 -0
- package/dist/convex/integrations.js +183 -0
- package/dist/convex/lib/auditLog.js +109 -0
- package/dist/convex/lib/auth.js +372 -0
- package/dist/convex/lib/rbac.js +123 -0
- package/dist/convex/lib/workspace.js +171 -0
- package/dist/convex/organizations.js +192 -0
- package/dist/convex/schema.js +690 -0
- package/dist/convex/users.js +217 -0
- package/dist/convex/workspaces.js +603 -0
- package/dist/mcp-server/lib/convexClient.js +50 -0
- package/dist/mcp-server/lib/scopeEnforcement.js +76 -0
- package/dist/mcp-server/registry.js +116 -0
- package/dist/mcp-server/server.js +97 -0
- package/dist/mcp-server/tests/registry.test.js +163 -0
- package/dist/mcp-server/tests/scopeEnforcement.test.js +137 -0
- package/dist/mcp-server/tests/security.test.js +257 -0
- package/dist/mcp-server/tests/tools.test.js +272 -0
- package/dist/mcp-server/tools/activities.js +207 -0
- package/dist/mcp-server/tools/admin.js +190 -0
- package/dist/mcp-server/tools/companies.js +233 -0
- package/dist/mcp-server/tools/contacts.js +306 -0
- package/dist/mcp-server/tools/customFields.js +222 -0
- package/dist/mcp-server/tools/customObjects.js +235 -0
- package/dist/mcp-server/tools/deals.js +297 -0
- package/dist/mcp-server/tools/rbac.js +177 -0
- package/dist/mcp-server/tools/search.js +155 -0
- package/dist/mcp-server/tools/workflows.js +234 -0
- package/dist/mcp-server/transport/http.js +257 -0
- package/dist/mcp-server/transport/stdio.js +90 -0
- package/package.json +45 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Organization management functions
|
|
4
|
+
*
|
|
5
|
+
* Handles syncing Clerk organizations to Convex
|
|
6
|
+
* and organization-specific operations
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.updatePlan = exports.updateSettings = exports.getUserOrganizations = exports.getMembers = exports.getBySlug = exports.getByClerkId = exports.getCurrent = void 0;
|
|
10
|
+
const values_1 = require("convex/values");
|
|
11
|
+
const server_1 = require("./_generated/server");
|
|
12
|
+
const auth_1 = require("./lib/auth");
|
|
13
|
+
/**
|
|
14
|
+
* Get the current organization (if in org context)
|
|
15
|
+
*/
|
|
16
|
+
exports.getCurrent = (0, server_1.query)({
|
|
17
|
+
args: {},
|
|
18
|
+
handler: async (ctx) => {
|
|
19
|
+
const workspace = await (0, auth_1.getWorkspaceContext)(ctx);
|
|
20
|
+
const currentOrgId = workspace.orgId;
|
|
21
|
+
if (!currentOrgId) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return await ctx.db
|
|
25
|
+
.query('organizations')
|
|
26
|
+
.withIndex('by_clerk_id', (q) => q.eq('clerkId', currentOrgId))
|
|
27
|
+
.first();
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Get organization by Clerk ID
|
|
32
|
+
*/
|
|
33
|
+
exports.getByClerkId = (0, server_1.query)({
|
|
34
|
+
args: { clerkId: values_1.v.string() },
|
|
35
|
+
handler: async (ctx, { clerkId }) => {
|
|
36
|
+
return await ctx.db
|
|
37
|
+
.query('organizations')
|
|
38
|
+
.withIndex('by_clerk_id', (q) => q.eq('clerkId', clerkId))
|
|
39
|
+
.first();
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Get organization by slug
|
|
44
|
+
*/
|
|
45
|
+
exports.getBySlug = (0, server_1.query)({
|
|
46
|
+
args: { slug: values_1.v.string() },
|
|
47
|
+
handler: async (ctx, { slug }) => {
|
|
48
|
+
return await ctx.db
|
|
49
|
+
.query('organizations')
|
|
50
|
+
.withIndex('by_slug', (q) => q.eq('slug', slug))
|
|
51
|
+
.first();
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Get all members of an organization
|
|
56
|
+
*/
|
|
57
|
+
exports.getMembers = (0, server_1.query)({
|
|
58
|
+
args: { orgId: values_1.v.id('organizations') },
|
|
59
|
+
handler: async (ctx, { orgId }) => {
|
|
60
|
+
const memberships = await ctx.db
|
|
61
|
+
.query('memberships')
|
|
62
|
+
.withIndex('by_org', (q) => q.eq('orgId', orgId))
|
|
63
|
+
.collect();
|
|
64
|
+
// Get user details for each membership
|
|
65
|
+
const members = await Promise.all(memberships.map(async (membership) => {
|
|
66
|
+
const user = await ctx.db.get(membership.userId);
|
|
67
|
+
return {
|
|
68
|
+
...membership,
|
|
69
|
+
user: user
|
|
70
|
+
? {
|
|
71
|
+
_id: user._id,
|
|
72
|
+
name: user.name,
|
|
73
|
+
email: user.email,
|
|
74
|
+
avatarUrl: user.avatarUrl,
|
|
75
|
+
}
|
|
76
|
+
: null,
|
|
77
|
+
};
|
|
78
|
+
}));
|
|
79
|
+
return members;
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* Get organizations a user belongs to
|
|
84
|
+
*/
|
|
85
|
+
exports.getUserOrganizations = (0, server_1.query)({
|
|
86
|
+
args: {},
|
|
87
|
+
handler: async (ctx) => {
|
|
88
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
89
|
+
if (!identity)
|
|
90
|
+
return [];
|
|
91
|
+
// Find user
|
|
92
|
+
const user = await ctx.db
|
|
93
|
+
.query('users')
|
|
94
|
+
.withIndex('by_clerk_id', (q) => q.eq('clerkId', identity.subject))
|
|
95
|
+
.first();
|
|
96
|
+
if (!user)
|
|
97
|
+
return [];
|
|
98
|
+
// Get memberships
|
|
99
|
+
const memberships = await ctx.db
|
|
100
|
+
.query('memberships')
|
|
101
|
+
.withIndex('by_user', (q) => q.eq('userId', user._id))
|
|
102
|
+
.collect();
|
|
103
|
+
// Get org details
|
|
104
|
+
const orgs = await Promise.all(memberships.map(async (membership) => {
|
|
105
|
+
const org = await ctx.db.get(membership.orgId);
|
|
106
|
+
return org
|
|
107
|
+
? {
|
|
108
|
+
...org,
|
|
109
|
+
role: membership.role,
|
|
110
|
+
membershipId: membership._id,
|
|
111
|
+
}
|
|
112
|
+
: null;
|
|
113
|
+
}));
|
|
114
|
+
return orgs.filter(Boolean);
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
/**
|
|
118
|
+
* Update organization settings (admin only)
|
|
119
|
+
*/
|
|
120
|
+
exports.updateSettings = (0, server_1.mutation)({
|
|
121
|
+
args: {
|
|
122
|
+
orgId: values_1.v.id('organizations'),
|
|
123
|
+
settings: values_1.v.object({
|
|
124
|
+
defaultModel: values_1.v.optional(values_1.v.string()),
|
|
125
|
+
allowPersonalTools: values_1.v.optional(values_1.v.boolean()),
|
|
126
|
+
requireApprovalForPublic: values_1.v.optional(values_1.v.boolean()),
|
|
127
|
+
}),
|
|
128
|
+
},
|
|
129
|
+
handler: async (ctx, { orgId, settings }) => {
|
|
130
|
+
const workspace = await (0, auth_1.getWorkspaceContext)(ctx);
|
|
131
|
+
// Verify user is org admin
|
|
132
|
+
const user = await ctx.db
|
|
133
|
+
.query('users')
|
|
134
|
+
.withIndex('by_clerk_id', (q) => q.eq('clerkId', workspace.userId))
|
|
135
|
+
.first();
|
|
136
|
+
if (!user)
|
|
137
|
+
throw new Error('User not found');
|
|
138
|
+
const membership = await ctx.db
|
|
139
|
+
.query('memberships')
|
|
140
|
+
.withIndex('by_user_org', (q) => q.eq('userId', user._id).eq('orgId', orgId))
|
|
141
|
+
.first();
|
|
142
|
+
if (!membership || membership.role !== 'org:admin') {
|
|
143
|
+
throw new Error('Only organization admins can update settings');
|
|
144
|
+
}
|
|
145
|
+
const org = await ctx.db.get(orgId);
|
|
146
|
+
if (!org)
|
|
147
|
+
throw new Error('Organization not found');
|
|
148
|
+
const currentSettings = org.settings || {};
|
|
149
|
+
const newSettings = { ...currentSettings, ...settings };
|
|
150
|
+
await ctx.db.patch(orgId, {
|
|
151
|
+
settings: newSettings,
|
|
152
|
+
updatedAt: Date.now(),
|
|
153
|
+
});
|
|
154
|
+
return { success: true };
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
/**
|
|
158
|
+
* Update organization plan (platform admin only)
|
|
159
|
+
*/
|
|
160
|
+
exports.updatePlan = (0, server_1.mutation)({
|
|
161
|
+
args: {
|
|
162
|
+
orgId: values_1.v.id('organizations'),
|
|
163
|
+
plan: values_1.v.string(),
|
|
164
|
+
usageLimits: values_1.v.optional(values_1.v.object({
|
|
165
|
+
maxChatsPerMonth: values_1.v.optional(values_1.v.number()),
|
|
166
|
+
maxFlowExecutionsPerMonth: values_1.v.optional(values_1.v.number()),
|
|
167
|
+
maxMembers: values_1.v.optional(values_1.v.number()),
|
|
168
|
+
})),
|
|
169
|
+
},
|
|
170
|
+
handler: async (ctx, { orgId, plan, usageLimits }) => {
|
|
171
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
172
|
+
if (!identity)
|
|
173
|
+
throw new Error('Not authenticated');
|
|
174
|
+
// Check if user is platform admin
|
|
175
|
+
const user = await ctx.db
|
|
176
|
+
.query('users')
|
|
177
|
+
.withIndex('by_clerk_id', (q) => q.eq('clerkId', identity.subject))
|
|
178
|
+
.first();
|
|
179
|
+
if (!user || user.role !== 'admin') {
|
|
180
|
+
throw new Error('Only platform admins can update plans');
|
|
181
|
+
}
|
|
182
|
+
const updates = {
|
|
183
|
+
plan,
|
|
184
|
+
updatedAt: Date.now(),
|
|
185
|
+
};
|
|
186
|
+
if (usageLimits) {
|
|
187
|
+
updates.usageLimits = usageLimits;
|
|
188
|
+
}
|
|
189
|
+
await ctx.db.patch(orgId, updates);
|
|
190
|
+
return { success: true };
|
|
191
|
+
},
|
|
192
|
+
});
|