mcp-zenskar 1.0.7 → 1.0.8
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 +30 -1
- package/package.json +1 -1
- package/src/server.js +51 -14
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/
|
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
> You can omit one or both environment variables from the config, but the server will error until Claude supplies them in a tool call. Keeping them in the env block prevents repeated credential prompts.
|
|
36
|
+
|
|
35
37
|
### For Other AI Applications
|
|
36
38
|
|
|
37
39
|
Install globally:
|
|
@@ -56,6 +58,8 @@ This MCP server requires two authentication parameters for every request:
|
|
|
56
58
|
1. **Organization ID**: Available in your Zenskar dashboard settings
|
|
57
59
|
2. **API Token**: Generate from Zenskar dashboard → Settings → API Keys
|
|
58
60
|
|
|
61
|
+
At runtime the server looks for these values in the tool invocation first, then falls back to the `ZENSKAR_ORGANIZATION` and `ZENSKAR_AUTH_TOKEN` environment variables. Tokens that look like JWTs are sent as `Authorization: Bearer ...`; everything else is sent as an `x-api-key` header automatically.
|
|
62
|
+
|
|
59
63
|
## Usage
|
|
60
64
|
|
|
61
65
|
### In Claude Desktop
|
|
@@ -114,6 +118,31 @@ npm install
|
|
|
114
118
|
npm start
|
|
115
119
|
```
|
|
116
120
|
|
|
121
|
+
### Developing Locally Without Publishing
|
|
122
|
+
|
|
123
|
+
If you want Claude Desktop to use a local checkout instead of the npm package:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Install dependencies once
|
|
127
|
+
npm install
|
|
128
|
+
|
|
129
|
+
# Optional: install the local build globally
|
|
130
|
+
npm install -g .
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Then either point Claude to the globally-installed binary (usually `$(npm bin -g)/mcp-zenskar`) or call the repo copy directly:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"command": "node",
|
|
138
|
+
"args": ["/absolute/path/to/mcp-zenskar/src/server.js"],
|
|
139
|
+
"env": {
|
|
140
|
+
"ZENSKAR_ORGANIZATION": "your-org-id",
|
|
141
|
+
"ZENSKAR_AUTH_TOKEN": "your-token"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
117
146
|
## Configuration
|
|
118
147
|
|
|
119
148
|
The server uses `src/mcp-config.json` to define available tools and API endpoints. This file contains the complete mapping of MCP tools to Zenskar API operations.
|
|
@@ -126,4 +155,4 @@ MIT
|
|
|
126
155
|
|
|
127
156
|
For issues and support:
|
|
128
157
|
- GitHub Issues: https://github.com/zenskar/mcp-zenskar/issues
|
|
129
|
-
- Zenskar Documentation: https://docs.zenskar.com
|
|
158
|
+
- Zenskar Documentation: https://docs.zenskar.com
|
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -64,11 +64,44 @@ function normalizeUsageEventPayload(eventPayload) {
|
|
|
64
64
|
return normalized;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
function resolveCredentialValue(providedValue, envValue) {
|
|
68
|
+
if (typeof providedValue === 'string' && providedValue.trim().length > 0) {
|
|
69
|
+
return providedValue.trim();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (typeof envValue === 'string' && envValue.trim().length > 0) {
|
|
73
|
+
return envValue.trim();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildAuthHeaders(rawToken) {
|
|
80
|
+
if (!rawToken) {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const token = rawToken.trim();
|
|
85
|
+
if (!token) {
|
|
86
|
+
return {};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (token.toLowerCase().startsWith('bearer ')) {
|
|
90
|
+
return { 'Authorization': token };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Basic JWT heuristic: three dot-separated segments
|
|
94
|
+
const isLikelyJwt = token.split('.').length === 3;
|
|
95
|
+
if (isLikelyJwt) {
|
|
96
|
+
return { 'Authorization': `Bearer ${token}` };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (token.toLowerCase().startsWith('x-api-key ')) {
|
|
100
|
+
return { 'x-api-key': token.substring('x-api-key '.length).trim() };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { 'x-api-key': token };
|
|
104
|
+
}
|
|
72
105
|
|
|
73
106
|
class ZenskarMcpServer {
|
|
74
107
|
constructor() {
|
|
@@ -107,8 +140,8 @@ class ZenskarMcpServer {
|
|
|
107
140
|
|
|
108
141
|
generateInputSchema(tool) {
|
|
109
142
|
const schemaObj = {
|
|
110
|
-
organization: z.string().describe("Organization ID for multi-tenant API access (
|
|
111
|
-
authorization: z.string().describe("
|
|
143
|
+
organization: z.string().describe("Organization ID for multi-tenant API access (defaults to ZENSKAR_ORGANIZATION env when omitted)").optional(),
|
|
144
|
+
authorization: z.string().describe("Auth token (JWT -> Authorization Bearer, API key -> x-api-key). Defaults to ZENSKAR_AUTH_TOKEN env when omitted").optional()
|
|
112
145
|
};
|
|
113
146
|
|
|
114
147
|
// Add tool-specific arguments
|
|
@@ -151,24 +184,28 @@ class ZenskarMcpServer {
|
|
|
151
184
|
// Extract authentication from arguments
|
|
152
185
|
const { organization, authorization, ...toolArgs } = args;
|
|
153
186
|
|
|
187
|
+
const resolvedOrganization = resolveCredentialValue(organization, process.env.ZENSKAR_ORGANIZATION);
|
|
188
|
+
const resolvedAuthorization = resolveCredentialValue(authorization, process.env.ZENSKAR_AUTH_TOKEN);
|
|
189
|
+
|
|
154
190
|
// Validate required authentication
|
|
155
|
-
if (!
|
|
156
|
-
throw new Error('Organization ID is required for API access');
|
|
191
|
+
if (!resolvedOrganization) {
|
|
192
|
+
throw new Error('Organization ID is required for API access. Provide it in the tool input or set ZENSKAR_ORGANIZATION in the environment.');
|
|
157
193
|
}
|
|
158
|
-
if (!
|
|
159
|
-
throw new Error('Authorization token is required for API access');
|
|
194
|
+
if (!resolvedAuthorization) {
|
|
195
|
+
throw new Error('Authorization token is required for API access. Provide it in the tool input or set ZENSKAR_AUTH_TOKEN in the environment.');
|
|
160
196
|
}
|
|
161
197
|
|
|
162
|
-
logger.info(`[${tool.name}] Executing with organization: ${
|
|
198
|
+
logger.info(`[${tool.name}] Executing with organization: ${resolvedOrganization.substring(0, 10)}...`);
|
|
163
199
|
|
|
164
200
|
// Build headers
|
|
165
201
|
const headers = {
|
|
166
202
|
'Content-Type': 'application/json',
|
|
167
203
|
'Accept': 'application/json',
|
|
168
|
-
'organisation':
|
|
169
|
-
'Authorization': authorization.startsWith('Bearer ') ? authorization : `Bearer ${authorization}`
|
|
204
|
+
'organisation': resolvedOrganization // Note: API uses 'organisation' not 'organization'
|
|
170
205
|
};
|
|
171
206
|
|
|
207
|
+
Object.assign(headers, buildAuthHeaders(resolvedAuthorization));
|
|
208
|
+
|
|
172
209
|
// Build URL from requestTemplate
|
|
173
210
|
let url = `${config.server.baseUrl}${tool.requestTemplate.url}`;
|
|
174
211
|
const method = tool.requestTemplate.method;
|