@zackbart/connecta 0.26.2 → 0.26.3

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/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ All notable changes to this package are documented here.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.26.3 — 2026-09-28
8
+
9
+ This patch lets downstream OAuth connections use a public client metadata
10
+ URL when a server supports URL-based client IDs but restricts dynamic
11
+ registration. Existing OAuth configurations keep their current behavior.
12
+ The Node template now pins 0.26.3.
13
+
14
+ ### Added
15
+
16
+ - `remoteMcp` OAuth auth accepts `clientMetadataUrl` and default `scope`.
17
+ The SDK negotiates URL-based client IDs, falling back to dynamic registration
18
+ when unsupported. Existing PKCE, issuer binding, encrypted storage, refresh,
19
+ and disconnect remain in use. Invalid settings fail at construction.
20
+
7
21
  ## 0.26.2 — 2026-09-27
8
22
 
9
23
  This patch restores named client tokens as an optional auth module. Deployments
@@ -850,6 +850,8 @@ export class KvOAuthProvider {
850
850
  signal;
851
851
  clientBinding;
852
852
  onReset;
853
+ scope;
854
+ clientMetadataUrl;
853
855
  /**
854
856
  * The reset generation this provider's flow started under. Every OAuth value
855
857
  * it writes carries this epoch, so a late write can land after a reset without
@@ -869,7 +871,9 @@ export class KvOAuthProvider {
869
871
  /** Stable connector configuration bound to dynamically registered clients. */
870
872
  clientBinding,
871
873
  /** Request-local observer so the operator route drains every reset it began. */
872
- onReset) {
874
+ onReset,
875
+ /** SDK uses this only when the authorization server advertises support. */
876
+ clientMetadataUrl, scope) {
873
877
  this.connectorId = connectorId;
874
878
  this.storage = storage;
875
879
  this.redirectUri = redirectUri;
@@ -879,6 +883,9 @@ export class KvOAuthProvider {
879
883
  this.signal = signal;
880
884
  this.clientBinding = clientBinding;
881
885
  this.onReset = onReset;
886
+ this.scope = scope;
887
+ if (clientMetadataUrl !== undefined)
888
+ this.clientMetadataUrl = clientMetadataUrl;
882
889
  }
883
890
  /**
884
891
  * Stamp the force-reauth generation the current connect flow started under.
@@ -1339,6 +1346,7 @@ export class KvOAuthProvider {
1339
1346
  grant_types: ["authorization_code", "refresh_token"],
1340
1347
  response_types: ["code"],
1341
1348
  token_endpoint_auth_method: "none",
1349
+ ...(this.scope !== undefined ? { scope: this.scope } : {}),
1342
1350
  };
1343
1351
  }
1344
1352
  async clientInformation(ctx) {
@@ -38,6 +38,10 @@ export type RemoteMcpAuth = {
38
38
  headers: Record<string, string>;
39
39
  } | RemoteMcpCredentialAuth | {
40
40
  type: "oauth";
41
+ /** Public HTTPS client metadata document, for servers supporting URL-based client IDs. */
42
+ clientMetadataUrl?: string;
43
+ /** Space-separated default scopes when the resource server does not advertise them. */
44
+ scope?: string;
41
45
  };
42
46
  /**
43
47
  * Apply a maintained provider's slot copy and header framing to credential
@@ -396,6 +396,22 @@ function learnedUrlSafeFetch(connectorId, configured, baseFetch) {
396
396
  * server or hide other connectors).
397
397
  */
