@k-system/tickr-mcp 1.22.0 → 1.23.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/dist/auth.d.ts +9 -2
- package/dist/auth.js +61 -5
- package/dist/config.d.ts +4 -0
- package/dist/config.js +9 -3
- package/dist/device-grant.d.ts +53 -0
- package/dist/device-grant.js +194 -0
- package/dist/server.js +4 -1
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -10,9 +10,16 @@ export declare function login(config: TickrConfig, username: string, password: s
|
|
|
10
10
|
export declare function refreshToken(config: TickrConfig): Promise<TokenPair>;
|
|
11
11
|
/**
|
|
12
12
|
* Vrátí Authorization header value.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* Priorita:
|
|
14
|
+
* 1. API key (tkr_...) — přímé použití, žádná expiry
|
|
15
|
+
* 2. Device Grant session (~/.tickr/sessions/) — auto-refresh
|
|
16
|
+
* 3. JWT token (login/password) — auto-refresh
|
|
15
17
|
*/
|
|
16
18
|
export declare function getAuthHeader(config: TickrConfig): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Inicializace device grant session při startu serveru.
|
|
21
|
+
* Načte existující session z disku — pokud existuje a je platná, nastaví cache.
|
|
22
|
+
*/
|
|
23
|
+
export declare function initDeviceGrantSession(config: TickrConfig): void;
|
|
17
24
|
export {};
|
|
18
25
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/auth.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { getDeviceGrantToken, loadSession, refreshAccessToken, saveSession, } from "./device-grant.js";
|
|
1
2
|
let currentTokens = null;
|
|
3
|
+
// Aktuální device grant session (pokud je aktivní)
|
|
4
|
+
let activeSession = null;
|
|
2
5
|
/** Přihlášení přes username/password — vrátí JWT token pair */
|
|
3
6
|
export async function login(config, username, password) {
|
|
4
7
|
const res = await fetch(`${config.apiUrl}/api/auth/login`, {
|
|
@@ -40,21 +43,74 @@ export async function refreshToken(config) {
|
|
|
40
43
|
}
|
|
41
44
|
/**
|
|
42
45
|
* Vrátí Authorization header value.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
46
|
+
* Priorita:
|
|
47
|
+
* 1. API key (tkr_...) — přímé použití, žádná expiry
|
|
48
|
+
* 2. Device Grant session (~/.tickr/sessions/) — auto-refresh
|
|
49
|
+
* 3. JWT token (login/password) — auto-refresh
|
|
45
50
|
*/
|
|
46
51
|
export async function getAuthHeader(config) {
|
|
47
|
-
// API key auth — jednoduché, bez expiry
|
|
52
|
+
// 1. API key auth — jednoduché, bez expiry
|
|
48
53
|
if (config.apiKey) {
|
|
49
54
|
return `Bearer ${config.apiKey}`;
|
|
50
55
|
}
|
|
51
|
-
//
|
|
56
|
+
// 2. Device Grant session — auto-refresh
|
|
57
|
+
if (config.tenantId && config.agentName) {
|
|
58
|
+
return `Bearer ${await getDeviceGrantAuthToken(config)}`;
|
|
59
|
+
}
|
|
60
|
+
// 3. JWT auth — refresh pokud token brzy vyprší (30s buffer)
|
|
52
61
|
if (currentTokens && currentTokens.expiresAt - Date.now() < 30_000) {
|
|
53
62
|
await refreshToken(config);
|
|
54
63
|
}
|
|
55
64
|
if (!currentTokens) {
|
|
56
|
-
throw new Error("Not authenticated — set TICKR_API_KEY or
|
|
65
|
+
throw new Error("Not authenticated — set TICKR_API_KEY or configure device grant");
|
|
57
66
|
}
|
|
58
67
|
return `Bearer ${currentTokens.accessToken}`;
|
|
59
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Device Grant auth token s auto-refresh a auto-pairing.
|
|
71
|
+
* Pokud session neexistuje, spustí interaktivní pairing flow.
|
|
72
|
+
*/
|
|
73
|
+
async function getDeviceGrantAuthToken(config) {
|
|
74
|
+
// Zkus cache
|
|
75
|
+
if (activeSession && activeSession.expiresAt - Date.now() > 30_000) {
|
|
76
|
+
return activeSession.accessToken;
|
|
77
|
+
}
|
|
78
|
+
// Zkus refresh existující session
|
|
79
|
+
if (activeSession && activeSession.refreshToken) {
|
|
80
|
+
try {
|
|
81
|
+
const result = await refreshAccessToken(config, activeSession.refreshToken);
|
|
82
|
+
activeSession = {
|
|
83
|
+
accessToken: result.access_token,
|
|
84
|
+
refreshToken: result.refresh_token,
|
|
85
|
+
expiresAt: Date.now() + result.expires_in * 1000,
|
|
86
|
+
agentIdentity: result.agent_identity,
|
|
87
|
+
apiUrl: config.apiUrl,
|
|
88
|
+
tenantId: config.tenantId,
|
|
89
|
+
};
|
|
90
|
+
saveSession(config.agentName, activeSession);
|
|
91
|
+
return activeSession.accessToken;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
activeSession = null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Načti z disku nebo spusť pairing
|
|
98
|
+
const token = await getDeviceGrantToken(config, config.agentName, config.tenantId);
|
|
99
|
+
// Aktualizuj cache
|
|
100
|
+
activeSession = loadSession(config.agentName);
|
|
101
|
+
return token;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Inicializace device grant session při startu serveru.
|
|
105
|
+
* Načte existující session z disku — pokud existuje a je platná, nastaví cache.
|
|
106
|
+
*/
|
|
107
|
+
export function initDeviceGrantSession(config) {
|
|
108
|
+
if (!config.agentName || !config.tenantId)
|
|
109
|
+
return;
|
|
110
|
+
const session = loadSession(config.agentName);
|
|
111
|
+
if (session) {
|
|
112
|
+
activeSession = session;
|
|
113
|
+
console.error(`[tickr] ✓ Connected as ${session.agentIdentity}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
60
116
|
//# sourceMappingURL=auth.js.map
|
package/dist/config.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ export interface TickrConfig {
|
|
|
2
2
|
apiUrl: string;
|
|
3
3
|
apiKey?: string;
|
|
4
4
|
defaultProject?: string;
|
|
5
|
+
/** Tenant ID pro device grant auth (UUID) */
|
|
6
|
+
tenantId?: string;
|
|
7
|
+
/** Jméno agenta pro device grant session storage */
|
|
8
|
+
agentName?: string;
|
|
5
9
|
}
|
|
6
10
|
/** Načte konfiguraci z env vars nebo ~/.tickr/config.json */
|
|
7
11
|
export declare function loadConfig(): TickrConfig;
|
package/dist/config.js
CHANGED
|
@@ -6,9 +6,11 @@ export function loadConfig() {
|
|
|
6
6
|
const apiUrl = process.env.TICKR_API_URL;
|
|
7
7
|
const apiKey = process.env.TICKR_API_KEY;
|
|
8
8
|
const defaultProject = process.env.TICKR_DEFAULT_PROJECT;
|
|
9
|
+
const tenantId = process.env.TICKR_TENANT_ID;
|
|
10
|
+
const agentName = process.env.TICKR_AGENT_NAME;
|
|
9
11
|
// Env vars mají prioritu
|
|
10
12
|
if (apiUrl && apiKey) {
|
|
11
|
-
const config = { apiUrl, apiKey, defaultProject };
|
|
13
|
+
const config = { apiUrl, apiKey, defaultProject, tenantId, agentName };
|
|
12
14
|
validateConfig(config);
|
|
13
15
|
return config;
|
|
14
16
|
}
|
|
@@ -21,6 +23,8 @@ export function loadConfig() {
|
|
|
21
23
|
apiUrl: apiUrl || file.apiUrl || "https://localhost:6001",
|
|
22
24
|
apiKey: apiKey || file.apiKey || "",
|
|
23
25
|
defaultProject: defaultProject || file.defaultProject,
|
|
26
|
+
tenantId: tenantId || file.tenantId,
|
|
27
|
+
agentName: agentName || file.agentName,
|
|
24
28
|
};
|
|
25
29
|
validateConfig(config);
|
|
26
30
|
return config;
|
|
@@ -31,6 +35,8 @@ export function loadConfig() {
|
|
|
31
35
|
apiUrl: apiUrl || "https://localhost:6001",
|
|
32
36
|
apiKey: apiKey || "",
|
|
33
37
|
defaultProject,
|
|
38
|
+
tenantId,
|
|
39
|
+
agentName,
|
|
34
40
|
};
|
|
35
41
|
validateConfig(config);
|
|
36
42
|
return config;
|
|
@@ -38,8 +44,8 @@ export function loadConfig() {
|
|
|
38
44
|
}
|
|
39
45
|
/** Validace konfigurace — loguje varování pro problematické hodnoty */
|
|
40
46
|
function validateConfig(config) {
|
|
41
|
-
if (!config.apiKey) {
|
|
42
|
-
console.error("[tickr-mcp] WARNING: No API key configured —
|
|
47
|
+
if (!config.apiKey && !config.tenantId) {
|
|
48
|
+
console.error("[tickr-mcp] WARNING: No API key or tenant ID configured — set TICKR_API_KEY or TICKR_TENANT_ID + TICKR_AGENT_NAME for device grant");
|
|
43
49
|
}
|
|
44
50
|
if (config.apiUrl && !config.apiUrl.startsWith("http://") && !config.apiUrl.startsWith("https://")) {
|
|
45
51
|
console.error(`[tickr-mcp] WARNING: apiUrl "${config.apiUrl}" doesn't start with http(s)://`);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { TickrConfig } from "./config.js";
|
|
2
|
+
interface DeviceCodeResponse {
|
|
3
|
+
device_code: string;
|
|
4
|
+
user_code: string;
|
|
5
|
+
verification_uri: string;
|
|
6
|
+
interval: number;
|
|
7
|
+
expires_in: number;
|
|
8
|
+
}
|
|
9
|
+
interface TokenResponse {
|
|
10
|
+
access_token: string;
|
|
11
|
+
token_type: string;
|
|
12
|
+
expires_in: number;
|
|
13
|
+
refresh_token: string;
|
|
14
|
+
agent_identity: string;
|
|
15
|
+
}
|
|
16
|
+
export interface StoredSession {
|
|
17
|
+
accessToken: string;
|
|
18
|
+
refreshToken: string;
|
|
19
|
+
expiresAt: number;
|
|
20
|
+
agentIdentity: string;
|
|
21
|
+
apiUrl: string;
|
|
22
|
+
tenantId: string;
|
|
23
|
+
}
|
|
24
|
+
/** Načte uloženou session — vrátí null pokud neexistuje nebo je poškozená */
|
|
25
|
+
export declare function loadSession(agentName: string): StoredSession | null;
|
|
26
|
+
/** Uloží session na disk */
|
|
27
|
+
export declare function saveSession(agentName: string, session: StoredSession): void;
|
|
28
|
+
/** Smaže uloženou session */
|
|
29
|
+
export declare function clearSession(agentName: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Zahájí device authorization flow — vrátí device code a user code.
|
|
32
|
+
* Agent zobrazí user code v terminálu, člověk ho zadá v browseru.
|
|
33
|
+
*/
|
|
34
|
+
export declare function initiateDeviceGrant(config: TickrConfig, tenantId: string): Promise<DeviceCodeResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* Polluje /oauth/token dokud člověk neschválí párování.
|
|
37
|
+
* Vrátí access + refresh token, nebo vyhodí chybu při expiraci/zamítnutí.
|
|
38
|
+
*/
|
|
39
|
+
export declare function pollForDeviceGrant(config: TickrConfig, deviceCode: string, interval: number, expiresIn: number, onStatus?: (message: string) => void): Promise<TokenResponse>;
|
|
40
|
+
/**
|
|
41
|
+
* Obnoví access token přes refresh token grant.
|
|
42
|
+
* Vrátí nový token pár (rotace — starý refresh token je zneplatněn).
|
|
43
|
+
*/
|
|
44
|
+
export declare function refreshAccessToken(config: TickrConfig, refreshToken: string): Promise<TokenResponse>;
|
|
45
|
+
/**
|
|
46
|
+
* Hlavní entry point: získej platný access token.
|
|
47
|
+
* 1. Pokud existuje uložená session a token je platný → vrať
|
|
48
|
+
* 2. Pokud token expiruje → auto-refresh
|
|
49
|
+
* 3. Pokud refresh selže → spusť device grant flow
|
|
50
|
+
*/
|
|
51
|
+
export declare function getDeviceGrantToken(config: TickrConfig, agentName: string, tenantId: string, onPairingRequired?: (userCode: string, verificationUri: string) => void): Promise<string>;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=device-grant.d.ts.map
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
// --- Session storage ---
|
|
5
|
+
const SESSIONS_DIR = join(homedir(), ".tickr", "sessions");
|
|
6
|
+
function ensureSessionsDir() {
|
|
7
|
+
if (!existsSync(SESSIONS_DIR)) {
|
|
8
|
+
mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function sessionPath(agentName) {
|
|
12
|
+
const safe = agentName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
13
|
+
return join(SESSIONS_DIR, `${safe}.json`);
|
|
14
|
+
}
|
|
15
|
+
/** Načte uloženou session — vrátí null pokud neexistuje nebo je poškozená */
|
|
16
|
+
export function loadSession(agentName) {
|
|
17
|
+
try {
|
|
18
|
+
const path = sessionPath(agentName);
|
|
19
|
+
if (!existsSync(path))
|
|
20
|
+
return null;
|
|
21
|
+
const raw = readFileSync(path, "utf-8");
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Uloží session na disk */
|
|
29
|
+
export function saveSession(agentName, session) {
|
|
30
|
+
ensureSessionsDir();
|
|
31
|
+
const path = sessionPath(agentName);
|
|
32
|
+
writeFileSync(path, JSON.stringify(session, null, 2), { mode: 0o600 });
|
|
33
|
+
}
|
|
34
|
+
/** Smaže uloženou session */
|
|
35
|
+
export function clearSession(agentName) {
|
|
36
|
+
try {
|
|
37
|
+
const path = sessionPath(agentName);
|
|
38
|
+
if (existsSync(path)) {
|
|
39
|
+
const { unlinkSync } = require("node:fs");
|
|
40
|
+
unlinkSync(path);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Ignoruj
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// --- Device Authorization Grant flow ---
|
|
48
|
+
/**
|
|
49
|
+
* Zahájí device authorization flow — vrátí device code a user code.
|
|
50
|
+
* Agent zobrazí user code v terminálu, člověk ho zadá v browseru.
|
|
51
|
+
*/
|
|
52
|
+
export async function initiateDeviceGrant(config, tenantId) {
|
|
53
|
+
const res = await fetch(`${config.apiUrl}/oauth/device/authorize`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: { "Content-Type": "application/json" },
|
|
56
|
+
body: JSON.stringify({ clientId: "claude-agent", tenantId }),
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
const body = await res.text();
|
|
60
|
+
throw new Error(`Device authorization failed: ${res.status} — ${body}`);
|
|
61
|
+
}
|
|
62
|
+
return (await res.json()).data;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Polluje /oauth/token dokud člověk neschválí párování.
|
|
66
|
+
* Vrátí access + refresh token, nebo vyhodí chybu při expiraci/zamítnutí.
|
|
67
|
+
*/
|
|
68
|
+
export async function pollForDeviceGrant(config, deviceCode, interval, expiresIn, onStatus) {
|
|
69
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
70
|
+
while (Date.now() < deadline) {
|
|
71
|
+
await sleep(interval * 1000);
|
|
72
|
+
try {
|
|
73
|
+
const res = await fetch(`${config.apiUrl}/oauth/token`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "Content-Type": "application/json" },
|
|
76
|
+
body: JSON.stringify({
|
|
77
|
+
grantType: "urn:ietf:params:oauth:grant-type:device_code",
|
|
78
|
+
deviceCode,
|
|
79
|
+
}),
|
|
80
|
+
});
|
|
81
|
+
if (res.ok) {
|
|
82
|
+
return (await res.json());
|
|
83
|
+
}
|
|
84
|
+
const error = (await res.json());
|
|
85
|
+
if (error.error === "authorization_pending") {
|
|
86
|
+
onStatus?.("Waiting for approval...");
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (error.error === "slow_down") {
|
|
90
|
+
interval = Math.min(interval + 1, 15);
|
|
91
|
+
onStatus?.("Slowing down polling...");
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (error.error === "expired_token") {
|
|
95
|
+
throw new Error("Device code expired — please try pairing again");
|
|
96
|
+
}
|
|
97
|
+
if (error.error === "access_denied") {
|
|
98
|
+
throw new Error("Pairing denied by user");
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Token exchange error: ${error.error} — ${error.error_description}`);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
if (err instanceof Error && (err.message.includes("expired") || err.message.includes("denied"))) {
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
// Síťová chyba — pokračuj v pollingu
|
|
107
|
+
onStatus?.("Connection error, retrying...");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
throw new Error("Device code expired — please try pairing again");
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Obnoví access token přes refresh token grant.
|
|
114
|
+
* Vrátí nový token pár (rotace — starý refresh token je zneplatněn).
|
|
115
|
+
*/
|
|
116
|
+
export async function refreshAccessToken(config, refreshToken) {
|
|
117
|
+
const res = await fetch(`${config.apiUrl}/oauth/token`, {
|
|
118
|
+
method: "POST",
|
|
119
|
+
headers: { "Content-Type": "application/json" },
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
grantType: "refresh_token",
|
|
122
|
+
refreshToken,
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
if (!res.ok) {
|
|
126
|
+
const body = await res.text();
|
|
127
|
+
throw new Error(`Token refresh failed: ${res.status} — ${body}`);
|
|
128
|
+
}
|
|
129
|
+
return (await res.json());
|
|
130
|
+
}
|
|
131
|
+
// --- Integrační funkce ---
|
|
132
|
+
/**
|
|
133
|
+
* Hlavní entry point: získej platný access token.
|
|
134
|
+
* 1. Pokud existuje uložená session a token je platný → vrať
|
|
135
|
+
* 2. Pokud token expiruje → auto-refresh
|
|
136
|
+
* 3. Pokud refresh selže → spusť device grant flow
|
|
137
|
+
*/
|
|
138
|
+
export async function getDeviceGrantToken(config, agentName, tenantId, onPairingRequired) {
|
|
139
|
+
// Zkus načíst existující session
|
|
140
|
+
let session = loadSession(agentName);
|
|
141
|
+
if (session) {
|
|
142
|
+
// Token ještě platný (30s buffer)
|
|
143
|
+
if (session.expiresAt - Date.now() > 30_000) {
|
|
144
|
+
return session.accessToken;
|
|
145
|
+
}
|
|
146
|
+
// Zkus refresh
|
|
147
|
+
try {
|
|
148
|
+
const result = await refreshAccessToken(config, session.refreshToken);
|
|
149
|
+
session = {
|
|
150
|
+
accessToken: result.access_token,
|
|
151
|
+
refreshToken: result.refresh_token,
|
|
152
|
+
expiresAt: Date.now() + result.expires_in * 1000,
|
|
153
|
+
agentIdentity: result.agent_identity,
|
|
154
|
+
apiUrl: config.apiUrl,
|
|
155
|
+
tenantId,
|
|
156
|
+
};
|
|
157
|
+
saveSession(agentName, session);
|
|
158
|
+
return session.accessToken;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Refresh selhal — session expirovala, potřebujeme nové párování
|
|
162
|
+
clearSession(agentName);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Žádná platná session — spusť device grant flow
|
|
166
|
+
const deviceResponse = await initiateDeviceGrant(config, tenantId);
|
|
167
|
+
// Oznám uživateli
|
|
168
|
+
if (onPairingRequired) {
|
|
169
|
+
onPairingRequired(deviceResponse.user_code, deviceResponse.verification_uri);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
console.error(`[tickr] Agent is not paired.`);
|
|
173
|
+
console.error(`[tickr] Open ${deviceResponse.verification_uri}`);
|
|
174
|
+
console.error(`[tickr] Enter code: ${deviceResponse.user_code}`);
|
|
175
|
+
console.error(`[tickr] Waiting for approval... (expires in ${Math.round(deviceResponse.expires_in / 60)} min)`);
|
|
176
|
+
}
|
|
177
|
+
const tokenResponse = await pollForDeviceGrant(config, deviceResponse.device_code, deviceResponse.interval, deviceResponse.expires_in, (msg) => console.error(`[tickr] ${msg}`));
|
|
178
|
+
// Ulož session
|
|
179
|
+
const newSession = {
|
|
180
|
+
accessToken: tokenResponse.access_token,
|
|
181
|
+
refreshToken: tokenResponse.refresh_token,
|
|
182
|
+
expiresAt: Date.now() + tokenResponse.expires_in * 1000,
|
|
183
|
+
agentIdentity: tokenResponse.agent_identity,
|
|
184
|
+
apiUrl: config.apiUrl,
|
|
185
|
+
tenantId,
|
|
186
|
+
};
|
|
187
|
+
saveSession(agentName, newSession);
|
|
188
|
+
console.error(`[tickr] ✓ Paired as ${tokenResponse.agent_identity}`);
|
|
189
|
+
return newSession.accessToken;
|
|
190
|
+
}
|
|
191
|
+
function sleep(ms) {
|
|
192
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=device-grant.js.map
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { loadConfig } from "./config.js";
|
|
4
|
+
import { initDeviceGrantSession } from "./auth.js";
|
|
4
5
|
import { ApiClient } from "./api-client.js";
|
|
5
6
|
import { debugLog, isDebugEnabled } from "./debug-logger.js";
|
|
6
7
|
// Tools
|
|
@@ -98,6 +99,8 @@ import { registerPendingTasksResource } from "./resources/pending-tasks-resource
|
|
|
98
99
|
import { initSignalRClient, stopSignalRClient } from "./signalr-client.js";
|
|
99
100
|
export async function startServer() {
|
|
100
101
|
const config = loadConfig();
|
|
102
|
+
// Inicializace device grant session (pokud je konfigurována)
|
|
103
|
+
initDeviceGrantSession(config);
|
|
101
104
|
const api = new ApiClient(config);
|
|
102
105
|
// Startup health check — ověření dostupnosti API
|
|
103
106
|
const healthy = await api.healthCheck();
|
|
@@ -109,7 +112,7 @@ export async function startServer() {
|
|
|
109
112
|
}
|
|
110
113
|
const server = new McpServer({
|
|
111
114
|
name: "tickr",
|
|
112
|
-
version: "1.
|
|
115
|
+
version: "1.23.0",
|
|
113
116
|
});
|
|
114
117
|
// Debug logging wrapper (dedup odstraněn — nefunkční cross-process, řeší se na API straně: TKR-ADR-0043)
|
|
115
118
|
{
|