@lovable.dev/mcp-js 0.5.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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +386 -0
  3. package/dist/authorize-DpTEIFvs.d.ts +9 -0
  4. package/dist/chunk-6DXGZZA4.js +6 -0
  5. package/dist/chunk-DDF63QWG.js +80 -0
  6. package/dist/chunk-GLG5RZGE.js +66 -0
  7. package/dist/chunk-MA5H6PSF.js +46 -0
  8. package/dist/chunk-QA3FWDUV.js +40 -0
  9. package/dist/chunk-VD6CS7Y6.js +144 -0
  10. package/dist/chunk-XEDRJFAR.js +371 -0
  11. package/dist/index.cjs +271 -0
  12. package/dist/index.d.cts +56 -0
  13. package/dist/index.d.ts +56 -0
  14. package/dist/index.js +172 -0
  15. package/dist/protocols/mcp/index.cjs +505 -0
  16. package/dist/protocols/mcp/index.d.cts +14 -0
  17. package/dist/protocols/mcp/index.d.ts +14 -0
  18. package/dist/protocols/mcp/index.js +10 -0
  19. package/dist/protocols/oauth-metadata.cjs +390 -0
  20. package/dist/protocols/oauth-metadata.d.cts +8 -0
  21. package/dist/protocols/oauth-metadata.d.ts +8 -0
  22. package/dist/protocols/oauth-metadata.js +9 -0
  23. package/dist/protocols/rest/index.cjs +599 -0
  24. package/dist/protocols/rest/index.d.cts +11 -0
  25. package/dist/protocols/rest/index.d.ts +11 -0
  26. package/dist/protocols/rest/index.js +12 -0
  27. package/dist/stacks/tanstack/index.cjs +743 -0
  28. package/dist/stacks/tanstack/index.d.cts +38 -0
  29. package/dist/stacks/tanstack/index.d.ts +38 -0
  30. package/dist/stacks/tanstack/index.js +38 -0
  31. package/dist/stacks/tanstack/vite.cjs +291 -0
  32. package/dist/stacks/tanstack/vite.d.cts +64 -0
  33. package/dist/stacks/tanstack/vite.d.ts +64 -0
  34. package/dist/stacks/tanstack/vite.js +263 -0
  35. package/dist/types-zMlr1mOK.d.ts +270 -0
  36. package/package.json +101 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ ToolContext: () => ToolContext,
