@koduhai/mcp-kit 0.2.0 → 0.3.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.
@@ -22,7 +22,7 @@ export interface JwtVerifierOptions {
22
22
  scopeClaim?: string;
23
23
  /** Provide the key directly (a `KeyLike`/JWKS/resolver) instead of discovering it. Mainly for tests. */
24
24
  key?: JwtKeyInput;
25
- /** Injectable fetch for discovery. */
25
+ /** Injectable fetch for issuer discovery and the JWKS request. */
26
26
  fetch?: typeof globalThis.fetch;
27
27
  }
28
28
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-verifier.d.ts","sourceRoot":"","sources":["../../src/auth/jwt-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,SAAS,EAAE,MAAM,MAAM,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAK5F,gGAAgG;AAChG,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,kGAAkG;IAClG,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,kEAAkE;IAClE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wGAAwG;IACxG,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,sCAAsC;IACtC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAcD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,CAyDxE"}
1
+ {"version":3,"file":"jwt-verifier.d.ts","sourceRoot":"","sources":["../../src/auth/jwt-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,SAAS,EAAe,MAAM,MAAM,CAAC;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAK5F,gGAAgG;AAChG,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,kGAAkG;IAClG,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,kEAAkE;IAClE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wGAAwG;IACxG,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAcD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,CA8DxE"}
@@ -1,4 +1,4 @@
1
- import { createRemoteJWKSet, jwtVerify } from 'jose';
1
+ import { createRemoteJWKSet, jwtVerify, customFetch } from 'jose';
2
2
  import { InvalidTokenError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
3
3
  import { DEFAULT_TIMEOUT_MS } from '../internal/http.js';
4
4
  import { discoverOAuthMetadata } from './metadata.js';
@@ -47,7 +47,12 @@ export function jwtVerifier(opts) {
47
47
  throw new Error('jwtVerifier: issuer metadata has no jwks_uri; pass `jwksUri` or `key`');
48
48
  }
49
49
  const jwksTimeout = opts.timeoutMs && opts.timeoutMs > 0 ? opts.timeoutMs : DEFAULT_TIMEOUT_MS;
50
- keyInput = createRemoteJWKSet(new URL(jwksUri), { timeoutDuration: jwksTimeout });
50
+ keyInput = createRemoteJWKSet(new URL(jwksUri), {
51
+ timeoutDuration: jwksTimeout,
52
+ // Route the JWKS fetch through the injected fetch too, so the whole
53
+ // discovery -> JWKS -> verify path is exercisable offline in tests.
54
+ ...(opts.fetch ? { [customFetch]: opts.fetch } : {}),
55
+ });
51
56
  return keyInput;
52
57
  })();
53
58
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-verifier.js","sourceRoot":"","sources":["../../src/auth/jwt-verifier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jwt-verifier.js","sourceRoot":"","sources":["../../src/auth/jwt-verifier.ts"],"names":[],"mappings":"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"}
@@ -23,7 +23,9 @@ export interface RetryOptions {
23
23
  /**
24
24
  * `fetchWithTimeout` plus bounded exponential-backoff retries on transient
25
25
  * failures (network errors, 429, and 5xx). A timeout abort counts as a failure
26
- * and is retried. With `retries: 0` (the default) this is exactly one attempt.
26
+ * and is retried. On a 429/503 carrying a `Retry-After` header, that delay is
27
+ * honored (capped) instead of the backoff. With `retries: 0` (the default) this
28
+ * is exactly one attempt.
27
29
  */
28
30
  export declare function fetchWithRetry(fetchImpl: typeof globalThis.fetch, input: FetchInput, init: RequestInit, timeoutMs: number, retry?: RetryOptions): Promise<Response>;
29
31
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,EAClC,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE,WAAgB,EACtB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,QAAQ,CAAC,CAWnB;AAKD,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mCAAmC;IACnC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,EAClC,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,YAAiB,GACvB,OAAO,CAAC,QAAQ,CAAC,CAqBnB"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,EAClC,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE,WAAgB,EACtB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,QAAQ,CAAC,CAWnB;AAoBD,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mCAAmC;IACnC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,EAClC,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,YAAiB,GACvB,OAAO,CAAC,QAAQ,CAAC,CAsBnB"}
@@ -27,10 +27,27 @@ export async function fetchWithTimeout(fetchImpl, input, init = {}, timeoutMs =
27
27
  }
28
28
  /** HTTP status codes worth retrying: rate limiting and transient server errors. */
29
29
  const RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504]);
