@lovable.dev/mcp-js 2.1.0 → 2.2.0-rc.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.
- package/README.md +97 -8
- package/dist/{authorize-CzyL7nmF.d.cts → authorize-BmYO5_-I.d.cts} +1 -1
- package/dist/{authorize-Drz_eJ7O.d.ts → authorize-d9-8n9u3.d.ts} +1 -1
- package/dist/{base-COwtdWE8.d.ts → base-BAxrhVjq.d.ts} +2 -2
- package/dist/{base-DD4MCXZ6.d.cts → base-Bmw6Wrb-.d.cts} +2 -2
- package/dist/cli/extract-manifest.cjs +1 -1
- package/dist/cli/extract-manifest.js +1 -1
- package/dist/{cors-BaRKDl4r.js → cors-BfacizN-.js} +2 -2
- package/dist/{cors-D-X0aP4O.cjs → cors-Dm9Yn8E5.cjs} +2 -2
- package/dist/errors-CpTdzogX.cjs +308 -0
- package/dist/errors-DGcJ8jPK.js +261 -0
- package/dist/index.cjs +5 -148
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +3 -147
- package/dist/{io-pl5npWDw.d.ts → io-7U860POB.d.ts} +1 -1
- package/dist/{io-Ds5MRSiK.d.cts → io-CL1GeE3D.d.cts} +1 -1
- package/dist/{io-DG83CLKx.js → io-DD8wjGjd.js} +3 -2
- package/dist/{io-DZD6xmJQ.cjs → io-DaqblVaG.cjs} +3 -2
- package/dist/{logger-CN1q-KNn.cjs → logger-C-Hdu57K.cjs} +5 -1
- package/dist/{logger-Ctv5xUSD.js → logger-CpLgYbCG.js} +5 -1
- package/dist/{mcp-Bx3LUn5O.cjs → mcp-BGsPYWs1.cjs} +93 -16
- package/dist/{mcp-DcmfehoI.js → mcp-DdJJjYYZ.js} +93 -16
- package/dist/{package-BNFIhH0F.js → package-cPx-zYIb.js} +1 -1
- package/dist/{package-CFVl3oIe.cjs → package-hWM0Ru0w.cjs} +1 -1
- package/dist/protocols/mcp/index.cjs +1 -1
- package/dist/protocols/mcp/index.d.cts +3 -3
- package/dist/protocols/mcp/index.d.ts +3 -3
- package/dist/protocols/mcp/index.js +1 -1
- package/dist/protocols/oauth-metadata.cjs +2 -2
- package/dist/protocols/oauth-metadata.d.cts +3 -3
- package/dist/protocols/oauth-metadata.d.ts +3 -3
- package/dist/protocols/oauth-metadata.js +2 -2
- package/dist/stacks/supabase/index.cjs +3 -3
- package/dist/stacks/supabase/index.d.cts +1 -1
- package/dist/stacks/supabase/index.d.ts +1 -1
- package/dist/stacks/supabase/index.js +3 -3
- package/dist/stacks/supabase/vite.cjs +1 -1
- package/dist/stacks/supabase/vite.d.cts +1 -1
- package/dist/stacks/supabase/vite.d.ts +1 -1
- package/dist/stacks/supabase/vite.js +1 -1
- package/dist/stacks/tanstack/index.cjs +2 -2
- package/dist/stacks/tanstack/index.d.cts +2 -2
- package/dist/stacks/tanstack/index.d.ts +2 -2
- package/dist/stacks/tanstack/index.js +2 -2
- package/dist/stacks/tanstack/vite.d.cts +1 -1
- package/dist/stacks/tanstack/vite.d.ts +1 -1
- package/dist/{types-B3_lX-L1.d.ts → types-BCKyT2wb.d.cts} +68 -20
- package/dist/{types-B3_lX-L1.d.cts → types-BCKyT2wb.d.ts} +68 -20
- package/package.json +2 -2
- package/dist/errors-Bwd1L0Rf.js +0 -100
- package/dist/errors-Cr95rSkB.cjs +0 -123
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { o as parseSafeUrl, s as trimTrailingSlash, u as resolveMetricsConfig } from "./logger-CpLgYbCG.js";
|
|
2
|
+
import { t as jsonSchemaFromDefinition } from "./schema-CW1jKvio.js";
|
|
3
|
+
//#region src/core/define.ts
|
|
4
|
+
function toolRequiresAppContext(tool) {
|
|
5
|
+
return "requiresAppContext" in tool && tool.requiresAppContext === true;
|
|
6
|
+
}
|
|
7
|
+
function assertUniqueNames(mcp) {
|
|
8
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9
|
+
for (const tool of mcp.tools) {
|
|
10
|
+
if (seen.has(tool.name)) throw new Error(`@lovable.dev/mcp-js: duplicate tool name "${tool.name}"`);
|
|
11
|
+
seen.add(tool.name);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function assertAppContextConfiguration(mcp) {
|
|
15
|
+
if (mcp.createAppContext && !mcp.auth) throw new Error(`@lovable.dev/mcp-js: createAppContext requires auth`);
|
|
16
|
+
if (!mcp.createAppContext && mcp.tools.some((tool) => tool.enabled || toolRequiresAppContext(tool))) throw new Error(`@lovable.dev/mcp-js: app-context or conditional tools require createAppContext`);
|
|
17
|
+
}
|
|
18
|
+
function assertNonEmptyString(label, value) {
|
|
19
|
+
if (value.trim() === "") throw new Error(`@lovable.dev/mcp-js: ${label} must not be empty`);
|
|
20
|
+
if (value !== value.trim()) throw new Error(`@lovable.dev/mcp-js: ${label} must not have leading or trailing whitespace`);
|
|
21
|
+
}
|
|
22
|
+
function assertHttpsUrlField(name, value) {
|
|
23
|
+
assertNonEmptyString(`auth.${name}`, value);
|
|
24
|
+
parseSafeUrl(`@lovable.dev/mcp-js: auth.${name}`, value);
|
|
25
|
+
}
|
|
26
|
+
function assertScope(scope) {
|
|
27
|
+
if (scope.trim() === "" || /\s/.test(scope)) throw new Error(`@lovable.dev/mcp-js: OAuth scopes must be non-empty space-free tokens`);
|
|
28
|
+
}
|
|
29
|
+
function assertJwtAlgorithm(algorithm) {
|
|
30
|
+
if (algorithm.trim() === "" || /\s/.test(algorithm)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must contain non-empty space-free tokens`);
|
|
31
|
+
if (/^HS\d+$/i.test(algorithm) || algorithm.toLowerCase() === "none") throw new Error(`@lovable.dev/mcp-js: auth.algorithms cannot include "${algorithm}"; this verifier is JWKS-only`);
|
|
32
|
+
}
|
|
33
|
+
const MAX_CLOCK_TOLERANCE_SECONDS = 300;
|
|
34
|
+
function assertClockToleranceSeconds(value) {
|
|
35
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > MAX_CLOCK_TOLERANCE_SECONDS) throw new Error(`@lovable.dev/mcp-js: auth.clockToleranceSeconds must be a non-negative number of seconds no greater than ${MAX_CLOCK_TOLERANCE_SECONDS}`);
|
|
36
|
+
}
|
|
37
|
+
function assertOAuthConfig(auth) {
|
|
38
|
+
if (auth.type !== "oauth") {
|
|
39
|
+
const authType = String(auth.type);
|
|
40
|
+
throw new Error(`@lovable.dev/mcp-js: unsupported auth type "${authType}"`);
|
|
41
|
+
}
|
|
42
|
+
if (auth.issuer === void 0) throw new Error(`@lovable.dev/mcp-js: auth.issuer is required`);
|
|
43
|
+
assertHttpsUrlField("issuer", auth.issuer);
|
|
44
|
+
if (auth.jwksUri !== void 0) assertHttpsUrlField("jwksUri", auth.jwksUri);
|
|
45
|
+
if (auth.resource !== void 0) assertHttpsUrlField("resource", auth.resource);
|
|
46
|
+
if (auth.resourceName !== void 0) assertNonEmptyString("auth.resourceName", auth.resourceName);
|
|
47
|
+
if (auth.resourceDocumentation !== void 0) assertHttpsUrlField("resourceDocumentation", auth.resourceDocumentation);
|
|
48
|
+
if (auth.protectedResourceMetadataUrl !== void 0) assertHttpsUrlField("protectedResourceMetadataUrl", auth.protectedResourceMetadataUrl);
|
|
49
|
+
if (auth.acceptedAudiences !== void 0) {
|
|
50
|
+
if (!Array.isArray(auth.acceptedAudiences)) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must be an array`);
|
|
51
|
+
if (auth.acceptedAudiences.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must not be empty`);
|
|
52
|
+
for (const audience of auth.acceptedAudiences) {
|
|
53
|
+
if (typeof audience !== "string") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
|
|
54
|
+
assertNonEmptyString("auth.acceptedAudiences", audience);
|
|
55
|
+
if (trimTrailingSlash(audience) === "") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences entries must not be only slashes`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (auth.requireOAuthClientClaim !== void 0 && typeof auth.requireOAuthClientClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.requireOAuthClientClaim must be a boolean`);
|
|
59
|
+
if (auth.acceptResourceClaim !== void 0 && typeof auth.acceptResourceClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.acceptResourceClaim must be a boolean`);
|
|
60
|
+
if (auth.requiredScopes !== void 0) {
|
|
61
|
+
if (!Array.isArray(auth.requiredScopes)) throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);
|
|
62
|
+
for (const scope of auth.requiredScopes) assertScope(scope);
|
|
63
|
+
}
|
|
64
|
+
if (auth.algorithms !== void 0) {
|
|
65
|
+
if (!Array.isArray(auth.algorithms)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must be an array`);
|
|
66
|
+
if (auth.algorithms.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must not be empty`);
|
|
67
|
+
for (const algorithm of auth.algorithms) assertJwtAlgorithm(algorithm);
|
|
68
|
+
}
|
|
69
|
+
if (auth.accessTokenTyp !== void 0) {
|
|
70
|
+
if (!Array.isArray(auth.accessTokenTyp)) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must be an array`);
|
|
71
|
+
if (auth.accessTokenTyp.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must not be empty`);
|
|
72
|
+
for (const typ of auth.accessTokenTyp) {
|
|
73
|
+
if (typeof typ !== "string") throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must contain strings`);
|
|
74
|
+
assertNonEmptyString("auth.accessTokenTyp", typ);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (auth.clockToleranceSeconds !== void 0) assertClockToleranceSeconds(auth.clockToleranceSeconds);
|
|
78
|
+
if (auth.resource === void 0 && auth.acceptedAudiences === void 0) throw new Error(`@lovable.dev/mcp-js: auth.resource or auth.acceptedAudiences is required`);
|
|
79
|
+
}
|
|
80
|
+
function freezeAuth(auth) {
|
|
81
|
+
if (!auth) return;
|
|
82
|
+
if (auth.acceptedAudiences) Object.freeze(auth.acceptedAudiences);
|
|
83
|
+
if (auth.requiredScopes) Object.freeze(auth.requiredScopes);
|
|
84
|
+
if (auth.algorithms) Object.freeze(auth.algorithms);
|
|
85
|
+
if (auth.accessTokenTyp) Object.freeze(auth.accessTokenTyp);
|
|
86
|
+
Object.freeze(auth);
|
|
87
|
+
}
|
|
88
|
+
function assertAllowedOrigins(allowedOrigins) {
|
|
89
|
+
if (allowedOrigins === void 0 || allowedOrigins === "any") return;
|
|
90
|
+
if (!Array.isArray(allowedOrigins)) throw new Error(`@lovable.dev/mcp-js: allowedOrigins must be "any" or an array of exact origins`);
|
|
91
|
+
for (const origin of allowedOrigins) {
|
|
92
|
+
if (typeof origin !== "string") throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain strings`);
|
|
93
|
+
let parsed;
|
|
94
|
+
try {
|
|
95
|
+
parsed = new URL(origin);
|
|
96
|
+
} catch {
|
|
97
|
+
throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain valid exact origins`);
|
|
98
|
+
}
|
|
99
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.origin !== origin) throw new Error(`@lovable.dev/mcp-js: allowedOrigins entry "${origin}" must be an exact http(s) origin without a path, query, fragment, or trailing slash`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function assertToolSchemas(mcp) {
|
|
103
|
+
for (const tool of mcp.tools) for (const [name, definition, strategy] of [[
|
|
104
|
+
"inputSchema",
|
|
105
|
+
tool.inputSchema,
|
|
106
|
+
"input"
|
|
107
|
+
], [
|
|
108
|
+
"outputSchema",
|
|
109
|
+
tool.outputSchema,
|
|
110
|
+
"output"
|
|
111
|
+
]]) {
|
|
112
|
+
if (!definition) continue;
|
|
113
|
+
try {
|
|
114
|
+
jsonSchemaFromDefinition(definition, strategy);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
117
|
+
throw new Error(`@lovable.dev/mcp-js: tool "${tool.name}" ${name} cannot be represented as JSON Schema${detail}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const defineStaticTool = (def) => def;
|
|
122
|
+
const defineTool = Object.assign(defineStaticTool, { withAppContext: () => (def) => {
|
|
123
|
+
return {
|
|
124
|
+
...def,
|
|
125
|
+
requiresAppContext: true
|
|
126
|
+
};
|
|
127
|
+
} });
|
|
128
|
+
/**
|
|
129
|
+
* Declare the MCP server. `export default` the result from your MCP
|
|
130
|
+
* entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
|
|
131
|
+
* emit the framework-specific route(s) at build time.
|
|
132
|
+
*/
|
|
133
|
+
function defineMcp(def) {
|
|
134
|
+
assertNonEmptyString("name", def.name);
|
|
135
|
+
assertNonEmptyString("title", def.title);
|
|
136
|
+
assertNonEmptyString("version", def.version);
|
|
137
|
+
assertUniqueNames(def);
|
|
138
|
+
assertAppContextConfiguration(def);
|
|
139
|
+
if (def.auth) assertOAuthConfig(def.auth);
|
|
140
|
+
assertAllowedOrigins(def.allowedOrigins);
|
|
141
|
+
assertToolSchemas(def);
|
|
142
|
+
resolveMetricsConfig(def.metrics);
|
|
143
|
+
freezeAuth(def.auth);
|
|
144
|
+
if (Array.isArray(def.allowedOrigins)) Object.freeze(def.allowedOrigins);
|
|
145
|
+
Object.freeze(def.tools);
|
|
146
|
+
for (const tool of def.tools) Object.freeze(tool);
|
|
147
|
+
return def;
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/auth/context.ts
|
|
151
|
+
const NEVER_ABORTED = new AbortController().signal;
|
|
152
|
+
/** Verified caller identity exposed to the app-context factory.
|
|
153
|
+
* `getToken()` is the sole bearer escape hatch. */
|
|
154
|
+
var AuthContext = class {
|
|
155
|
+
#auth;
|
|
156
|
+
constructor(auth) {
|
|
157
|
+
this.#auth = auth;
|
|
158
|
+
}
|
|
159
|
+
/** Whether the in-flight tool call carries a verified auth context. */
|
|
160
|
+
isAuthenticated() {
|
|
161
|
+
return this.#auth !== void 0;
|
|
162
|
+
}
|
|
163
|
+
/** The verified bearer token, or `undefined` when unauthenticated. Pass it to downstream APIs; never return or log it. */
|
|
164
|
+
getToken() {
|
|
165
|
+
return this.#auth?.bearer.token;
|
|
166
|
+
}
|
|
167
|
+
/** The verified user id (the token `sub`), or `undefined`. */
|
|
168
|
+
getUserId() {
|
|
169
|
+
return this.#auth?.principal.sub;
|
|
170
|
+
}
|
|
171
|
+
/** The verified user email, or `undefined` when absent. */
|
|
172
|
+
getUserEmail() {
|
|
173
|
+
return this.#auth?.principal.email;
|
|
174
|
+
}
|
|
175
|
+
/** The verified OAuth `client_id`, or `undefined`. */
|
|
176
|
+
getClientId() {
|
|
177
|
+
return this.#auth?.principal.clientId;
|
|
178
|
+
}
|
|
179
|
+
/** The verified OAuth scopes, or `undefined` when unauthenticated. */
|
|
180
|
+
getScopes() {
|
|
181
|
+
return this.#auth?.principal.scopes;
|
|
182
|
+
}
|
|
183
|
+
/** The verified token issuer, or `undefined`. */
|
|
184
|
+
getIssuer() {
|
|
185
|
+
return this.#auth?.principal.issuer;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* The full verified JWT claims, or `undefined`. Use this for app/business
|
|
189
|
+
* authorization on issuer-specific claims that have no dedicated accessor.
|
|
190
|
+
*/
|
|
191
|
+
getClaims() {
|
|
192
|
+
return this.#auth?.principal.claims;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
/** The per-request context passed to every tool handler as its second argument. */
|
|
196
|
+
var ToolContext = class extends AuthContext {
|
|
197
|
+
#appContext;
|
|
198
|
+
#signal;
|
|
199
|
+
#client;
|
|
200
|
+
#sendProgress;
|
|
201
|
+
constructor(auth, request = {}, appContext) {
|
|
202
|
+
super(auth);
|
|
203
|
+
this.#appContext = appContext;
|
|
204
|
+
this.#signal = request.signal ?? NEVER_ABORTED;
|
|
205
|
+
this.#client = request.client ?? { protocol: "legacy" };
|
|
206
|
+
this.#sendProgress = request.sendProgress;
|
|
207
|
+
}
|
|
208
|
+
/** App-defined context created for this tool call. */
|
|
209
|
+
get appContext() {
|
|
210
|
+
return this.#appContext;
|
|
211
|
+
}
|
|
212
|
+
/** Aborts when the client cancels the request or disconnects. */
|
|
213
|
+
get signal() {
|
|
214
|
+
return this.#signal;
|
|
215
|
+
}
|
|
216
|
+
/** What the client declared about itself on this request. Unverified input. */
|
|
217
|
+
get client() {
|
|
218
|
+
return this.#client;
|
|
219
|
+
}
|
|
220
|
+
/** Send a progress notification for this call. A no-op when the client
|
|
221
|
+
* didn't request progress (no `progressToken` on the request). */
|
|
222
|
+
async progress(update) {
|
|
223
|
+
await this.#sendProgress?.(update);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/core/errors.ts
|
|
228
|
+
const TOOL_ERROR_BRAND = Symbol.for("@lovable.dev/mcp-js/tool-error");
|
|
229
|
+
/** Error whose message is meant for the remote MCP caller; thrown from a handler
|
|
230
|
+
* it becomes an `isError` result carrying exactly `message`. */
|
|
231
|
+
var ToolError = class extends Error {
|
|
232
|
+
constructor(message, options) {
|
|
233
|
+
super(message, options);
|
|
234
|
+
this.name = "ToolError";
|
|
235
|
+
Object.defineProperty(this, TOOL_ERROR_BRAND, { value: true });
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
function isToolError(err) {
|
|
239
|
+
return err instanceof Error && Object.getOwnPropertyDescriptor(err, TOOL_ERROR_BRAND)?.value === true;
|
|
240
|
+
}
|
|
241
|
+
/** The caller-visible message of a thrown ToolError, or undefined for anything
|
|
242
|
+
* else — including when inspecting the value itself throws (fail closed). */
|
|
243
|
+
function resolveToolErrorMessage(err) {
|
|
244
|
+
try {
|
|
245
|
+
return isToolError(err) ? String(err.message) : void 0;
|
|
246
|
+
} catch {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const MAX_ERROR_SUMMARY = 500;
|
|
251
|
+
/** Bounded name+message line for local logs; never for wire responses. */
|
|
252
|
+
function errorSummary(err) {
|
|
253
|
+
try {
|
|
254
|
+
const text = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
|
|
255
|
+
return text.length > MAX_ERROR_SUMMARY ? `${text.slice(0, MAX_ERROR_SUMMARY)}…` : text;
|
|
256
|
+
} catch {
|
|
257
|
+
return "unprintable error";
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//#endregion
|
|
261
|
+
export { ToolContext as a, toolRequiresAppContext as c, AuthContext as i, errorSummary as n, defineMcp as o, resolveToolErrorMessage as r, defineTool as s, ToolError as t };
|
package/dist/index.cjs
CHANGED
|
@@ -1,150 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_logger = require("./logger-
|
|
3
|
-
const
|
|
4
|
-
const require_errors = require("./errors-Cr95rSkB.cjs");
|
|
5
|
-
//#region src/core/define.ts
|
|
6
|
-
function assertUniqueNames(mcp) {
|
|
7
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8
|
-
for (const tool of mcp.tools) {
|
|
9
|
-
if (seen.has(tool.name)) throw new Error(`@lovable.dev/mcp-js: duplicate tool name "${tool.name}"`);
|
|
10
|
-
seen.add(tool.name);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function assertNonEmptyString(label, value) {
|
|
14
|
-
if (value.trim() === "") throw new Error(`@lovable.dev/mcp-js: ${label} must not be empty`);
|
|
15
|
-
if (value !== value.trim()) throw new Error(`@lovable.dev/mcp-js: ${label} must not have leading or trailing whitespace`);
|
|
16
|
-
}
|
|
17
|
-
function assertHttpsUrlField(name, value) {
|
|
18
|
-
assertNonEmptyString(`auth.${name}`, value);
|
|
19
|
-
require_logger.parseSafeUrl(`@lovable.dev/mcp-js: auth.${name}`, value);
|
|
20
|
-
}
|
|
21
|
-
function assertScope(scope) {
|
|
22
|
-
if (scope.trim() === "" || /\s/.test(scope)) throw new Error(`@lovable.dev/mcp-js: OAuth scopes must be non-empty space-free tokens`);
|
|
23
|
-
}
|
|
24
|
-
function assertJwtAlgorithm(algorithm) {
|
|
25
|
-
if (algorithm.trim() === "" || /\s/.test(algorithm)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must contain non-empty space-free tokens`);
|
|
26
|
-
if (/^HS\d+$/i.test(algorithm) || algorithm.toLowerCase() === "none") throw new Error(`@lovable.dev/mcp-js: auth.algorithms cannot include "${algorithm}"; this verifier is JWKS-only`);
|
|
27
|
-
}
|
|
28
|
-
const MAX_CLOCK_TOLERANCE_SECONDS = 300;
|
|
29
|
-
function assertClockToleranceSeconds(value) {
|
|
30
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > MAX_CLOCK_TOLERANCE_SECONDS) throw new Error(`@lovable.dev/mcp-js: auth.clockToleranceSeconds must be a non-negative number of seconds no greater than ${MAX_CLOCK_TOLERANCE_SECONDS}`);
|
|
31
|
-
}
|
|
32
|
-
function assertOAuthConfig(auth) {
|
|
33
|
-
if (auth.type !== "oauth") {
|
|
34
|
-
const authType = String(auth.type);
|
|
35
|
-
throw new Error(`@lovable.dev/mcp-js: unsupported auth type "${authType}"`);
|
|
36
|
-
}
|
|
37
|
-
if (auth.issuer === void 0) throw new Error(`@lovable.dev/mcp-js: auth.issuer is required`);
|
|
38
|
-
assertHttpsUrlField("issuer", auth.issuer);
|
|
39
|
-
if (auth.jwksUri !== void 0) assertHttpsUrlField("jwksUri", auth.jwksUri);
|
|
40
|
-
if (auth.resource !== void 0) assertHttpsUrlField("resource", auth.resource);
|
|
41
|
-
if (auth.resourceName !== void 0) assertNonEmptyString("auth.resourceName", auth.resourceName);
|
|
42
|
-
if (auth.resourceDocumentation !== void 0) assertHttpsUrlField("resourceDocumentation", auth.resourceDocumentation);
|
|
43
|
-
if (auth.protectedResourceMetadataUrl !== void 0) assertHttpsUrlField("protectedResourceMetadataUrl", auth.protectedResourceMetadataUrl);
|
|
44
|
-
if (auth.acceptedAudiences !== void 0) {
|
|
45
|
-
if (!Array.isArray(auth.acceptedAudiences)) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must be an array`);
|
|
46
|
-
if (auth.acceptedAudiences.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must not be empty`);
|
|
47
|
-
for (const audience of auth.acceptedAudiences) {
|
|
48
|
-
if (typeof audience !== "string") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
|
|
49
|
-
assertNonEmptyString("auth.acceptedAudiences", audience);
|
|
50
|
-
if (require_logger.trimTrailingSlash(audience) === "") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences entries must not be only slashes`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (auth.requireOAuthClientClaim !== void 0 && typeof auth.requireOAuthClientClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.requireOAuthClientClaim must be a boolean`);
|
|
54
|
-
if (auth.acceptResourceClaim !== void 0 && typeof auth.acceptResourceClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.acceptResourceClaim must be a boolean`);
|
|
55
|
-
if (auth.requiredScopes !== void 0) {
|
|
56
|
-
if (!Array.isArray(auth.requiredScopes)) throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);
|
|
57
|
-
for (const scope of auth.requiredScopes) assertScope(scope);
|
|
58
|
-
}
|
|
59
|
-
if (auth.algorithms !== void 0) {
|
|
60
|
-
if (!Array.isArray(auth.algorithms)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must be an array`);
|
|
61
|
-
if (auth.algorithms.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must not be empty`);
|
|
62
|
-
for (const algorithm of auth.algorithms) assertJwtAlgorithm(algorithm);
|
|
63
|
-
}
|
|
64
|
-
if (auth.accessTokenTyp !== void 0) {
|
|
65
|
-
if (!Array.isArray(auth.accessTokenTyp)) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must be an array`);
|
|
66
|
-
if (auth.accessTokenTyp.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must not be empty`);
|
|
67
|
-
for (const typ of auth.accessTokenTyp) {
|
|
68
|
-
if (typeof typ !== "string") throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must contain strings`);
|
|
69
|
-
assertNonEmptyString("auth.accessTokenTyp", typ);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (auth.clockToleranceSeconds !== void 0) assertClockToleranceSeconds(auth.clockToleranceSeconds);
|
|
73
|
-
if (auth.resource === void 0 && auth.acceptedAudiences === void 0) throw new Error(`@lovable.dev/mcp-js: auth.resource or auth.acceptedAudiences is required`);
|
|
74
|
-
}
|
|
75
|
-
function freezeAuth(auth) {
|
|
76
|
-
if (!auth) return;
|
|
77
|
-
if (auth.acceptedAudiences) Object.freeze(auth.acceptedAudiences);
|
|
78
|
-
if (auth.requiredScopes) Object.freeze(auth.requiredScopes);
|
|
79
|
-
if (auth.algorithms) Object.freeze(auth.algorithms);
|
|
80
|
-
if (auth.accessTokenTyp) Object.freeze(auth.accessTokenTyp);
|
|
81
|
-
Object.freeze(auth);
|
|
82
|
-
}
|
|
83
|
-
function assertAllowedOrigins(allowedOrigins) {
|
|
84
|
-
if (allowedOrigins === void 0 || allowedOrigins === "any") return;
|
|
85
|
-
if (!Array.isArray(allowedOrigins)) throw new Error(`@lovable.dev/mcp-js: allowedOrigins must be "any" or an array of exact origins`);
|
|
86
|
-
for (const origin of allowedOrigins) {
|
|
87
|
-
if (typeof origin !== "string") throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain strings`);
|
|
88
|
-
let parsed;
|
|
89
|
-
try {
|
|
90
|
-
parsed = new URL(origin);
|
|
91
|
-
} catch {
|
|
92
|
-
throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain valid exact origins`);
|
|
93
|
-
}
|
|
94
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.origin !== origin) throw new Error(`@lovable.dev/mcp-js: allowedOrigins entry "${origin}" must be an exact http(s) origin without a path, query, fragment, or trailing slash`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function assertToolSchemas(mcp) {
|
|
98
|
-
for (const tool of mcp.tools) for (const [name, definition, strategy] of [[
|
|
99
|
-
"inputSchema",
|
|
100
|
-
tool.inputSchema,
|
|
101
|
-
"input"
|
|
102
|
-
], [
|
|
103
|
-
"outputSchema",
|
|
104
|
-
tool.outputSchema,
|
|
105
|
-
"output"
|
|
106
|
-
]]) {
|
|
107
|
-
if (!definition) continue;
|
|
108
|
-
try {
|
|
109
|
-
require_schema.jsonSchemaFromDefinition(definition, strategy);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
112
|
-
throw new Error(`@lovable.dev/mcp-js: tool "${tool.name}" ${name} cannot be represented as JSON Schema${detail}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Declare a single MCP tool. Import the result into your MCP definition's
|
|
118
|
-
* `tools` array — `defineMcp({ tools: [echoTool, ...] })`.
|
|
119
|
-
*
|
|
120
|
-
* `inputSchema` is a raw zod shape (e.g. `{ text: z.string() }`), not a
|
|
121
|
-
* full `z.object(...)` — the MCP SDK builds the object wrapper internally
|
|
122
|
-
* and the raw shape is what the JSON-RPC `tools/list` payload exposes.
|
|
123
|
-
*/
|
|
124
|
-
function defineTool(def) {
|
|
125
|
-
return def;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Declare the MCP server. `export default` the result from your MCP
|
|
129
|
-
* entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
|
|
130
|
-
* emit the framework-specific route(s) at build time.
|
|
131
|
-
*/
|
|
132
|
-
function defineMcp(def) {
|
|
133
|
-
assertNonEmptyString("name", def.name);
|
|
134
|
-
assertNonEmptyString("title", def.title);
|
|
135
|
-
assertNonEmptyString("version", def.version);
|
|
136
|
-
assertUniqueNames(def);
|
|
137
|
-
if (def.auth) assertOAuthConfig(def.auth);
|
|
138
|
-
assertAllowedOrigins(def.allowedOrigins);
|
|
139
|
-
assertToolSchemas(def);
|
|
140
|
-
require_logger.resolveMetricsConfig(def.metrics);
|
|
141
|
-
freezeAuth(def.auth);
|
|
142
|
-
if (Array.isArray(def.allowedOrigins)) Object.freeze(def.allowedOrigins);
|
|
143
|
-
Object.freeze(def.tools);
|
|
144
|
-
for (const tool of def.tools) Object.freeze(tool);
|
|
145
|
-
return def;
|
|
146
|
-
}
|
|
147
|
-
//#endregion
|
|
2
|
+
const require_logger = require("./logger-C-Hdu57K.cjs");
|
|
3
|
+
const require_errors = require("./errors-CpTdzogX.cjs");
|
|
148
4
|
//#region src/auth/config.ts
|
|
149
5
|
function frozenArray(value) {
|
|
150
6
|
return value === void 0 ? void 0 : Object.freeze([...value]);
|
|
@@ -179,9 +35,10 @@ function issuer(options) {
|
|
|
179
35
|
const oauth = Object.freeze({ issuer });
|
|
180
36
|
const auth = Object.freeze({ oauth });
|
|
181
37
|
//#endregion
|
|
38
|
+
exports.AuthContext = require_errors.AuthContext;
|
|
182
39
|
exports.ToolContext = require_errors.ToolContext;
|
|
183
40
|
exports.ToolError = require_errors.ToolError;
|
|
184
41
|
exports.auth = auth;
|
|
185
|
-
exports.defineMcp = defineMcp;
|
|
186
|
-
exports.defineTool = defineTool;
|
|
42
|
+
exports.defineMcp = require_errors.defineMcp;
|
|
43
|
+
exports.defineTool = require_errors.defineTool;
|
|
187
44
|
exports.setLogLevel = require_logger.setLogLevel;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as McpClientInfo, C as ToolVisibilityContext, D as MetricsConfig, E as ZodSchema, F as McpAuthConfig, M as ProgressUpdate, N as ToolContext, O as MetricsOptions, P as JwtClaims, S as ToolHandlerResult, T as ZodRawShape, _ as ResourceLinkIcon, a as ContentBlock, b as ToolContent, c as EmbeddedResource, d as JsonValue, f as JsonValueInput, g as ResourceLink, h as McpDefinitionInput, i as ContentAnnotations, j as McpProtocolEra, k as AuthContext, l as EmbeddedTextResource, m as McpDefinition, n as AppContextToolDefinitionInput, o as CreateAppContextInput, p as McpAllowedOrigins, r as AudioContent, s as EmbeddedBlobResource, t as AppContextToolDefinition, u as ImageContent, v as TextContent, w as ZodOutputSchema, x as ToolDefinition, y as ToolAnnotations } from "./types-BCKyT2wb.cjs";
|
|
2
2
|
//#region src/core/define.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Declare a single MCP tool. Import the result into your MCP definition's
|
|
@@ -8,13 +8,18 @@ import { A as McpAuthConfig, C as MetricsConfig, D as ProgressUpdate, E as McpPr
|
|
|
8
8
|
* full `z.object(...)` — the MCP SDK builds the object wrapper internally
|
|
9
9
|
* and the raw shape is what the JSON-RPC `tools/list` payload exposes.
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
interface DefineTool {
|
|
12
|
+
<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodOutputSchema | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
|
|
13
|
+
/** Bind app context once while retaining input/output inference for every tool. */
|
|
14
|
+
withAppContext<TAppContext>(): <TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodOutputSchema | undefined = undefined>(def: AppContextToolDefinitionInput<TInput, TOutput, TAppContext>) => AppContextToolDefinition<TInput, TOutput, TAppContext>;
|
|
15
|
+
}
|
|
16
|
+
declare const defineTool: DefineTool;
|
|
12
17
|
/**
|
|
13
18
|
* Declare the MCP server. `export default` the result from your MCP
|
|
14
19
|
* entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
|
|
15
20
|
* emit the framework-specific route(s) at build time.
|
|
16
21
|
*/
|
|
17
|
-
declare function defineMcp(def: McpDefinitionInput): McpDefinition
|
|
22
|
+
declare function defineMcp<TAppContext = undefined>(def: McpDefinitionInput<TAppContext>): McpDefinition<TAppContext>;
|
|
18
23
|
//#endregion
|
|
19
24
|
//#region src/auth/config.d.ts
|
|
20
25
|
type IssuerAcceptedAudiences = string | readonly string[];
|
|
@@ -71,4 +76,4 @@ type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
|
71
76
|
*/
|
|
72
77
|
declare function setLogLevel(level: LogLevel): LogLevel;
|
|
73
78
|
//#endregion
|
|
74
|
-
export { type AudioContent, type ContentAnnotations, type ContentBlock, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JsonValue, type JsonValueInput, type JwtClaims, type LogLevel, type McpAllowedOrigins, type McpClientInfo, type McpDefinitionInput, type McpProtocolEra, type MetricsConfig, type MetricsOptions, type ProgressUpdate, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ZodOutputSchema, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
|
|
79
|
+
export { type AppContextToolDefinition, type AppContextToolDefinitionInput, type AudioContent, AuthContext, type ContentAnnotations, type ContentBlock, type CreateAppContextInput, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JsonValue, type JsonValueInput, type JwtClaims, type LogLevel, type McpAllowedOrigins, type McpClientInfo, type McpDefinitionInput, type McpProtocolEra, type MetricsConfig, type MetricsOptions, type ProgressUpdate, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ToolVisibilityContext, type ZodOutputSchema, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as McpClientInfo, C as ToolVisibilityContext, D as MetricsConfig, E as ZodSchema, F as McpAuthConfig, M as ProgressUpdate, N as ToolContext, O as MetricsOptions, P as JwtClaims, S as ToolHandlerResult, T as ZodRawShape, _ as ResourceLinkIcon, a as ContentBlock, b as ToolContent, c as EmbeddedResource, d as JsonValue, f as JsonValueInput, g as ResourceLink, h as McpDefinitionInput, i as ContentAnnotations, j as McpProtocolEra, k as AuthContext, l as EmbeddedTextResource, m as McpDefinition, n as AppContextToolDefinitionInput, o as CreateAppContextInput, p as McpAllowedOrigins, r as AudioContent, s as EmbeddedBlobResource, t as AppContextToolDefinition, u as ImageContent, v as TextContent, w as ZodOutputSchema, x as ToolDefinition, y as ToolAnnotations } from "./types-BCKyT2wb.js";
|
|
2
2
|
//#region src/core/define.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Declare a single MCP tool. Import the result into your MCP definition's
|
|
@@ -8,13 +8,18 @@ import { A as McpAuthConfig, C as MetricsConfig, D as ProgressUpdate, E as McpPr
|
|
|
8
8
|
* full `z.object(...)` — the MCP SDK builds the object wrapper internally
|
|
9
9
|
* and the raw shape is what the JSON-RPC `tools/list` payload exposes.
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
interface DefineTool {
|
|
12
|
+
<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodOutputSchema | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
|
|
13
|
+
/** Bind app context once while retaining input/output inference for every tool. */
|
|
14
|
+
withAppContext<TAppContext>(): <TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodOutputSchema | undefined = undefined>(def: AppContextToolDefinitionInput<TInput, TOutput, TAppContext>) => AppContextToolDefinition<TInput, TOutput, TAppContext>;
|
|
15
|
+
}
|
|
16
|
+
declare const defineTool: DefineTool;
|
|
12
17
|
/**
|
|
13
18
|
* Declare the MCP server. `export default` the result from your MCP
|
|
14
19
|
* entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
|
|
15
20
|
* emit the framework-specific route(s) at build time.
|
|
16
21
|
*/
|
|
17
|
-
declare function defineMcp(def: McpDefinitionInput): McpDefinition
|
|
22
|
+
declare function defineMcp<TAppContext = undefined>(def: McpDefinitionInput<TAppContext>): McpDefinition<TAppContext>;
|
|
18
23
|
//#endregion
|
|
19
24
|
//#region src/auth/config.d.ts
|
|
20
25
|
type IssuerAcceptedAudiences = string | readonly string[];
|
|
@@ -71,4 +76,4 @@ type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
|
71
76
|
*/
|
|
72
77
|
declare function setLogLevel(level: LogLevel): LogLevel;
|
|
73
78
|
//#endregion
|
|
74
|
-
export { type AudioContent, type ContentAnnotations, type ContentBlock, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JsonValue, type JsonValueInput, type JwtClaims, type LogLevel, type McpAllowedOrigins, type McpClientInfo, type McpDefinitionInput, type McpProtocolEra, type MetricsConfig, type MetricsOptions, type ProgressUpdate, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ZodOutputSchema, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
|
|
79
|
+
export { type AppContextToolDefinition, type AppContextToolDefinitionInput, type AudioContent, AuthContext, type ContentAnnotations, type ContentBlock, type CreateAppContextInput, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JsonValue, type JsonValueInput, type JwtClaims, type LogLevel, type McpAllowedOrigins, type McpClientInfo, type McpDefinitionInput, type McpProtocolEra, type MetricsConfig, type MetricsOptions, type ProgressUpdate, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ToolVisibilityContext, type ZodOutputSchema, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
|
package/dist/index.js
CHANGED
|
@@ -1,149 +1,5 @@
|
|
|
1
|
-
import { a as setLogLevel
|
|
2
|
-
import { t as
|
|
3
|
-
import { i as ToolContext, t as ToolError } from "./errors-Bwd1L0Rf.js";
|
|
4
|
-
//#region src/core/define.ts
|
|
5
|
-
function assertUniqueNames(mcp) {
|
|
6
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7
|
-
for (const tool of mcp.tools) {
|
|
8
|
-
if (seen.has(tool.name)) throw new Error(`@lovable.dev/mcp-js: duplicate tool name "${tool.name}"`);
|
|
9
|
-
seen.add(tool.name);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
function assertNonEmptyString(label, value) {
|
|
13
|
-
if (value.trim() === "") throw new Error(`@lovable.dev/mcp-js: ${label} must not be empty`);
|
|
14
|
-
if (value !== value.trim()) throw new Error(`@lovable.dev/mcp-js: ${label} must not have leading or trailing whitespace`);
|
|
15
|
-
}
|
|
16
|
-
function assertHttpsUrlField(name, value) {
|
|
17
|
-
assertNonEmptyString(`auth.${name}`, value);
|
|
18
|
-
parseSafeUrl(`@lovable.dev/mcp-js: auth.${name}`, value);
|
|
19
|
-
}
|
|
20
|
-
function assertScope(scope) {
|
|
21
|
-
if (scope.trim() === "" || /\s/.test(scope)) throw new Error(`@lovable.dev/mcp-js: OAuth scopes must be non-empty space-free tokens`);
|
|
22
|
-
}
|
|
23
|
-
function assertJwtAlgorithm(algorithm) {
|
|
24
|
-
if (algorithm.trim() === "" || /\s/.test(algorithm)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must contain non-empty space-free tokens`);
|
|
25
|
-
if (/^HS\d+$/i.test(algorithm) || algorithm.toLowerCase() === "none") throw new Error(`@lovable.dev/mcp-js: auth.algorithms cannot include "${algorithm}"; this verifier is JWKS-only`);
|
|
26
|
-
}
|
|
27
|
-
const MAX_CLOCK_TOLERANCE_SECONDS = 300;
|
|
28
|
-
function assertClockToleranceSeconds(value) {
|
|
29
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > MAX_CLOCK_TOLERANCE_SECONDS) throw new Error(`@lovable.dev/mcp-js: auth.clockToleranceSeconds must be a non-negative number of seconds no greater than ${MAX_CLOCK_TOLERANCE_SECONDS}`);
|
|
30
|
-
}
|
|
31
|
-
function assertOAuthConfig(auth) {
|
|
32
|
-
if (auth.type !== "oauth") {
|
|
33
|
-
const authType = String(auth.type);
|
|
34
|
-
throw new Error(`@lovable.dev/mcp-js: unsupported auth type "${authType}"`);
|
|
35
|
-
}
|
|
36
|
-
if (auth.issuer === void 0) throw new Error(`@lovable.dev/mcp-js: auth.issuer is required`);
|
|
37
|
-
assertHttpsUrlField("issuer", auth.issuer);
|
|
38
|
-
if (auth.jwksUri !== void 0) assertHttpsUrlField("jwksUri", auth.jwksUri);
|
|
39
|
-
if (auth.resource !== void 0) assertHttpsUrlField("resource", auth.resource);
|
|
40
|
-
if (auth.resourceName !== void 0) assertNonEmptyString("auth.resourceName", auth.resourceName);
|
|
41
|
-
if (auth.resourceDocumentation !== void 0) assertHttpsUrlField("resourceDocumentation", auth.resourceDocumentation);
|
|
42
|
-
if (auth.protectedResourceMetadataUrl !== void 0) assertHttpsUrlField("protectedResourceMetadataUrl", auth.protectedResourceMetadataUrl);
|
|
43
|
-
if (auth.acceptedAudiences !== void 0) {
|
|
44
|
-
if (!Array.isArray(auth.acceptedAudiences)) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must be an array`);
|
|
45
|
-
if (auth.acceptedAudiences.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must not be empty`);
|
|
46
|
-
for (const audience of auth.acceptedAudiences) {
|
|
47
|
-
if (typeof audience !== "string") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
|
|
48
|
-
assertNonEmptyString("auth.acceptedAudiences", audience);
|
|
49
|
-
if (trimTrailingSlash(audience) === "") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences entries must not be only slashes`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (auth.requireOAuthClientClaim !== void 0 && typeof auth.requireOAuthClientClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.requireOAuthClientClaim must be a boolean`);
|
|
53
|
-
if (auth.acceptResourceClaim !== void 0 && typeof auth.acceptResourceClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.acceptResourceClaim must be a boolean`);
|
|
54
|
-
if (auth.requiredScopes !== void 0) {
|
|
55
|
-
if (!Array.isArray(auth.requiredScopes)) throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);
|
|
56
|
-
for (const scope of auth.requiredScopes) assertScope(scope);
|
|
57
|
-
}
|
|
58
|
-
if (auth.algorithms !== void 0) {
|
|
59
|
-
if (!Array.isArray(auth.algorithms)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must be an array`);
|
|
60
|
-
if (auth.algorithms.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must not be empty`);
|
|
61
|
-
for (const algorithm of auth.algorithms) assertJwtAlgorithm(algorithm);
|
|
62
|
-
}
|
|
63
|
-
if (auth.accessTokenTyp !== void 0) {
|
|
64
|
-
if (!Array.isArray(auth.accessTokenTyp)) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must be an array`);
|
|
65
|
-
if (auth.accessTokenTyp.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must not be empty`);
|
|
66
|
-
for (const typ of auth.accessTokenTyp) {
|
|
67
|
-
if (typeof typ !== "string") throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must contain strings`);
|
|
68
|
-
assertNonEmptyString("auth.accessTokenTyp", typ);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (auth.clockToleranceSeconds !== void 0) assertClockToleranceSeconds(auth.clockToleranceSeconds);
|
|
72
|
-
if (auth.resource === void 0 && auth.acceptedAudiences === void 0) throw new Error(`@lovable.dev/mcp-js: auth.resource or auth.acceptedAudiences is required`);
|
|
73
|
-
}
|
|
74
|
-
function freezeAuth(auth) {
|
|
75
|
-
if (!auth) return;
|
|
76
|
-
if (auth.acceptedAudiences) Object.freeze(auth.acceptedAudiences);
|
|
77
|
-
if (auth.requiredScopes) Object.freeze(auth.requiredScopes);
|
|
78
|
-
if (auth.algorithms) Object.freeze(auth.algorithms);
|
|
79
|
-
if (auth.accessTokenTyp) Object.freeze(auth.accessTokenTyp);
|
|
80
|
-
Object.freeze(auth);
|
|
81
|
-
}
|
|
82
|
-
function assertAllowedOrigins(allowedOrigins) {
|
|
83
|
-
if (allowedOrigins === void 0 || allowedOrigins === "any") return;
|
|
84
|
-
if (!Array.isArray(allowedOrigins)) throw new Error(`@lovable.dev/mcp-js: allowedOrigins must be "any" or an array of exact origins`);
|
|
85
|
-
for (const origin of allowedOrigins) {
|
|
86
|
-
if (typeof origin !== "string") throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain strings`);
|
|
87
|
-
let parsed;
|
|
88
|
-
try {
|
|
89
|
-
parsed = new URL(origin);
|
|
90
|
-
} catch {
|
|
91
|
-
throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain valid exact origins`);
|
|
92
|
-
}
|
|
93
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.origin !== origin) throw new Error(`@lovable.dev/mcp-js: allowedOrigins entry "${origin}" must be an exact http(s) origin without a path, query, fragment, or trailing slash`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function assertToolSchemas(mcp) {
|
|
97
|
-
for (const tool of mcp.tools) for (const [name, definition, strategy] of [[
|
|
98
|
-
"inputSchema",
|
|
99
|
-
tool.inputSchema,
|
|
100
|
-
"input"
|
|
101
|
-
], [
|
|
102
|
-
"outputSchema",
|
|
103
|
-
tool.outputSchema,
|
|
104
|
-
"output"
|
|
105
|
-
]]) {
|
|
106
|
-
if (!definition) continue;
|
|
107
|
-
try {
|
|
108
|
-
jsonSchemaFromDefinition(definition, strategy);
|
|
109
|
-
} catch (error) {
|
|
110
|
-
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
111
|
-
throw new Error(`@lovable.dev/mcp-js: tool "${tool.name}" ${name} cannot be represented as JSON Schema${detail}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Declare a single MCP tool. Import the result into your MCP definition's
|
|
117
|
-
* `tools` array — `defineMcp({ tools: [echoTool, ...] })`.
|
|
118
|
-
*
|
|
119
|
-
* `inputSchema` is a raw zod shape (e.g. `{ text: z.string() }`), not a
|
|
120
|
-
* full `z.object(...)` — the MCP SDK builds the object wrapper internally
|
|
121
|
-
* and the raw shape is what the JSON-RPC `tools/list` payload exposes.
|
|
122
|
-
*/
|
|
123
|
-
function defineTool(def) {
|
|
124
|
-
return def;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Declare the MCP server. `export default` the result from your MCP
|
|
128
|
-
* entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
|
|
129
|
-
* emit the framework-specific route(s) at build time.
|
|
130
|
-
*/
|
|
131
|
-
function defineMcp(def) {
|
|
132
|
-
assertNonEmptyString("name", def.name);
|
|
133
|
-
assertNonEmptyString("title", def.title);
|
|
134
|
-
assertNonEmptyString("version", def.version);
|
|
135
|
-
assertUniqueNames(def);
|
|
136
|
-
if (def.auth) assertOAuthConfig(def.auth);
|
|
137
|
-
assertAllowedOrigins(def.allowedOrigins);
|
|
138
|
-
assertToolSchemas(def);
|
|
139
|
-
resolveMetricsConfig(def.metrics);
|
|
140
|
-
freezeAuth(def.auth);
|
|
141
|
-
if (Array.isArray(def.allowedOrigins)) Object.freeze(def.allowedOrigins);
|
|
142
|
-
Object.freeze(def.tools);
|
|
143
|
-
for (const tool of def.tools) Object.freeze(tool);
|
|
144
|
-
return def;
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
1
|
+
import { a as setLogLevel } from "./logger-CpLgYbCG.js";
|
|
2
|
+
import { a as ToolContext, i as AuthContext, o as defineMcp, s as defineTool, t as ToolError } from "./errors-DGcJ8jPK.js";
|
|
147
3
|
//#region src/auth/config.ts
|
|
148
4
|
function frozenArray(value) {
|
|
149
5
|
return value === void 0 ? void 0 : Object.freeze([...value]);
|
|
@@ -178,4 +34,4 @@ function issuer(options) {
|
|
|
178
34
|
const oauth = Object.freeze({ issuer });
|
|
179
35
|
const auth = Object.freeze({ oauth });
|
|
180
36
|
//#endregion
|
|
181
|
-
export { ToolContext, ToolError, auth, defineMcp, defineTool, setLogLevel };
|
|
37
|
+
export { AuthContext, ToolContext, ToolError, auth, defineMcp, defineTool, setLogLevel };
|