@mastra/mcp 1.0.0-beta.9 → 1.0.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/CHANGELOG.md +359 -0
- package/README.md +191 -22
- package/dist/__fixtures__/tools.d.ts +8 -5
- package/dist/__fixtures__/tools.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/oauth-provider.d.ts +230 -0
- package/dist/client/oauth-provider.d.ts.map +1 -0
- package/dist/docs/README.md +1 -1
- package/dist/docs/SKILL.md +14 -2
- package/dist/docs/SOURCE_MAP.json +55 -2
- package/dist/docs/mcp/01-overview.md +24 -14
- package/dist/docs/mcp/02-publishing-mcp-server.md +2 -2
- package/dist/docs/tools/01-reference.md +326 -25
- package/dist/docs/tools-mcp/01-mcp-overview.md +8 -0
- package/dist/index.cjs +459 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +399 -5
- package/dist/index.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/oauth-middleware.d.ts +142 -0
- package/dist/server/oauth-middleware.d.ts.map +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/oauth-types.d.ts +137 -0
- package/dist/shared/oauth-types.d.ts.map +1 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
22
22
|
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
23
23
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
24
24
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
25
|
+
export { UnauthorizedError, auth, buildDiscoveryUrls, discoverAuthorizationServerMetadata, discoverOAuthMetadata, discoverOAuthProtectedResourceMetadata, exchangeAuthorization, extractResourceMetadataUrl, parseErrorResponse, refreshAuthorization, registerClient, selectResourceURL, startAuthorization } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
25
26
|
|
|
26
27
|
// src/client/client.ts
|
|
27
28
|
|
|
@@ -577,7 +578,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
577
578
|
}
|
|
578
579
|
}
|
|
579
580
|
async connectHttp(url) {
|
|
580
|
-
const { requestInit, eventSourceInit, authProvider, connectTimeout, fetch } = this.serverConfig;
|
|
581
|
+
const { requestInit, eventSourceInit, authProvider, connectTimeout, fetch: fetch2 } = this.serverConfig;
|
|
581
582
|
this.log("debug", `Attempting to connect to URL: ${url}`);
|
|
582
583
|
let shouldTrySSE = url.pathname.endsWith(`/sse`);
|
|
583
584
|
if (!shouldTrySSE) {
|
|
@@ -587,7 +588,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
587
588
|
requestInit,
|
|
588
589
|
reconnectionOptions: this.serverConfig.reconnectionOptions,
|
|
589
590
|
authProvider,
|
|
590
|
-
fetch
|
|
591
|
+
fetch: fetch2
|
|
591
592
|
});
|
|
592
593
|
await this.client.connect(streamableTransport, {
|
|
593
594
|
timeout: connectTimeout ?? DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC
|
|
@@ -606,12 +607,12 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
606
607
|
if (shouldTrySSE) {
|
|
607
608
|
this.log("debug", "Falling back to deprecated HTTP+SSE transport...");
|
|
608
609
|
try {
|
|
609
|
-
const sseEventSourceInit =
|
|
610
|
+
const sseEventSourceInit = fetch2 ? { ...eventSourceInit, fetch: fetch2 } : eventSourceInit;
|
|
610
611
|
const sseTransport = new SSEClientTransport(url, {
|
|
611
612
|
requestInit,
|
|
612
613
|
eventSourceInit: sseEventSourceInit,
|
|
613
614
|
authProvider,
|
|
614
|
-
fetch
|
|
615
|
+
fetch: fetch2
|
|
615
616
|
});
|
|
616
617
|
await this.client.connect(sseTransport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
617
618
|
this.transport = sseTransport;
|
|
@@ -1814,6 +1815,190 @@ To fix this you have three different options:
|
|
|
1814
1815
|
}
|
|
1815
1816
|
};
|
|
1816
1817
|
|
|
1818
|
+
// src/client/oauth-provider.ts
|
|
1819
|
+
var InMemoryOAuthStorage = class {
|
|
1820
|
+
data = /* @__PURE__ */ new Map();
|
|
1821
|
+
set(key, value) {
|
|
1822
|
+
this.data.set(key, value);
|
|
1823
|
+
}
|
|
1824
|
+
get(key) {
|
|
1825
|
+
return this.data.get(key);
|
|
1826
|
+
}
|
|
1827
|
+
delete(key) {
|
|
1828
|
+
this.data.delete(key);
|
|
1829
|
+
}
|
|
1830
|
+
clear() {
|
|
1831
|
+
this.data.clear();
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
var MCPOAuthClientProvider = class {
|
|
1835
|
+
_redirectUrl;
|
|
1836
|
+
_clientMetadata;
|
|
1837
|
+
storage;
|
|
1838
|
+
onRedirect;
|
|
1839
|
+
generateState;
|
|
1840
|
+
_clientInfo;
|
|
1841
|
+
constructor(options) {
|
|
1842
|
+
this._redirectUrl = options.redirectUrl;
|
|
1843
|
+
this._clientMetadata = options.clientMetadata;
|
|
1844
|
+
this._clientInfo = options.clientInformation;
|
|
1845
|
+
this.storage = options.storage ?? new InMemoryOAuthStorage();
|
|
1846
|
+
this.onRedirect = options.onRedirectToAuthorization;
|
|
1847
|
+
this.generateState = options.stateGenerator ?? (() => crypto.randomUUID());
|
|
1848
|
+
}
|
|
1849
|
+
/**
|
|
1850
|
+
* The URL to redirect the user agent to after authorization.
|
|
1851
|
+
*/
|
|
1852
|
+
get redirectUrl() {
|
|
1853
|
+
return this._redirectUrl;
|
|
1854
|
+
}
|
|
1855
|
+
/**
|
|
1856
|
+
* Metadata about this OAuth client.
|
|
1857
|
+
*/
|
|
1858
|
+
get clientMetadata() {
|
|
1859
|
+
return this._clientMetadata;
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* Returns a OAuth2 state parameter.
|
|
1863
|
+
*/
|
|
1864
|
+
async state() {
|
|
1865
|
+
return this.generateState();
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* Loads information about this OAuth client.
|
|
1869
|
+
*/
|
|
1870
|
+
async clientInformation() {
|
|
1871
|
+
if (this._clientInfo) {
|
|
1872
|
+
return this._clientInfo;
|
|
1873
|
+
}
|
|
1874
|
+
const stored = await this.storage.get("client_info");
|
|
1875
|
+
if (stored) {
|
|
1876
|
+
try {
|
|
1877
|
+
return JSON.parse(stored);
|
|
1878
|
+
} catch {
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
return void 0;
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* Saves dynamically registered client information.
|
|
1885
|
+
*/
|
|
1886
|
+
async saveClientInformation(clientInformation) {
|
|
1887
|
+
this._clientInfo = clientInformation;
|
|
1888
|
+
await this.storage.set("client_info", JSON.stringify(clientInformation));
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* Loads existing OAuth tokens.
|
|
1892
|
+
*/
|
|
1893
|
+
async tokens() {
|
|
1894
|
+
const stored = await this.storage.get("tokens");
|
|
1895
|
+
if (stored) {
|
|
1896
|
+
try {
|
|
1897
|
+
return JSON.parse(stored);
|
|
1898
|
+
} catch {
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
return void 0;
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* Stores new OAuth tokens after successful authorization.
|
|
1905
|
+
*/
|
|
1906
|
+
async saveTokens(tokens) {
|
|
1907
|
+
await this.storage.set("tokens", JSON.stringify(tokens));
|
|
1908
|
+
}
|
|
1909
|
+
/**
|
|
1910
|
+
* Invoked to redirect the user agent to the authorization URL.
|
|
1911
|
+
*/
|
|
1912
|
+
async redirectToAuthorization(authorizationUrl) {
|
|
1913
|
+
if (this.onRedirect) {
|
|
1914
|
+
await this.onRedirect(authorizationUrl);
|
|
1915
|
+
} else {
|
|
1916
|
+
console.info(`Authorization required. Please visit: ${authorizationUrl.toString()}`);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
* Saves a PKCE code verifier before redirecting to authorization.
|
|
1921
|
+
*/
|
|
1922
|
+
async saveCodeVerifier(codeVerifier) {
|
|
1923
|
+
await this.storage.set("code_verifier", codeVerifier);
|
|
1924
|
+
}
|
|
1925
|
+
/**
|
|
1926
|
+
* Loads the PKCE code verifier for validating authorization result.
|
|
1927
|
+
*/
|
|
1928
|
+
async codeVerifier() {
|
|
1929
|
+
const verifier = await this.storage.get("code_verifier");
|
|
1930
|
+
if (!verifier) {
|
|
1931
|
+
throw new Error("No code verifier found. Authorization flow may not have started properly.");
|
|
1932
|
+
}
|
|
1933
|
+
return verifier;
|
|
1934
|
+
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Optional: Custom client authentication for token requests.
|
|
1937
|
+
* Uses default behavior if not implemented.
|
|
1938
|
+
*/
|
|
1939
|
+
async addClientAuthentication(_headers, _params, _url, _metadata) {
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* Invalidate credentials when server indicates they're no longer valid.
|
|
1943
|
+
*/
|
|
1944
|
+
async invalidateCredentials(scope) {
|
|
1945
|
+
switch (scope) {
|
|
1946
|
+
case "all":
|
|
1947
|
+
await this.storage.delete("tokens");
|
|
1948
|
+
await this.storage.delete("client_info");
|
|
1949
|
+
await this.storage.delete("code_verifier");
|
|
1950
|
+
this._clientInfo = void 0;
|
|
1951
|
+
break;
|
|
1952
|
+
case "client":
|
|
1953
|
+
await this.storage.delete("client_info");
|
|
1954
|
+
this._clientInfo = void 0;
|
|
1955
|
+
break;
|
|
1956
|
+
case "tokens":
|
|
1957
|
+
await this.storage.delete("tokens");
|
|
1958
|
+
break;
|
|
1959
|
+
case "verifier":
|
|
1960
|
+
await this.storage.delete("code_verifier");
|
|
1961
|
+
break;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Clear all stored OAuth data.
|
|
1966
|
+
* Useful for logging out or resetting state.
|
|
1967
|
+
*/
|
|
1968
|
+
async clear() {
|
|
1969
|
+
await this.invalidateCredentials("all");
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Check if the provider has valid (non-expired) tokens.
|
|
1973
|
+
*/
|
|
1974
|
+
async hasValidTokens() {
|
|
1975
|
+
const currentTokens = await this.tokens();
|
|
1976
|
+
if (!currentTokens) return false;
|
|
1977
|
+
if (!currentTokens.access_token) return false;
|
|
1978
|
+
return true;
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
function createSimpleTokenProvider(accessToken, options) {
|
|
1982
|
+
const tokens = {
|
|
1983
|
+
access_token: accessToken,
|
|
1984
|
+
token_type: options.tokenType ?? "Bearer",
|
|
1985
|
+
refresh_token: options.refreshToken,
|
|
1986
|
+
expires_in: options.expiresIn,
|
|
1987
|
+
scope: options.scope
|
|
1988
|
+
};
|
|
1989
|
+
const storage = new InMemoryOAuthStorage();
|
|
1990
|
+
storage.set("tokens", JSON.stringify(tokens));
|
|
1991
|
+
if (options.clientInformation) {
|
|
1992
|
+
storage.set("client_info", JSON.stringify(options.clientInformation));
|
|
1993
|
+
}
|
|
1994
|
+
return new MCPOAuthClientProvider({
|
|
1995
|
+
redirectUrl: options.redirectUrl,
|
|
1996
|
+
clientMetadata: options.clientMetadata,
|
|
1997
|
+
clientInformation: options.clientInformation,
|
|
1998
|
+
storage
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
|
|
1817
2002
|
// ../../node_modules/.pnpm/hono@4.11.3/node_modules/hono/dist/utils/stream.js
|
|
1818
2003
|
var StreamingApi = class {
|
|
1819
2004
|
writer;
|
|
@@ -2517,6 +2702,12 @@ var MCPServer = class extends MCPServerBase {
|
|
|
2517
2702
|
if (tool.outputSchema) {
|
|
2518
2703
|
toolSpec.outputSchema = tool.outputSchema.jsonSchema;
|
|
2519
2704
|
}
|
|
2705
|
+
if (tool.mcp?.annotations) {
|
|
2706
|
+
toolSpec.annotations = tool.mcp.annotations;
|
|
2707
|
+
}
|
|
2708
|
+
if (tool.mcp?._meta) {
|
|
2709
|
+
toolSpec._meta = tool.mcp._meta;
|
|
2710
|
+
}
|
|
2520
2711
|
return toolSpec;
|
|
2521
2712
|
})
|
|
2522
2713
|
};
|
|
@@ -3888,7 +4079,210 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
|
|
|
3888
4079
|
}
|
|
3889
4080
|
}
|
|
3890
4081
|
};
|
|
4082
|
+
function escapeHeaderValue(value) {
|
|
4083
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
4084
|
+
}
|
|
4085
|
+
function generateWWWAuthenticateHeader(options = {}) {
|
|
4086
|
+
const params = [];
|
|
4087
|
+
if (options.resourceMetadataUrl) {
|
|
4088
|
+
params.push(`resource_metadata="${escapeHeaderValue(options.resourceMetadataUrl)}"`);
|
|
4089
|
+
}
|
|
4090
|
+
if (options.additionalParams) {
|
|
4091
|
+
for (const [key, value] of Object.entries(options.additionalParams)) {
|
|
4092
|
+
params.push(`${key}="${escapeHeaderValue(value)}"`);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
if (params.length === 0) {
|
|
4096
|
+
return "Bearer";
|
|
4097
|
+
}
|
|
4098
|
+
return `Bearer ${params.join(", ")}`;
|
|
4099
|
+
}
|
|
4100
|
+
function generateProtectedResourceMetadata(config) {
|
|
4101
|
+
return {
|
|
4102
|
+
resource: config.resource,
|
|
4103
|
+
authorization_servers: config.authorizationServers,
|
|
4104
|
+
scopes_supported: config.scopesSupported ?? ["mcp:read", "mcp:write"],
|
|
4105
|
+
bearer_methods_supported: ["header"],
|
|
4106
|
+
...config.resourceName && { resource_name: config.resourceName },
|
|
4107
|
+
...config.resourceDocumentation && {
|
|
4108
|
+
resource_documentation: config.resourceDocumentation
|
|
4109
|
+
}
|
|
4110
|
+
};
|
|
4111
|
+
}
|
|
4112
|
+
function extractBearerToken(authHeader) {
|
|
4113
|
+
if (!authHeader) return void 0;
|
|
4114
|
+
const prefix = "bearer ";
|
|
4115
|
+
if (authHeader.length <= prefix.length) return void 0;
|
|
4116
|
+
if (authHeader.slice(0, prefix.length).toLowerCase() !== prefix) return void 0;
|
|
4117
|
+
const token = authHeader.slice(prefix.length).trim();
|
|
4118
|
+
return token || void 0;
|
|
4119
|
+
}
|
|
4120
|
+
|
|
4121
|
+
// src/server/oauth-middleware.ts
|
|
4122
|
+
function createOAuthMiddleware(options) {
|
|
4123
|
+
const { oauth, mcpPath = "/mcp", logger } = options;
|
|
4124
|
+
const protectedResourceMetadata = generateProtectedResourceMetadata(oauth);
|
|
4125
|
+
const wellKnownPath = "/.well-known/oauth-protected-resource";
|
|
4126
|
+
const resourceMetadataUrl = new URL(wellKnownPath, oauth.resource).toString();
|
|
4127
|
+
return async function oauthMiddleware(req, res, url) {
|
|
4128
|
+
logger?.debug?.(`OAuth middleware: ${req.method} ${url.pathname}`);
|
|
4129
|
+
if (url.pathname === wellKnownPath && req.method === "GET") {
|
|
4130
|
+
logger?.debug?.("OAuth middleware: Serving Protected Resource Metadata");
|
|
4131
|
+
res.writeHead(200, {
|
|
4132
|
+
"Content-Type": "application/json",
|
|
4133
|
+
"Cache-Control": "max-age=3600",
|
|
4134
|
+
"Access-Control-Allow-Origin": "*"
|
|
4135
|
+
});
|
|
4136
|
+
res.end(JSON.stringify(protectedResourceMetadata));
|
|
4137
|
+
return { proceed: false, handled: true };
|
|
4138
|
+
}
|
|
4139
|
+
if (url.pathname === wellKnownPath && req.method === "OPTIONS") {
|
|
4140
|
+
res.writeHead(204, {
|
|
4141
|
+
"Access-Control-Allow-Origin": "*",
|
|
4142
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
4143
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
4144
|
+
"Access-Control-Max-Age": "86400"
|
|
4145
|
+
});
|
|
4146
|
+
res.end();
|
|
4147
|
+
return { proceed: false, handled: true };
|
|
4148
|
+
}
|
|
4149
|
+
if (!url.pathname.startsWith(mcpPath)) {
|
|
4150
|
+
return { proceed: true, handled: false };
|
|
4151
|
+
}
|
|
4152
|
+
const authHeader = req.headers["authorization"];
|
|
4153
|
+
const token = extractBearerToken(authHeader);
|
|
4154
|
+
if (!token) {
|
|
4155
|
+
logger?.debug?.("OAuth middleware: No bearer token provided");
|
|
4156
|
+
res.writeHead(401, {
|
|
4157
|
+
"Content-Type": "application/json",
|
|
4158
|
+
"WWW-Authenticate": generateWWWAuthenticateHeader({ resourceMetadataUrl })
|
|
4159
|
+
});
|
|
4160
|
+
res.end(
|
|
4161
|
+
JSON.stringify({
|
|
4162
|
+
error: "unauthorized",
|
|
4163
|
+
error_description: "Bearer token required"
|
|
4164
|
+
})
|
|
4165
|
+
);
|
|
4166
|
+
return { proceed: false, handled: true };
|
|
4167
|
+
}
|
|
4168
|
+
if (oauth.validateToken) {
|
|
4169
|
+
logger?.debug?.("OAuth middleware: Validating token");
|
|
4170
|
+
const validationResult = await oauth.validateToken(token, oauth.resource);
|
|
4171
|
+
if (!validationResult.valid) {
|
|
4172
|
+
logger?.debug?.(`OAuth middleware: Token validation failed: ${validationResult.error}`);
|
|
4173
|
+
res.writeHead(401, {
|
|
4174
|
+
"Content-Type": "application/json",
|
|
4175
|
+
"WWW-Authenticate": generateWWWAuthenticateHeader({
|
|
4176
|
+
resourceMetadataUrl,
|
|
4177
|
+
additionalParams: {
|
|
4178
|
+
error: validationResult.error || "invalid_token",
|
|
4179
|
+
...validationResult.errorDescription && {
|
|
4180
|
+
error_description: validationResult.errorDescription
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
})
|
|
4184
|
+
});
|
|
4185
|
+
res.end(
|
|
4186
|
+
JSON.stringify({
|
|
4187
|
+
error: validationResult.error || "invalid_token",
|
|
4188
|
+
error_description: validationResult.errorDescription || "Token validation failed"
|
|
4189
|
+
})
|
|
4190
|
+
);
|
|
4191
|
+
return { proceed: false, handled: true, tokenValidation: validationResult };
|
|
4192
|
+
}
|
|
4193
|
+
logger?.debug?.("OAuth middleware: Token validated successfully");
|
|
4194
|
+
return { proceed: true, handled: false, tokenValidation: validationResult };
|
|
4195
|
+
}
|
|
4196
|
+
logger?.debug?.("OAuth middleware: No token validation configured, accepting token");
|
|
4197
|
+
return {
|
|
4198
|
+
proceed: true,
|
|
4199
|
+
handled: false,
|
|
4200
|
+
tokenValidation: { valid: true }
|
|
4201
|
+
};
|
|
4202
|
+
};
|
|
4203
|
+
}
|
|
4204
|
+
function createStaticTokenValidator(validTokens) {
|
|
4205
|
+
const tokenSet = new Set(validTokens);
|
|
4206
|
+
return async (token) => {
|
|
4207
|
+
if (tokenSet.has(token)) {
|
|
4208
|
+
return { valid: true, scopes: ["mcp:read", "mcp:write"] };
|
|
4209
|
+
}
|
|
4210
|
+
return {
|
|
4211
|
+
valid: false,
|
|
4212
|
+
error: "invalid_token",
|
|
4213
|
+
errorDescription: "Token not recognized"
|
|
4214
|
+
};
|
|
4215
|
+
};
|
|
4216
|
+
}
|
|
4217
|
+
function createIntrospectionValidator(introspectionEndpoint, clientCredentials) {
|
|
4218
|
+
return async (token, resource) => {
|
|
4219
|
+
try {
|
|
4220
|
+
const headers = {
|
|
4221
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
4222
|
+
};
|
|
4223
|
+
if (clientCredentials) {
|
|
4224
|
+
if (clientCredentials.clientId.includes(":")) {
|
|
4225
|
+
return {
|
|
4226
|
+
valid: false,
|
|
4227
|
+
error: "invalid_request",
|
|
4228
|
+
errorDescription: "clientId cannot contain a colon character per RFC 7617"
|
|
4229
|
+
};
|
|
4230
|
+
}
|
|
4231
|
+
const credentials = Buffer.from(`${clientCredentials.clientId}:${clientCredentials.clientSecret}`).toString(
|
|
4232
|
+
"base64"
|
|
4233
|
+
);
|
|
4234
|
+
headers["Authorization"] = `Basic ${credentials}`;
|
|
4235
|
+
}
|
|
4236
|
+
const response = await fetch(introspectionEndpoint, {
|
|
4237
|
+
method: "POST",
|
|
4238
|
+
headers,
|
|
4239
|
+
body: new URLSearchParams({
|
|
4240
|
+
token,
|
|
4241
|
+
token_type_hint: "access_token"
|
|
4242
|
+
})
|
|
4243
|
+
});
|
|
4244
|
+
if (!response.ok) {
|
|
4245
|
+
return {
|
|
4246
|
+
valid: false,
|
|
4247
|
+
error: "server_error",
|
|
4248
|
+
errorDescription: `Introspection failed: ${response.status}`
|
|
4249
|
+
};
|
|
4250
|
+
}
|
|
4251
|
+
const data = await response.json();
|
|
4252
|
+
if (!data.active) {
|
|
4253
|
+
return {
|
|
4254
|
+
valid: false,
|
|
4255
|
+
error: "invalid_token",
|
|
4256
|
+
errorDescription: "Token is not active"
|
|
4257
|
+
};
|
|
4258
|
+
}
|
|
4259
|
+
if (data.aud) {
|
|
4260
|
+
const audiences = Array.isArray(data.aud) ? data.aud : [data.aud];
|
|
4261
|
+
if (!audiences.includes(resource)) {
|
|
4262
|
+
return {
|
|
4263
|
+
valid: false,
|
|
4264
|
+
error: "invalid_token",
|
|
4265
|
+
errorDescription: "Token audience does not match this resource"
|
|
4266
|
+
};
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
return {
|
|
4270
|
+
valid: true,
|
|
4271
|
+
scopes: data.scope?.trim().split(" ").filter((s) => s !== "") || [],
|
|
4272
|
+
subject: data.sub,
|
|
4273
|
+
expiresAt: data.exp,
|
|
4274
|
+
claims: data
|
|
4275
|
+
};
|
|
4276
|
+
} catch (error) {
|
|
4277
|
+
return {
|
|
4278
|
+
valid: false,
|
|
4279
|
+
error: "server_error",
|
|
4280
|
+
errorDescription: error instanceof Error ? error.message : "Introspection failed"
|
|
4281
|
+
};
|
|
4282
|
+
}
|
|
4283
|
+
};
|
|
4284
|
+
}
|
|
3891
4285
|
|
|
3892
|
-
export { InternalMastraMCPClient, MCPClient, MCPServer };
|
|
4286
|
+
export { InMemoryOAuthStorage, InternalMastraMCPClient, MCPClient, MCPOAuthClientProvider, MCPServer, createIntrospectionValidator, createOAuthMiddleware, createSimpleTokenProvider, createStaticTokenValidator, extractBearerToken, generateProtectedResourceMetadata, generateWWWAuthenticateHeader };
|
|
3893
4287
|
//# sourceMappingURL=index.js.map
|
|
3894
4288
|
//# sourceMappingURL=index.js.map
|