@aihubspot/agent-trade-mcp 0.1.7 → 0.1.8
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.js +82 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -656,29 +656,82 @@ function optionalClientOrderId(input) {
|
|
|
656
656
|
}
|
|
657
657
|
|
|
658
658
|
// ../core/src/tools/asset-tools.ts
|
|
659
|
-
var
|
|
659
|
+
var ACCOUNT_TYPES = ["1", "2", "3", "4", "5"];
|
|
660
|
+
var ACCOUNT_TYPE_NAMES = {
|
|
661
|
+
"1": "Spot",
|
|
662
|
+
"2": "Isolated Margin",
|
|
663
|
+
"3": "Cross Margin",
|
|
664
|
+
"4": "C2C",
|
|
665
|
+
"5": "Derivatives"
|
|
666
|
+
};
|
|
667
|
+
var accountTypeSchema = {
|
|
668
|
+
type: "string",
|
|
669
|
+
oneOf: [
|
|
670
|
+
{ const: "1", title: "Spot (1)" },
|
|
671
|
+
{ const: "2", title: "Isolated Margin (2; symbol required)" },
|
|
672
|
+
{ const: "3", title: "Cross Margin (3)" },
|
|
673
|
+
{ const: "4", title: "C2C (4)" },
|
|
674
|
+
{ const: "5", title: "Derivatives (5)" }
|
|
675
|
+
],
|
|
676
|
+
description: "Account type: 1=Spot, 2=Isolated Margin (requires symbol), 3=Cross Margin, 4=C2C, 5=Derivatives. Do not use 2 for Derivatives."
|
|
677
|
+
};
|
|
678
|
+
var spotDerivativeAccounts = ["EXCHANGE", "FUTURE"];
|
|
660
679
|
function accountType(value, name) {
|
|
661
680
|
const result2 = requiredString(value, name);
|
|
662
|
-
if (!
|
|
681
|
+
if (!ACCOUNT_TYPES.includes(result2)) throw new AiHubError("AI_HUB_INVALID_ARGUMENT", `${name} must be an account type: 1=Spot, 2=Isolated Margin, 3=Cross Margin, 4=C2C, or 5=Derivatives.`);
|
|
663
682
|
return result2;
|
|
664
683
|
}
|
|
684
|
+
function accountTypeName(value) {
|
|
685
|
+
return ACCOUNT_TYPE_NAMES[value];
|
|
686
|
+
}
|
|
687
|
+
function isIsolatedMarginTransfer(fromAccountType, toAccountType) {
|
|
688
|
+
return fromAccountType === "2" || toAccountType === "2";
|
|
689
|
+
}
|
|
665
690
|
function requiredTransfer(input) {
|
|
666
691
|
const value = strictObject(input, ["fromAccountType", "toAccountType", "symbol", "coinSymbol", "amount"]);
|
|
667
|
-
|
|
692
|
+
const fromAccountType = accountType(value, "fromAccountType");
|
|
693
|
+
const toAccountType = accountType(value, "toAccountType");
|
|
694
|
+
if (fromAccountType === toAccountType) throw new AiHubError("AI_HUB_INVALID_ARGUMENT", "fromAccountType and toAccountType must be different.");
|
|
695
|
+
const symbol = optionalString(value, "symbol");
|
|
696
|
+
if (isIsolatedMarginTransfer(fromAccountType, toAccountType) && !symbol) {
|
|
697
|
+
throw new AiHubError("AI_HUB_ISOLATED_MARGIN_SYMBOL_REQUIRED", "symbol is required when fromAccountType or toAccountType is 2 (Isolated Margin). Provide the isolated-margin trading pair, for example ETHUSDT.");
|
|
698
|
+
}
|
|
699
|
+
return { fromAccountType, toAccountType, coinSymbol: requiredString(value, "coinSymbol"), amount: positiveDecimal(value, "amount"), ...symbol ? { symbol } : {} };
|
|
668
700
|
}
|
|
669
701
|
function transferQuery(input) {
|
|
670
702
|
const value = strictObject(input, ["fromAccountType", "toAccountType", "symbol", "coinSymbol", "page", "pageSize"]);
|
|
671
|
-
|
|
703
|
+
const fromAccountType = accountType(value, "fromAccountType");
|
|
704
|
+
const toAccountType = accountType(value, "toAccountType");
|
|
705
|
+
const symbol = optionalString(value, "symbol");
|
|
706
|
+
if (isIsolatedMarginTransfer(fromAccountType, toAccountType) && !symbol) {
|
|
707
|
+
throw new AiHubError("AI_HUB_ISOLATED_MARGIN_SYMBOL_REQUIRED", "symbol is required when fromAccountType or toAccountType is 2 (Isolated Margin). Provide the isolated-margin trading pair, for example ETHUSDT.");
|
|
708
|
+
}
|
|
709
|
+
return { fromAccountType, toAccountType, page: optionalPositiveInteger(value, "page", 1), pageSize: optionalPositiveInteger(value, "pageSize", 20, 100), ...symbol ? { symbol } : {}, ...optionalString(value, "coinSymbol") ? { coinSymbol: optionalString(value, "coinSymbol") } : {} };
|
|
672
710
|
}
|
|
673
711
|
function transferAccounts(input) {
|
|
674
712
|
const value = strictObject(input, ["coinSymbol", "amount", "fromAccount", "toAccount"]);
|
|
675
|
-
|
|
713
|
+
const fromAccount = requiredString(value, "fromAccount").toUpperCase();
|
|
714
|
+
const toAccount = requiredString(value, "toAccount").toUpperCase();
|
|
715
|
+
if (!spotDerivativeAccounts.includes(fromAccount) || !spotDerivativeAccounts.includes(toAccount) || fromAccount === toAccount) {
|
|
716
|
+
throw new AiHubError("AI_HUB_INVALID_ARGUMENT", "account transfer supports only EXCHANGE -> FUTURE or FUTURE -> EXCHANGE. Use wallet transfer for isolated margin, cross margin, or C2C.");
|
|
717
|
+
}
|
|
718
|
+
return { coinSymbol: requiredString(value, "coinSymbol"), amount: positiveDecimal(value, "amount"), fromAccount, toAccount };
|
|
676
719
|
}
|
|
677
720
|
function transferAccountHistory(input) {
|
|
678
721
|
const value = strictObject(input, ["transferId", "coinSymbol", "fromAccount", "toAccount", "startTime", "endTime", "page", "limit"]);
|
|
679
722
|
const transferId = optionalString(value, "transferId");
|
|
680
723
|
if (!transferId && (!optionalString(value, "fromAccount") || !optionalString(value, "toAccount"))) throw new AiHubError("AI_HUB_INVALID_ARGUMENT", "fromAccount and toAccount are required when transferId is omitted.");
|
|
681
|
-
|
|
724
|
+
const fromAccount = optionalString(value, "fromAccount")?.toUpperCase();
|
|
725
|
+
const toAccount = optionalString(value, "toAccount")?.toUpperCase();
|
|
726
|
+
if (!transferId && (!spotDerivativeAccounts.includes(fromAccount) || !spotDerivativeAccounts.includes(toAccount) || fromAccount === toAccount)) {
|
|
727
|
+
throw new AiHubError("AI_HUB_INVALID_ARGUMENT", "account transfer history supports only EXCHANGE -> FUTURE or FUTURE -> EXCHANGE when transferId is omitted.");
|
|
728
|
+
}
|
|
729
|
+
return { ...transferId ? { transferId } : {}, ...optionalString(value, "coinSymbol") ? { coinSymbol: optionalString(value, "coinSymbol") } : {}, ...fromAccount ? { fromAccount } : {}, ...toAccount ? { toAccount } : {}, ...optionalString(value, "startTime") ? { startTime: optionalString(value, "startTime") } : {}, ...optionalString(value, "endTime") ? { endTime: optionalString(value, "endTime") } : {}, page: optionalPositiveInteger(value, "page", 1), limit: optionalPositiveInteger(value, "limit", 20, 100) };
|
|
730
|
+
}
|
|
731
|
+
function withAccountTypeMetadata(response, value) {
|
|
732
|
+
const metadata = { accountType: value, accountTypeName: accountTypeName(value) };
|
|
733
|
+
if (response && typeof response === "object" && !Array.isArray(response)) return { ...response, ...metadata };
|
|
734
|
+
return { ...metadata, response };
|
|
682
735
|
}
|
|
683
736
|
function pagedDates(input) {
|
|
684
737
|
const value = strictObject(input, ["startTime", "endTime", "page", "pageSize"]);
|
|
@@ -691,18 +744,21 @@ function coinOnly(input) {
|
|
|
691
744
|
var assetTools = [
|
|
692
745
|
{
|
|
693
746
|
name: "account_transfer",
|
|
694
|
-
title: "Transfer Between
|
|
695
|
-
description: "Transfer
|
|
747
|
+
title: "Transfer Between Spot and Derivatives",
|
|
748
|
+
description: "Transfer only between Spot and Derivatives after confirmation. Use fromAccount=EXCHANGE and toAccount=FUTURE for Spot to Derivatives; use the reverse for Derivatives to Spot. Do not pass numeric account types to this Tool.",
|
|
696
749
|
cliPath: ["account", "transfer"],
|
|
697
750
|
module: "spot-account",
|
|
698
751
|
access: "signed",
|
|
699
752
|
operation: "write",
|
|
700
753
|
riskLevel: "high",
|
|
701
|
-
inputSchema: { type: "object", properties: { coinSymbol: { type: "string" }, amount: { type: "string" }, fromAccount: { type: "string" }, toAccount: { type: "string" } }, required: ["coinSymbol", "amount", "fromAccount", "toAccount"], additionalProperties: false },
|
|
754
|
+
inputSchema: { type: "object", properties: { coinSymbol: { type: "string" }, amount: { type: "string" }, fromAccount: { type: "string", enum: spotDerivativeAccounts, description: "EXCHANGE means Spot; FUTURE means Derivatives." }, toAccount: { type: "string", enum: spotDerivativeAccounts, description: "EXCHANGE means Spot; FUTURE means Derivatives." } }, required: ["coinSymbol", "amount", "fromAccount", "toAccount"], additionalProperties: false },
|
|
702
755
|
errorCodes: writeErrors,
|
|
703
756
|
validate: transferAccounts,
|
|
704
757
|
handler: (input, context) => context.api.signedPost("/sapi/v1/asset/transfer", input, signed(context)),
|
|
705
|
-
writeSummary: (input) =>
|
|
758
|
+
writeSummary: (input) => {
|
|
759
|
+
const value = input;
|
|
760
|
+
return { action: "spot_derivatives_transfer", coinSymbol: value.coinSymbol, amount: value.amount, fromAccount: value.fromAccount, fromAccountName: value.fromAccount === "EXCHANGE" ? "Spot" : "Derivatives", toAccount: value.toAccount, toAccountName: value.toAccount === "EXCHANGE" ? "Spot" : "Derivatives" };
|
|
761
|
+
}
|
|
706
762
|
},
|
|
707
763
|
{
|
|
708
764
|
name: "account_get_transfer_history",
|
|
@@ -721,28 +777,31 @@ var assetTools = [
|
|
|
721
777
|
{
|
|
722
778
|
name: "wallet_universal_transfer",
|
|
723
779
|
title: "Universal Asset Transfer",
|
|
724
|
-
description: "Transfer between account types after confirmation.",
|
|
780
|
+
description: "Transfer between numeric account types after confirmation: 1=Spot, 2=Isolated Margin, 3=Cross Margin, 4=C2C, 5=Derivatives. Account type 2 is not Derivatives and requires symbol. For a straightforward Spot to Derivatives transfer, prefer account_transfer with EXCHANGE -> FUTURE.",
|
|
725
781
|
cliPath: ["wallet", "transfer"],
|
|
726
782
|
module: "spot-deposit-withdraw",
|
|
727
783
|
access: "signed",
|
|
728
784
|
operation: "write",
|
|
729
785
|
riskLevel: "high",
|
|
730
|
-
inputSchema: { type: "object", properties: { fromAccountType:
|
|
786
|
+
inputSchema: { type: "object", properties: { fromAccountType: accountTypeSchema, toAccountType: accountTypeSchema, symbol: { type: "string", description: "Required isolated-margin trading pair when either account type is 2, for example ETHUSDT. Not a Derivatives identifier." }, coinSymbol: { type: "string" }, amount: { type: "string" } }, required: ["fromAccountType", "toAccountType", "coinSymbol", "amount"], additionalProperties: false },
|
|
731
787
|
errorCodes: writeErrors,
|
|
732
788
|
validate: requiredTransfer,
|
|
733
789
|
handler: (input, context) => context.api.signedPost("/sapi/v1/asset/universal_transfer", input, signed(context)),
|
|
734
|
-
writeSummary: (input) =>
|
|
790
|
+
writeSummary: (input) => {
|
|
791
|
+
const value = input;
|
|
792
|
+
return { action: "universal_transfer", fromAccountType: value.fromAccountType, fromAccountTypeName: accountTypeName(String(value.fromAccountType)), toAccountType: value.toAccountType, toAccountTypeName: accountTypeName(String(value.toAccountType)), coinSymbol: value.coinSymbol, amount: value.amount, symbol: value.symbol ?? null };
|
|
793
|
+
}
|
|
735
794
|
},
|
|
736
795
|
{
|
|
737
796
|
name: "wallet_get_universal_transfer_history",
|
|
738
797
|
title: "Get Universal Transfer History",
|
|
739
|
-
description: "Query universal
|
|
798
|
+
description: "Query universal transfer history using account types 1=Spot, 2=Isolated Margin, 3=Cross Margin, 4=C2C, and 5=Derivatives.",
|
|
740
799
|
cliPath: ["wallet", "transfer-history"],
|
|
741
800
|
module: "spot-deposit-withdraw",
|
|
742
801
|
access: "signed",
|
|
743
802
|
operation: "read",
|
|
744
803
|
riskLevel: "low",
|
|
745
|
-
inputSchema: { type: "object", properties: { fromAccountType:
|
|
804
|
+
inputSchema: { type: "object", properties: { fromAccountType: accountTypeSchema, toAccountType: accountTypeSchema, symbol: { type: "string", description: "Isolated-margin trading pair when account type 2 is involved." }, coinSymbol: { type: "string" }, page: { type: "integer" }, pageSize: { type: "integer" } }, required: ["fromAccountType", "toAccountType"], additionalProperties: false },
|
|
746
805
|
errorCodes: signedReadErrors,
|
|
747
806
|
validate: transferQuery,
|
|
748
807
|
handler: (input, context) => context.api.signedPost("/sapi/v1/asset/universal_transfer_query", input, signed(context))
|
|
@@ -795,19 +854,22 @@ var assetTools = [
|
|
|
795
854
|
{
|
|
796
855
|
name: "wallet_get_transferable_assets",
|
|
797
856
|
title: "Get Transferable Assets",
|
|
798
|
-
description: "Query assets
|
|
857
|
+
description: "Query transferable assets for one account type. The response echoes the selected account type and its name: 1=Spot, 2=Isolated Margin, 3=Cross Margin, 4=C2C, 5=Derivatives.",
|
|
799
858
|
cliPath: ["wallet", "transferable-assets"],
|
|
800
859
|
module: "spot-deposit-withdraw",
|
|
801
860
|
access: "signed",
|
|
802
861
|
operation: "read",
|
|
803
862
|
riskLevel: "low",
|
|
804
|
-
inputSchema: { type: "object", properties: { accountType:
|
|
863
|
+
inputSchema: { type: "object", properties: { accountType: accountTypeSchema }, required: ["accountType"], additionalProperties: false },
|
|
805
864
|
errorCodes: signedReadErrors,
|
|
806
865
|
validate: (input) => {
|
|
807
866
|
const value = strictObject(input, ["accountType"]);
|
|
808
867
|
return { accountType: accountType(value, "accountType") };
|
|
809
868
|
},
|
|
810
|
-
handler: (input, context) =>
|
|
869
|
+
handler: async (input, context) => {
|
|
870
|
+
const value = input;
|
|
871
|
+
return withAccountTypeMetadata(await context.api.signedPost("/sapi/v1/asset/account/by_type", value, signed(context)), value.accountType);
|
|
872
|
+
}
|
|
811
873
|
},
|
|
812
874
|
{
|
|
813
875
|
name: "wallet_get_exchange_account",
|
|
@@ -2581,10 +2643,10 @@ function createServer(profileName, readOnly) {
|
|
|
2581
2643
|
const registry = createToolRegistry();
|
|
2582
2644
|
const writeExecutor = new ToolWriteExecutor(registry);
|
|
2583
2645
|
const server = new Server(
|
|
2584
|
-
{ name: "ai-hub-agent-trade", version: "0.1.
|
|
2646
|
+
{ name: "ai-hub-agent-trade", version: "0.1.8" },
|
|
2585
2647
|
{
|
|
2586
2648
|
capabilities: { tools: {} },
|
|
2587
|
-
instructions: "Every successful read-tool response provides both JSON text and MCP structuredContent in the envelope { ok: true, data: ... }. All read-tool data is normalized: dataType=array means use data.items and data.count; dataType=object or scalar means use data.value; dataType=null means no value. Inspect data.dataType before formatting and never assume undocumented nested keys. For symbol lookup, use market_search_symbols. It returns an object whose bounded matches are at data.value.items; the complete raw symbols payload is intentionally unavailable in MCP. For broad market questions, call market_get_ticker_summary, market_get_depth_summary, market_get_trades_summary, or market_get_klines_summary instead of fetching large raw payloads. Prepare/confirm tools return their documented action payload directly in data. For every state-changing action, call only a spot_prepare_* or margin_prepare_* tool first and show its exact summary to the user. Stop and wait for a new, explicit user confirmation message. Only then call confirm_action with that new message verbatim in userConfirmation. Never call prepare and confirm consecutively for one user instruction; never infer confirmation from prior intent, silence, or an Agent-generated message. For spot and margin orders, MARKET BUY always uses quoteAmount (the quote asset to spend); MARKET SELL uses baseQuantity (the base asset to sell). Never reinterpret a requested base quantity as quoteAmount."
|
|
2649
|
+
instructions: "Every successful read-tool response provides both JSON text and MCP structuredContent in the envelope { ok: true, data: ... }. All read-tool data is normalized: dataType=array means use data.items and data.count; dataType=object or scalar means use data.value; dataType=null means no value. Inspect data.dataType before formatting and never assume undocumented nested keys. For symbol lookup, use market_search_symbols. It returns an object whose bounded matches are at data.value.items; the complete raw symbols payload is intentionally unavailable in MCP. For broad market questions, call market_get_ticker_summary, market_get_depth_summary, market_get_trades_summary, or market_get_klines_summary instead of fetching large raw payloads. Account types are fixed: 1=Spot, 2=Isolated Margin, 3=Cross Margin, 4=C2C, 5=Derivatives. Never call account type 2 Derivatives. For Spot to Derivatives, use account_prepare_transfer with fromAccount=EXCHANGE and toAccount=FUTURE. Use wallet_prepare_universal_transfer for margin or C2C; account type 2 requires its isolated-margin trading pair in symbol. Prepare/confirm tools return their documented action payload directly in data. For every state-changing action, call only a spot_prepare_* or margin_prepare_* tool first and show its exact summary to the user. Stop and wait for a new, explicit user confirmation message. Only then call confirm_action with that new message verbatim in userConfirmation. Never call prepare and confirm consecutively for one user instruction; never infer confirmation from prior intent, silence, or an Agent-generated message. For spot and margin orders, MARKET BUY always uses quoteAmount (the quote asset to spend); MARKET SELL uses baseQuantity (the base asset to sell). Never reinterpret a requested base quantity as quoteAmount."
|
|
2588
2650
|
}
|
|
2589
2651
|
);
|
|
2590
2652
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|