@cyanmycelium/mcp-broker 1.8.0 → 1.9.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/bin.js +5 -4
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-HMQDU4UG.js → chunk-CR5GZBFT.js} +9 -4
- package/dist/chunk-CR5GZBFT.js.map +1 -0
- package/dist/{chunk-ACF2R4O3.js → chunk-WEUCJH6C.js} +62 -6
- package/dist/chunk-WEUCJH6C.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +2 -2
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/{ws.tunnel.builder-Ce0JzZUz.d.ts → ws.tunnel.builder-DbKxtyki.d.ts} +48 -2
- package/package.json +1 -1
- package/src/auth/auth.types.ts +6 -0
- package/src/auth/dev.auth.ts +108 -6
- package/src/auth/http.auth.ts +6 -3
- package/src/auth/index.ts +11 -1
- package/src/bin.ts +4 -3
- package/src/config.ts +8 -1
- package/src/index.ts +3 -0
- package/dist/chunk-ACF2R4O3.js.map +0 -1
- package/dist/chunk-HMQDU4UG.js.map +0 -1
|
@@ -12,6 +12,7 @@ import { WebSocket, WebSocketServer } from 'ws';
|
|
|
12
12
|
import { fileURLToPath } from 'url';
|
|
13
13
|
import { McpAuthError, McpGrammar, McpBehavior, McpAdapterBase, McpToolResults, LoopbackTransport, McpServerBuilder, scopesOf as scopesOf$1, buildProtectedResourceMetadata, PROTECTED_RESOURCE_METADATA_PREFIX, bearerToken, buildChallengeHeader, createEventEmitter } from '@cyanmycelium/mcp-core';
|
|
14
14
|
import { createRemoteJWKSet, jwtVerify, errors } from 'jose';
|
|
15
|
+
import { BlockList, isIP } from 'net';
|
|
15
16
|
import { createRequire } from 'module';
|
|
16
17
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
17
18
|
import { StdioTransport, StreamableHttpEndpoint } from '@cyanmycelium/mcp-core/node';
|
|
@@ -4521,6 +4522,7 @@ function buildResourceMetadata(params) {
|
|
|
4521
4522
|
}
|
|
4522
4523
|
var DEV_ISSUER = "urn:mcp-broker:dev";
|
|
4523
4524
|
var DEV_TOKEN_MIN_LENGTH = 16;
|
|
4525
|
+
var DEV_LAN_NETWORKS = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16", "fc00::/7", "fe80::/10"];
|
|
4524
4526
|
var DEV_SUBJECT_MAPPING = { userClaim: "sub", groupClaims: ["groups"], serviceClaims: ["service"], clientClaim: "client_id" };
|
|
4525
4527
|
var CALLER_KEYS = /* @__PURE__ */ new Set(["id", "tokenEnv", "user", "groups", "service", "client", "scopes"]);
|
|
4526
4528
|
var digest = (token) => createHash("sha256").update(token, "utf8").digest("hex");
|
|
@@ -4528,7 +4530,7 @@ function resolveDevCallers(dev, env) {
|
|
|
4528
4530
|
const problems = [];
|
|
4529
4531
|
const callers = [];
|
|
4530
4532
|
if (typeof dev !== "object" || dev === null || Array.isArray(dev)) return { callers, problems: ['"auth.dev" must be an object: { "callers": [...] }'] };
|
|
4531
|
-
for (const key of Object.keys(dev)) if (key !== "callers") problems.push(`auth.dev: unknown key "${key}"`);
|
|
4533
|
+
for (const key of Object.keys(dev)) if (key !== "callers" && key !== "networks") problems.push(`auth.dev: unknown key "${key}"`);
|
|
4532
4534
|
const list = dev.callers;
|
|
4533
4535
|
if (!Array.isArray(list) || list.length === 0) {
|
|
4534
4536
|
problems.push('"auth.dev.callers" must be a non-empty array');
|
|
@@ -4586,6 +4588,55 @@ function resolveDevCallers(dev, env) {
|
|
|
4586
4588
|
}
|
|
4587
4589
|
return { callers, problems };
|
|
4588
4590
|
}
|
|
4591
|
+
function parseNetwork(entry) {
|
|
4592
|
+
const [address, prefixText, extra] = entry.trim().split("/");
|
|
4593
|
+
const version = isIP(address);
|
|
4594
|
+
if (version === 0 || extra !== void 0) return `"${entry}" is not "lan", an IPv4 or IPv6 address, or a CIDR network`;
|
|
4595
|
+
const max = version === 4 ? 32 : 128;
|
|
4596
|
+
const prefix = prefixText === void 0 ? max : /^[0-9]{1,3}$/.test(prefixText) ? Number(prefixText) : NaN;
|
|
4597
|
+
if (!Number.isInteger(prefix) || prefix > max) return `"${entry}": the prefix length must be an integer from 1 to ${max}`;
|
|
4598
|
+
if (prefix === 0) return `"${entry}" would accept every client, the internet included; write "lan" for the bench's network, or use OAuth`;
|
|
4599
|
+
return { address, prefix, family: version === 4 ? "ipv4" : "ipv6" };
|
|
4600
|
+
}
|
|
4601
|
+
function resolveDevNetworks(networks) {
|
|
4602
|
+
if (networks === void 0) return { networks: [], problems: [] };
|
|
4603
|
+
if (!Array.isArray(networks)) return { networks: [], problems: ['"auth.dev.networks" must be an array, e.g. ["lan"] or ["192.168.4.0/24"]'] };
|
|
4604
|
+
const out = [];
|
|
4605
|
+
const problems = [];
|
|
4606
|
+
for (const [index, entry] of networks.entries()) {
|
|
4607
|
+
if (typeof entry !== "string" || entry.trim() === "") {
|
|
4608
|
+
problems.push(`auth.dev.networks[${index}] must be a non-empty string`);
|
|
4609
|
+
continue;
|
|
4610
|
+
}
|
|
4611
|
+
for (const one of entry.trim().toLowerCase() === "lan" ? DEV_LAN_NETWORKS : [entry]) {
|
|
4612
|
+
const parsed = parseNetwork(one);
|
|
4613
|
+
if (typeof parsed === "string") problems.push(`auth.dev.networks[${index}]: ${parsed}`);
|
|
4614
|
+
else if (!out.includes(`${parsed.address}/${parsed.prefix}`)) out.push(`${parsed.address}/${parsed.prefix}`);
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
return { networks: out, problems };
|
|
4618
|
+
}
|
|
4619
|
+
var DevClientFilter = class {
|
|
4620
|
+
_list = new BlockList();
|
|
4621
|
+
networks;
|
|
4622
|
+
constructor(networks = []) {
|
|
4623
|
+
const resolved = resolveDevNetworks(networks);
|
|
4624
|
+
if (resolved.problems.length > 0) throw new Error(resolved.problems.join("; "));
|
|
4625
|
+
for (const n of resolved.networks) {
|
|
4626
|
+
const parsed = parseNetwork(n);
|
|
4627
|
+
this._list.addSubnet(parsed.address, parsed.prefix, parsed.family);
|
|
4628
|
+
}
|
|
4629
|
+
this.networks = resolved.networks;
|
|
4630
|
+
}
|
|
4631
|
+
allows(req) {
|
|
4632
|
+
if (isLoopbackRequest(req)) return true;
|
|
4633
|
+
const address = req.socket?.remoteAddress;
|
|
4634
|
+
if (!address || this.networks.length === 0) return false;
|
|
4635
|
+
const plain = address.startsWith("::ffff:") ? address.slice(7) : address;
|
|
4636
|
+
const version = isIP(plain);
|
|
4637
|
+
return version !== 0 && this._list.check(plain, version === 4 ? "ipv4" : "ipv6");
|
|
4638
|
+
}
|
|
4639
|
+
};
|
|
4589
4640
|
function isLoopbackRequest(req) {
|
|
4590
4641
|
const address = req.socket?.remoteAddress;
|
|
4591
4642
|
if (!address) return false;
|
|
@@ -4620,6 +4671,8 @@ function buildDevAuth(options) {
|
|
|
4620
4671
|
validator: new DevTokenValidator(options.callers),
|
|
4621
4672
|
loopbackOnly: true
|
|
4622
4673
|
};
|
|
4674
|
+
const networks = new DevClientFilter(options.networks).networks;
|
|
4675
|
+
if (networks.length > 0) resolved.clientNetworks = networks;
|
|
4623
4676
|
if (options.scopesSupported) resolved.scopesSupported = options.scopesSupported;
|
|
4624
4677
|
if (options.requiredScopes) resolved.requiredScopes = options.requiredScopes;
|
|
4625
4678
|
if (options.perSlotScopes) resolved.perSlotScopes = options.perSlotScopes;
|
|
@@ -4645,8 +4698,11 @@ var HttpAuthGuard = class {
|
|
|
4645
4698
|
_auth;
|
|
4646
4699
|
/** The `/mcp` suffix without a leading slash, e.g. `"mcp"`. */
|
|
4647
4700
|
_mcpSuffix;
|
|
4701
|
+
/** The clients a `loopbackOnly` auth accepts: loopback and its `clientNetworks`. */
|
|
4702
|
+
_clients;
|
|
4648
4703
|
constructor(auth, mcpSuffix) {
|
|
4649
4704
|
this._auth = auth;
|
|
4705
|
+
this._clients = auth.loopbackOnly ? new DevClientFilter(auth.clientNetworks) : null;
|
|
4650
4706
|
this._mcpSuffix = mcpSuffix.replace(/^\//, "");
|
|
4651
4707
|
}
|
|
4652
4708
|
/** Canonical resource identifier for a slot (RFC 8707 §2). */
|
|
@@ -4687,8 +4743,8 @@ var HttpAuthGuard = class {
|
|
|
4687
4743
|
* `403` insufficient scope) otherwise.
|
|
4688
4744
|
*/
|
|
4689
4745
|
async authorize(req, slot) {
|
|
4690
|
-
if (this.
|
|
4691
|
-
throw new AuthError(401, "invalid_token", "Development tokens are accepted from
|
|
4746
|
+
if (this._clients && !this._clients.allows(req)) {
|
|
4747
|
+
throw new AuthError(401, "invalid_token", "Development tokens are not accepted from this client's network");
|
|
4692
4748
|
}
|
|
4693
4749
|
const token = bearerToken(req.headers["authorization"]);
|
|
4694
4750
|
if (!token) {
|
|
@@ -9105,6 +9161,6 @@ var WsTunnelBuilder = class {
|
|
|
9105
9161
|
}
|
|
9106
9162
|
};
|
|
9107
9163
|
|
|
9108
|
-
export { AuthError, BROKER_AGGREGATE_NAME, BROKER_AUDIT_RESULT_METHOD, BROKER_AUTHORIZE_METHOD, BROKER_DECLARE_METHOD, BROKER_GUIDES, BROKER_GUIDE_MIME_TYPE, BROKER_GUIDE_TOPICS, BROKER_GUIDE_URI_PREFIX, BROKER_GUIDE_URI_TEMPLATE, BROKER_METHOD_PREFIX, BROKER_PROVIDER_NAME, BROKER_RESERVED_SLOTS, BrokerAuthority, BrokerDiagnoseAdapter, BrokerDiagnoseBehavior, BrokerGuideAdapter, BrokerGuideBehavior, BrokerInfoBehavior, BrokerProvidersBehavior, CALLER_META_KEY, CORRELATION_ID_PATTERN, ConfigPolicyEngine, ConfiguredCapabilityClassifier, DEFAULT_AUTHORIZE_BATCH_LIMIT, DEFAULT_RESOURCE_SUBSCRIPTION_LIMITS, DEV_ISSUER, DEV_TOKEN_MIN_LENGTH, DefaultSlotResourceResolver, DevTokenValidator, HttpAuthGuard, JwtSubjectMapper, JwtTokenValidator, LimitController, OtlpHttpTraceExporter, PACKAGE_NAME, ProviderTableAuthenticator, ProviderTelemetryDispatcher, RemoteUpstream, ResourcePath, ResourcePathPattern, ResourceSubscriptionRegistry, SUBSCRIPTION_LIMIT_ERROR_CODE, SharedSecretProviderAuthenticator, StdioUpstream, SubjectMappingError, TELEMETRY_NOTIFICATION_METHOD, TRACEPARENT_META_KEY, VERSION, WsTunnel, WsTunnelBuilder, authorizationWithEngine, brokerGrammarKey, brokerGuide, brokerGuideIndex, brokerGuideTopicFromUri, brokerGuideUri, buildDevAuth, buildJwtAuth, buildResourceMetadata, compileAuthorizationPolicy, compileProviderAllowedResources, compileRegex, compileResourceLimits, createTraceparent, diagnoseBroker, ensureTraceparent, formatTraceparent, hasAuthorizationPolicies, isLoopbackRequest, isReservedBrokerSlot, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar, normalizeProviderAuthentication, parseTraceparent, providerMayPublish, providerPublishDecision, resolveDevCallers, scopesOf, startBrokerServer, validateCapability, validateLimitsConfig };
|
|
9109
|
-
//# sourceMappingURL=chunk-
|
|
9110
|
-
//# sourceMappingURL=chunk-
|
|
9164
|
+
export { AuthError, BROKER_AGGREGATE_NAME, BROKER_AUDIT_RESULT_METHOD, BROKER_AUTHORIZE_METHOD, BROKER_DECLARE_METHOD, BROKER_GUIDES, BROKER_GUIDE_MIME_TYPE, BROKER_GUIDE_TOPICS, BROKER_GUIDE_URI_PREFIX, BROKER_GUIDE_URI_TEMPLATE, BROKER_METHOD_PREFIX, BROKER_PROVIDER_NAME, BROKER_RESERVED_SLOTS, BrokerAuthority, BrokerDiagnoseAdapter, BrokerDiagnoseBehavior, BrokerGuideAdapter, BrokerGuideBehavior, BrokerInfoBehavior, BrokerProvidersBehavior, CALLER_META_KEY, CORRELATION_ID_PATTERN, ConfigPolicyEngine, ConfiguredCapabilityClassifier, DEFAULT_AUTHORIZE_BATCH_LIMIT, DEFAULT_RESOURCE_SUBSCRIPTION_LIMITS, DEV_ISSUER, DEV_LAN_NETWORKS, DEV_TOKEN_MIN_LENGTH, DefaultSlotResourceResolver, DevClientFilter, DevTokenValidator, HttpAuthGuard, JwtSubjectMapper, JwtTokenValidator, LimitController, OtlpHttpTraceExporter, PACKAGE_NAME, ProviderTableAuthenticator, ProviderTelemetryDispatcher, RemoteUpstream, ResourcePath, ResourcePathPattern, ResourceSubscriptionRegistry, SUBSCRIPTION_LIMIT_ERROR_CODE, SharedSecretProviderAuthenticator, StdioUpstream, SubjectMappingError, TELEMETRY_NOTIFICATION_METHOD, TRACEPARENT_META_KEY, VERSION, WsTunnel, WsTunnelBuilder, authorizationWithEngine, brokerGrammarKey, brokerGuide, brokerGuideIndex, brokerGuideTopicFromUri, brokerGuideUri, buildDevAuth, buildJwtAuth, buildResourceMetadata, compileAuthorizationPolicy, compileProviderAllowedResources, compileRegex, compileResourceLimits, createTraceparent, diagnoseBroker, ensureTraceparent, formatTraceparent, hasAuthorizationPolicies, isLoopbackRequest, isReservedBrokerSlot, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar, normalizeProviderAuthentication, parseTraceparent, providerMayPublish, providerPublishDecision, resolveDevCallers, resolveDevNetworks, scopesOf, startBrokerServer, validateCapability, validateLimitsConfig };
|
|
9165
|
+
//# sourceMappingURL=chunk-WEUCJH6C.js.map
|
|
9166
|
+
//# sourceMappingURL=chunk-WEUCJH6C.js.map
|