coregrid-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.
Files changed (3) hide show
  1. package/README.md +41 -0
  2. package/index.js +178 -0
  3. package/package.json +28 -0
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # coregrid-crm-mcp
2
+
3
+ MCP server para el **CRM CoreGrid**. Expone el pipeline de ventas como tools
4
+ para que un agente lo opere y pruebe.
5
+
6
+ ## Tools
7
+
8
+ | Tool | Qué hace |
9
+ |------|----------|
10
+ | `get_pipeline` | Etapas con sus deals + estadísticas (valor total, conversión) |
11
+ | `create_deal` | Crea una oportunidad |
12
+ | `update_deal` | Actualiza título/valor/cliente/etiquetas/etapa |
13
+ | `move_deal` | Mueve una oportunidad a otra etapa |
14
+ | `delete_deal` | Elimina una oportunidad |
15
+
16
+ ## Configuración
17
+
18
+ Variables de entorno:
19
+
20
+ - `CRM_API_KEY` (requerido) — bearer token del workspace.
21
+ - `CRM_API_URL` (opcional) — base del CRM. Default `https://crm-coregrid.fly.dev`.
22
+
23
+ ## Uso con un agente (config MCP)
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "coregrid-crm": {
29
+ "command": "npx",
30
+ "args": ["-y", "coregrid-crm-mcp"],
31
+ "env": {
32
+ "CRM_API_KEY": "crm_sk_..."
33
+ }
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ ## Etapas del pipeline (stageId)
40
+
41
+ `nuevo` · `contactado` · `cotizado` · `negociacion` · `ganado` · `perdido`
package/index.js ADDED
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ // MCP server para el CRM CoreGrid.
3
+ // Expone el pipeline de ventas como tools para que un agente lo opere/pruebe.
4
+ //
5
+ // Configuración (env):
6
+ // CRM_API_URL — base del CRM (default https://crm-coregrid.fly.dev)
7
+ // CRM_API_KEY — bearer token del workspace (requerido)
8
+ //
9
+ // Uso típico (config de un agente MCP):
10
+ // {
11
+ // "command": "npx",
12
+ // "args": ["-y", "coregrid-crm-mcp"],
13
+ // "env": { "CRM_API_KEY": "crm_sk_..." }
14
+ // }
15
+
16
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import { z } from "zod";
19
+
20
+ const API_URL = (process.env.CRM_API_URL || "https://crm-coregrid.fly.dev").replace(/\/$/, "");
21
+ const API_KEY = process.env.CRM_API_KEY;
22
+
23
+ if (!API_KEY) {
24
+ console.error("[coregrid-crm-mcp] Falta CRM_API_KEY en el entorno.");
25
+ process.exit(1);
26
+ }
27
+
28
+ const CRM_ENDPOINT = `${API_URL}/api/v1/crm`;
29
+
30
+ async function getPipeline() {
31
+ const res = await fetch(CRM_ENDPOINT, {
32
+ headers: { Authorization: `Bearer ${API_KEY}` },
33
+ });
34
+ if (!res.ok) throw new Error(`GET pipeline ${res.status}: ${await res.text()}`);
35
+ return res.json();
36
+ }
37
+
38
+ async function postCrm(body) {
39
+ const res = await fetch(CRM_ENDPOINT, {
40
+ method: "POST",
41
+ headers: {
42
+ "Content-Type": "application/json",
43
+ Authorization: `Bearer ${API_KEY}`,
44
+ },
45
+ body: JSON.stringify(body),
46
+ });
47
+ const json = await res.json().catch(() => ({}));
48
+ if (!res.ok || json.ok === false) {
49
+ throw new Error(json.error || `POST ${res.status}`);
50
+ }
51
+ return json;
52
+ }
53
+
54
+ const ok = (data) => ({
55
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
56
+ });
57
+ const fail = (e) => ({
58
+ content: [{ type: "text", text: `Error: ${e instanceof Error ? e.message : String(e)}` }],
59
+ isError: true,
60
+ });
61
+
62
+ const server = new McpServer({
63
+ name: "coregrid-crm",
64
+ version: "0.1.0",
65
+ });
66
+
67
+ server.tool(
68
+ "get_pipeline",
69
+ "Devuelve el pipeline de ventas: etapas (stages) con sus deals y estadísticas (valor total, conversión). Úsalo para ver el estado actual del tablero.",
70
+ {},
71
+ async () => {
72
+ try {
73
+ const data = await getPipeline();
74
+ const summary = {
75
+ stages: data.stages.map((s) => ({
76
+ id: s.id,
77
+ name: s.name,
78
+ count: s.deals.length,
79
+ totalValue: s.totalValue,
80
+ deals: s.deals.map((d) => ({
81
+ id: d.id,
82
+ title: d.title,
83
+ value: d.value,
84
+ customerName: d.customerName,
85
+ tags: d.tags,
86
+ })),
87
+ })),
88
+ stats: data.stats,
89
+ };
90
+ return ok(summary);
91
+ } catch (e) {
92
+ return fail(e);
93
+ }
94
+ }
95
+ );
96
+
97
+ server.tool(
98
+ "create_deal",
99
+ "Crea una nueva oportunidad (deal) en el pipeline. Si no se indica stageId, entra en la primera etapa.",
100
+ {
101
+ title: z.string().describe("Título de la oportunidad"),
102
+ value: z.number().optional().describe("Valor en MXN"),
103
+ stageId: z.string().optional().describe("ID de la etapa (ej. nuevo, contactado, cotizado, negociacion, ganado, perdido)"),
104
+ customerName: z.string().optional(),
105
+ customerPhone: z.string().optional(),
106
+ customerEmail: z.string().optional(),
107
+ tags: z.array(z.string()).optional(),
108
+ },
109
+ async (args) => {
110
+ try {
111
+ const r = await postCrm({ intent: "create_deal", deal: args });
112
+ return ok({ created: true, dealId: r.dealId });
113
+ } catch (e) {
114
+ return fail(e);
115
+ }
116
+ }
117
+ );
118
+
119
+ server.tool(
120
+ "update_deal",
121
+ "Actualiza campos de una oportunidad existente (título, valor, cliente, etiquetas, etapa).",
122
+ {
123
+ dealId: z.string().describe("ID del deal a actualizar"),
124
+ title: z.string().optional(),
125
+ value: z.number().nullable().optional(),
126
+ stageId: z.string().optional(),
127
+ customerName: z.string().nullable().optional(),
128
+ customerPhone: z.string().nullable().optional(),
129
+ customerEmail: z.string().nullable().optional(),
130
+ tags: z.array(z.string()).optional(),
131
+ },
132
+ async ({ dealId, ...deal }) => {
133
+ try {
134
+ await postCrm({ intent: "update_deal", dealId, deal });
135
+ return ok({ updated: true, dealId });
136
+ } catch (e) {
137
+ return fail(e);
138
+ }
139
+ }
140
+ );
141
+
142
+ server.tool(
143
+ "move_deal",
144
+ "Mueve una oportunidad a otra etapa del pipeline (drag & drop programático).",
145
+ {
146
+ dealId: z.string().describe("ID del deal a mover"),
147
+ stageId: z.string().describe("ID de la etapa destino"),
148
+ position: z.number().optional().describe("Posición dentro de la etapa (0 = arriba)"),
149
+ },
150
+ async ({ dealId, stageId, position }) => {
151
+ try {
152
+ await postCrm({ intent: "move_deal", dealId, stageId, position });
153
+ return ok({ moved: true, dealId, stageId });
154
+ } catch (e) {
155
+ return fail(e);
156
+ }
157
+ }
158
+ );
159
+
160
+ server.tool(
161
+ "delete_deal",
162
+ "Elimina una oportunidad del pipeline.",
163
+ {
164
+ dealId: z.string().describe("ID del deal a eliminar"),
165
+ },
166
+ async ({ dealId }) => {
167
+ try {
168
+ await postCrm({ intent: "delete_deal", dealId });
169
+ return ok({ deleted: true, dealId });
170
+ } catch (e) {
171
+ return fail(e);
172
+ }
173
+ }
174
+ );
175
+
176
+ const transport = new StdioServerTransport();
177
+ await server.connect(transport);
178
+ console.error(`[coregrid-crm-mcp] conectado a ${API_URL}`);
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "coregrid-crm-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server para el CRM CoreGrid — tools de pipeline/deals para agentes",
5
+ "type": "module",
6
+ "bin": {
7
+ "coregrid-crm-mcp": "index.js"
8
+ },
9
+ "files": [
10
+ "index.js",
11
+ "README.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "model-context-protocol",
19
+ "crm",
20
+ "coregrid",
21
+ "pipeline"
22
+ ],
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@modelcontextprotocol/sdk": "^1.12.0",
26
+ "zod": "^3.23.8"
27
+ }
28
+ }