kntor-mcp 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.
Files changed (3) hide show
  1. package/README.md +179 -0
  2. package/bin/kntor-mcp.mjs +170 -0
  3. package/package.json +43 -0
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # Kntor MCP Server
2
+
3
+ Model Context Protocol (MCP) server for Kntor.io Healthcare ERP. Allows AI agents (Claude, n8n, WhatsApp bots) to interact with the ERP system.
4
+
5
+ ## Claude Desktop Setup
6
+
7
+ ### Option 1: Using npx (Recommended)
8
+
9
+ Add to your Claude Desktop config (`%APPDATA%\Claude\claude_desktop_config.json` on Windows, `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "kntor-erp": {
15
+ "command": "npx",
16
+ "args": ["-y", "kntor-mcp"],
17
+ "env": {
18
+ "KNTOR_API_KEY": "kntor_your_api_key_here"
19
+ }
20
+ }
21
+ }
22
+ }
23
+ ```
24
+
25
+ ### Option 2: Using local installation
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "kntor-erp": {
31
+ "command": "node",
32
+ "args": ["C:\\path\\to\\kntor-mcp-server\\bin\\kntor-mcp.mjs"],
33
+ "env": {
34
+ "KNTOR_API_KEY": "kntor_your_api_key_here"
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ After saving the config, restart Claude Desktop.
42
+
43
+ ## Server Development
44
+
45
+ ```bash
46
+ # Install dependencies
47
+ pnpm install
48
+
49
+ # Set up secrets
50
+ wrangler secret put SUPABASE_URL
51
+ wrangler secret put SUPABASE_ANON_KEY
52
+ wrangler secret put SUPABASE_SERVICE_ROLE_KEY
53
+
54
+ # Run locally
55
+ pnpm run dev
56
+
57
+ # Deploy
58
+ pnpm run deploy
59
+ ```
60
+
61
+ ## Authentication
62
+
63
+ The server uses a 3-layer authentication model:
64
+
65
+ 1. **API Key** (`x-api-key` header) - Identifies the brand/tenant
66
+ 2. **JWT** (in tool calls) - Identifies the user, preserves `auth.uid()`
67
+ 3. **RBAC** - Verifies permissions before executing
68
+
69
+ ### Getting an API Key
70
+
71
+ API keys are created by brand admins in the Kntor.io dashboard:
72
+ 1. Go to Settings → MCP Integration
73
+ 2. Click "Create API Key"
74
+ 3. Save the key (shown only once)
75
+
76
+ ## Available Tools
77
+
78
+ ### `get_availability`
79
+ Check professional availability for appointment scheduling.
80
+
81
+ ```json
82
+ {
83
+ "method": "tools/call",
84
+ "params": {
85
+ "name": "get_availability",
86
+ "arguments": {
87
+ "jwt": "eyJhbGciOiJS...",
88
+ "date": "2025-01-20",
89
+ "professional_id": "uuid-optional",
90
+ "profession_type": "psychologist"
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ ### `schedule_appointment`
97
+ Schedule a new appointment.
98
+
99
+ ```json
100
+ {
101
+ "method": "tools/call",
102
+ "params": {
103
+ "name": "schedule_appointment",
104
+ "arguments": {
105
+ "jwt": "eyJhbGciOiJS...",
106
+ "patient_id": "patient-uuid",
107
+ "professional_id": "prof-uuid",
108
+ "appointment_date": "2025-01-20",
109
+ "start_time": "10:00",
110
+ "duration_minutes": 60
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ ## API Endpoints
117
+
118
+ | Endpoint | Method | Description |
119
+ |----------|--------|-------------|
120
+ | `/` | GET | Health check |
121
+ | `/health` | GET | Health check |
122
+ | `/mcp` | POST | MCP JSON-RPC endpoint |
123
+ | `/messages` | POST | MCP JSON-RPC endpoint (alias) |
124
+
125
+ ## Example Request
126
+
127
+ ```bash
128
+ curl -X POST https://mcp.kntor.io/mcp \
129
+ -H "Content-Type: application/json" \
130
+ -H "x-api-key: kntor_your_api_key_here" \
131
+ -d '{
132
+ "jsonrpc": "2.0",
133
+ "id": 1,
134
+ "method": "tools/list"
135
+ }'
136
+ ```
137
+
138
+ ## Pricing Tiers
139
+
140
+ | Tier | Monthly Limit | Price |
141
+ |------|--------------|-------|
142
+ | free | 100 calls | $0 |
143
+ | starter | 1,000 calls | $29/mo |
144
+ | pro | 10,000 calls | $99/mo |
145
+ | enterprise | Unlimited | Custom |
146
+
147
+ ## Development
148
+
149
+ ```bash
150
+ # Type check
151
+ pnpm run typecheck
152
+
153
+ # Run locally
154
+ pnpm run dev
155
+
156
+ # Deploy to production
157
+ pnpm run deploy
158
+ ```
159
+
160
+ ## Architecture
161
+
162
+ ```
163
+ mcp-server/
164
+ ├── src/
165
+ │ ├── index.ts # Worker entry point
166
+ │ ├── types.ts # TypeScript types
167
+ │ ├── auth/
168
+ │ │ ├── api-key.ts # API key validation
169
+ │ │ └── jwt.ts # JWT validation + user client
170
+ │ ├── tools/
171
+ │ │ ├── index.ts # Tool registry
172
+ │ │ ├── get-availability.ts
173
+ │ │ └── schedule-appointment.ts
174
+ │ └── utils/
175
+ │ ├── supabase.ts # Supabase client factory
176
+ │ └── metering.ts # Usage logging
177
+ ├── wrangler.toml # Cloudflare config
178
+ └── package.json
179
+ ```
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Kntor MCP Client
4
+ *
5
+ * Stdio proxy that connects Claude Desktop to Kntor.io ERP.
6
+ * Handles MCP protocol communication over stdin/stdout.
7
+ *
8
+ * Usage:
9
+ * KNTOR_API_KEY=kntor_xxx npx kntor-mcp
10
+ *
11
+ * Configuration for Claude Desktop (claude_desktop_config.json):
12
+ * {
13
+ * "mcpServers": {
14
+ * "kntor-erp": {
15
+ * "command": "npx",
16
+ * "args": ["-y", "kntor-mcp"],
17
+ * "env": {
18
+ * "KNTOR_API_KEY": "kntor_your_api_key_here"
19
+ * }
20
+ * }
21
+ * }
22
+ * }
23
+ */
24
+
25
+ const SERVER_URL = process.env.KNTOR_MCP_URL || 'https://mcp.kntor.io/mcp';
26
+ const API_KEY = process.env.KNTOR_API_KEY;
27
+
28
+ // Validate API key
29
+ if (!API_KEY) {
30
+ const error = {
31
+ jsonrpc: '2.0',
32
+ id: null,
33
+ error: {
34
+ code: -32600,
35
+ message: 'KNTOR_API_KEY environment variable is required. Get your API key at https://kntor.io/settings/mcp'
36
+ }
37
+ };
38
+ console.log(JSON.stringify(error));
39
+ process.exit(1);
40
+ }
41
+
42
+ if (!API_KEY.startsWith('kntor_')) {
43
+ const error = {
44
+ jsonrpc: '2.0',
45
+ id: null,
46
+ error: {
47
+ code: -32600,
48
+ message: 'Invalid API key format. Key should start with "kntor_"'
49
+ }
50
+ };
51
+ console.log(JSON.stringify(error));
52
+ process.exit(1);
53
+ }
54
+
55
+ // Buffer for incomplete JSON messages
56
+ let buffer = '';
57
+
58
+ // Process stdin data
59
+ process.stdin.setEncoding('utf8');
60
+ process.stdin.on('data', async (chunk) => {
61
+ buffer += chunk;
62
+
63
+ // Process complete lines
64
+ const lines = buffer.split('\n');
65
+ buffer = lines.pop() || ''; // Keep incomplete line in buffer
66
+
67
+ for (const line of lines) {
68
+ if (!line.trim()) continue;
69
+
70
+ try {
71
+ const message = JSON.parse(line);
72
+ await handleMessage(message);
73
+ } catch (parseError) {
74
+ // Log parse errors to stderr (won't interfere with protocol)
75
+ console.error('[kntor-mcp] Parse error:', parseError.message);
76
+ }
77
+ }
78
+ });
79
+
80
+ // Handle a single MCP message
81
+ async function handleMessage(message) {
82
+ // Preserve the request id (use 0 as fallback, not null - Claude Desktop requires string/number)
83
+ const requestId = message.id !== undefined ? message.id : 0;
84
+
85
+ try {
86
+ console.error(`[kntor-mcp] Sending: ${message.method}`);
87
+
88
+ const response = await fetch(SERVER_URL, {
89
+ method: 'POST',
90
+ headers: {
91
+ 'Content-Type': 'application/json',
92
+ 'x-api-key': API_KEY
93
+ },
94
+ body: JSON.stringify(message)
95
+ });
96
+
97
+ const responseText = await response.text();
98
+ console.error(`[kntor-mcp] Response (${response.status}): ${responseText.substring(0, 200)}`);
99
+
100
+ if (!response.ok) {
101
+ let errorData;
102
+ try {
103
+ errorData = JSON.parse(responseText);
104
+ } catch {
105
+ errorData = { message: responseText };
106
+ }
107
+
108
+ const errorResponse = {
109
+ jsonrpc: '2.0',
110
+ id: requestId,
111
+ error: {
112
+ code: -32000,
113
+ message: `Server error (${response.status}): ${errorData.error?.message || errorData.message || responseText}`
114
+ }
115
+ };
116
+ console.log(JSON.stringify(errorResponse));
117
+ return;
118
+ }
119
+
120
+ let result;
121
+ try {
122
+ result = JSON.parse(responseText);
123
+ } catch {
124
+ const errorResponse = {
125
+ jsonrpc: '2.0',
126
+ id: requestId,
127
+ error: {
128
+ code: -32603,
129
+ message: `Invalid JSON response: ${responseText.substring(0, 100)}`
130
+ }
131
+ };
132
+ console.log(JSON.stringify(errorResponse));
133
+ return;
134
+ }
135
+
136
+ // Ensure the response has the correct id
137
+ if (result.id === null || result.id === undefined) {
138
+ result.id = requestId;
139
+ }
140
+
141
+ console.log(JSON.stringify(result));
142
+
143
+ } catch (networkError) {
144
+ console.error(`[kntor-mcp] Network error: ${networkError.message}`);
145
+ const errorResponse = {
146
+ jsonrpc: '2.0',
147
+ id: requestId,
148
+ error: {
149
+ code: -32603,
150
+ message: `Network error: ${networkError.message}`
151
+ }
152
+ };
153
+ console.log(JSON.stringify(errorResponse));
154
+ }
155
+ }
156
+
157
+ // Handle stdin close
158
+ process.stdin.on('end', () => {
159
+ process.exit(0);
160
+ });
161
+
162
+ // Handle process signals
163
+ process.on('SIGINT', () => process.exit(0));
164
+ process.on('SIGTERM', () => process.exit(0));
165
+
166
+ // Keep process alive
167
+ process.stdin.resume();
168
+
169
+ // Log startup to stderr (doesn't interfere with protocol)
170
+ console.error('[kntor-mcp] Connected to Kntor.io ERP');
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "kntor-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP client for Kntor.io ERP - Connect AI agents to your business management system",
5
+ "type": "module",
6
+ "bin": {
7
+ "kntor-mcp": "./bin/kntor-mcp.mjs"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "dev": "wrangler dev",
15
+ "deploy": "wrangler deploy",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "keywords": [
19
+ "mcp",
20
+ "model-context-protocol",
21
+ "kntor",
22
+ "healthcare",
23
+ "erp",
24
+ "ai",
25
+ "claude"
26
+ ],
27
+ "author": "Kntor.io",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/edgargomero/kntor-mcp-server"
32
+ },
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@cloudflare/workers-types": "^4.20241127.0",
38
+ "@modelcontextprotocol/sdk": "^1.0.4",
39
+ "typescript": "^5.8.3",
40
+ "wrangler": "^4.59.2",
41
+ "zod": "^3.22.4"
42
+ }
43
+ }