@scupit/mcp-ecosystem 0.1.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/dist/auth0/index.d.ts +3 -0
- package/dist/auth0/index.d.ts.map +1 -0
- package/dist/auth0/index.js +2 -0
- package/dist/auth0/index.js.map +1 -0
- package/dist/auth0/management-client.d.ts +78 -0
- package/dist/auth0/management-client.d.ts.map +1 -0
- package/dist/auth0/management-client.js +183 -0
- package/dist/auth0/management-client.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +150 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add-scope.d.ts +9 -0
- package/dist/commands/add-scope.d.ts.map +1 -0
- package/dist/commands/add-scope.js +55 -0
- package/dist/commands/add-scope.js.map +1 -0
- package/dist/commands/generate-artifacts.d.ts +10 -0
- package/dist/commands/generate-artifacts.d.ts.map +1 -0
- package/dist/commands/generate-artifacts.js +91 -0
- package/dist/commands/generate-artifacts.js.map +1 -0
- package/dist/commands/grant-client.d.ts +12 -0
- package/dist/commands/grant-client.d.ts.map +1 -0
- package/dist/commands/grant-client.js +111 -0
- package/dist/commands/grant-client.js.map +1 -0
- package/dist/commands/index.d.ts +15 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/reconcile-all.d.ts +10 -0
- package/dist/commands/reconcile-all.d.ts.map +1 -0
- package/dist/commands/reconcile-all.js +58 -0
- package/dist/commands/reconcile-all.js.map +1 -0
- package/dist/commands/reconcile-client.d.ts +11 -0
- package/dist/commands/reconcile-client.d.ts.map +1 -0
- package/dist/commands/reconcile-client.js +295 -0
- package/dist/commands/reconcile-client.js.map +1 -0
- package/dist/commands/reconcile-server.d.ts +18 -0
- package/dist/commands/reconcile-server.d.ts.map +1 -0
- package/dist/commands/reconcile-server.js +213 -0
- package/dist/commands/reconcile-server.js.map +1 -0
- package/dist/commands/verify-tenant.d.ts +10 -0
- package/dist/commands/verify-tenant.d.ts.map +1 -0
- package/dist/commands/verify-tenant.js +76 -0
- package/dist/commands/verify-tenant.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +21 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +181 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-runtime/auth-middleware.d.ts +27 -0
- package/dist/mcp-runtime/auth-middleware.d.ts.map +1 -0
- package/dist/mcp-runtime/auth-middleware.js +88 -0
- package/dist/mcp-runtime/auth-middleware.js.map +1 -0
- package/dist/mcp-runtime/index.d.ts +9 -0
- package/dist/mcp-runtime/index.d.ts.map +1 -0
- package/dist/mcp-runtime/index.js +5 -0
- package/dist/mcp-runtime/index.js.map +1 -0
- package/dist/mcp-runtime/protected-resource-metadata.d.ts +20 -0
- package/dist/mcp-runtime/protected-resource-metadata.d.ts.map +1 -0
- package/dist/mcp-runtime/protected-resource-metadata.js +30 -0
- package/dist/mcp-runtime/protected-resource-metadata.js.map +1 -0
- package/dist/mcp-runtime/token-validator.d.ts +32 -0
- package/dist/mcp-runtime/token-validator.d.ts.map +1 -0
- package/dist/mcp-runtime/token-validator.js +59 -0
- package/dist/mcp-runtime/token-validator.js.map +1 -0
- package/dist/mcp-runtime/www-authenticate.d.ts +19 -0
- package/dist/mcp-runtime/www-authenticate.d.ts.map +1 -0
- package/dist/mcp-runtime/www-authenticate.js +39 -0
- package/dist/mcp-runtime/www-authenticate.js.map +1 -0
- package/dist/mcp-server/create-server.d.ts +44 -0
- package/dist/mcp-server/create-server.d.ts.map +1 -0
- package/dist/mcp-server/create-server.js +73 -0
- package/dist/mcp-server/create-server.js.map +1 -0
- package/dist/mcp-server/index.d.ts +3 -0
- package/dist/mcp-server/index.d.ts.map +1 -0
- package/dist/mcp-server/index.js +2 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/types/auth0-responses.d.ts +46 -0
- package/dist/types/auth0-responses.d.ts.map +1 -0
- package/dist/types/auth0-responses.js +6 -0
- package/dist/types/auth0-responses.js.map +1 -0
- package/dist/types/client-config.d.ts +96 -0
- package/dist/types/client-config.d.ts.map +1 -0
- package/dist/types/client-config.js +32 -0
- package/dist/types/client-config.js.map +1 -0
- package/dist/types/client-descriptor.d.ts +45 -0
- package/dist/types/client-descriptor.d.ts.map +1 -0
- package/dist/types/client-descriptor.js +22 -0
- package/dist/types/client-descriptor.js.map +1 -0
- package/dist/types/ecosystem-config.d.ts +210 -0
- package/dist/types/ecosystem-config.d.ts.map +1 -0
- package/dist/types/ecosystem-config.js +64 -0
- package/dist/types/ecosystem-config.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/server-config.d.ts +73 -0
- package/dist/types/server-config.d.ts.map +1 -0
- package/dist/types/server-config.js +30 -0
- package/dist/types/server-config.js.map +1 -0
- package/dist/utils/context.d.ts +19 -0
- package/dist/utils/context.d.ts.map +1 -0
- package/dist/utils/context.js +29 -0
- package/dist/utils/context.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +29 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { TokenValidator, InsufficientScopeError } from "./token-validator.js";
|
|
2
|
+
import { send401Challenge } from "./www-authenticate.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates an Express/Connect-compatible middleware that validates bearer tokens.
|
|
5
|
+
*
|
|
6
|
+
* On success, attaches `req.auth` with the validated token claims.
|
|
7
|
+
* On failure, sends a proper 401 WWW-Authenticate challenge per MCP spec.
|
|
8
|
+
*/
|
|
9
|
+
export function createAuthMiddleware(options) {
|
|
10
|
+
const validator = new TokenValidator({
|
|
11
|
+
issuer: options.issuer,
|
|
12
|
+
audience: options.audience,
|
|
13
|
+
jwksUri: options.jwksUri,
|
|
14
|
+
});
|
|
15
|
+
return async (req, res, next) => {
|
|
16
|
+
const authHeader = req.headers.authorization;
|
|
17
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
18
|
+
send401Challenge(res, {
|
|
19
|
+
resourceMetadataUrl: options.resourceMetadataUrl,
|
|
20
|
+
error: "invalid_request",
|
|
21
|
+
errorDescription: "Missing or malformed Authorization header",
|
|
22
|
+
});
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const token = authHeader.slice(7);
|
|
26
|
+
try {
|
|
27
|
+
const payload = await validator.validate(token);
|
|
28
|
+
req.auth = payload;
|
|
29
|
+
next?.();
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (err instanceof InsufficientScopeError) {
|
|
33
|
+
send401Challenge(res, {
|
|
34
|
+
resourceMetadataUrl: options.resourceMetadataUrl,
|
|
35
|
+
requiredScopes: err.requiredScopes,
|
|
36
|
+
error: "insufficient_scope",
|
|
37
|
+
errorDescription: err.message,
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
send401Challenge(res, {
|
|
42
|
+
resourceMetadataUrl: options.resourceMetadataUrl,
|
|
43
|
+
error: "invalid_token",
|
|
44
|
+
errorDescription: err instanceof Error ? err.message : "Token validation failed",
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Factory for route-level scope enforcement middleware.
|
|
51
|
+
*
|
|
52
|
+
* Usage:
|
|
53
|
+
* app.post('/tools/execute', requireScopes(['tools.write']), handler);
|
|
54
|
+
*/
|
|
55
|
+
export function requireScopes(scopes) {
|
|
56
|
+
return (req, res, next) => {
|
|
57
|
+
const auth = req.auth;
|
|
58
|
+
if (!auth) {
|
|
59
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
60
|
+
res.end(JSON.stringify({ error: "unauthorized" }));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const tokenScopes = new Set();
|
|
64
|
+
if (typeof auth["scope"] === "string") {
|
|
65
|
+
for (const s of auth["scope"].split(" ")) {
|
|
66
|
+
if (s)
|
|
67
|
+
tokenScopes.add(s);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (Array.isArray(auth["permissions"])) {
|
|
71
|
+
for (const p of auth["permissions"]) {
|
|
72
|
+
if (typeof p === "string")
|
|
73
|
+
tokenScopes.add(p);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const hasSufficientScope = scopes.some((s) => tokenScopes.has(s));
|
|
77
|
+
if (!hasSufficientScope) {
|
|
78
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
79
|
+
res.end(JSON.stringify({
|
|
80
|
+
error: "insufficient_scope",
|
|
81
|
+
required_scopes: scopes,
|
|
82
|
+
}));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
next?.();
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=auth-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../../src/mcp-runtime/auth-middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { buildProtectedResourceMetadata, protectedResourceMetadataHandler, } from "./protected-resource-metadata.js";
|
|
2
|
+
export type { ProtectedResourceMetadata, ProtectedResourceMetadataOptions, } from "./protected-resource-metadata.js";
|
|
3
|
+
export { TokenValidator, InsufficientScopeError, } from "./token-validator.js";
|
|
4
|
+
export type { TokenValidatorOptions, ValidatedToken, } from "./token-validator.js";
|
|
5
|
+
export { buildWwwAuthenticateChallenge, send401Challenge, } from "./www-authenticate.js";
|
|
6
|
+
export type { ChallengeOptions } from "./www-authenticate.js";
|
|
7
|
+
export { createAuthMiddleware, requireScopes, } from "./auth-middleware.js";
|
|
8
|
+
export type { AuthMiddlewareOptions } from "./auth-middleware.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp-runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EACV,yBAAyB,EACzB,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,cAAc,EACd,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { buildProtectedResourceMetadata, protectedResourceMetadataHandler, } from "./protected-resource-metadata.js";
|
|
2
|
+
export { TokenValidator, InsufficientScopeError, } from "./token-validator.js";
|
|
3
|
+
export { buildWwwAuthenticateChallenge, send401Challenge, } from "./www-authenticate.js";
|
|
4
|
+
export { createAuthMiddleware, requireScopes, } from "./auth-middleware.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAM1C,OAAO,EACL,cAAc,EACd,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
export interface ProtectedResourceMetadata {
|
|
3
|
+
resource: string;
|
|
4
|
+
authorization_servers: string[];
|
|
5
|
+
scopes_supported?: string[];
|
|
6
|
+
bearer_methods_supported?: string[];
|
|
7
|
+
resource_documentation?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ProtectedResourceMetadataOptions {
|
|
10
|
+
resourceUri: string;
|
|
11
|
+
authorizationServerUri: string;
|
|
12
|
+
scopes?: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function buildProtectedResourceMetadata(options: ProtectedResourceMetadataOptions): ProtectedResourceMetadata;
|
|
15
|
+
/**
|
|
16
|
+
* Express/Connect-compatible middleware that serves the Protected Resource
|
|
17
|
+
* Metadata document at `/.well-known/oauth-protected-resource`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function protectedResourceMetadataHandler(metadata: ProtectedResourceMetadata): (req: IncomingMessage, res: ServerResponse, next?: () => void) => void;
|
|
20
|
+
//# sourceMappingURL=protected-resource-metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protected-resource-metadata.d.ts","sourceRoot":"","sources":["../../src/mcp-runtime/protected-resource-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IACpC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,gCAAgC;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,gCAAgC,GACxC,yBAAyB,CAU3B;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,yBAAyB,IAI3B,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,OAAO,MAAM,IAAI,UAWrE"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function buildProtectedResourceMetadata(options) {
|
|
2
|
+
return {
|
|
3
|
+
resource: options.resourceUri,
|
|
4
|
+
authorization_servers: [options.authorizationServerUri],
|
|
5
|
+
...(options.scopes &&
|
|
6
|
+
options.scopes.length > 0 && {
|
|
7
|
+
scopes_supported: options.scopes,
|
|
8
|
+
}),
|
|
9
|
+
bearer_methods_supported: ["header"],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Express/Connect-compatible middleware that serves the Protected Resource
|
|
14
|
+
* Metadata document at `/.well-known/oauth-protected-resource`.
|
|
15
|
+
*/
|
|
16
|
+
export function protectedResourceMetadataHandler(metadata) {
|
|
17
|
+
const body = JSON.stringify(metadata);
|
|
18
|
+
return (req, res, next) => {
|
|
19
|
+
if (req.url === "/.well-known/oauth-protected-resource") {
|
|
20
|
+
res.writeHead(200, {
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
"Cache-Control": "public, max-age=3600",
|
|
23
|
+
});
|
|
24
|
+
res.end(body);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
next?.();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=protected-resource-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protected-resource-metadata.js","sourceRoot":"","sources":["../../src/mcp-runtime/protected-resource-metadata.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,8BAA8B,CAC5C,OAAyC;IAEzC,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,WAAW;QAC7B,qBAAqB,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC;QACvD,GAAG,CAAC,OAAO,CAAC,MAAM;YAChB,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI;YAC3B,gBAAgB,EAAE,OAAO,CAAC,MAAM;SACjC,CAAC;QACJ,wBAAwB,EAAE,CAAC,QAAQ,CAAC;KACrC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gCAAgC,CAC9C,QAAmC;IAEnC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEtC,OAAO,CAAC,GAAoB,EAAE,GAAmB,EAAE,IAAiB,EAAE,EAAE;QACtE,IAAI,GAAG,CAAC,GAAG,KAAK,uCAAuC,EAAE,CAAC;YACxD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,sBAAsB;aACxC,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QACD,IAAI,EAAE,EAAE,CAAC;IACX,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface TokenValidatorOptions {
|
|
2
|
+
issuer: string;
|
|
3
|
+
audience: string;
|
|
4
|
+
jwksUri?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ValidatedToken {
|
|
7
|
+
sub: string;
|
|
8
|
+
iss: string;
|
|
9
|
+
aud: string | string[];
|
|
10
|
+
exp: number;
|
|
11
|
+
iat: number;
|
|
12
|
+
scope?: string;
|
|
13
|
+
permissions?: string[];
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export declare class TokenValidator {
|
|
17
|
+
private readonly issuer;
|
|
18
|
+
private readonly audience;
|
|
19
|
+
private readonly jwks;
|
|
20
|
+
constructor(options: TokenValidatorOptions);
|
|
21
|
+
validate(token: string): Promise<ValidatedToken>;
|
|
22
|
+
/**
|
|
23
|
+
* Validate the token and check that it contains at least one of the required scopes.
|
|
24
|
+
*/
|
|
25
|
+
validateWithScopes(token: string, requiredScopes: string[]): Promise<ValidatedToken>;
|
|
26
|
+
}
|
|
27
|
+
export declare class InsufficientScopeError extends Error {
|
|
28
|
+
readonly requiredScopes: string[];
|
|
29
|
+
readonly presentScopes: Set<string>;
|
|
30
|
+
constructor(required: string[], present: Set<string>);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=token-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-validator.d.ts","sourceRoot":"","sources":["../../src/mcp-runtime/token-validator.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6C;gBAEtD,OAAO,EAAE,qBAAqB;IAQpC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAUtD;;OAEG;IACG,kBAAkB,CACtB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,cAAc,CAAC;CAY3B;AAoBD,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzC,SAAgB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBAE/B,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC;CAQrD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as jose from "jose";
|
|
2
|
+
export class TokenValidator {
|
|
3
|
+
issuer;
|
|
4
|
+
audience;
|
|
5
|
+
jwks;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.issuer = options.issuer;
|
|
8
|
+
this.audience = options.audience;
|
|
9
|
+
const jwksUrl = options.jwksUri ?? `${this.issuer}.well-known/jwks.json`;
|
|
10
|
+
this.jwks = jose.createRemoteJWKSet(new URL(jwksUrl));
|
|
11
|
+
}
|
|
12
|
+
async validate(token) {
|
|
13
|
+
const { payload } = await jose.jwtVerify(token, this.jwks, {
|
|
14
|
+
issuer: this.issuer,
|
|
15
|
+
audience: this.audience,
|
|
16
|
+
algorithms: ["RS256"],
|
|
17
|
+
});
|
|
18
|
+
return payload;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Validate the token and check that it contains at least one of the required scopes.
|
|
22
|
+
*/
|
|
23
|
+
async validateWithScopes(token, requiredScopes) {
|
|
24
|
+
const payload = await this.validate(token);
|
|
25
|
+
const tokenScopes = extractScopes(payload);
|
|
26
|
+
const hasScope = requiredScopes.some((s) => tokenScopes.has(s));
|
|
27
|
+
if (!hasScope) {
|
|
28
|
+
throw new InsufficientScopeError(requiredScopes, tokenScopes);
|
|
29
|
+
}
|
|
30
|
+
return payload;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function extractScopes(payload) {
|
|
34
|
+
const scopes = new Set();
|
|
35
|
+
if (typeof payload.scope === "string") {
|
|
36
|
+
for (const s of payload.scope.split(" ")) {
|
|
37
|
+
if (s)
|
|
38
|
+
scopes.add(s);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(payload.permissions)) {
|
|
42
|
+
for (const p of payload.permissions) {
|
|
43
|
+
if (typeof p === "string")
|
|
44
|
+
scopes.add(p);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return scopes;
|
|
48
|
+
}
|
|
49
|
+
export class InsufficientScopeError extends Error {
|
|
50
|
+
requiredScopes;
|
|
51
|
+
presentScopes;
|
|
52
|
+
constructor(required, present) {
|
|
53
|
+
super(`Insufficient scope. Required one of: [${required.join(", ")}]. Present: [${[...present].join(", ")}]`);
|
|
54
|
+
this.name = "InsufficientScopeError";
|
|
55
|
+
this.requiredScopes = required;
|
|
56
|
+
this.presentScopes = present;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=token-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-validator.js","sourceRoot":"","sources":["../../src/mcp-runtime/token-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAmB7B,MAAM,OAAO,cAAc;IACR,MAAM,CAAS;IACf,QAAQ,CAAS;IACjB,IAAI,CAA6C;IAElE,YAAY,OAA8B;QACxC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,MAAM,OAAO,GACX,OAAO,CAAC,OAAO,IAAI,GAAG,IAAI,CAAC,MAAM,uBAAuB,CAAC;QAC3D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC1B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE;YACzD,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,CAAC,OAAO,CAAC;SACtB,CAAC,CAAC;QAEH,OAAO,OAAoC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CACtB,KAAa,EACb,cAAwB;QAExB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAE3C,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,sBAAsB,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,SAAS,aAAa,CAAC,OAAuB;IAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IAEjC,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACpC,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/B,cAAc,CAAW;IACzB,aAAa,CAAc;IAE3C,YAAY,QAAkB,EAAE,OAAoB;QAClD,KAAK,CACH,yCAAyC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACvG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC;QAC/B,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ServerResponse } from "node:http";
|
|
2
|
+
export interface ChallengeOptions {
|
|
3
|
+
resourceMetadataUrl: string;
|
|
4
|
+
requiredScopes?: string[];
|
|
5
|
+
error?: string;
|
|
6
|
+
errorDescription?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Build a WWW-Authenticate header value conforming to MCP's authorization spec.
|
|
10
|
+
*
|
|
11
|
+
* MCP requires servers to include `resource_metadata` in the challenge,
|
|
12
|
+
* and recommends including `scope` when applicable.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildWwwAuthenticateChallenge(options: ChallengeOptions): string;
|
|
15
|
+
/**
|
|
16
|
+
* Send a 401 response with a proper WWW-Authenticate challenge.
|
|
17
|
+
*/
|
|
18
|
+
export declare function send401Challenge(res: ServerResponse, options: ChallengeOptions): void;
|
|
19
|
+
//# sourceMappingURL=www-authenticate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"www-authenticate.d.ts","sourceRoot":"","sources":["../../src/mcp-runtime/www-authenticate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAuBR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAaN"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a WWW-Authenticate header value conforming to MCP's authorization spec.
|
|
3
|
+
*
|
|
4
|
+
* MCP requires servers to include `resource_metadata` in the challenge,
|
|
5
|
+
* and recommends including `scope` when applicable.
|
|
6
|
+
*/
|
|
7
|
+
export function buildWwwAuthenticateChallenge(options) {
|
|
8
|
+
const parts = ["Bearer"];
|
|
9
|
+
const params = [];
|
|
10
|
+
params.push(`resource_metadata="${options.resourceMetadataUrl}"`);
|
|
11
|
+
if (options.requiredScopes && options.requiredScopes.length > 0) {
|
|
12
|
+
params.push(`scope="${options.requiredScopes.join(" ")}"`);
|
|
13
|
+
}
|
|
14
|
+
if (options.error) {
|
|
15
|
+
params.push(`error="${options.error}"`);
|
|
16
|
+
}
|
|
17
|
+
if (options.errorDescription) {
|
|
18
|
+
params.push(`error_description="${options.errorDescription}"`);
|
|
19
|
+
}
|
|
20
|
+
if (params.length > 0) {
|
|
21
|
+
parts.push(params.join(", "));
|
|
22
|
+
}
|
|
23
|
+
return parts.join(" ");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Send a 401 response with a proper WWW-Authenticate challenge.
|
|
27
|
+
*/
|
|
28
|
+
export function send401Challenge(res, options) {
|
|
29
|
+
const challenge = buildWwwAuthenticateChallenge(options);
|
|
30
|
+
res.writeHead(401, {
|
|
31
|
+
"WWW-Authenticate": challenge,
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
});
|
|
34
|
+
res.end(JSON.stringify({
|
|
35
|
+
error: options.error ?? "unauthorized",
|
|
36
|
+
error_description: options.errorDescription ?? "Authentication required",
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=www-authenticate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"www-authenticate.js","sourceRoot":"","sources":["../../src/mcp-runtime/www-authenticate.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAC3C,OAAyB;IAEzB,MAAM,KAAK,GAAa,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,CAAC,IAAI,CAAC,sBAAsB,OAAO,CAAC,mBAAmB,GAAG,CAAC,CAAC;IAElE,IAAI,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,sBAAsB,OAAO,CAAC,gBAAgB,GAAG,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAmB,EACnB,OAAyB;IAEzB,MAAM,SAAS,GAAG,6BAA6B,CAAC,OAAO,CAAC,CAAC;IACzD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,kBAAkB,EAAE,SAAS;QAC7B,cAAc,EAAE,kBAAkB;KACnC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,cAAc;QACtC,iBAAiB,EACf,OAAO,CAAC,gBAAgB,IAAI,yBAAyB;KACxD,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
export interface RuntimeConfig {
|
|
4
|
+
server: {
|
|
5
|
+
name: string;
|
|
6
|
+
slug: string;
|
|
7
|
+
hostname: string;
|
|
8
|
+
resource_uri: string;
|
|
9
|
+
mcp_endpoint: string;
|
|
10
|
+
};
|
|
11
|
+
auth: {
|
|
12
|
+
issuer: string;
|
|
13
|
+
audience: string;
|
|
14
|
+
jwks_uri: string;
|
|
15
|
+
protected_resource_metadata_url: string;
|
|
16
|
+
};
|
|
17
|
+
scopes: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Load the generated runtime config from an MCP server's directory.
|
|
21
|
+
* Reads `runtime-config.generated.json` produced by `mcp-ecosystem generate-artifacts`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadRuntimeConfig(mcpDir: string): RuntimeConfig;
|
|
24
|
+
export interface CreateMcpHttpServerOptions {
|
|
25
|
+
/** Override the MCP server version string. Defaults to "0.1.0". */
|
|
26
|
+
version?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create an Express app wired up with:
|
|
30
|
+
* - Protected Resource Metadata at `/.well-known/oauth-protected-resource`
|
|
31
|
+
* - Health check at `/health`
|
|
32
|
+
* - MCP Streamable HTTP transport at `/mcp`
|
|
33
|
+
*
|
|
34
|
+
* Returns the Express app and the McpServer instance for tool/resource registration.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createMcpHttpServer(config: RuntimeConfig, options?: CreateMcpHttpServerOptions): {
|
|
37
|
+
app: import("express-serve-static-core").Express;
|
|
38
|
+
mcpServer: McpServer;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Start listening on the given port with a startup banner.
|
|
42
|
+
*/
|
|
43
|
+
export declare function startServer(app: express.Express, config: RuntimeConfig, port: number): void;
|
|
44
|
+
//# sourceMappingURL=create-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-server.d.ts","sourceRoot":"","sources":["../../src/mcp-server/create-server.ts"],"names":[],"mappings":"AAEA,OAAO,OAAwC,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,IAAI,EAAE;QACJ,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,+BAA+B,EAAE,MAAM,CAAC;KACzC,CAAC;IACF,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAI/D;AAED,MAAM,WAAW,0BAA0B;IACzC,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,0BAA0B;;;EA+CrC;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,GACX,IAAI,CAUN"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
6
|
+
/**
|
|
7
|
+
* Load the generated runtime config from an MCP server's directory.
|
|
8
|
+
* Reads `runtime-config.generated.json` produced by `mcp-ecosystem generate-artifacts`.
|
|
9
|
+
*/
|
|
10
|
+
export function loadRuntimeConfig(mcpDir) {
|
|
11
|
+
const configPath = join(mcpDir, "runtime-config.generated.json");
|
|
12
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
13
|
+
return JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create an Express app wired up with:
|
|
17
|
+
* - Protected Resource Metadata at `/.well-known/oauth-protected-resource`
|
|
18
|
+
* - Health check at `/health`
|
|
19
|
+
* - MCP Streamable HTTP transport at `/mcp`
|
|
20
|
+
*
|
|
21
|
+
* Returns the Express app and the McpServer instance for tool/resource registration.
|
|
22
|
+
*/
|
|
23
|
+
export function createMcpHttpServer(config, options) {
|
|
24
|
+
const app = express();
|
|
25
|
+
app.use(express.json());
|
|
26
|
+
app.get("/.well-known/oauth-protected-resource", (_req, res) => {
|
|
27
|
+
res.setHeader("Content-Type", "application/json");
|
|
28
|
+
res.setHeader("Cache-Control", "public, max-age=3600");
|
|
29
|
+
res.json({
|
|
30
|
+
resource: config.server.resource_uri,
|
|
31
|
+
authorization_servers: [config.auth.issuer],
|
|
32
|
+
scopes_supported: config.scopes,
|
|
33
|
+
bearer_methods_supported: ["header"],
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
app.get("/health", (_req, res) => {
|
|
37
|
+
res.json({ status: "ok", server: config.server.name });
|
|
38
|
+
});
|
|
39
|
+
const mcpServer = new McpServer({
|
|
40
|
+
name: config.server.name,
|
|
41
|
+
version: options?.version ?? "0.1.0",
|
|
42
|
+
});
|
|
43
|
+
app.post("/mcp", async (req, res) => {
|
|
44
|
+
const transport = new StreamableHTTPServerTransport({
|
|
45
|
+
sessionIdGenerator: undefined,
|
|
46
|
+
});
|
|
47
|
+
res.on("close", () => {
|
|
48
|
+
transport.close().catch(() => { });
|
|
49
|
+
});
|
|
50
|
+
await mcpServer.connect(transport);
|
|
51
|
+
await transport.handleRequest(req, res, req.body);
|
|
52
|
+
});
|
|
53
|
+
app.get("/mcp", (_req, res) => {
|
|
54
|
+
res.status(405).json({ error: "Method not allowed. Use POST for MCP requests." });
|
|
55
|
+
});
|
|
56
|
+
app.delete("/mcp", (_req, res) => {
|
|
57
|
+
res.status(405).json({ error: "Method not allowed." });
|
|
58
|
+
});
|
|
59
|
+
return { app, mcpServer };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Start listening on the given port with a startup banner.
|
|
63
|
+
*/
|
|
64
|
+
export function startServer(app, config, port) {
|
|
65
|
+
app.listen(port, () => {
|
|
66
|
+
console.log(`\n ${config.server.name}`);
|
|
67
|
+
console.log(` Listening on http://127.0.0.1:${port}`);
|
|
68
|
+
console.log(` MCP endpoint: http://127.0.0.1:${port}/mcp`);
|
|
69
|
+
console.log(` Protected Resource Metadata: http://127.0.0.1:${port}/.well-known/oauth-protected-resource`);
|
|
70
|
+
console.log(` Health: http://127.0.0.1:${port}/health\n`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=create-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-server.js","sourceRoot":"","sources":["../../src/mcp-server/create-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp-server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,aAAa,EACb,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,WAAW,GACZ,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subset of Auth0 Management API response types used by the provisioner.
|
|
3
|
+
* These are not exhaustive -- only fields we read or write.
|
|
4
|
+
*/
|
|
5
|
+
export interface Auth0Application {
|
|
6
|
+
client_id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
app_type?: string;
|
|
9
|
+
token_endpoint_auth_method?: string;
|
|
10
|
+
grant_types?: string[];
|
|
11
|
+
callbacks?: string[];
|
|
12
|
+
allowed_logout_urls?: string[];
|
|
13
|
+
web_origins?: string[];
|
|
14
|
+
client_metadata?: Record<string, string>;
|
|
15
|
+
refresh_token?: {
|
|
16
|
+
rotation_type?: string;
|
|
17
|
+
expiration_type?: string;
|
|
18
|
+
token_lifetime?: number;
|
|
19
|
+
};
|
|
20
|
+
client_secret?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface Auth0ApiScope {
|
|
23
|
+
value: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Auth0Api {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
identifier: string;
|
|
30
|
+
signing_alg?: string;
|
|
31
|
+
token_dialect?: string;
|
|
32
|
+
enforce_policies?: boolean;
|
|
33
|
+
scopes?: Auth0ApiScope[];
|
|
34
|
+
}
|
|
35
|
+
export interface Auth0ClientGrant {
|
|
36
|
+
id: string;
|
|
37
|
+
client_id: string;
|
|
38
|
+
audience: string;
|
|
39
|
+
scope: string[];
|
|
40
|
+
subject_type?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface Auth0TenantSettings {
|
|
43
|
+
flags?: Record<string, boolean>;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=auth0-responses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth0-responses.d.ts","sourceRoot":"","sources":["../../src/types/auth0-responses.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth0-responses.js","sourceRoot":"","sources":["../../src/types/auth0-responses.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|