@k-system/tickr-mcp 1.0.0 → 1.0.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.
@@ -4,6 +4,7 @@ import { homedir } from "node:os";
4
4
  const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10 MB
5
5
  const MAX_PARAMS_LENGTH = 200;
6
6
  let _debugEnabled = null;
7
+ let _versionLogged = false;
7
8
  /**
8
9
  * Zkontroluje zda je debug logování zapnuté (TICKR_DEBUG=true|1).
9
10
  */
@@ -36,6 +37,18 @@ export function debugLog(toolName, params, responseStatus, durationMs) {
36
37
  catch {
37
38
  // Soubor ještě neexistuje — ok
38
39
  }
40
+ // Zalogovat verzi MCP serveru při prvním volání
41
+ if (!_versionLogged) {
42
+ _versionLogged = true;
43
+ try {
44
+ const pkg = JSON.parse(require("node:fs").readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
45
+ const timestamp = new Date().toISOString();
46
+ appendFileSync(logPath, `[${timestamp}] [init] MCP server v${pkg.version} started (debug=true)\n`, "utf-8");
47
+ }
48
+ catch {
49
+ // package.json nenalezen — pokračuj bez verze
50
+ }
51
+ }
39
52
  // Zkrátit params na max 200 znaků
40
53
  let paramsStr = JSON.stringify(params);
41
54
  if (paramsStr.length > MAX_PARAMS_LENGTH) {
package/dist/server.js CHANGED
@@ -96,9 +96,10 @@ export async function startServer() {
96
96
  name: "tickr",
97
97
  version: "0.1.5",
98
98
  });
99
- // Dedup cache pro create operace — eliminuje race condition z double dispatch (4ms gap)
99
+ // Dedup cache pro create operace — eliminuje race condition z double dispatch (1-4ms gap)
100
100
  const MUTATING_PREFIXES = ["create_", "add_", "triage_accept", "triage_reject"];
101
101
  const dedupCache = new Map();
102
+ const pendingOps = new Map();
102
103
  const DEDUP_TTL_MS = 30_000; // 30 sekund
103
104
  // Obalení server.tool — dedup cache (vždy) + debug logging (volitelné)
104
105
  {
@@ -113,29 +114,58 @@ export async function startServer() {
113
114
  // Dedup pro mutující operace
114
115
  if (isMutating) {
115
116
  const hash = name + ":" + JSON.stringify(params);
117
+ // 1. Check completed cache
116
118
  const cached = dedupCache.get(hash);
117
119
  if (cached && Date.now() - cached.timestamp < DEDUP_TTL_MS) {
118
120
  if (debug)
119
121
  debugLog(name, (params ?? {}), "dedup-cached", 0);
120
122
  return cached.result;
121
123
  }
124
+ // 2. Check if another call with same params is already in-flight
125
+ const pending = pendingOps.get(hash);
126
+ if (pending) {
127
+ if (debug)
128
+ debugLog(name, (params ?? {}), "dedup-pending", 0);
129
+ return pending;
130
+ }
131
+ // 3. Mark as pending BEFORE starting async work — prevents race condition
132
+ const promise = (async () => {
133
+ const start = Date.now();
134
+ try {
135
+ const result = await originalHandler(params, extra);
136
+ // Cache úspěšné mutující výsledky
137
+ if (!result.isError) {
138
+ dedupCache.set(hash, { result, timestamp: Date.now() });
139
+ if (dedupCache.size > 100) {
140
+ const now = Date.now();
141
+ for (const [k, v] of dedupCache) {
142
+ if (now - v.timestamp > DEDUP_TTL_MS)
143
+ dedupCache.delete(k);
144
+ }
145
+ }
146
+ }
147
+ if (debug)
148
+ debugLog(name, (params ?? {}), result.isError ? "error" : "ok", Date.now() - start);
149
+ return result;
150
+ }
151
+ catch (err) {
152
+ if (debug)
153
+ debugLog(name, (params ?? {}), "error", Date.now() - start);
154
+ throw err;
155
+ }
156
+ })();
157
+ pendingOps.set(hash, promise);
158
+ try {
159
+ return await promise;
160
+ }
161
+ finally {
162
+ pendingOps.delete(hash);
163
+ }
122
164
  }
165
+ // Non-mutating operace — bez dedup
123
166
  const start = Date.now();
124
167
  try {
125
168
  const result = await originalHandler(params, extra);
126
- // Cache úspěšné mutující výsledky
127
- if (isMutating && !result.isError) {
128
- const hash = name + ":" + JSON.stringify(params);
129
- dedupCache.set(hash, { result, timestamp: Date.now() });
130
- // Cleanup starých záznamů
131
- if (dedupCache.size > 100) {
132
- const now = Date.now();
133
- for (const [k, v] of dedupCache) {
134
- if (now - v.timestamp > DEDUP_TTL_MS)
135
- dedupCache.delete(k);
136
- }
137
- }
138
- }
139
169
  if (debug)
140
170
  debugLog(name, (params ?? {}), result.isError ? "error" : "ok", Date.now() - start);
141
171
  return result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-system/tickr-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "MCP server for Tickr project management — 56 tools + setup CLI wizard",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",