modality-ai 0.5.2 → 0.5.4

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 CHANGED
@@ -138837,9 +138837,16 @@ import { createHash } from "node:crypto";
138837
138837
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
138838
138838
  import { homedir } from "node:os";
138839
138839
  import { join as join8 } from "node:path";
138840
+ var SERVER_IDENTITY_WHITELIST = {
138841
+ "figma.com": {
138842
+ client_name: "Claude Code",
138843
+ client_uri: "https://claude.ai"
138844
+ }
138845
+ };
138840
138846
 
138841
138847
  class CLIBrowserOAuthProvider {
138842
138848
  _clientName;
138849
+ _serverIdentity;
138843
138850
  _noOpen;
138844
138851
  _cachePath;
138845
138852
  _port;
@@ -138854,10 +138861,11 @@ class CLIBrowserOAuthProvider {
138854
138861
  constructor(options = {}) {
138855
138862
  this._clientName = options.clientName ?? "mcp-cli";
138856
138863
  this._noOpen = options.noOpen ?? false;
138857
- if (options.storageKey === null) {
138864
+ this._serverIdentity = options.serverUrl ? resolveServerIdentity(options.serverUrl) : null;
138865
+ if (options.serverUrl === null) {
138858
138866
  this._cachePath = null;
138859
138867
  } else {
138860
- const key = options.storageKey ?? "default";
138868
+ const key = options.serverUrl ? urlStorageKey(options.serverUrl) : "default";
138861
138869
  const dir3 = join8(homedir(), ".cache", "counter");
138862
138870
  mkdirSync(dir3, { recursive: true });
138863
138871
  this._cachePath = join8(dir3, `${key}.json`);
@@ -138873,19 +138881,27 @@ class CLIBrowserOAuthProvider {
138873
138881
  this._rejectCode = reject3;
138874
138882
  });
138875
138883
  this._server = Bun.serve({
138876
- port: options.callbackPort ?? 0,
138884
+ port: options.callbackPort ?? 9876,
138877
138885
  fetch: (req) => this._handleCallback(req)
138878
138886
  });
138879
- this._port = this._server.port ?? 0;
138887
+ this._port = this._server.port ?? 9876;
138888
+ if (this._clientInfo) {
138889
+ const uris = this._clientInfo.redirect_uris ?? [];
138890
+ if (!uris.includes(this.redirectUrl)) {
138891
+ this._clientInfo = undefined;
138892
+ }
138893
+ }
138880
138894
  }
138881
138895
  get redirectUrl() {
138882
138896
  return `http://127.0.0.1:${this._port}/callback`;
138883
138897
  }
138884
138898
  get clientMetadata() {
138899
+ const identity7 = this._serverIdentity;
138885
138900
  return {
138886
- client_name: this._clientName,
138901
+ client_name: identity7?.client_name ?? this._clientName,
138902
+ ...identity7?.client_uri ? { client_uri: identity7.client_uri } : {},
138887
138903
  redirect_uris: [this.redirectUrl],
138888
- grant_types: ["authorization_code"],
138904
+ grant_types: ["authorization_code", "refresh_token"],
138889
138905
  response_types: ["code"],
138890
138906
  token_endpoint_auth_method: "none"
138891
138907
  };
@@ -138918,6 +138934,16 @@ class CLIBrowserOAuthProvider {
138918
138934
  throw new Error("No PKCE code verifier saved");
138919
138935
  return this._codeVerifier;
138920
138936
  }
138937
+ addClientAuthentication = (_headers, params) => {
138938
+ const info3 = this._clientInfo;
138939
+ if (!info3)
138940
+ return;
138941
+ params.set("client_id", info3.client_id);
138942
+ const secret3 = info3.client_secret;
138943
+ if (secret3) {
138944
+ params.set("client_secret", secret3);
138945
+ }
138946
+ };
138921
138947
  async redirectToAuthorization(authorizationUrl) {
138922
138948
  const url5 = authorizationUrl.toString();
138923
138949
  if (this._noOpen) {
@@ -138945,13 +138971,8 @@ class CLIBrowserOAuthProvider {
138945
138971
  return this._discoveryState;
138946
138972
  }
138947
138973
  clearCache() {
138948
- this._clientInfo = undefined;
138949
138974
  this._tokens = undefined;
138950
- if (this._cachePath) {
138951
- try {
138952
- writeFileSync(this._cachePath, "{}");
138953
- } catch {}
138954
- }
138975
+ this._persistCache();
138955
138976
  }
138956
138977
  stop() {
138957
138978
  this._server.stop(true);
@@ -139097,8 +139118,21 @@ function openBrowser(url5) {
139097
139118
  function urlStorageKey(url5) {
139098
139119
  return createHash("sha1").update(url5).digest("hex").slice(0, 12);
139099
139120
  }
139121
+ function resolveServerIdentity(serverUrl) {
139122
+ let hostname4;
139123
+ try {
139124
+ hostname4 = new URL(serverUrl).hostname;
139125
+ } catch {
139126
+ return null;
139127
+ }
139128
+ for (const [key, identity7] of Object.entries(SERVER_IDENTITY_WHITELIST)) {
139129
+ if (hostname4 === key || hostname4.endsWith(`.${key}`)) {
139130
+ return identity7;
139131
+ }
139132
+ }
139133
+ return null;
139134
+ }
139100
139135
  export {
139101
- urlStorageKey,
139102
139136
  setupStdioToHttpTools,
139103
139137
  mergeToolCallsAndResults,
139104
139138
  createStdioClient,
@@ -3,4 +3,4 @@ export { ModalityClient } from "./ModalityClient";
3
3
  export { setupStdioToHttpTools, createStdioClient, } from "./setupStdioToHttpTools";
4
4
  export type { ModalityClientInstance } from "./ModalityClient";
5
5
  export type { StdioClientOptions } from "./setupStdioToHttpTools";
6
- export { CLIBrowserOAuthProvider, urlStorageKey, } from "./mcp-oauth-provider";
6
+ export { CLIBrowserOAuthProvider } from "./mcp-oauth-provider";
@@ -1,4 +1,4 @@
1
- import type { OAuthClientProvider, OAuthDiscoveryState } from "@modelcontextprotocol/sdk/client/auth.js";
1
+ import type { OAuthClientProvider, OAuthDiscoveryState, AddClientAuthentication } from "@modelcontextprotocol/sdk/client/auth.js";
2
2
  import type { OAuthClientInformationMixed, OAuthClientMetadata, OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
3
3
  interface CLIBrowserOAuthProviderOptions {
4
4
  /** Display name registered with the OAuth server. Default: "mcp-cli" */
@@ -10,9 +10,7 @@ interface CLIBrowserOAuthProviderOptions {
10
10
  clientId?: string;
11
11
  /**
12
12
  * Port for the local callback server.
13
- * 0 (default) picks a random available port.
14
- * Use a fixed port when registering an OAuth app manually so the redirect
15
- * URI stays stable across runs (e.g. callbackPort: 9876).
13
+ * Defaults to 9876 for a stable redirect_uri across runs.
16
14
  */
17
15
  callbackPort?: number;
18
16
  /**
@@ -22,14 +20,11 @@ interface CLIBrowserOAuthProviderOptions {
22
20
  */
23
21
  noOpen?: boolean;
24
22
  /**
25
- * Key used to namespace the persisted OAuth cache for this server.
26
- * Defaults to a short hash of the server URL so each MCP server gets its
27
- * own cache entry and re-runs skip dynamic registration entirely.
28
- *
29
- * Pass an explicit string (e.g. "figma") for a human-readable cache name.
23
+ * MCP server URL used to derive a unique cache key via urlStorageKey().
24
+ * Each server gets its own cache entry so re-runs skip dynamic registration.
30
25
  * Pass null to disable persistence entirely.
31
26
  */
32
- storageKey?: string | null;
27
+ serverUrl?: string | null;
33
28
  }
34
29
  /**
35
30
  * OAuthClientProvider for CLI tools.
@@ -42,7 +37,7 @@ interface CLIBrowserOAuthProviderOptions {
42
37
  * and the browser prompt (until the token expires).
43
38
  *
44
39
  * Usage:
45
- * const provider = new CLIBrowserOAuthProvider({ clientName: "my-cli", storageKey: "figma" });
40
+ * const provider = new CLIBrowserOAuthProvider({ clientName: "my-cli", serverUrl: "https://mcp.figma.com/mcp" });
46
41
  * const transport = new StreamableHTTPClientTransport(url, { authProvider: provider });
47
42
  * const client = new Client(...);
48
43
  *
@@ -60,6 +55,7 @@ interface CLIBrowserOAuthProviderOptions {
60
55
  */
61
56
  export declare class CLIBrowserOAuthProvider implements OAuthClientProvider {
62
57
  private readonly _clientName;
58
+ private readonly _serverIdentity;
63
59
  private readonly _noOpen;
64
60
  private readonly _cachePath;
65
61
  private _port;
@@ -82,6 +78,17 @@ export declare class CLIBrowserOAuthProvider implements OAuthClientProvider {
82
78
  discoveryState(): OAuthDiscoveryState | undefined;
83
79
  saveCodeVerifier(verifier: string): void;
84
80
  codeVerifier(): string;
81
+ /**
82
+ * Custom client authentication for token exchange.
83
+ *
84
+ * Figma's dynamic registration returns `token_endpoint_auth_method: "none"` yet
85
+ * also issues a `client_secret`. The MCP SDK honours the registered
86
+ * `token_endpoint_auth_method` and therefore sends only `client_id`, which Figma
87
+ * rejects. When a `client_secret` is present we always send it as
88
+ * `client_secret_post` so the credentials reach Figma regardless of whatever
89
+ * auth-method string the registration response contained.
90
+ */
91
+ readonly addClientAuthentication: AddClientAuthentication;
85
92
  redirectToAuthorization(authorizationUrl: URL): Promise<void>;
86
93
  /**
87
94
  * Resolves with the authorization code once the browser redirect completes.
@@ -89,7 +96,7 @@ export declare class CLIBrowserOAuthProvider implements OAuthClientProvider {
89
96
  waitForCode(): Promise<string>;
90
97
  /** Discovery state captured before registration — available even when registration fails. */
91
98
  getDiscoveryState(): OAuthDiscoveryState | undefined;
92
- /** Remove all persisted state for this server (forces re-registration + re-auth on next run). */
99
+ /** Clear cached tokens only forces browser re-auth on next run while keeping client registration. */
93
100
  clearCache(): void;
94
101
  /** Stop the local callback HTTP server. Call once auth is complete. */
95
102
  stop(): void;
@@ -97,6 +104,4 @@ export declare class CLIBrowserOAuthProvider implements OAuthClientProvider {
97
104
  private _persistCache;
98
105
  private _handleCallback;
99
106
  }
100
- /** Short stable hash of a string — used to derive a cache file name from a URL. */
101
- export declare function urlStorageKey(url: string): string;
102
107
  export {};
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.5.2",
2
+ "version": "0.5.4",
3
3
  "name": "modality-ai",
4
4
  "repository": {
5
5
  "type": "git",