clokio-mcp 0.1.1 → 0.1.2

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/dist/client.js CHANGED
@@ -30,7 +30,16 @@ export function loadConfig() {
30
30
  * but passing them through is harmless.
31
31
  */
32
32
  export function seg(value) {
33
- return encodeURIComponent(String(value));
33
+ const s = String(value);
34
+ // encodeURIComponent leaves `.` alone, so a bare `.` or `..` would survive
35
+ // as a real dot-segment and be normalised away by new URL(). The prefix
36
+ // guard in request() already catches the escape; refusing here keeps the
37
+ // error at the argument that caused it, and an empty segment would silently
38
+ // collapse `/a//b` into `/a/b` and hit a neighbouring route.
39
+ if (s === '' || s === '.' || s === '..') {
40
+ throw new ClokioApiError(0, `Invalid path argument ${JSON.stringify(s)}.`);
41
+ }
42
+ return encodeURIComponent(s);
34
43
  }
35
44
  /** A Clokio API error, carrying the HTTP status and the server's message. */
36
45
  export class ClokioApiError extends Error {
@@ -88,7 +97,12 @@ export async function request(config, path, options = {}) {
88
97
  }
89
98
  let res;
90
99
  try {
91
- res = await fetch(url, { method, headers, body: payload });
100
+ // redirect: 'error' - Node's fetch follows redirects and RESENDS the
101
+ // request headers, including X-API-Key, to wherever Location points, on
102
+ // any origin. The API never redirects an /api/v1 call, so a redirect here
103
+ // means something between us and it is not the API, and the key must not
104
+ // be handed over. Failing closed costs nothing on the happy path.
105
+ res = await fetch(url, { method, headers, body: payload, redirect: 'error' });
92
106
  }
93
107
  catch (e) {
94
108
  throw new ClokioApiError(0, `Network error reaching Clokio: ${e.message}`);
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@
10
10
  * Or register with: claude mcp add clokio -- npx -y clokio-mcp
11
11
  * (set CLOKIO_API_KEY, and optionally CLOKIO_BASE_URL, in the MCP env).
12
12
  */
13
+ import { createRequire } from 'node:module';
13
14
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
14
15
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
15
16
  import { loadConfig } from './client.js';
@@ -17,11 +18,14 @@ import { registerTaskTools } from './tools/tasks.js';
17
18
  import { registerProjectTools } from './tools/projects.js';
18
19
  import { registerEmployeeTools } from './tools/employees.js';
19
20
  import { registerAttendanceTools } from './tools/attendance.js';
21
+ // The version the MCP handshake announces is package.json's, read at runtime -
22
+ // a literal here went stale on the first patch release (0.1.1 said 0.1.0).
23
+ const { version } = createRequire(import.meta.url)('../package.json');
20
24
  async function main() {
21
25
  const config = loadConfig();
22
26
  const server = new McpServer({
23
27
  name: 'clokio-mcp',
24
- version: '0.1.0',
28
+ version,
25
29
  });
26
30
  registerTaskTools(server, config);
27
31
  registerProjectTools(server, config);
@@ -16,7 +16,13 @@ export function registerTool(server, config, def) {
16
16
  content: [
17
17
  {
18
18
  type: 'text',
19
- text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
19
+ // A 204 (delete) has no body, so request() resolves undefined and
20
+ // JSON.stringify(undefined) is undefined - not a valid text block.
21
+ text: result === undefined
22
+ ? 'OK (no content)'
23
+ : typeof result === 'string'
24
+ ? result
25
+ : JSON.stringify(result, null, 2),
20
26
  },
21
27
  ],
22
28
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clokio-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Model Context Protocol (MCP) server for Clokio — manage tasks, projects, clients, employees and attendance from Claude and any MCP client.",
5
5
  "type": "module",
6
6
  "bin": {