30
+ /** Upper bound on any single retry wait, so a hostile `Retry-After` can't stall a request. */
31
+ const MAX_RETRY_DELAY_MS = 30_000;
32
+ /**
33
+ * Parse a `Retry-After` header into milliseconds. Handles the delta-seconds form
34
+ * (e.g. `120`); the HTTP-date form is not special-cased and falls back to backoff.
35
+ * Capped at {@link MAX_RETRY_DELAY_MS}.
36
+ */
37
+ function parseRetryAfterMs(header) {
38
+ if (!header)
39
+ return undefined;
40
+ const seconds = Number(header);
41
+ if (!Number.isFinite(seconds) || seconds < 0)
42
+ return undefined;
43
+ return Math.min(seconds * 1000, MAX_RETRY_DELAY_MS);
44
+ }
30
45
  /**
31
46
  * `fetchWithTimeout` plus bounded exponential-backoff retries on transient
32
47
  * failures (network errors, 429, and 5xx). A timeout abort counts as a failure
33
- * and is retried. With `retries: 0` (the default) this is exactly one attempt.
48
+ * and is retried. On a 429/503 carrying a `Retry-After` header, that delay is
49
+ * honored (capped) instead of the backoff. With `retries: 0` (the default) this
50
+ * is exactly one attempt.
34
51
  */
35
52
  export async function fetchWithRetry(fetchImpl, input, init, timeoutMs, retry = {}) {
36
53
  const retries = retry.retries ?? 0;
@@ -41,7 +58,8 @@ export async function fetchWithRetry(fetchImpl, input, init, timeoutMs, retry =
41
58
  try {
42
59
  const res = await fetchWithTimeout(fetchImpl, input, init, timeoutMs);
43
60
  if (RETRYABLE_STATUS.has(res.status) && attempt < retries) {
44
- await sleep(base * 2 ** attempt);
61
+ const backoff = Math.min(base * 2 ** attempt, MAX_RETRY_DELAY_MS);
62
+ await sleep(parseRetryAfterMs(res.headers.get('retry-after')) ?? backoff);
45
63
  attempt++;
46
64
  continue;
47
65
  }
@@ -50,7 +68,7 @@ export async function fetchWithRetry(fetchImpl, input, init, timeoutMs, retry =
50
68
  catch (e) {
51
69
  if (attempt >= retries)
52
70
  throw e;
53
- await sleep(base * 2 ** attempt);
71
+ await sleep(Math.min(base * 2 ** attempt, MAX_RETRY_DELAY_MS));
54
72
  attempt++;
55
73
  }
56
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAIzC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAkC,EAClC,KAAiB,EACjB,OAAoB,EAAE,EACtB,YAAoB,kBAAkB;IAEtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/E,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,4EAA4E;QAC5E,IAAI,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,SAAS,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7F,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAW5D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAkC,EAClC,KAAiB,EACjB,IAAiB,EACjB,SAAiB,EACjB,QAAsB,EAAE;IAExB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,KAAK,CAAC,gBAAgB,IAAI,GAAG,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAEnF,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,SAAS,CAAC;QACR,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YACtE,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;gBAC1D,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC;gBACjC,OAAO,EAAE,CAAC;gBACV,SAAS;YACX,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,OAAO,IAAI,OAAO;gBAAE,MAAM,CAAC,CAAC;YAChC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koduhai/mcp-kit",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Auth and versioning for MCP servers, solved. Upstream API auth (API key / bearer / OAuth client-credentials), API versioning with a get_version tool, and a one-call OAuth 2.1 Resource Server (JWKS + introspection verifiers, RFC 9728 metadata) on top of the MCP SDK.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -68,8 +68,11 @@
68
68
  "format": "prettier --write .",
69
69
  "format:check": "prettier --check .",
70
70
  "test": "vitest run",
71
+ "test:watch": "vitest",
71
72
  "test:coverage": "vitest run --coverage",
73
+ "check": "npm run typecheck && npm run lint && npm run format:check && npm test",
72
74
  "typecheck:examples": "tsc -p examples/tsconfig.json",
75
+ "check:exports": "publint && attw --pack . --profile esm-only",
73
76
  "docs": "typedoc",
74
77
  "prepublishOnly": "npm run build"
75
78
  },
@@ -90,6 +93,7 @@
90
93
  }
91
94
  },
92
95
  "devDependencies": {
96
+ "@arethetypeswrong/cli": "^0.18.3",
93
97
  "@eslint/js": "^10.0.1",
94
98
  "@modelcontextprotocol/sdk": "^1.29.0",
95
99
  "@types/express": "^5.0.0",
@@ -101,6 +105,7 @@
101
105
  "express": "^5.0.0",
102
106
  "jose": "^6.0.0",
103
107
  "prettier": "^3.8.4",
108
+ "publint": "^0.3.21",
104
109
  "supertest": "^7.0.0",
105
110
  "typedoc": "^0.28.19",
106
111
  "typescript": "^6.0.3",