24
+ auth: () => auth,
25
+ defineMcp: () => defineMcp,
26
+ defineTool: () => defineTool
27
+ });
28
+ module.exports = __toCommonJS(src_exports);
29
+
30
+ // src/core/url.ts
31
+ function isLocalHTTPHost(hostname) {
32
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
33
+ }
34
+ function urlSafetyProblem(url) {
35
+ const isAllowedHTTP = url.protocol === "http:" && isLocalHTTPHost(url.hostname);
36
+ if (url.protocol !== "https:" && !isAllowedHTTP) {
37
+ return "must use https://, except localhost development URLs";
38
+ }
39
+ if (url.username || url.password) {
40
+ return "must not include credentials";
41
+ }
42
+ if (url.search || url.hash) {
43
+ return "must not include query or fragment";
44
+ }
45
+ return void 0;
46
+ }
47
+
48
+ // src/core/validation.ts
49
+ function parseSafeUrl(subject, raw, ErrorClass = Error) {
50
+ let url;
51
+ try {
52
+ url = new URL(raw);
53
+ } catch {
54
+ throw new ErrorClass(`${subject} must be an absolute URL`);
55
+ }
56
+ const problem = urlSafetyProblem(url);
57
+ if (problem) {
58
+ throw new ErrorClass(`${subject} ${problem}`);
59
+ }
60
+ return url;
61
+ }
62
+
63
+ // src/core/define.ts
64
+ function assertUniqueNames(mcp) {
65
+ const seen = /* @__PURE__ */ new Set();
66
+ for (const tool of mcp.tools) {
67
+ if (seen.has(tool.name)) {
68
+ throw new Error(`@lovable.dev/mcp-js: duplicate tool name "${tool.name}"`);
69
+ }
70
+ seen.add(tool.name);
71
+ }
72
+ }
73
+ function assertNonEmptyString(label, value) {
74
+ if (value.trim() === "") {
75
+ throw new Error(`@lovable.dev/mcp-js: ${label} must not be empty`);
76
+ }
77
+ if (value !== value.trim()) {
78
+ throw new Error(`@lovable.dev/mcp-js: ${label} must not have leading or trailing whitespace`);
79
+ }
80
+ }
81
+ function assertHttpsUrlField(name, value) {
82
+ assertNonEmptyString(`auth.${name}`, value);
83
+ parseSafeUrl(`@lovable.dev/mcp-js: auth.${name}`, value);
84
+ }
85
+ function assertScope(scope) {
86
+ if (scope.trim() === "" || /\s/.test(scope)) {
87
+ throw new Error(`@lovable.dev/mcp-js: OAuth scopes must be non-empty space-free tokens`);
88
+ }
89
+ }
90
+ function assertJwtAlgorithm(algorithm) {
91
+ if (algorithm.trim() === "" || /\s/.test(algorithm)) {
92
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms must contain non-empty space-free tokens`);
93
+ }
94
+ if (/^HS\d+$/i.test(algorithm) || algorithm.toLowerCase() === "none") {
95
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms cannot include "${algorithm}"; this verifier is JWKS-only`);
96
+ }
97
+ }
98
+ var MAX_CLOCK_TOLERANCE_SECONDS = 300;
99
+ function assertClockToleranceSeconds(value) {
100
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > MAX_CLOCK_TOLERANCE_SECONDS) {
101
+ throw new Error(
102
+ `@lovable.dev/mcp-js: auth.clockToleranceSeconds must be a non-negative number of seconds no greater than ${MAX_CLOCK_TOLERANCE_SECONDS}`
103
+ );
104
+ }
105
+ }
106
+ function assertOAuthConfig(auth2) {
107
+ if (auth2.type !== "oauth") {
108
+ const authType = String(auth2.type);
109
+ throw new Error(`@lovable.dev/mcp-js: unsupported auth type "${authType}"`);
110
+ }
111
+ if (auth2.issuer === void 0) {
112
+ throw new Error(`@lovable.dev/mcp-js: auth.issuer is required`);
113
+ }
114
+ assertHttpsUrlField("issuer", auth2.issuer);
115
+ if (auth2.jwksUri !== void 0) {
116
+ assertHttpsUrlField("jwksUri", auth2.jwksUri);
117
+ }
118
+ if (auth2.resource !== void 0) {
119
+ assertHttpsUrlField("resource", auth2.resource);
120
+ }
121
+ if (auth2.resourceName !== void 0) {
122
+ assertNonEmptyString("auth.resourceName", auth2.resourceName);
123
+ }
124
+ if (auth2.resourceDocumentation !== void 0) {
125
+ assertHttpsUrlField("resourceDocumentation", auth2.resourceDocumentation);
126
+ }
127
+ if (auth2.protectedResourceMetadataUrl !== void 0) {
128
+ assertHttpsUrlField("protectedResourceMetadataUrl", auth2.protectedResourceMetadataUrl);
129
+ }
130
+ if (auth2.acceptedAudiences !== void 0) {
131
+ if (!Array.isArray(auth2.acceptedAudiences)) {
132
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must be an array`);
133
+ }
134
+ if (auth2.acceptedAudiences.length === 0) {
135
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must not be empty`);
136
+ }
137
+ for (const audience of auth2.acceptedAudiences) {
138
+ if (typeof audience !== "string") {
139
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
140
+ }
141
+ assertNonEmptyString("auth.acceptedAudiences", audience);
142
+ }
143
+ }
144
+ if (auth2.requiredScopes !== void 0) {
145
+ if (!Array.isArray(auth2.requiredScopes)) {
146
+ throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);
147
+ }
148
+ for (const scope of auth2.requiredScopes)
149
+ assertScope(scope);
150
+ }
151
+ if (auth2.algorithms !== void 0) {
152
+ if (!Array.isArray(auth2.algorithms)) {
153
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms must be an array`);
154
+ }
155
+ if (auth2.algorithms.length === 0) {
156
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms must not be empty`);
157
+ }
158
+ for (const algorithm of auth2.algorithms)
159
+ assertJwtAlgorithm(algorithm);
160
+ }
161
+ if (auth2.clockToleranceSeconds !== void 0)
162
+ assertClockToleranceSeconds(auth2.clockToleranceSeconds);
163
+ if (auth2.resource === void 0 && auth2.acceptedAudiences === void 0) {
164
+ throw new Error(`@lovable.dev/mcp-js: auth.resource or auth.acceptedAudiences is required`);
165
+ }
166
+ }
167
+ function freezeAuth(auth2) {
168
+ if (!auth2)
169
+ return;
170
+ if (auth2.acceptedAudiences)
171
+ Object.freeze(auth2.acceptedAudiences);
172
+ if (auth2.requiredScopes)
173
+ Object.freeze(auth2.requiredScopes);
174
+ if (auth2.algorithms)
175
+ Object.freeze(auth2.algorithms);
176
+ Object.freeze(auth2);
177
+ }
178
+ function defineTool(def) {
179
+ return def;
180
+ }
181
+ function defineMcp(def) {
182
+ assertNonEmptyString("name", def.name);
183
+ assertNonEmptyString("title", def.title);
184
+ assertNonEmptyString("version", def.version);
185
+ assertUniqueNames(def);
186
+ if (def.auth)
187
+ assertOAuthConfig(def.auth);
188
+ freezeAuth(def.auth);
189
+ Object.freeze(def.tools);
190
+ for (const tool of def.tools)
191
+ Object.freeze(tool);
192
+ return def;
193
+ }
194
+
195
+ // src/auth/config.ts
196
+ function frozenArray(value) {
197
+ return value === void 0 ? void 0 : Object.freeze([...value]);
198
+ }
199
+ function frozenAudiences(value) {
200
+ return frozenArray(typeof value === "string" ? [value] : value);
201
+ }
202
+ function stripUndefined(value) {
203
+ for (const key of Object.keys(value)) {
204
+ if (value[key] === void 0)
205
+ delete value[key];
206
+ }
207
+ return value;
208
+ }
209
+ function issuer(options) {
210
+ return Object.freeze(
211
+ stripUndefined({
212
+ type: "oauth",
213
+ ...options,
214
+ acceptedAudiences: frozenAudiences(options.acceptedAudiences),
215
+ requiredScopes: frozenArray(options.requiredScopes),
216
+ algorithms: frozenArray(options.algorithms)
217
+ })
218
+ );
219
+ }
220
+ var oauth = Object.freeze({ issuer });
221
+ var auth = Object.freeze({ oauth });
222
+
223
+ // src/auth/context.ts
224
+ var ToolContext = class {
225
+ #auth;
226
+ constructor(auth2) {
227
+ this.#auth = auth2;
228
+ }
229
+ /** Whether the in-flight tool call carries a verified auth context. */
230
+ isAuthenticated() {
231
+ return this.#auth !== void 0;
232
+ }
233
+ /** The verified bearer token, or `undefined` when unauthenticated. Pass it to downstream APIs; never return or log it. */
234
+ getToken() {
235
+ return this.#auth?.bearer.token;
236
+ }
237
+ /** The verified user id (the token `sub`), or `undefined`. */
238
+ getUserId() {
239
+ return this.#auth?.principal.sub;
240
+ }
241
+ /** The verified user email, or `undefined` when absent. */
242
+ getUserEmail() {
243
+ return this.#auth?.principal.email;
244
+ }
245
+ /** The verified OAuth `client_id`, or `undefined`. */
246
+ getClientId() {
247
+ return this.#auth?.principal.clientId;
248
+ }
249
+ /** The verified OAuth scopes, or `undefined` when unauthenticated. */
250
+ getScopes() {
251
+ return this.#auth?.principal.scopes;
252
+ }
253
+ /** The verified token issuer, or `undefined`. */
254
+ getIssuer() {
255
+ return this.#auth?.principal.issuer;
256
+ }
257
+ /**
258
+ * The full verified JWT claims, or `undefined`. Use this for app/business
259
+ * authorization on issuer-specific claims that have no dedicated accessor.
260
+ */
261
+ getClaims() {
262
+ return this.#auth?.principal.claims;
263
+ }
264
+ };
265
+ // Annotate the CommonJS export names for ESM import in node:
266
+ 0 && (module.exports = {
267
+ ToolContext,
268
+ auth,
269
+ defineMcp,
270
+ defineTool
271
+ });
@@ -0,0 +1,56 @@
1
+ import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, j as ToolDefinition, M as McpAuthConfig } from './types-zMlr1mOK.js';
2
+ export { A as AudioContent, C as ContentAnnotations, a as ContentBlock, E as EmbeddedBlobResource, b as EmbeddedResource, c as EmbeddedTextResource, I as ImageContent, J as JwtClaims, R as ResourceLink, f as ResourceLinkIcon, T as TextContent, g as ToolAnnotations, h as ToolContent, i as ToolContext, k as ToolHandlerResult, l as ZodSchema } from './types-zMlr1mOK.js';
3
+ import 'zod';
4
+
5
+ /**
6
+ * Declare a single MCP tool. Import the result into your MCP definition's
7
+ * `tools` array — `defineMcp({ tools: [echoTool, ...] })`.
8
+ *
9
+ * `inputSchema` is a raw zod shape (e.g. `{ text: z.string() }`), not a
10
+ * full `z.object(...)` — the MCP SDK builds the object wrapper internally
11
+ * and the raw shape is what the JSON-RPC `tools/list` payload exposes.
12
+ */
13
+ declare function defineTool<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodRawShape | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
14
+ /**
15
+ * Declare the MCP server. `export default` the result from your MCP
16
+ * entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
17
+ * emit the framework-specific route(s) at build time.
18
+ */
19
+ declare function defineMcp(def: McpDefinitionInput): McpDefinition;
20
+
21
+ type IssuerAcceptedAudiences = string | readonly string[];
22
+ interface IssuerOAuthOptionsBase {
23
+ readonly resourceName?: string;
24
+ readonly resourceDocumentation?: string;
25
+ readonly protectedResourceMetadataUrl?: string;
26
+ readonly requireOAuthClientClaim?: boolean;
27
+ readonly issuer: string;
28
+ readonly requiredScopes?: readonly string[];
29
+ readonly jwksUri?: string;
30
+ readonly algorithms?: readonly string[];
31
+ readonly clockToleranceSeconds?: number;
32
+ }
33
+ type IssuerOAuthOptions = IssuerOAuthOptionsBase & ({
34
+ readonly resource: string;
35
+ readonly acceptedAudiences?: IssuerAcceptedAudiences;
36
+ } | {
37
+ readonly resource?: string;
38
+ readonly acceptedAudiences: IssuerAcceptedAudiences;
39
+ });
40
+ /**
41
+ * Configure OAuth against an issuer. `acceptedAudiences` (or `resource`) is the
42
+ * token-acceptance policy, not a per-request authorization decision: any token
43
+ * carrying an accepted `aud` passes. When an issuer mints broad project-wide
44
+ * audiences (e.g. Supabase's `aud: "authenticated"`), a token for one resource
45
+ * is structurally accepted by another sharing that audience — so gate per-tool
46
+ * authorization on `ctx.getClaims()` / `ctx.getClientId()`, never on the
47
+ * accepted audience.
48
+ */
49
+ declare function issuer(options: IssuerOAuthOptions): McpAuthConfig;
50
+ declare const auth: Readonly<{
51
+ oauth: Readonly<{
52
+ issuer: typeof issuer;
53
+ }>;
54
+ }>;
55
+
56
+ export { type IssuerOAuthOptions, McpDefinitionInput, ToolDefinition, ZodRawShape, auth, defineMcp, defineTool };
@@ -0,0 +1,56 @@
1
+ import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, j as ToolDefinition, M as McpAuthConfig } from './types-zMlr1mOK.js';
2
+ export { A as AudioContent, C as ContentAnnotations, a as ContentBlock, E as EmbeddedBlobResource, b as EmbeddedResource, c as EmbeddedTextResource, I as ImageContent, J as JwtClaims, R as ResourceLink, f as ResourceLinkIcon, T as TextContent, g as ToolAnnotations, h as ToolContent, i as ToolContext, k as ToolHandlerResult, l as ZodSchema } from './types-zMlr1mOK.js';
3
+ import 'zod';
4
+
5
+ /**
6
+ * Declare a single MCP tool. Import the result into your MCP definition's
7
+ * `tools` array — `defineMcp({ tools: [echoTool, ...] })`.
8
+ *
9
+ * `inputSchema` is a raw zod shape (e.g. `{ text: z.string() }`), not a
10
+ * full `z.object(...)` — the MCP SDK builds the object wrapper internally
11
+ * and the raw shape is what the JSON-RPC `tools/list` payload exposes.
12
+ */
13
+ declare function defineTool<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodRawShape | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
14
+ /**
15
+ * Declare the MCP server. `export default` the result from your MCP
16
+ * entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
17
+ * emit the framework-specific route(s) at build time.
18
+ */
19
+ declare function defineMcp(def: McpDefinitionInput): McpDefinition;
20
+
21
+ type IssuerAcceptedAudiences = string | readonly string[];
22
+ interface IssuerOAuthOptionsBase {
23
+ readonly resourceName?: string;
24
+ readonly resourceDocumentation?: string;
25
+ readonly protectedResourceMetadataUrl?: string;
26
+ readonly requireOAuthClientClaim?: boolean;
27
+ readonly issuer: string;
28
+ readonly requiredScopes?: readonly string[];
29
+ readonly jwksUri?: string;
30
+ readonly algorithms?: readonly string[];
31
+ readonly clockToleranceSeconds?: number;
32
+ }
33
+ type IssuerOAuthOptions = IssuerOAuthOptionsBase & ({
34
+ readonly resource: string;
35
+ readonly acceptedAudiences?: IssuerAcceptedAudiences;
36
+ } | {
37
+ readonly resource?: string;
38
+ readonly acceptedAudiences: IssuerAcceptedAudiences;
39
+ });
40
+ /**
41
+ * Configure OAuth against an issuer. `acceptedAudiences` (or `resource`) is the
42
+ * token-acceptance policy, not a per-request authorization decision: any token
43
+ * carrying an accepted `aud` passes. When an issuer mints broad project-wide
44
+ * audiences (e.g. Supabase's `aud: "authenticated"`), a token for one resource
45
+ * is structurally accepted by another sharing that audience — so gate per-tool
46
+ * authorization on `ctx.getClaims()` / `ctx.getClientId()`, never on the
47
+ * accepted audience.
48
+ */
49
+ declare function issuer(options: IssuerOAuthOptions): McpAuthConfig;
50
+ declare const auth: Readonly<{
51
+ oauth: Readonly<{
52
+ issuer: typeof issuer;
53
+ }>;
54
+ }>;
55
+
56
+ export { type IssuerOAuthOptions, McpDefinitionInput, ToolDefinition, ZodRawShape, auth, defineMcp, defineTool };
package/dist/index.js ADDED
@@ -0,0 +1,172 @@
1
+ import {
2
+ ToolContext
3
+ } from "./chunk-MA5H6PSF.js";
4
+ import {
5
+ parseSafeUrl
6
+ } from "./chunk-QA3FWDUV.js";
7
+
8
+ // src/core/define.ts
9
+ function assertUniqueNames(mcp) {
10
+ const seen = /* @__PURE__ */ new Set();
11
+ for (const tool of mcp.tools) {
12
+ if (seen.has(tool.name)) {
13
+ throw new Error(`@lovable.dev/mcp-js: duplicate tool name "${tool.name}"`);
14
+ }
15
+ seen.add(tool.name);
16
+ }
17
+ }
18
+ function assertNonEmptyString(label, value) {
19
+ if (value.trim() === "") {
20
+ throw new Error(`@lovable.dev/mcp-js: ${label} must not be empty`);
21
+ }
22
+ if (value !== value.trim()) {
23
+ throw new Error(`@lovable.dev/mcp-js: ${label} must not have leading or trailing whitespace`);
24
+ }
25
+ }
26
+ function assertHttpsUrlField(name, value) {
27
+ assertNonEmptyString(`auth.${name}`, value);
28
+ parseSafeUrl(`@lovable.dev/mcp-js: auth.${name}`, value);
29
+ }
30
+ function assertScope(scope) {
31
+ if (scope.trim() === "" || /\s/.test(scope)) {
32
+ throw new Error(`@lovable.dev/mcp-js: OAuth scopes must be non-empty space-free tokens`);
33
+ }
34
+ }
35
+ function assertJwtAlgorithm(algorithm) {
36
+ if (algorithm.trim() === "" || /\s/.test(algorithm)) {
37
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms must contain non-empty space-free tokens`);
38
+ }
39
+ if (/^HS\d+$/i.test(algorithm) || algorithm.toLowerCase() === "none") {
40
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms cannot include "${algorithm}"; this verifier is JWKS-only`);
41
+ }
42
+ }
43
+ var MAX_CLOCK_TOLERANCE_SECONDS = 300;
44
+ function assertClockToleranceSeconds(value) {
45
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > MAX_CLOCK_TOLERANCE_SECONDS) {
46
+ throw new Error(
47
+ `@lovable.dev/mcp-js: auth.clockToleranceSeconds must be a non-negative number of seconds no greater than ${MAX_CLOCK_TOLERANCE_SECONDS}`
48
+ );
49
+ }
50
+ }
51
+ function assertOAuthConfig(auth2) {
52
+ if (auth2.type !== "oauth") {
53
+ const authType = String(auth2.type);
54
+ throw new Error(`@lovable.dev/mcp-js: unsupported auth type "${authType}"`);
55
+ }
56
+ if (auth2.issuer === void 0) {
57
+ throw new Error(`@lovable.dev/mcp-js: auth.issuer is required`);
58
+ }
59
+ assertHttpsUrlField("issuer", auth2.issuer);
60
+ if (auth2.jwksUri !== void 0) {
61
+ assertHttpsUrlField("jwksUri", auth2.jwksUri);
62
+ }
63
+ if (auth2.resource !== void 0) {
64
+ assertHttpsUrlField("resource", auth2.resource);
65
+ }
66
+ if (auth2.resourceName !== void 0) {
67
+ assertNonEmptyString("auth.resourceName", auth2.resourceName);
68
+ }
69
+ if (auth2.resourceDocumentation !== void 0) {
70
+ assertHttpsUrlField("resourceDocumentation", auth2.resourceDocumentation);
71
+ }
72
+ if (auth2.protectedResourceMetadataUrl !== void 0) {
73
+ assertHttpsUrlField("protectedResourceMetadataUrl", auth2.protectedResourceMetadataUrl);
74
+ }
75
+ if (auth2.acceptedAudiences !== void 0) {
76
+ if (!Array.isArray(auth2.acceptedAudiences)) {
77
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must be an array`);
78
+ }
79
+ if (auth2.acceptedAudiences.length === 0) {
80
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must not be empty`);
81
+ }
82
+ for (const audience of auth2.acceptedAudiences) {
83
+ if (typeof audience !== "string") {
84
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
85
+ }
86
+ assertNonEmptyString("auth.acceptedAudiences", audience);
87
+ }
88
+ }
89
+ if (auth2.requiredScopes !== void 0) {
90
+ if (!Array.isArray(auth2.requiredScopes)) {
91
+ throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);
92
+ }
93
+ for (const scope of auth2.requiredScopes)
94
+ assertScope(scope);
95
+ }
96
+ if (auth2.algorithms !== void 0) {
97
+ if (!Array.isArray(auth2.algorithms)) {
98
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms must be an array`);
99
+ }
100
+ if (auth2.algorithms.length === 0) {
101
+ throw new Error(`@lovable.dev/mcp-js: auth.algorithms must not be empty`);
102
+ }
103
+ for (const algorithm of auth2.algorithms)
104
+ assertJwtAlgorithm(algorithm);
105
+ }
106
+ if (auth2.clockToleranceSeconds !== void 0)
107
+ assertClockToleranceSeconds(auth2.clockToleranceSeconds);
108
+ if (auth2.resource === void 0 && auth2.acceptedAudiences === void 0) {
109
+ throw new Error(`@lovable.dev/mcp-js: auth.resource or auth.acceptedAudiences is required`);
110
+ }
111
+ }
112
+ function freezeAuth(auth2) {
113
+ if (!auth2)
114
+ return;
115
+ if (auth2.acceptedAudiences)
116
+ Object.freeze(auth2.acceptedAudiences);
117
+ if (auth2.requiredScopes)
118
+ Object.freeze(auth2.requiredScopes);
119
+ if (auth2.algorithms)
120
+ Object.freeze(auth2.algorithms);
121
+ Object.freeze(auth2);
122
+ }
123
+ function defineTool(def) {
124
+ return def;
125
+ }
126
+ function defineMcp(def) {
127
+ assertNonEmptyString("name", def.name);
128
+ assertNonEmptyString("title", def.title);
129
+ assertNonEmptyString("version", def.version);
130
+ assertUniqueNames(def);
131
+ if (def.auth)
132
+ assertOAuthConfig(def.auth);
133
+ freezeAuth(def.auth);
134
+ Object.freeze(def.tools);
135
+ for (const tool of def.tools)
136
+ Object.freeze(tool);
137
+ return def;
138
+ }
139
+
140
+ // src/auth/config.ts
141
+ function frozenArray(value) {
142
+ return value === void 0 ? void 0 : Object.freeze([...value]);
143
+ }
144
+ function frozenAudiences(value) {
145
+ return frozenArray(typeof value === "string" ? [value] : value);
146
+ }
147
+ function stripUndefined(value) {
148
+ for (const key of Object.keys(value)) {
149
+ if (value[key] === void 0)
150
+ delete value[key];
151
+ }
152
+ return value;
153
+ }
154
+ function issuer(options) {
155
+ return Object.freeze(
156
+ stripUndefined({
157
+ type: "oauth",
158
+ ...options,
159
+ acceptedAudiences: frozenAudiences(options.acceptedAudiences),
160
+ requiredScopes: frozenArray(options.requiredScopes),
161
+ algorithms: frozenArray(options.algorithms)
162
+ })
163
+ );
164
+ }
165
+ var oauth = Object.freeze({ issuer });
166
+ var auth = Object.freeze({ oauth });
167
+ export {
168
+ ToolContext,
169
+ auth,
170
+ defineMcp,
171
+ defineTool
172
+ };