@toromarket/mcp-server 0.2.2 → 0.2.3
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/index.cjs +29 -299
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +27 -297
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2983,17 +2983,11 @@ async function executeTool(client, baseUrl2, name, rawArgs, options) {
|
|
|
2983
2983
|
}
|
|
2984
2984
|
case "get_compliance_status": {
|
|
2985
2985
|
const me = await client.auth.me();
|
|
2986
|
-
const
|
|
2987
|
-
enabled: false,
|
|
2988
|
-
flags: { velocityWarning: false, regionBlocked: false, largeTransaction: false },
|
|
2989
|
-
velocity: { tradesLastMinute: 0, sessionVolume: 0 },
|
|
2990
|
-
region: null,
|
|
2991
|
-
blockedRegions: []
|
|
2992
|
-
};
|
|
2986
|
+
const compliance = await client.auth.complianceStatus();
|
|
2993
2987
|
return {
|
|
2994
2988
|
trustTier: me.trustTier,
|
|
2995
2989
|
trustScore: me.trustScore,
|
|
2996
|
-
compliance
|
|
2990
|
+
compliance
|
|
2997
2991
|
};
|
|
2998
2992
|
}
|
|
2999
2993
|
// Registry tools
|
|
@@ -3362,6 +3356,18 @@ function classifyError(error) {
|
|
|
3362
3356
|
if (error.code === "NETWORK_ERROR") {
|
|
3363
3357
|
return { error: error.message, statusCode: 0, retryable: true, recovery: "Toromarket API is unreachable. Check that the server is running." };
|
|
3364
3358
|
}
|
|
3359
|
+
if (error.code === "SPENDING_LIMIT") {
|
|
3360
|
+
return { error: error.message, statusCode: 403, retryable: false, recovery: "Daily spending limit reached. Read-only tools still work. Call get_upgrade_url to increase your limit." };
|
|
3361
|
+
}
|
|
3362
|
+
if (error.code === "SPOOFING_DETECTED") {
|
|
3363
|
+
return { error: error.message, statusCode: 403, retryable: false, recovery: "Suspicious trading pattern detected (high cancel ratio). Slow down and wait 30 seconds." };
|
|
3364
|
+
}
|
|
3365
|
+
if (error.code === "REGISTRATION_THROTTLE") {
|
|
3366
|
+
return { error: error.message, statusCode: 403, retryable: false, recovery: "Registration limit reached for this IP. Use authenticate to log in to an existing account." };
|
|
3367
|
+
}
|
|
3368
|
+
if (error.code === "RATE_LIMITED") {
|
|
3369
|
+
return { error: error.message, statusCode: 429, retryable: true, recovery: "Rate limit exceeded. Wait for the indicated cooldown period, or call get_upgrade_url to increase your tier." };
|
|
3370
|
+
}
|
|
3365
3371
|
if (status >= 500) {
|
|
3366
3372
|
return { error: error.message, statusCode: status, retryable: true, recovery: "Server error. Try again in a few seconds." };
|
|
3367
3373
|
}
|
|
@@ -3695,28 +3701,8 @@ function createLogger(level = "info") {
|
|
|
3695
3701
|
};
|
|
3696
3702
|
}
|
|
3697
3703
|
|
|
3698
|
-
// src/middleware/registration.ts
|
|
3699
|
-
import { ToromarketError as ToromarketError3 } from "@toromarket/sdk";
|
|
3700
|
-
var RegistrationThrottle = class {
|
|
3701
|
-
hasRegistered = false;
|
|
3702
|
-
async beforeExecute(toolName, _args) {
|
|
3703
|
-
if (toolName === "register_agent" && this.hasRegistered) {
|
|
3704
|
-
throw new ToromarketError3(
|
|
3705
|
-
"Only one account can be registered per session. Use authenticate to log in to an existing account.",
|
|
3706
|
-
403,
|
|
3707
|
-
"REGISTRATION_THROTTLE"
|
|
3708
|
-
);
|
|
3709
|
-
}
|
|
3710
|
-
}
|
|
3711
|
-
async afterExecute(toolName, _args, _result, error) {
|
|
3712
|
-
if (toolName === "register_agent" && !error) {
|
|
3713
|
-
this.hasRegistered = true;
|
|
3714
|
-
}
|
|
3715
|
-
}
|
|
3716
|
-
};
|
|
3717
|
-
|
|
3718
3704
|
// src/middleware/rate-limiter.ts
|
|
3719
|
-
import { ToromarketError as
|
|
3705
|
+
import { ToromarketError as ToromarketError3 } from "@toromarket/sdk";
|
|
3720
3706
|
var ORDER_TOOLS = /* @__PURE__ */ new Set(["place_order", "cancel_order", "trade_crypto", "place_fund_order", "trade_fund_crypto", "cancel_fund_order"]);
|
|
3721
3707
|
var CHAT_TOOLS = /* @__PURE__ */ new Set(["post_market_comment", "post_fund_message", "react_to_chat"]);
|
|
3722
3708
|
var HEAVY_TOOLS = /* @__PURE__ */ new Set(["get_trading_context"]);
|
|
@@ -3763,7 +3749,7 @@ var RateLimiter = class {
|
|
|
3763
3749
|
const waitSec = Math.ceil((oldestInWindow + config.windowMs - now) / 1e3);
|
|
3764
3750
|
const proLimits = { orders: "100 orders/min", chat: "30 messages/min", reads: "300 reads/min" };
|
|
3765
3751
|
const upgradeHint = this.currentTier === "FREE" ? ` To increase your ${category} limit to ${proLimits[category] ?? "higher"}, call get_upgrade_url with tier PRO ($29/mo) or ENTERPRISE ($99/mo, unlimited). It will generate a payment link for your operator.` : this.currentTier === "PRO" ? ` To remove all ${category} limits, call get_upgrade_url with tier ENTERPRISE ($99/mo, unlimited). It will generate a payment link for your operator.` : "";
|
|
3766
|
-
throw new
|
|
3752
|
+
throw new ToromarketError3(
|
|
3767
3753
|
`Rate limit exceeded for ${category}. Limit: ${config.limit} per minute. Wait ${waitSec}s.${upgradeHint}`,
|
|
3768
3754
|
429,
|
|
3769
3755
|
"RATE_LIMITED"
|
|
@@ -3785,7 +3771,7 @@ function buildCategories(config) {
|
|
|
3785
3771
|
}
|
|
3786
3772
|
|
|
3787
3773
|
// src/middleware/error-budget.ts
|
|
3788
|
-
import { ToromarketError as
|
|
3774
|
+
import { ToromarketError as ToromarketError4 } from "@toromarket/sdk";
|
|
3789
3775
|
var ErrorBudget = class {
|
|
3790
3776
|
consecutiveErrors = 0;
|
|
3791
3777
|
cooldownUntil = 0;
|
|
@@ -3799,7 +3785,7 @@ var ErrorBudget = class {
|
|
|
3799
3785
|
const now = Date.now();
|
|
3800
3786
|
if (now < this.cooldownUntil) {
|
|
3801
3787
|
const waitSec = Math.ceil((this.cooldownUntil - now) / 1e3);
|
|
3802
|
-
throw new
|
|
3788
|
+
throw new ToromarketError4(
|
|
3803
3789
|
`Too many consecutive errors. Automatic backoff for ${waitSec}s.`,
|
|
3804
3790
|
429,
|
|
3805
3791
|
"ERROR_BUDGET_EXCEEDED"
|
|
@@ -3807,20 +3793,20 @@ var ErrorBudget = class {
|
|
|
3807
3793
|
}
|
|
3808
3794
|
}
|
|
3809
3795
|
async afterExecute(_toolName, _args, _result, error) {
|
|
3810
|
-
if (error instanceof
|
|
3811
|
-
const
|
|
3796
|
+
if (error instanceof ToromarketError4) {
|
|
3797
|
+
const EXCLUDED_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
3812
3798
|
"ERROR_BUDGET_EXCEEDED",
|
|
3813
3799
|
"RATE_LIMITED",
|
|
3814
3800
|
"REGISTRATION_THROTTLE",
|
|
3815
3801
|
"SPOOFING_DETECTED",
|
|
3816
3802
|
"SPENDING_LIMIT"
|
|
3817
3803
|
]);
|
|
3818
|
-
if (error.code &&
|
|
3804
|
+
if (error.code && EXCLUDED_ERROR_CODES.has(error.code)) {
|
|
3819
3805
|
return;
|
|
3820
3806
|
}
|
|
3821
3807
|
}
|
|
3822
3808
|
if (error) {
|
|
3823
|
-
const statusCode = error instanceof
|
|
3809
|
+
const statusCode = error instanceof ToromarketError4 ? error.statusCode : void 0;
|
|
3824
3810
|
if (statusCode !== void 0 && statusCode < 500) {
|
|
3825
3811
|
return;
|
|
3826
3812
|
}
|
|
@@ -3839,241 +3825,6 @@ var ErrorBudget = class {
|
|
|
3839
3825
|
}
|
|
3840
3826
|
};
|
|
3841
3827
|
|
|
3842
|
-
// src/middleware/spoofing.ts
|
|
3843
|
-
import { ToromarketError as ToromarketError6 } from "@toromarket/sdk";
|
|
3844
|
-
var SpoofingDetector = class {
|
|
3845
|
-
events = [];
|
|
3846
|
-
windowMs;
|
|
3847
|
-
maxCancelRatio;
|
|
3848
|
-
minActions;
|
|
3849
|
-
constructor(config = {}) {
|
|
3850
|
-
this.windowMs = config.windowMs ?? 3e4;
|
|
3851
|
-
this.maxCancelRatio = config.maxCancelRatio ?? 0.8;
|
|
3852
|
-
this.minActions = config.minActions ?? 5;
|
|
3853
|
-
}
|
|
3854
|
-
pruneExpired() {
|
|
3855
|
-
const cutoff = Date.now() - this.windowMs;
|
|
3856
|
-
while (this.events.length > 0 && this.events[0].time < cutoff) {
|
|
3857
|
-
this.events.shift();
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
async beforeExecute(toolName, _args) {
|
|
3861
|
-
if (toolName !== "place_order" && toolName !== "place_fund_order") return;
|
|
3862
|
-
this.pruneExpired();
|
|
3863
|
-
if (this.events.length < this.minActions) return;
|
|
3864
|
-
const cancels = this.events.filter((e) => e.type === "cancel").length;
|
|
3865
|
-
const ratio = cancels / this.events.length;
|
|
3866
|
-
if (ratio > this.maxCancelRatio) {
|
|
3867
|
-
throw new ToromarketError6(
|
|
3868
|
-
`Suspicious trading pattern detected: ${Math.round(ratio * 100)}% of recent orders were cancelled. Slow down.`,
|
|
3869
|
-
403,
|
|
3870
|
-
"SPOOFING_DETECTED"
|
|
3871
|
-
);
|
|
3872
|
-
}
|
|
3873
|
-
}
|
|
3874
|
-
async afterExecute(toolName, _args, _result, error) {
|
|
3875
|
-
if (error) return;
|
|
3876
|
-
this.pruneExpired();
|
|
3877
|
-
if (toolName === "place_order" || toolName === "place_fund_order") {
|
|
3878
|
-
this.events.push({ type: "place", time: Date.now() });
|
|
3879
|
-
} else if (toolName === "cancel_order" || toolName === "cancel_fund_order") {
|
|
3880
|
-
this.events.push({ type: "cancel", time: Date.now() });
|
|
3881
|
-
}
|
|
3882
|
-
}
|
|
3883
|
-
};
|
|
3884
|
-
|
|
3885
|
-
// src/middleware/spending.ts
|
|
3886
|
-
import { ToromarketError as ToromarketError7 } from "@toromarket/sdk";
|
|
3887
|
-
var TRADE_TOOLS = /* @__PURE__ */ new Set(["place_order", "trade_crypto", "place_fund_order", "trade_fund_crypto"]);
|
|
3888
|
-
var SpendingGuardrails = class {
|
|
3889
|
-
startingBalance = null;
|
|
3890
|
-
blocked = false;
|
|
3891
|
-
maxLoss;
|
|
3892
|
-
constructor(maxSessionLoss2) {
|
|
3893
|
-
this.maxLoss = maxSessionLoss2 ?? 5e3;
|
|
3894
|
-
}
|
|
3895
|
-
async beforeExecute(toolName, _args) {
|
|
3896
|
-
if (!TRADE_TOOLS.has(toolName)) return;
|
|
3897
|
-
if (this.blocked) {
|
|
3898
|
-
throw new ToromarketError7(
|
|
3899
|
-
`Session spending limit reached (${this.maxLoss} TC). No further trades allowed. Read-only tools still work.`,
|
|
3900
|
-
403,
|
|
3901
|
-
"SPENDING_LIMIT"
|
|
3902
|
-
);
|
|
3903
|
-
}
|
|
3904
|
-
if (this.startingBalance === null) {
|
|
3905
|
-
throw new ToromarketError7(
|
|
3906
|
-
"Call get_balance or get_portfolio before your first trade so spending limits can be tracked.",
|
|
3907
|
-
400,
|
|
3908
|
-
"BALANCE_REQUIRED"
|
|
3909
|
-
);
|
|
3910
|
-
}
|
|
3911
|
-
}
|
|
3912
|
-
async afterExecute(toolName, _args, result, error) {
|
|
3913
|
-
if (error) return;
|
|
3914
|
-
if (this.maxLoss === null) return;
|
|
3915
|
-
if (this.startingBalance === null) {
|
|
3916
|
-
const bal = extractBalance(result);
|
|
3917
|
-
if (bal !== null) {
|
|
3918
|
-
this.startingBalance = bal;
|
|
3919
|
-
return;
|
|
3920
|
-
}
|
|
3921
|
-
}
|
|
3922
|
-
if (TRADE_TOOLS.has(toolName) && result) {
|
|
3923
|
-
const remaining = extractRemainingBalance(result);
|
|
3924
|
-
if (remaining !== null && this.startingBalance !== null) {
|
|
3925
|
-
const loss = this.startingBalance - remaining;
|
|
3926
|
-
if (loss >= this.maxLoss) {
|
|
3927
|
-
this.blocked = true;
|
|
3928
|
-
}
|
|
3929
|
-
}
|
|
3930
|
-
}
|
|
3931
|
-
}
|
|
3932
|
-
};
|
|
3933
|
-
function extractBalance(result) {
|
|
3934
|
-
if (typeof result !== "object" || result === null) return null;
|
|
3935
|
-
const r = result;
|
|
3936
|
-
if (typeof r.balance === "number") return r.balance;
|
|
3937
|
-
if (typeof r.totalValue === "number") return r.totalValue;
|
|
3938
|
-
return null;
|
|
3939
|
-
}
|
|
3940
|
-
function extractRemainingBalance(result) {
|
|
3941
|
-
if (typeof result !== "object" || result === null) return null;
|
|
3942
|
-
const r = result;
|
|
3943
|
-
if (typeof r.remainingBalance === "number") return r.remainingBalance;
|
|
3944
|
-
return null;
|
|
3945
|
-
}
|
|
3946
|
-
|
|
3947
|
-
// src/middleware/compliance-gate.ts
|
|
3948
|
-
var FINANCIAL_TOOLS = /* @__PURE__ */ new Set([
|
|
3949
|
-
"place_order",
|
|
3950
|
-
"cancel_order",
|
|
3951
|
-
"trade_crypto",
|
|
3952
|
-
"place_fund_order",
|
|
3953
|
-
"trade_fund_crypto",
|
|
3954
|
-
"cancel_fund_order",
|
|
3955
|
-
"create_escrow",
|
|
3956
|
-
"settle_escrow",
|
|
3957
|
-
"create_delegation",
|
|
3958
|
-
"topup_stake",
|
|
3959
|
-
"claim_challenge",
|
|
3960
|
-
"claim_quest",
|
|
3961
|
-
"claim_mystery_box"
|
|
3962
|
-
]);
|
|
3963
|
-
var ComplianceGate = class {
|
|
3964
|
-
constructor(config, logger) {
|
|
3965
|
-
this.config = config;
|
|
3966
|
-
this.logger = logger;
|
|
3967
|
-
}
|
|
3968
|
-
tradeTimestamps = [];
|
|
3969
|
-
sessionTcVolume = 0;
|
|
3970
|
-
region = null;
|
|
3971
|
-
flags = {
|
|
3972
|
-
velocityWarning: false,
|
|
3973
|
-
regionBlocked: false,
|
|
3974
|
-
largeTransaction: false
|
|
3975
|
-
};
|
|
3976
|
-
/**
|
|
3977
|
-
* Set the session's region for geographic restriction checks.
|
|
3978
|
-
* Call this when region info is available (e.g., from HTTP transport
|
|
3979
|
-
* X-Forwarded-For / CF-IPCountry headers, or operator-provided region).
|
|
3980
|
-
*/
|
|
3981
|
-
setRegion(region) {
|
|
3982
|
-
this.region = region.toUpperCase();
|
|
3983
|
-
if (this.config.blockedRegions.length > 0 && this.config.blockedRegions.includes(this.region)) {
|
|
3984
|
-
this.flags.regionBlocked = true;
|
|
3985
|
-
this.logger.warn({
|
|
3986
|
-
event: "compliance:region_blocked",
|
|
3987
|
-
region: this.region,
|
|
3988
|
-
blockedRegions: this.config.blockedRegions
|
|
3989
|
-
});
|
|
3990
|
-
}
|
|
3991
|
-
}
|
|
3992
|
-
async beforeExecute(toolName, args) {
|
|
3993
|
-
if (!this.config.enabled) return;
|
|
3994
|
-
if (!FINANCIAL_TOOLS.has(toolName)) return;
|
|
3995
|
-
const now = Date.now();
|
|
3996
|
-
this.tradeTimestamps.push(now);
|
|
3997
|
-
const oneMinAgo = now - 6e4;
|
|
3998
|
-
this.tradeTimestamps = this.tradeTimestamps.filter((t) => t > oneMinAgo);
|
|
3999
|
-
const amount = this.parseAmount(args);
|
|
4000
|
-
if (amount > 0) {
|
|
4001
|
-
this.sessionTcVolume += amount;
|
|
4002
|
-
}
|
|
4003
|
-
if (this.tradeTimestamps.length > this.config.velocityTradesPerMin) {
|
|
4004
|
-
this.flags.velocityWarning = true;
|
|
4005
|
-
this.logger.warn({
|
|
4006
|
-
event: "compliance:velocity_warning",
|
|
4007
|
-
tradesInLastMinute: this.tradeTimestamps.length,
|
|
4008
|
-
threshold: this.config.velocityTradesPerMin,
|
|
4009
|
-
tool: toolName
|
|
4010
|
-
});
|
|
4011
|
-
}
|
|
4012
|
-
if (this.sessionTcVolume > this.config.velocityTcPerHour) {
|
|
4013
|
-
this.flags.velocityWarning = true;
|
|
4014
|
-
this.logger.warn({
|
|
4015
|
-
event: "compliance:volume_warning",
|
|
4016
|
-
sessionVolume: this.sessionTcVolume,
|
|
4017
|
-
threshold: this.config.velocityTcPerHour,
|
|
4018
|
-
tool: toolName
|
|
4019
|
-
});
|
|
4020
|
-
}
|
|
4021
|
-
if (amount > 1e4) {
|
|
4022
|
-
this.flags.largeTransaction = true;
|
|
4023
|
-
this.logger.warn({
|
|
4024
|
-
event: "compliance:large_transaction",
|
|
4025
|
-
amount,
|
|
4026
|
-
tool: toolName
|
|
4027
|
-
});
|
|
4028
|
-
}
|
|
4029
|
-
if (this.flags.regionBlocked) {
|
|
4030
|
-
this.logger.warn({
|
|
4031
|
-
event: "compliance:region_blocked_trade_attempt",
|
|
4032
|
-
region: this.region,
|
|
4033
|
-
tool: toolName
|
|
4034
|
-
});
|
|
4035
|
-
}
|
|
4036
|
-
this.logger.info({
|
|
4037
|
-
event: "compliance:financial_tool",
|
|
4038
|
-
tool: toolName,
|
|
4039
|
-
amount: amount > 0 ? amount : void 0,
|
|
4040
|
-
sessionVolume: this.sessionTcVolume,
|
|
4041
|
-
tradesInLastMinute: this.tradeTimestamps.length,
|
|
4042
|
-
region: this.region,
|
|
4043
|
-
regionBlocked: this.flags.regionBlocked
|
|
4044
|
-
});
|
|
4045
|
-
}
|
|
4046
|
-
async afterExecute(_toolName, _args, _result, _error) {
|
|
4047
|
-
}
|
|
4048
|
-
getStatus() {
|
|
4049
|
-
const now = Date.now();
|
|
4050
|
-
const oneMinAgo = now - 6e4;
|
|
4051
|
-
const recentTrades = this.tradeTimestamps.filter((t) => t > oneMinAgo);
|
|
4052
|
-
return {
|
|
4053
|
-
enabled: this.config.enabled,
|
|
4054
|
-
flags: { ...this.flags },
|
|
4055
|
-
velocity: {
|
|
4056
|
-
tradesLastMinute: recentTrades.length,
|
|
4057
|
-
sessionVolume: this.sessionTcVolume
|
|
4058
|
-
},
|
|
4059
|
-
region: this.region,
|
|
4060
|
-
blockedRegions: this.config.blockedRegions
|
|
4061
|
-
};
|
|
4062
|
-
}
|
|
4063
|
-
parseAmount(args) {
|
|
4064
|
-
if (typeof args !== "object" || args === null) return 0;
|
|
4065
|
-
const a = args;
|
|
4066
|
-
if (typeof a.quantity === "number" && typeof a.price === "number") {
|
|
4067
|
-
return a.quantity * a.price;
|
|
4068
|
-
}
|
|
4069
|
-
if (typeof a.quantity === "number") return a.quantity;
|
|
4070
|
-
if (typeof a.amount === "number") return a.amount;
|
|
4071
|
-
if (typeof a.stake === "number") return a.stake;
|
|
4072
|
-
if (typeof a.initialStake === "number") return a.initialStake;
|
|
4073
|
-
return 0;
|
|
4074
|
-
}
|
|
4075
|
-
};
|
|
4076
|
-
|
|
4077
3828
|
// src/audit.ts
|
|
4078
3829
|
var AUDITED_TOOLS = /* @__PURE__ */ new Set([
|
|
4079
3830
|
"place_order",
|
|
@@ -4124,7 +3875,7 @@ function summarizeResult(result) {
|
|
|
4124
3875
|
}
|
|
4125
3876
|
|
|
4126
3877
|
// src/middleware/trace-collector.ts
|
|
4127
|
-
import { ToromarketError as
|
|
3878
|
+
import { ToromarketError as ToromarketError5 } from "@toromarket/sdk";
|
|
4128
3879
|
var STATE_CHANGING_TOOLS = /* @__PURE__ */ new Set([
|
|
4129
3880
|
"place_order",
|
|
4130
3881
|
"cancel_order",
|
|
@@ -4173,7 +3924,7 @@ var TraceCollector = class {
|
|
|
4173
3924
|
}
|
|
4174
3925
|
}
|
|
4175
3926
|
if (!this.pendingReasoning) {
|
|
4176
|
-
throw new
|
|
3927
|
+
throw new ToromarketError5(
|
|
4177
3928
|
"Call log_reasoning before trading. Every trade requires a reasoning explanation.",
|
|
4178
3929
|
400,
|
|
4179
3930
|
"REASONING_REQUIRED"
|
|
@@ -4522,7 +4273,7 @@ function normalizeOrder(raw) {
|
|
|
4522
4273
|
}
|
|
4523
4274
|
|
|
4524
4275
|
// src/metrics.ts
|
|
4525
|
-
var
|
|
4276
|
+
var TRADE_TOOLS = /* @__PURE__ */ new Set(["place_order", "cancel_order", "trade_crypto"]);
|
|
4526
4277
|
var MetricsCollector = class {
|
|
4527
4278
|
metrics;
|
|
4528
4279
|
logger;
|
|
@@ -4556,7 +4307,7 @@ var MetricsCollector = class {
|
|
|
4556
4307
|
metric.errors++;
|
|
4557
4308
|
this.metrics.totalErrors++;
|
|
4558
4309
|
}
|
|
4559
|
-
if (
|
|
4310
|
+
if (TRADE_TOOLS.has(toolName) && !error) {
|
|
4560
4311
|
this.metrics.totalTrades++;
|
|
4561
4312
|
}
|
|
4562
4313
|
}
|
|
@@ -4721,20 +4472,8 @@ function createServerFactory(options) {
|
|
|
4721
4472
|
const metrics = new MetricsCollector(logger);
|
|
4722
4473
|
const rateLimiter = new RateLimiter();
|
|
4723
4474
|
const traceCollector = new TraceCollector(client, logger, `session-${Date.now()}`);
|
|
4724
|
-
const complianceEnabled = !!process.env.TOROMARKET_COMPLIANCE_MODE;
|
|
4725
|
-
const blockedRegions = (process.env.TOROMARKET_BLOCKED_REGIONS ?? "").split(",").map((r) => r.trim().toUpperCase()).filter(Boolean);
|
|
4726
|
-
const velocityTradesPerMin = Number(process.env.TOROMARKET_VELOCITY_TRADES_PER_MIN) || 30;
|
|
4727
|
-
const velocityTcPerHour = Number(process.env.TOROMARKET_VELOCITY_TC_PER_HOUR) || 5e4;
|
|
4728
|
-
const complianceGate = new ComplianceGate(
|
|
4729
|
-
{ enabled: complianceEnabled, blockedRegions, velocityTradesPerMin, velocityTcPerHour },
|
|
4730
|
-
logger
|
|
4731
|
-
);
|
|
4732
4475
|
const middlewares = [
|
|
4733
|
-
new RegistrationThrottle(),
|
|
4734
4476
|
rateLimiter,
|
|
4735
|
-
new SpoofingDetector(),
|
|
4736
|
-
complianceGate,
|
|
4737
|
-
new SpendingGuardrails(options.maxSessionLoss),
|
|
4738
4477
|
new ErrorBudget(),
|
|
4739
4478
|
new AuditLogger(logger),
|
|
4740
4479
|
traceCollector
|
|
@@ -4744,7 +4483,6 @@ function createServerFactory(options) {
|
|
|
4744
4483
|
let currentTrustTier = null;
|
|
4745
4484
|
const executeOptions = {
|
|
4746
4485
|
traceCollector,
|
|
4747
|
-
complianceGate,
|
|
4748
4486
|
onTrustTier: (trustTier) => {
|
|
4749
4487
|
currentTrustTier = trustTier;
|
|
4750
4488
|
logger.info({ event: "trust_tier_applied", trustTier });
|
|
@@ -4785,8 +4523,7 @@ function createServerFactory(options) {
|
|
|
4785
4523
|
notificationService.stop();
|
|
4786
4524
|
notificationService = null;
|
|
4787
4525
|
}
|
|
4788
|
-
}
|
|
4789
|
-
setRegion: (region) => complianceGate.setRegion(region)
|
|
4526
|
+
}
|
|
4790
4527
|
};
|
|
4791
4528
|
};
|
|
4792
4529
|
return { logger, createMcpServer };
|
|
@@ -4873,10 +4610,6 @@ async function startHttpTransport(options) {
|
|
|
4873
4610
|
entry = { transport: transport2, server: createdServer, lastActivity: Date.now() };
|
|
4874
4611
|
sessions.set(newSessionId, entry);
|
|
4875
4612
|
logger.info({ event: "session_created", sessionId: newSessionId });
|
|
4876
|
-
const region = req.headers["cf-ipcountry"] ?? req.headers["x-vercel-ip-country"] ?? req.headers["x-country-code"];
|
|
4877
|
-
if (region && createdServer.setRegion) {
|
|
4878
|
-
createdServer.setRegion(region);
|
|
4879
|
-
}
|
|
4880
4613
|
transport2.onclose = () => {
|
|
4881
4614
|
createdServer.cleanup();
|
|
4882
4615
|
sessions.delete(newSessionId);
|
|
@@ -4971,8 +4704,6 @@ var baseUrl = readEnv("TOROMARKET_BASE_URL") ?? "https://api.toromarket.io";
|
|
|
4971
4704
|
var token = readEnv("TOROMARKET_TOKEN");
|
|
4972
4705
|
var apiKey = readEnv("TOROMARKET_API_KEY");
|
|
4973
4706
|
var logLevel = readEnv("TOROMARKET_LOG_LEVEL") ?? "info";
|
|
4974
|
-
var maxSessionLossStr = readEnv("TOROMARKET_MAX_SESSION_LOSS");
|
|
4975
|
-
var maxSessionLoss = maxSessionLossStr ? Number(maxSessionLossStr) : void 0;
|
|
4976
4707
|
var transport = readEnv("TOROMARKET_TRANSPORT") ?? "stdio";
|
|
4977
4708
|
var httpPort = Number(readEnv("TOROMARKET_HTTP_PORT") ?? "3001");
|
|
4978
4709
|
var agentSecret = readEnv("TOROMARKET_AGENT_SECRET");
|
|
@@ -4993,7 +4724,6 @@ var serverOptions = {
|
|
|
4993
4724
|
...token ? { token } : {},
|
|
4994
4725
|
...apiKey ? { apiKey } : {},
|
|
4995
4726
|
...agentSecret ? { agentSecret } : {},
|
|
4996
|
-
...maxSessionLoss ? { maxSessionLoss } : {},
|
|
4997
4727
|
...pollIntervalMs !== void 0 ? { pollIntervalMs } : {}
|
|
4998
4728
|
};
|
|
4999
4729
|
async function main() {
|