@snokam/mcp-api 0.6.0 → 0.7.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/index.js +105 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { getAccessToken } from "./auth.js";
|
|
|
17
17
|
let currentEnvironment = process.env.SNOKAM_ENVIRONMENT ?? "production";
|
|
18
18
|
let endpoints = [];
|
|
19
19
|
let endpointsByTool = new Map();
|
|
20
|
+
const serviceUrlOverrides = new Map();
|
|
20
21
|
async function loadEndpoints(environment) {
|
|
21
22
|
currentEnvironment = environment;
|
|
22
23
|
endpoints = await fetchSpecs(environment);
|
|
@@ -24,6 +25,16 @@ async function loadEndpoints(environment) {
|
|
|
24
25
|
for (const ep of endpoints) {
|
|
25
26
|
endpointsByTool.set(ep.toolName, ep);
|
|
26
27
|
}
|
|
28
|
+
// Re-apply any active URL overrides
|
|
29
|
+
applyUrlOverrides();
|
|
30
|
+
}
|
|
31
|
+
function applyUrlOverrides() {
|
|
32
|
+
for (const ep of endpoints) {
|
|
33
|
+
const override = serviceUrlOverrides.get(ep.service);
|
|
34
|
+
if (override) {
|
|
35
|
+
ep.baseUrl = override;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
27
38
|
}
|
|
28
39
|
// ---------------------------------------------------------------------------
|
|
29
40
|
// Built-in tool: SwitchEnvironment
|
|
@@ -46,6 +57,42 @@ const switchToolDef = {
|
|
|
46
57
|
},
|
|
47
58
|
};
|
|
48
59
|
// ---------------------------------------------------------------------------
|
|
60
|
+
// Built-in tool: SetServiceUrl
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
const SET_URL_TOOL_NAME = "SetServiceUrl";
|
|
63
|
+
const RESET_URL_TOOL_NAME = "ResetServiceUrl";
|
|
64
|
+
const setUrlToolDef = {
|
|
65
|
+
name: SET_URL_TOOL_NAME,
|
|
66
|
+
description: "Override a service's base URL, e.g. to point to a locally running function. Auth is skipped for localhost URLs. Use ResetServiceUrl to revert.",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
service: {
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "The service name (e.g. employees, notifications, events)",
|
|
73
|
+
},
|
|
74
|
+
url: {
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "The base URL to use (e.g. http://localhost:7071)",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
required: ["service", "url"],
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
const resetUrlToolDef = {
|
|
83
|
+
name: RESET_URL_TOOL_NAME,
|
|
84
|
+
description: "Reset a service's base URL back to the environment default. Call without arguments to reset all overrides.",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: {
|
|
88
|
+
service: {
|
|
89
|
+
type: "string",
|
|
90
|
+
description: "The service name to reset. Omit to reset all overrides.",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
49
96
|
// JSON Schema builder for tool inputs
|
|
50
97
|
// ---------------------------------------------------------------------------
|
|
51
98
|
function buildInputSchema(endpoint) {
|
|
@@ -114,9 +161,12 @@ async function executeCall(endpoint, args) {
|
|
|
114
161
|
const headers = {
|
|
115
162
|
Accept: "application/json",
|
|
116
163
|
};
|
|
117
|
-
const
|
|
118
|
-
if (
|
|
119
|
-
|
|
164
|
+
const isLocal = url.startsWith("http://localhost") || url.startsWith("http://127.0.0.1");
|
|
165
|
+
if (!isLocal) {
|
|
166
|
+
const token = await getAccessToken(endpoint.scope);
|
|
167
|
+
if (token) {
|
|
168
|
+
headers.Authorization = `Bearer ${token}`;
|
|
169
|
+
}
|
|
120
170
|
}
|
|
121
171
|
let fetchBody;
|
|
122
172
|
if (args.body !== undefined && endpoint.method !== "GET") {
|
|
@@ -246,6 +296,8 @@ Controls: Sonos speakers, lights, YouTube queue
|
|
|
246
296
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
247
297
|
tools: [
|
|
248
298
|
switchToolDef,
|
|
299
|
+
setUrlToolDef,
|
|
300
|
+
resetUrlToolDef,
|
|
249
301
|
...endpoints.map((ep) => ({
|
|
250
302
|
name: ep.toolName,
|
|
251
303
|
description: ep.description || ep.summary || `${ep.method} ${ep.path}`,
|
|
@@ -292,6 +344,56 @@ Controls: Sonos speakers, lights, YouTube queue
|
|
|
292
344
|
],
|
|
293
345
|
};
|
|
294
346
|
}
|
|
347
|
+
// Handle SetServiceUrl
|
|
348
|
+
if (name === SET_URL_TOOL_NAME) {
|
|
349
|
+
const service = String(args.service ?? "");
|
|
350
|
+
const url = String(args.url ?? "");
|
|
351
|
+
const serviceEndpoints = endpoints.filter((ep) => ep.service === service);
|
|
352
|
+
if (serviceEndpoints.length === 0) {
|
|
353
|
+
const available = [
|
|
354
|
+
...new Set(endpoints.map((ep) => ep.service)),
|
|
355
|
+
].sort();
|
|
356
|
+
return {
|
|
357
|
+
content: [
|
|
358
|
+
{
|
|
359
|
+
type: "text",
|
|
360
|
+
text: `Unknown service: ${service}. Available: ${available.join(", ")}`,
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
isError: true,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
serviceUrlOverrides.set(service, url);
|
|
367
|
+
for (const ep of serviceEndpoints) {
|
|
368
|
+
ep.baseUrl = url;
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
content: [
|
|
372
|
+
{
|
|
373
|
+
type: "text",
|
|
374
|
+
text: `Overrode ${service} → ${url} (${serviceEndpoints.length} endpoints). Auth ${url.startsWith("http://localhost") || url.startsWith("http://127.0.0.1") ? "skipped" : "active"}.`,
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
// Handle ResetServiceUrl
|
|
380
|
+
if (name === RESET_URL_TOOL_NAME) {
|
|
381
|
+
const service = args.service ? String(args.service) : undefined;
|
|
382
|
+
if (service) {
|
|
383
|
+
serviceUrlOverrides.delete(service);
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
serviceUrlOverrides.clear();
|
|
387
|
+
}
|
|
388
|
+
// Reload to restore original URLs
|
|
389
|
+
await loadEndpoints(currentEnvironment);
|
|
390
|
+
const msg = service
|
|
391
|
+
? `Reset ${service} to environment default`
|
|
392
|
+
: `Reset all service URL overrides`;
|
|
393
|
+
return {
|
|
394
|
+
content: [{ type: "text", text: msg }],
|
|
395
|
+
};
|
|
396
|
+
}
|
|
295
397
|
const endpoint = endpointsByTool.get(name);
|
|
296
398
|
if (!endpoint) {
|
|
297
399
|
return {
|