@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 CHANGED
@@ -1,16 +1,15 @@
1
1
  /**
2
2
  * Token acquisition for Snokam backend APIs.
3
3
  *
4
- * Supports three modes (auto-detected):
4
+ * Modes (auto-detected, in order):
5
5
  *
6
- * 1. **OBO (On-Behalf-Of):** When SNOKAM_USER_JWT is set, exchanges the user
7
- * JWT for a service-specific token via Azure AD OBO flow.
8
- * Requires AZURE_AD_CLIENT_ID, AZURE_AD_TENANT_ID, and either
9
- * AZURE_AD_SECRET (client secret) or managed identity.
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
- * 2. **DefaultAzureCredential:** When no user JWT is present, falls back to
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
- * Supports three modes (auto-detected):
4
+ * Modes (auto-detected, in order):
5
5
  *
6
- * 1. **OBO (On-Behalf-Of):** When SNOKAM_USER_JWT is set, exchanges the user
7
- * JWT for a service-specific token via Azure AD OBO flow.
8
- * Requires AZURE_AD_CLIENT_ID, AZURE_AD_TENANT_ID, and either
9
- * AZURE_AD_SECRET (client secret) or managed identity.
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
- * 2. **DefaultAzureCredential:** When no user JWT is present, falls back to
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 { DefaultAzureCredential, OnBehalfOfCredential, } from "@azure/identity";
17
- // Cache credentials per scope to avoid re-creating them
18
- const credentialCache = new Map();
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 userJwt = process.env.SNOKAM_USER_JWT;
45
- const clientId = process.env.AZURE_AD_CLIENT_ID ?? "";
46
- const tenantId = process.env.AZURE_AD_TENANT_ID ?? "";
47
- let credential;
48
- if (userJwt && clientId && tenantId) {
49
- // OBO mode
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
- credential = credentialCache.get(cacheKey);
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
- const token = await credential.getToken(scope);
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 is handled via @azure/identity — supports Azure CLI (local),
7
- * managed identity (Azure), and OBO (when SNOKAM_USER_JWT is set).
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 is handled via @azure/identity — supports Azure CLI (local),
7
- * managed identity (Azure), and OBO (when SNOKAM_USER_JWT is set).
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 environment default (snokam).",
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 snokam default.",
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"],
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Fetch OpenAPI specs from live Snokam APIs and produce tool definitions.
3
3
  *
4
- * Each backend function is available at `{service}.api.snokam.no` (prod)
5
- * or `{service}.api.test.snokam.no` (test). The loader fetches `/swagger.json`
6
- * from each, extracts endpoints, parameters, and OAuth scopes to generate
7
- * MCP-compatible tool metadata.
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;
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Fetch OpenAPI specs from live Snokam APIs and produce tool definitions.
3
3
  *
4
- * Each backend function is available at `{service}.api.snokam.no` (prod)
5
- * or `{service}.api.test.snokam.no` (test). The loader fetches `/swagger.json`
6
- * from each, extracts endpoints, parameters, and OAuth scopes to generate
7
- * MCP-compatible tool metadata.
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.snokam.no";
34
- const TEST_DOMAIN = "api.test.snokam.no";
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snokam/mcp-api",
3
- "version": "0.110.2",
3
+ "version": "0.111.1",
4
4
  "description": "MCP server exposing Snokam backend APIs as tools for Claude Code and other MCP clients",
5
5
  "type": "module",
6
6
  "bin": {