@vantageos/vantage-crm-mcp
v0.2.7
Published
VantageCRM MCP Server — agents-first CRM over Model Context Protocol
Maintainers
Readme
VantageCRM MCP Server
Model Context Protocol server for VantageCRM — 60 tools across 10 categories exposing the full CRM backend to AI agents.
Transports
stdio (local / Claude Desktop)
Runs as a subprocess. Full tool access, no scope filtering (trusted local user).
CONVEX_URL=https://your-deployment.convex.cloud node dist/server.js
# or explicitly:
CONVEX_URL=https://... node dist/server.js --mode stdioClaude Desktop .mcp.json:
{
"mcpServers": {
"vantageCRM": {
"command": "node",
"args": ["/path/to/vantageos-crm/mcp-server/dist/server.js"],
"env": {
"CONVEX_URL": "https://your-deployment.convex.cloud"
}
}
}
}HTTP (multi-tenant / Railway)
Runs as an HTTP server. OAuth Bearer tokens required. Tools filtered by token scope.
CONVEX_URL=https://your-deployment.convex.cloud \
VANTAGE_MCP_MODE=http \
PORT=3001 \
node dist/server.js --mode httpEndpoints:
| Method | Path | Description |
|--------|------|-------------|
| GET | /health | Liveness probe |
| GET | /mcp/tools | List tools visible to token |
| POST | /mcp/call | Call a tool |
Request format:
POST /mcp/call
Authorization: Bearer <token>
Content-Type: application/json
{
"tool": "create_contact",
"args": { "workspaceId": "ws_xxx", "firstName": "Jane", "lastName": "Doe" }
}Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| CONVEX_URL | Yes | Convex deployment URL |
| VANTAGE_MCP_MODE | No | stdio (default) or http |
| PORT | No | HTTP port (default: 3001) |
| BEARER_SECRET_MASTER | Admin only | Master secret for admin mutations (patchScopeProfileEmergency, backfills) |
| CONVEX_DEPLOY_KEY | CI/CD only | Production deploy key |
Tool Catalog
Contacts (8 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| create_contact | write | Create a CRM contact |
| get_contact | read | Retrieve contact by ID |
| update_contact | write | Update contact fields |
| list_contacts | read | List by workspace/type |
| search_contacts | read | Full-text search |
| delete_contact | write | Soft delete (30-day grace) |
| list_contacts_by_custom_field | read | Filter by custom field value |
| restore_contact | write | Restore soft-deleted contact |
Companies (6 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| create_company | write | Create company record |
| get_company | read | Retrieve by ID |
| update_company | write | Update fields |
| list_companies | read | List by workspace/industry |
| search_companies | read | Full-text search |
| delete_company | write | Soft delete |
Deals (8 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| create_deal | write | Create deal in pipeline |
| get_deal | read | Retrieve by ID |
| update_deal | write | Update fields |
| list_deals | read | List by workspace/stage/contact |
| search_deals | read | Search by title |
| delete_deal | write | Soft delete |
| move_deal_stage | write | Move stage with optional probability override |
| forecast_pipeline | read | Weighted pipeline value (Σ value × probability) |
Activities (5 tools — no delete per OQ-4)
| Tool | Scope | Description |
|------|-------|-------------|
| create_activity | write | Create activity (call/email/meeting/note/task) |
| get_activity | read | Retrieve by ID |
| update_activity | write | Update mutable fields (description, dueAt, completedAt) |
| list_activities | read | List by workspace/contact/deal |
| list_activities_by_type | read | Filter by type with time range |
Activities are immutable audit trail — subject and type cannot be changed after creation.
Custom Fields (5 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| add_custom_field | write | Define custom field for entity type |
| update_custom_field_definition | write | Update label/options/validation |
| list_custom_fields | read | List definitions by workspace |
| set_custom_field_value | write | Set value on an entity |
| delete_custom_field | admin | Delete definition (irreversible) |
Custom Objects (7 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| add_custom_object | admin | DDL: define new object type |
| list_custom_objects | read | List object type definitions |
| create_record | write | Create a custom object record |
| update_record | write | Update record fields |
| delete_record | write | Soft delete record |
| list_records | read | List records by type |
| search_records | read | Search records by field values |
Workflows (7 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| create_workflow | write | Create automation workflow |
| update_workflow | write | Update workflow config |
| list_workflows | read | List by workspace |
| pause_workflow | write | Pause (disable) workflow |
| resume_workflow | write | Resume (enable) workflow |
| list_executions | read | List workflow execution history |
| replay_execution | workflow-trigger | Re-run a failed execution |
Search / Analytics (4 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| pipeline_value | read | Weighted pipeline Σ value × probability |
| win_rate | read | Deals won / total closed in period |
| conversion_rate | read | Stage conversion rate |
| activity_summary | read | Activity counts grouped by type |
Admin (5 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| list_audit_log | admin | Query audit event log |
| get_entity_history | admin | Change history for an entity |
| get_actor_history | admin | All actions by a user |
| purge_archived_records | admin | Hard delete archived records (30+ days) |
| list_workspace_limits | admin | Workspace plan limits |
RBAC (5 tools)
| Tool | Scope | Description |
|------|-------|-------------|
| list_workspace_members | read | List workspace members and roles |
| add_workspace_member | admin | Add member with role |
| update_member_role | admin | Change member role |
| remove_workspace_member | admin | Remove member from workspace |
| update_member_permissions | admin | Fine-grained permission overrides |
Security & Multi-Tenancy
OAuth 2.1 Security (Wave 1 — D6 + D7)
- D6 — clientSecret validation:
/tokenvalidatesclient_secretfor confidential clients (tokenEndpointAuthMethod !== "none"). Constant-timetimingSafeEqualcompare (RFC 6749 §10.4). Public PKCE-only clients (tokenEndpointAuthMethod=none) bypass secret check. - D7 — redirect_uri exact-match:
/authorizevalidates redirect_uri againstmcp_oauth_clients.redirectUris[](RFC 6749 §3.1.2). Empty list → 400 invalid_client. Mismatch → 400 invalid_request. - DCR defaults:
/registersetstokenEndpointAuthMethod="client_secret_basic"per RFC 7591 §2.
Multi-Tenant Workspace Isolation (D2 Enforcement)
All 26+ tool handler surfaces auto-inject workspaceId from token context via getEffectiveWorkspaceId(ctx, args) in convex/lib/workspace.ts. Cross-tenant override attempts throw CROSS_WORKSPACE 403. Bearer absent → UNAUTHENTICATED 401.
Scope Profiles (D4 + D9)
mcp_oauth_scope_profilestable:namespaceReadPrefixes,namespaceWritePrefixes,fromAllowListper workspace.- D4:
globaland*prefixes banned exceptmasterprofile. - D9: workspace-level naming (
iris-rhnotmarie-iris-rh).fromAllowListenables multi-role consumption. - Seeded profiles:
master,iris-rh(post Day 91 rename),client-generic,public-readonly,vcrm-cloud-solo.
Emergency Scope Patching
patchScopeProfileEmergency mutation: renames scope_profile, cascade-updates oauth clients, cascade-revokes tokens, appends to oauth_audit_log (append-only audit trail). See root README.md for full usage.
Test reports: docs/test-reports/s1.6-oauth-d6-d7-2026-06-03.md · docs/test-reports/s1.2-mutation-2026-06-03.md · docs/test-reports/s2.1-d9-cascade-clients-2026-06-03.md · docs/test-reports/s3.1-b9-workspaceid-auto-inject-2026-06-03.md
Scope Tier Matrix
cloud-admin ──── satisfies all scopes
│
admin ──────── satisfies read + write
│
write ──────── satisfies read
│
read ──────── base tier
workflow-trigger ── lateral tier (peer of write, different domain)Token scopes are extracted from the Bearer token via validateToken Convex query. In stdio mode, all tools are always accessible.
Response Envelope
All tool responses use the same envelope:
// Success
{ success: true, data: <result> }
// Failure
{ success: false, error: { code: string, message: string } }Common error codes: CONVEX_ERROR, SCOPE_ERROR, ZOD_VALIDATION_ERROR, NOT_IMPLEMENTED.
Development
# Install dependencies
npm install
# Run tests
npm test
# Type check
npx tsc --noEmit --skipLibCheck
# Run in stdio mode (local dev)
CONVEX_URL=https://... npx tsx mcp-server/server.tsArchitecture
mcp-server/
├── server.ts # Entry point — mode detection
├── registry.ts # All 60 tools + handler map
├── lib/
│ ├── convexClient.ts # ConvexHttpClient wrapper + ToolResult envelope
│ └── scopeEnforcement.ts # 4-tier scope hierarchy
├── transport/
│ ├── stdio.ts # MCP SDK stdio transport
│ └── http.ts # HTTP transport with OAuth
├── tools/
│ ├── contacts.ts # 8 tools
│ ├── companies.ts # 6 tools
│ ├── deals.ts # 8 tools
│ ├── activities.ts # 5 tools
│ ├── customFields.ts # 5 tools
│ ├── customObjects.ts # 7 tools
│ ├── workflows.ts # 7 tools
│ ├── search.ts # 4 tools
│ ├── admin.ts # 5 tools
│ └── rbac.ts # 5 tools
└── tests/
├── tools.test.ts # Zod validation + envelope per category
├── scopeEnforcement.test.ts # Scope hierarchy coverage
└── registry.test.ts # 60-tool count + integrity checks