@snokam/mcp-api 0.110.2 → 0.111.1
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 +8 -9
- package/dist/auth.js +24 -52
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/openapi-loader.d.ts +5 -4
- package/dist/openapi-loader.js +7 -6
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Token acquisition for Snokam backend APIs.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Modes (auto-detected, in order):
|
|
5
5
|
*
|
|
6
|
-
* 1. **
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* 1. **SNOKAM_ACCESS_TOKEN_FILE:** path to a bearer the host refreshes (every
|
|
7
|
+
* ~30 min via the VM managed identity). Read fresh per call so a rotated
|
|
8
|
+
* token is picked up without restarting. Preferred for egress-isolated
|
|
9
|
+
* containers that can't reach IMDS.
|
|
10
|
+
* 2. **SNOKAM_ACCESS_TOKEN:** a pre-minted bearer injected directly.
|
|
11
|
+
* 3. **DefaultAzureCredential:** Azure CLI (local dev) or managed identity (Azure).
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
* Azure CLI (local dev), managed identity (Azure), etc.
|
|
13
|
-
*
|
|
14
|
-
* 3. **No auth:** Endpoints without a scope get no Authorization header.
|
|
13
|
+
* Endpoints without a scope get no Authorization header.
|
|
15
14
|
*/
|
|
16
15
|
export declare function getAccessToken(scope: string | null): Promise<string | null>;
|
package/dist/auth.js
CHANGED
|
@@ -1,68 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Token acquisition for Snokam backend APIs.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Modes (auto-detected, in order):
|
|
5
5
|
*
|
|
6
|
-
* 1. **
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* 1. **SNOKAM_ACCESS_TOKEN_FILE:** path to a bearer the host refreshes (every
|
|
7
|
+
* ~30 min via the VM managed identity). Read fresh per call so a rotated
|
|
8
|
+
* token is picked up without restarting. Preferred for egress-isolated
|
|
9
|
+
* containers that can't reach IMDS.
|
|
10
|
+
* 2. **SNOKAM_ACCESS_TOKEN:** a pre-minted bearer injected directly.
|
|
11
|
+
* 3. **DefaultAzureCredential:** Azure CLI (local dev) or managed identity (Azure).
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
* Azure CLI (local dev), managed identity (Azure), etc.
|
|
13
|
-
*
|
|
14
|
-
* 3. **No auth:** Endpoints without a scope get no Authorization header.
|
|
13
|
+
* Endpoints without a scope get no Authorization header.
|
|
15
14
|
*/
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function getOboCredential(userJwt, clientId, tenantId) {
|
|
20
|
-
const clientSecret = process.env.AZURE_AD_SECRET;
|
|
21
|
-
if (clientSecret) {
|
|
22
|
-
return new OnBehalfOfCredential({
|
|
23
|
-
tenantId,
|
|
24
|
-
clientId,
|
|
25
|
-
clientSecret,
|
|
26
|
-
userAssertionToken: userJwt,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
// Managed identity as client assertion (federated identity)
|
|
30
|
-
const mi = new DefaultAzureCredential();
|
|
31
|
-
return new OnBehalfOfCredential({
|
|
32
|
-
tenantId,
|
|
33
|
-
clientId,
|
|
34
|
-
userAssertionToken: userJwt,
|
|
35
|
-
getAssertion: async () => {
|
|
36
|
-
const token = await mi.getToken("api://AzureADTokenExchange");
|
|
37
|
-
return token.token;
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
}
|
|
15
|
+
import { readFileSync } from "fs";
|
|
16
|
+
import { DefaultAzureCredential } from "@azure/identity";
|
|
17
|
+
let defaultCredential = null;
|
|
41
18
|
export async function getAccessToken(scope) {
|
|
42
19
|
if (!scope)
|
|
43
20
|
return null;
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const cacheKey = `obo:${scope}`;
|
|
51
|
-
if (!credentialCache.has(cacheKey)) {
|
|
52
|
-
credentialCache.set(cacheKey, getOboCredential(userJwt, clientId, tenantId));
|
|
21
|
+
const tokenFile = process.env.SNOKAM_ACCESS_TOKEN_FILE;
|
|
22
|
+
if (tokenFile) {
|
|
23
|
+
try {
|
|
24
|
+
const fromFile = readFileSync(tokenFile, "utf8").trim();
|
|
25
|
+
if (fromFile)
|
|
26
|
+
return fromFile;
|
|
53
27
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
else {
|
|
57
|
-
// Default credential (Azure CLI locally, managed identity in Azure)
|
|
58
|
-
const cacheKey = "default";
|
|
59
|
-
if (!credentialCache.has(cacheKey)) {
|
|
60
|
-
credentialCache.set(cacheKey, new DefaultAzureCredential());
|
|
28
|
+
catch {
|
|
29
|
+
// fall through to the other modes
|
|
61
30
|
}
|
|
62
|
-
credential = credentialCache.get(cacheKey);
|
|
63
31
|
}
|
|
32
|
+
const preMinted = process.env.SNOKAM_ACCESS_TOKEN;
|
|
33
|
+
if (preMinted)
|
|
34
|
+
return preMinted;
|
|
64
35
|
try {
|
|
65
|
-
|
|
36
|
+
defaultCredential ??= new DefaultAzureCredential();
|
|
37
|
+
const token = await defaultCredential.getToken(scope);
|
|
66
38
|
return token?.token ?? null;
|
|
67
39
|
}
|
|
68
40
|
catch (error) {
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Snokam MCP Server
|
|
4
4
|
*
|
|
5
5
|
* Exposes Snokam backend APIs as MCP tools by reading bundled OpenAPI specs.
|
|
6
|
-
* Auth
|
|
7
|
-
*
|
|
6
|
+
* Auth: a pre-minted SNOKAM_ACCESS_TOKEN when present, else @azure/identity
|
|
7
|
+
* (Azure CLI locally, managed identity in Azure).
|
|
8
8
|
*/
|
|
9
9
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Snokam MCP Server
|
|
4
4
|
*
|
|
5
5
|
* Exposes Snokam backend APIs as MCP tools by reading bundled OpenAPI specs.
|
|
6
|
-
* Auth
|
|
7
|
-
*
|
|
6
|
+
* Auth: a pre-minted SNOKAM_ACCESS_TOKEN when present, else @azure/identity
|
|
7
|
+
* (Azure CLI locally, managed identity in Azure).
|
|
8
8
|
*/
|
|
9
9
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
10
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -111,13 +111,13 @@ const resetUrlToolDef = {
|
|
|
111
111
|
const SWITCH_DOMAIN_TOOL_NAME = "SwitchDomain";
|
|
112
112
|
const switchDomainToolDef = {
|
|
113
113
|
name: SWITCH_DOMAIN_TOOL_NAME,
|
|
114
|
-
description: "Point all Snokam API calls at a specific business's API domain, so the same MCP can serve any tenant. Pass the business's API domain (custom, e.g. api.acme.com, or its snosky fallback, e.g. api.acme.snosky.no); calls then go to {service}.{domain}. Pass an empty string to reset to the
|
|
114
|
+
description: "Point all Snokam API calls at a specific business's API domain, so the same MCP can serve any tenant. Pass the business's API domain (custom, e.g. api.acme.com, or its snosky fallback, e.g. api.acme.snosky.no); calls then go to {service}.{domain}. Pass an empty string to reset to the platform-wide snosky default.",
|
|
115
115
|
inputSchema: {
|
|
116
116
|
type: "object",
|
|
117
117
|
properties: {
|
|
118
118
|
domain: {
|
|
119
119
|
type: "string",
|
|
120
|
-
description: "The business's API base domain (e.g. api.acme.com). Empty string resets to the
|
|
120
|
+
description: "The business's API base domain (e.g. api.acme.com). Empty string resets to the platform-wide snosky default.",
|
|
121
121
|
},
|
|
122
122
|
},
|
|
123
123
|
required: ["domain"],
|
package/dist/openapi-loader.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fetch OpenAPI specs from live Snokam APIs and produce tool definitions.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Backends are reached on the platform-wide snosky domain, which is uniform
|
|
5
|
+
* across every business (no per-customer hostname): `{service}.api.snosky.no`
|
|
6
|
+
* (prod) or `{service}.api.test.snosky.no` (test). A specific business domain
|
|
7
|
+
* can still be targeted at runtime via the SwitchDomain tool. The loader
|
|
8
|
+
* extracts endpoints, parameters, and OAuth scopes for MCP tool metadata.
|
|
8
9
|
*/
|
|
9
10
|
export interface ApiEndpoint {
|
|
10
11
|
service: string;
|
package/dist/openapi-loader.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fetch OpenAPI specs from live Snokam APIs and produce tool definitions.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Backends are reached on the platform-wide snosky domain, which is uniform
|
|
5
|
+
* across every business (no per-customer hostname): `{service}.api.snosky.no`
|
|
6
|
+
* (prod) or `{service}.api.test.snosky.no` (test). A specific business domain
|
|
7
|
+
* can still be targeted at runtime via the SwitchDomain tool. The loader
|
|
8
|
+
* extracts endpoints, parameters, and OAuth scopes for MCP tool metadata.
|
|
8
9
|
*/
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
10
11
|
// Service discovery - reads from bundled specs directory at runtime
|
|
@@ -30,8 +31,8 @@ async function discoverServices(environment) {
|
|
|
30
31
|
// ---------------------------------------------------------------------------
|
|
31
32
|
// Environment-aware URL resolution
|
|
32
33
|
// ---------------------------------------------------------------------------
|
|
33
|
-
const PROD_DOMAIN = "api.
|
|
34
|
-
const TEST_DOMAIN = "api.test.
|
|
34
|
+
const PROD_DOMAIN = "api.snosky.no";
|
|
35
|
+
const TEST_DOMAIN = "api.test.snosky.no";
|
|
35
36
|
function getBaseDomain(environment) {
|
|
36
37
|
return environment === "test" ? TEST_DOMAIN : PROD_DOMAIN;
|
|
37
38
|
}
|