398
398
  export function remoteMcp(id, opts) {
399
+ const clientMetadataUrl = opts.auth?.type === "oauth" ? opts.auth.clientMetadataUrl : undefined;
400
+ const oauthScope = opts.auth?.type === "oauth" ? opts.auth.scope : undefined;
401
+ if (oauthScope !== undefined && !/^[\x21\x23-\x5B\x5D-\x7E]+(?: [\x21\x23-\x5B\x5D-\x7E]+)*$/.test(oauthScope)) {
402
+ throw new Error(`[connecta] connector "${id}" OAuth scope must contain space-separated scope tokens.`);
403
+ }
404
+ if (clientMetadataUrl !== undefined) {
405
+ let valid = false;
406
+ try {
407
+ const url = new URL(clientMetadataUrl);
408
+ valid = url.protocol === "https:" && url.pathname !== "/" &&
409
+ !url.username && !url.password && !url.hash;
410
+ }
411
+ catch { /* Invalid configuration is rejected below without echoing its value. */ }
412
+ if (!valid)
413
+ throw new Error(`[connecta] connector "${id}" clientMetadataUrl must be an HTTPS URL with a non-root path, without credentials or a fragment.`);
414
+ }
399
415
  if (opts.authScope === "personal" && opts.auth?.type === "headers") {
400
416
  throw new Error(`[connecta] connector "${id}" cannot combine authScope "personal" ` +
401
417
  "with static headers. Use credential or OAuth auth so each principal " +
@@ -597,11 +613,13 @@ export function remoteMcp(id, opts) {
597
613
  grant_types: ["authorization_code", "refresh_token"],
598
614
  response_types: ["code"],
599
615
  token_endpoint_auth_method: "none",
616
+ ...(oauthScope !== undefined ? { scope: oauthScope } : {}),
600
617
  },
601
618
  authScope: opts.authScope ?? "shared",
602
619
  versionNegotiation: opts.versionNegotiation ?? "auto",
603
620
  redirects: opts.redirects ?? "none",
604
- }), (reset) => trackOAuthStartReset(ctx.requestScope ?? ctx, reset));
621
+ clientMetadataUrl,
622
+ }), (reset) => trackOAuthStartReset(ctx.requestScope ?? ctx, reset), clientMetadataUrl, oauthScope);
605
623
  if (state)
606
624
  state.provider = provider;
607
625
  return provider;
package/dist/version.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export declare const CONNECTA_VERSION = "0.26.2";
7
+ export declare const CONNECTA_VERSION = "0.26.3";
package/dist/version.js CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export const CONNECTA_VERSION = "0.26.2";
7
+ export const CONNECTA_VERSION = "0.26.3";
@@ -615,3 +615,26 @@ present, must match that owner and may then manage the connector, while an
615
615
  interactive provider's explicit 403 still refuses the flow. See
616
616
  [meta-tools](./meta-tools.md#authorization-recovery) for the recovery shapes a
617
617
  caller actually receives.
618
+
619
+ ## URL-based downstream OAuth clients
620
+
621
+ `remoteMcp` accepts `auth: { type: "oauth", clientMetadataUrl, scope }`.
622
+ `clientMetadataUrl` names a public HTTPS OAuth client metadata document with a
623
+ non-root path. It must not contain credentials or a fragment. The document
624
+ must include its own URL as `client_id`, the deployment's exact
625
+ `/oauth/callback/<connector-id>` in `redirect_uris`, authorization-code and
626
+ refresh-token grants, and `token_endpoint_auth_method: "none"`. Hosting that
627
+ public document belongs to the deployment; Connecta does not expose a public
628
+ route through inbound authentication.
629
+
630
+ The SDK uses the URL as the client ID only when the authorization server
631
+ advertises `client_id_metadata_document_supported`. Otherwise it keeps the
632
+ existing dynamic registration flow. State validation, PKCE, issuer binding,
633
+ encrypted token storage, refresh, and disconnect follow the same code paths.
634
+ The metadata URL and scopes participate in the saved-client configuration
635
+ binding, so restarting after either changes cannot reuse an old registration.
636
+
637
+ `scope` supplies space-separated default OAuth scopes through client metadata.
638
+ A downstream challenge or protected-resource scope declaration takes precedence,
639
+ and the SDK adds `offline_access` when advertised for refresh-token grants.
640
+ Omitting both settings preserves the existing discovery and registration flow.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta",
3
- "version": "0.26.2",
3
+ "version": "0.26.3",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of eight meta-tools.",
@@ -15,7 +15,7 @@
15
15
  "typecheck": "tsc --noEmit"
16
16
  },
17
17
  "dependencies": {
18
- "@zackbart/connecta": "0.26.2",
18
+ "@zackbart/connecta": "0.26.3",
19
19
  "quickjs-emscripten": "0.32.0"
20
20
  },
21
21
  "devDependencies": {