@orkesflow/mcp-server 1.0.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 ADDED
@@ -0,0 +1,82 @@
1
+ # Orkesflow MCP Server
2
+
3
+ El servidor **Orkesflow MCP** permite integrar tus herramientas de IA (como Claude Desktop) directamente con tu plataforma Orkesflow. Podrás gestionar tareas, tableros y registros de tiempo utilizando lenguaje natural a través del protocolo MCP (Model Context Protocol).
4
+
5
+ ## Características
6
+
7
+ - 📋 **Listar tareas**: Obtén una visión general de tus tareas pendientes.
8
+ - 🏗️ **Gestión de tableros**: Explora los espacios y tableros disponibles.
9
+ - ➕ **Creación de tareas**: Crea nuevas tarjetas especificando título, prioridad, etiquetas y tablero (por ID o nombre).
10
+ - 🔄 **Actualización de tareas**: Modifica estados, mueve tareas entre columnas o cambia prioridades.
11
+ - ⏱️ **Registro de tiempo**: Añade registros de tiempo y costes a tareas específicas.
12
+
13
+ ## Requisitos Previos
14
+
15
+ 1. **Token de Acceso Personal (PAT)**: Necesitas un token generado desde tu perfil en Orkesflow con los permisos adecuados.
16
+ 2. **Node.js**: Versión 18 o superior.
17
+
18
+ ## Instalación y Ejecución
19
+
20
+ Puedes ejecutar el servidor directamente usando `npx` sin necesidad de instalación global:
21
+
22
+ ```bash
23
+ npx @orkesflow/mcp-server
24
+ ```
25
+
26
+ ## Configuración en Claude Desktop
27
+
28
+ Para usar Orkesflow con Claude Desktop, añade la siguiente configuración en tu archivo `claude_desktop_config.json`:
29
+
30
+ ### macOS
31
+ `~/Library/Application Support/Claude/claude_desktop_config.json`
32
+
33
+ ### Windows
34
+ `%APPDATA%\Claude\claude_desktop_config.json`
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "orkesflow": {
40
+ "command": "npx",
41
+ "args": ["-y", "@orkesflow/mcp-server"],
42
+ "env": {
43
+ "ORKESFLOW_TOKEN": "TU_TOKEN_DE_ACCESO_AQUÍ",
44
+ "ORKESFLOW_API_URL": "https://api.orkesflow.com"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Herramientas Disponibles (Tools)
52
+
53
+ ### `list_tasks`
54
+ Recupera la lista de tareas del usuario.
55
+
56
+ ### `list_boards`
57
+ Lista todos los espacios y tableros a los que tienes acceso.
58
+
59
+ ### `create_task`
60
+ Crea una nueva tarea. Argumentos:
61
+ - `title` (requerido)
62
+ - `boardName` o `boardId` (opcional)
63
+ - `priority` (URGENT, HIGH, MEDIUM, LOW, NONE)
64
+ - `labels` (array de nombres)
65
+
66
+ ### `update_task`
67
+ Actualiza una tarea existente. Permite mover tareas usando `columnName`.
68
+
69
+ ### `add_time_log`
70
+ Registra minutos trabajados en una tarea.
71
+
72
+ ## Desarrollo
73
+
74
+ Si deseas contribuir o ejecutar el servidor localmente:
75
+
76
+ 1. Clona el repositorio.
77
+ 2. Instala dependencias: `pnpm install`.
78
+ 3. Compila el proyecto: `pnpm run build`.
79
+ 4. Ejecuta: `ORKESFLOW_TOKEN=tu_token node dist/index.js`.
80
+
81
+ ---
82
+ © 2026 Orkesflow Team.
package/dist/index.js ADDED
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const axios_1 = __importDefault(require("axios"));
10
+ const zod_1 = require("zod");
11
+ const ORKESFLOW_TOKEN = process.env.ORKESFLOW_TOKEN;
12
+ const ORKESFLOW_API_URL = process.env.ORKESFLOW_API_URL || "https://api.orkesflow.com";
13
+ if (!ORKESFLOW_TOKEN) {
14
+ console.error("Error: ORKESFLOW_TOKEN environment variable is required.");
15
+ process.exit(1);
16
+ }
17
+ const apiClient = axios_1.default.create({
18
+ baseURL: ORKESFLOW_API_URL,
19
+ headers: {
20
+ Authorization: `Bearer ${ORKESFLOW_TOKEN}`,
21
+ "Content-Type": "application/json",
22
+ },
23
+ });
24
+ const server = new mcp_js_1.McpServer({
25
+ name: "@orkesflow/mcp-server",
26
+ version: "1.0.0",
27
+ });
28
+ function handleApiError(error) {
29
+ if (axios_1.default.isAxiosError(error)) {
30
+ const status = error.response?.status;
31
+ const data = error.response?.data;
32
+ let message = error.message;
33
+ if (data && typeof data === 'object') {
34
+ message = JSON.stringify(data);
35
+ }
36
+ if (status === 403) {
37
+ return {
38
+ content: [
39
+ {
40
+ type: "text",
41
+ text: `API Error 403 Forbidden: The provided token does not have the necessary permissions (e.g., tasks:read) or access to the required Space. Details: ${message}`,
42
+ },
43
+ ],
44
+ isError: true,
45
+ };
46
+ }
47
+ return {
48
+ content: [
49
+ {
50
+ type: "text",
51
+ text: `Orkesflow API Error (${status || 'Unknown'}): ${message}`,
52
+ },
53
+ ],
54
+ isError: true,
55
+ };
56
+ }
57
+ if (error instanceof Error) {
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: `Unexpected Error: ${error.message}`,
63
+ },
64
+ ],
65
+ isError: true,
66
+ };
67
+ }
68
+ return {
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: `Unknown Error occurred`,
73
+ },
74
+ ],
75
+ isError: true,
76
+ };
77
+ }
78
+ server.tool("list_tasks", "Retrieve a list of tasks from Orkesflow", {}, async () => {
79
+ try {
80
+ const response = await apiClient.get("/api/v1/tasks");
81
+ return {
82
+ content: [
83
+ {
84
+ type: "text",
85
+ text: JSON.stringify(response.data, null, 2),
86
+ },
87
+ ],
88
+ };
89
+ }
90
+ catch (error) {
91
+ return handleApiError(error);
92
+ }
93
+ });
94
+ server.tool("list_boards", "Retrieve a list of available Boards and Spaces from Orkesflow", {}, async () => {
95
+ try {
96
+ const response = await apiClient.get("/api/v1/tasks/boards");
97
+ return {
98
+ content: [
99
+ {
100
+ type: "text",
101
+ text: JSON.stringify(response.data, null, 2),
102
+ },
103
+ ],
104
+ };
105
+ }
106
+ catch (error) {
107
+ return handleApiError(error);
108
+ }
109
+ });
110
+ server.tool("create_task", "Create a new task in Orkesflow", {
111
+ title: zod_1.z.string().describe("The title of the task"),
112
+ spaceId: zod_1.z.string().optional().describe("The ID of the Space where the task should be created"),
113
+ boardId: zod_1.z.string().optional().describe("The ID of the Board where the task should be created"),
114
+ boardName: zod_1.z.string().optional().describe("The name of the Board where the task should be created (e.g., 'Tareas de casa')"),
115
+ description: zod_1.z.string().optional().describe("Detailed description of the task"),
116
+ priority: zod_1.z.enum(["URGENT", "HIGH", "MEDIUM", "LOW", "NONE"]).optional().describe("Task priority"),
117
+ type: zod_1.z.string().optional().describe("The name of the task type (e.g., 'Tarea', 'Bug', 'Evento')"),
118
+ labels: zod_1.z.array(zod_1.z.string()).optional().describe("List of label names to assign")
119
+ }, async (args) => {
120
+ try {
121
+ const response = await apiClient.post("/api/v1/tasks", args);
122
+ return {
123
+ content: [
124
+ {
125
+ type: "text",
126
+ text: JSON.stringify(response.data, null, 2),
127
+ },
128
+ ],
129
+ };
130
+ }
131
+ catch (error) {
132
+ return handleApiError(error);
133
+ }
134
+ });
135
+ server.tool("update_task", "Update an existing task in Orkesflow", {
136
+ taskId: zod_1.z.string().describe("The ID of the task to update"),
137
+ title: zod_1.z.string().optional().describe("New title for the task"),
138
+ description: zod_1.z.string().optional().describe("New description for the task"),
139
+ priority: zod_1.z.enum(["URGENT", "HIGH", "MEDIUM", "LOW", "NONE"]).optional().describe("New task priority"),
140
+ type: zod_1.z.string().optional().describe("New task type name"),
141
+ labels: zod_1.z.array(zod_1.z.string()).optional().describe("New list of labels (replaces existing ones)"),
142
+ columnId: zod_1.z.string().optional().describe("The ID of the column to move the task to"),
143
+ boardId: zod_1.z.string().optional().describe("The ID of the board (required if columnId is provided)"),
144
+ columnName: zod_1.z.string().optional().describe("The name of the column to move the task to"),
145
+ boardName: zod_1.z.string().optional().describe("The name of the board (used to resolve columnName if boardId is missing)")
146
+ }, async (args) => {
147
+ try {
148
+ const { taskId, ...updateData } = args;
149
+ const response = await apiClient.patch(`/api/v1/tasks/${taskId}`, updateData);
150
+ return {
151
+ content: [
152
+ {
153
+ type: "text",
154
+ text: JSON.stringify(response.data, null, 2),
155
+ },
156
+ ],
157
+ };
158
+ }
159
+ catch (error) {
160
+ return handleApiError(error);
161
+ }
162
+ });
163
+ server.tool("add_time_log", "Add a time log (cost log) to an existing task", {
164
+ taskId: zod_1.z.string().describe("The ID of the task to log time for"),
165
+ durationMinutes: zod_1.z.number().describe("Duration of the time log in minutes"),
166
+ description: zod_1.z.string().optional().describe("Description of the work performed")
167
+ }, async (args) => {
168
+ try {
169
+ const response = await apiClient.post("/api/v1/tasks/" + args.taskId + "/time-log", args);
170
+ return {
171
+ content: [
172
+ {
173
+ type: "text",
174
+ text: JSON.stringify(response.data, null, 2),
175
+ },
176
+ ],
177
+ };
178
+ }
179
+ catch (error) {
180
+ return handleApiError(error);
181
+ }
182
+ });
183
+ async function main() {
184
+ const transport = new stdio_js_1.StdioServerTransport();
185
+ await server.connect(transport);
186
+ console.error("Orkesflow MCP Server running on stdio");
187
+ }
188
+ main().catch((error) => {
189
+ console.error("Fatal error:", error);
190
+ process.exit(1);
191
+ });
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@orkesflow/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP Server for Orkesflow API",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "orkesflow-mcp": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "tsc --watch"
13
+ },
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^1.29.0",
16
+ "axios": "^1.15.0",
17
+ "zod": "^4.3.6"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^25.8.0",
21
+ "typescript": "^5.7.3"
22
+ }
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import axios from "axios";
6
+ import { z } from "zod";
7
+
8
+ const ORKESFLOW_TOKEN = process.env.ORKESFLOW_TOKEN;
9
+ const ORKESFLOW_API_URL = process.env.ORKESFLOW_API_URL || "https://api.orkesflow.com";
10
+
11
+ if (!ORKESFLOW_TOKEN) {
12
+ console.error("Error: ORKESFLOW_TOKEN environment variable is required.");
13
+ process.exit(1);
14
+ }
15
+
16
+ const apiClient = axios.create({
17
+ baseURL: ORKESFLOW_API_URL,
18
+ headers: {
19
+ Authorization: `Bearer ${ORKESFLOW_TOKEN}`,
20
+ "Content-Type": "application/json",
21
+ },
22
+ });
23
+
24
+ const server = new McpServer(
25
+ {
26
+ name: "@orkesflow/mcp-server",
27
+ version: "1.0.0",
28
+ }
29
+ );
30
+
31
+ function handleApiError(error: unknown) {
32
+ if (axios.isAxiosError(error)) {
33
+ const status = error.response?.status;
34
+ const data = error.response?.data;
35
+
36
+ let message = error.message;
37
+ if (data && typeof data === 'object') {
38
+ message = JSON.stringify(data);
39
+ }
40
+
41
+ if (status === 403) {
42
+ return {
43
+ content: [
44
+ {
45
+ type: "text" as const,
46
+ text: `API Error 403 Forbidden: The provided token does not have the necessary permissions (e.g., tasks:read) or access to the required Space. Details: ${message}`,
47
+ },
48
+ ],
49
+ isError: true,
50
+ };
51
+ }
52
+
53
+ return {
54
+ content: [
55
+ {
56
+ type: "text" as const,
57
+ text: `Orkesflow API Error (${status || 'Unknown'}): ${message}`,
58
+ },
59
+ ],
60
+ isError: true,
61
+ };
62
+ }
63
+
64
+ if (error instanceof Error) {
65
+ return {
66
+ content: [
67
+ {
68
+ type: "text" as const,
69
+ text: `Unexpected Error: ${error.message}`,
70
+ },
71
+ ],
72
+ isError: true,
73
+ };
74
+ }
75
+
76
+ return {
77
+ content: [
78
+ {
79
+ type: "text" as const,
80
+ text: `Unknown Error occurred`,
81
+ },
82
+ ],
83
+ isError: true,
84
+ };
85
+ }
86
+
87
+ server.tool(
88
+ "list_tasks",
89
+ "Retrieve a list of tasks from Orkesflow",
90
+ {},
91
+ async () => {
92
+ try {
93
+ const response = await apiClient.get("/api/v1/tasks");
94
+ return {
95
+ content: [
96
+ {
97
+ type: "text" as const,
98
+ text: JSON.stringify(response.data, null, 2),
99
+ },
100
+ ],
101
+ };
102
+ } catch (error) {
103
+ return handleApiError(error);
104
+ }
105
+ }
106
+ );
107
+
108
+ server.tool(
109
+ "list_boards",
110
+ "Retrieve a list of available Boards and Spaces from Orkesflow",
111
+ {},
112
+ async () => {
113
+ try {
114
+ const response = await apiClient.get("/api/v1/tasks/boards");
115
+ return {
116
+ content: [
117
+ {
118
+ type: "text" as const,
119
+ text: JSON.stringify(response.data, null, 2),
120
+ },
121
+ ],
122
+ };
123
+ } catch (error) {
124
+ return handleApiError(error);
125
+ }
126
+ }
127
+ );
128
+
129
+ server.tool(
130
+ "create_task",
131
+ "Create a new task in Orkesflow",
132
+ {
133
+ title: z.string().describe("The title of the task"),
134
+ spaceId: z.string().optional().describe("The ID of the Space where the task should be created"),
135
+ boardId: z.string().optional().describe("The ID of the Board where the task should be created"),
136
+ boardName: z.string().optional().describe("The name of the Board where the task should be created (e.g., 'Tareas de casa')"),
137
+ description: z.string().optional().describe("Detailed description of the task"),
138
+ priority: z.enum(["URGENT", "HIGH", "MEDIUM", "LOW", "NONE"]).optional().describe("Task priority"),
139
+ type: z.string().optional().describe("The name of the task type (e.g., 'Tarea', 'Bug', 'Evento')"),
140
+ labels: z.array(z.string()).optional().describe("List of label names to assign")
141
+ },
142
+ async (args) => {
143
+ try {
144
+ const response = await apiClient.post("/api/v1/tasks", args);
145
+ return {
146
+ content: [
147
+ {
148
+ type: "text" as const,
149
+ text: JSON.stringify(response.data, null, 2),
150
+ },
151
+ ],
152
+ };
153
+ } catch (error) {
154
+ return handleApiError(error);
155
+ }
156
+ }
157
+ );
158
+
159
+ server.tool(
160
+ "update_task",
161
+ "Update an existing task in Orkesflow",
162
+ {
163
+ taskId: z.string().describe("The ID of the task to update"),
164
+ title: z.string().optional().describe("New title for the task"),
165
+ description: z.string().optional().describe("New description for the task"),
166
+ priority: z.enum(["URGENT", "HIGH", "MEDIUM", "LOW", "NONE"]).optional().describe("New task priority"),
167
+ type: z.string().optional().describe("New task type name"),
168
+ labels: z.array(z.string()).optional().describe("New list of labels (replaces existing ones)"),
169
+ columnId: z.string().optional().describe("The ID of the column to move the task to"),
170
+ boardId: z.string().optional().describe("The ID of the board (required if columnId is provided)"),
171
+ columnName: z.string().optional().describe("The name of the column to move the task to"),
172
+ boardName: z.string().optional().describe("The name of the board (used to resolve columnName if boardId is missing)")
173
+ },
174
+ async (args) => {
175
+ try {
176
+ const { taskId, ...updateData } = args;
177
+ const response = await apiClient.patch(`/api/v1/tasks/${taskId}`, updateData);
178
+ return {
179
+ content: [
180
+ {
181
+ type: "text" as const,
182
+ text: JSON.stringify(response.data, null, 2),
183
+ },
184
+ ],
185
+ };
186
+ } catch (error) {
187
+ return handleApiError(error);
188
+ }
189
+ }
190
+ );
191
+
192
+ server.tool(
193
+ "add_time_log",
194
+ "Add a time log (cost log) to an existing task",
195
+ {
196
+ taskId: z.string().describe("The ID of the task to log time for"),
197
+ durationMinutes: z.number().describe("Duration of the time log in minutes"),
198
+ description: z.string().optional().describe("Description of the work performed")
199
+ },
200
+ async (args) => {
201
+ try {
202
+ const response = await apiClient.post("/api/v1/tasks/" + args.taskId + "/time-log", args);
203
+ return {
204
+ content: [
205
+ {
206
+ type: "text" as const,
207
+ text: JSON.stringify(response.data, null, 2),
208
+ },
209
+ ],
210
+ };
211
+ } catch (error) {
212
+ return handleApiError(error);
213
+ }
214
+ }
215
+ );
216
+
217
+ async function main() {
218
+ const transport = new StdioServerTransport();
219
+ await server.connect(transport);
220
+ console.error("Orkesflow MCP Server running on stdio");
221
+ }
222
+
223
+ main().catch((error) => {
224
+ console.error("Fatal error:", error);
225
+ process.exit(1);
226
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "CommonJS",
5
+ "outDir": "./dist",
6
+ "rootDir": "./src",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true
12
+ },
13
+ "include": ["src/**/*"],
14
+ "exclude": ["node_modules", "dist"]
15
+ }