@elisym/mcp 0.29.0 → 0.30.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/README.md CHANGED
@@ -206,7 +206,7 @@ npx @elisym/mcp disable-agent-switch <agent>
206
206
 
207
207
  The MCP process enforces a shared cap on total amount spent per asset by `submit_and_pay_job`, `buy_capability`, and `send_payment`. `withdraw` is NOT counted (uses its own gate).
208
208
 
209
- Defaults (hardcoded): `0.5 SOL` (shared), `50 USDC` per network, and `1,000,000 LSM` (mainnet-only) (the limiter is mint-keyed, so devnet USDC and mainnet USDC each get their own cap). Native SOL has no mint, so its cap is a single entry shared across networks - deliberate: in a mixed-network process the shared draw-down can only under-allow, never over-spend.
209
+ Defaults (hardcoded): `0.5 SOL` (shared), `50 USDC` per network, `1,000,000 LSM` (mainnet-only), and on Tempo `50 USDC.e` (mainnet) and `50 pathUSD` (one contract on both networks, so one shared cap - listed ahead of Tempo payments, so no build can pay in a coin without a cap; these two cannot be overridden yet) (the limiter is mint-keyed, so devnet USDC and mainnet USDC each get their own cap). Native SOL has no mint, so its cap is a single entry shared across networks - deliberate: in a mixed-network process the shared draw-down can only under-allow, never over-spend.
210
210
 
211
211
  Soft warnings fire once per process when committed spend first crosses 50% and 80% of the cap for an asset; the warning is appended to the tool result and logged at `warn` level. Crossing the cap is still a hard reject (the tool call fails).
212
212
 
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { LIMITS, SESSION_ID_REGEX, DEFAULT_KIND_OFFSET, SolanaPaymentStrategy, makeCensor, DEFAULT_REDACT_PATHS, validateAgentName, exportKeyPairBytes, RELAYS, toDTag, utf8ByteLength, JobWaitTimeoutError, attachmentsOf, decodeJobPayload, formatAssetAmount, estimateNetworkBaseline, formatSol as formatSol$1, resolveKnownAsset, verifyAgentIdentities, splAssetsForNetwork, deriveOwnerDelegationAta, getDelegation, resolveUsdcAsset, parseAssetAmount, delegationApproveFeeSubunits, buildApproveDelegate, decodeApproveDelegate, decodeDelegationFeeTransfer, buildRevokeDelegate, estimateSolFeeLamports, formatFeeBreakdown, getProtocolProgramId, isDefinitelyUnpaid, resolveAssetFromPaymentRequest as resolveAssetFromPaymentRequest$1, resolveLsmAsset, ElisymIdentity, ElisymClient, mintDelegationNonce, buildDelegationAuthProof, assetKey, MAX_PROOF_TTL_SECS, encodeJobPayload, NATIVE_SOL, assetByKey, sendConfirmToTerminal, ONCHAIN_DISCLAIMER, defaultCeilings, verifyOnchainCall, ONCHAIN_REFUSAL_HEADLINES, getProtocolConfig, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT_BASE, USDC_SOLANA_DEVNET, USDC_SOLANA_MAINNET, LSM_SOLANA_MAINNET, estimateAssetStatsRentLamports, formatNetworkBaseline, MAX_CALL_BASE64_CHARS, MAX_EXPLAIN_ENTRIES, MAX_EXPLAIN_TEXT_CHARS, ONCHAIN_UNATTRIBUTED_NOTICE, ONCHAIN_AUTHORITY_CHANGE_NOTICE, KNOWN_ASSETS } from '@elisym/sdk';
2
+ import { LIMITS, SESSION_ID_REGEX, DEFAULT_KIND_OFFSET, SolanaPaymentStrategy, makeCensor, DEFAULT_REDACT_PATHS, validateAgentName, exportKeyPairBytes, RELAYS, toDTag, utf8ByteLength, JobWaitTimeoutError, attachmentsOf, decodeJobPayload, formatAssetAmount, estimateNetworkBaseline, formatSol as formatSol$1, resolveKnownAsset, verifyAgentIdentities, splAssetsForNetwork, deriveOwnerDelegationAta, getDelegation, resolveUsdcAsset, parseAssetAmount, delegationApproveFeeSubunits, buildApproveDelegate, decodeApproveDelegate, decodeDelegationFeeTransfer, buildRevokeDelegate, estimateSolFeeLamports, formatFeeBreakdown, getProtocolProgramId, isDefinitelyUnpaid, resolveAssetFromPaymentRequest as resolveAssetFromPaymentRequest$1, resolveLsmAsset, ElisymIdentity, ElisymClient, mintDelegationNonce, buildDelegationAuthProof, assetKey, MAX_PROOF_TTL_SECS, encodeJobPayload, NATIVE_SOL, assetByKey, sendConfirmToTerminal, ONCHAIN_DISCLAIMER, defaultCeilings, verifyOnchainCall, ONCHAIN_REFUSAL_HEADLINES, getProtocolConfig, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT_BASE, USDC_SOLANA_DEVNET, USDC_SOLANA_MAINNET, LSM_SOLANA_MAINNET, USDCE_TEMPO_MAINNET, PATHUSD_TEMPO, estimateAssetStatsRentLamports, formatNetworkBaseline, MAX_CALL_BASE64_CHARS, MAX_EXPLAIN_ENTRIES, MAX_EXPLAIN_TEXT_CHARS, ONCHAIN_UNATTRIBUTED_NOTICE, ONCHAIN_AUTHORITY_CHANGE_NOTICE, KNOWN_ASSETS } from '@elisym/sdk';
3
3
  import { listAgents, createAgentDir, writeYamlInitial, writeExampleSkillTemplate, writeSecrets, resolveAgent, loadAgent, globalConfigPath, isBlockingNode, writeYaml, ensureGitignoreHasPrivateStateEntries, writeFileAtomic as writeFileAtomic$1, ensureGitignoreHasIrohEntry, ensureGitignoreHasMessagesEntry, ensureGitignoreHasJobSessionsEntry } from '@elisym/sdk/agent-store';
4
4
  import { loadGlobalConfig, writeGlobalConfig, createIrohTransport } from '@elisym/sdk/node';
5
5
  import { getBase58Encoder, getBase58Decoder, generateKeyPairSigner, createSolanaRpc, address, getSignatureFromTransaction, createSolanaRpcSubscriptions, sendAndConfirmTransactionFactory, pipe, createTransactionMessage, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, signTransactionMessageWithSigners, createKeyPairSignerFromBytes, getBase64Encoder, getTransactionDecoder, signTransaction, isAddress } from '@solana/kit';
@@ -1272,7 +1272,9 @@ var DEFAULT_SESSION_LIMITS = [
1272
1272
  { asset: NATIVE_SOL, humanAmount: "0.5" },
1273
1273
  { asset: USDC_SOLANA_DEVNET, humanAmount: "50" },
1274
1274
  { asset: USDC_SOLANA_MAINNET, humanAmount: "50" },
1275
- { asset: LSM_SOLANA_MAINNET, humanAmount: "1000000" }
1275
+ { asset: LSM_SOLANA_MAINNET, humanAmount: "1000000" },
1276
+ { asset: USDCE_TEMPO_MAINNET, humanAmount: "50" },
1277
+ { asset: PATHUSD_TEMPO, humanAmount: "50" }
1276
1278
  ];
1277
1279
  function defaultSpendLimitsMap() {
1278
1280
  const map = /* @__PURE__ */ new Map();
@@ -1292,7 +1294,7 @@ async function buildEffectiveLimits() {
1292
1294
  if (!asset || !key) {
1293
1295
  const display = entry.mint ? `${entry.chain}:${entry.token}:${entry.mint}` : `${entry.chain}:${entry.token}`;
1294
1296
  throw new Error(
1295
- `Unknown asset in ${globalConfigPath()}: ${display}. Update the SDK KNOWN_ASSETS list or remove the override.`
1297
+ `Unknown asset in ${globalConfigPath()}: ${display}. Update the SDK asset lists or remove the override.`
1296
1298
  );
1297
1299
  }
1298
1300
  if (seen.has(key)) {
@@ -2000,6 +2002,30 @@ async function computeGitDiff(repoPath, base, options) {
2000
2002
  return { diff, describedRange };
2001
2003
  }
2002
2004
 
2005
+ // src/payable-cards.ts
2006
+ function isPayableCard(card) {
2007
+ return (card.payment?.chain ?? "solana") === "solana";
2008
+ }
2009
+ function withPayableCards(agents) {
2010
+ const kept = [];
2011
+ for (const agent of agents) {
2012
+ const cards = agent.cards.filter((card) => isPayableCard(card));
2013
+ if (cards.length === 0) {
2014
+ continue;
2015
+ }
2016
+ kept.push(cards.length === agent.cards.length ? agent : { ...agent, cards });
2017
+ }
2018
+ return kept;
2019
+ }
2020
+ function findAgentByNpub(agents, npub) {
2021
+ const agent = agents.find((candidate) => candidate.npub === npub);
2022
+ if (agent === void 0) {
2023
+ return { found: false, reason: "absent" };
2024
+ }
2025
+ const cards = agent.cards.filter((card) => isPayableCard(card));
2026
+ return cards.length === 0 ? { found: false, reason: "nothing-payable" } : { found: true, agent: cards.length === agent.cards.length ? agent : { ...agent, cards } };
2027
+ }
2028
+
2003
2029
  // src/sanitize.ts
2004
2030
  var MAX_LINE_LEN = 1e4;
2005
2031
  var BOUNDARY_BEGIN = "--- [UNTRUSTED EXTERNAL CONTENT BEGIN] ---";
@@ -3135,8 +3161,16 @@ async function executeSubmitAndPay(ctx, agent, params) {
3135
3161
  `Provider ${params.providerNpub} is offline. Run search_agents to find currently-online providers.`
3136
3162
  );
3137
3163
  }
3138
- const providers = await agent.client.discovery.fetchAgents(agent.network);
3139
- const provider = providers.find((a) => a.npub === params.providerNpub);
3164
+ const lookup = findAgentByNpub(
3165
+ await agent.client.discovery.fetchAgents(agent.network),
3166
+ params.providerNpub
3167
+ );
3168
+ if (!lookup.found && lookup.reason === "nothing-payable") {
3169
+ return errorResult(
3170
+ `Provider ${params.providerNpub} prices every capability on a chain this server cannot pay (it pays on Solana). Ask for a Solana price, or pay from a client that supports that chain.`
3171
+ );
3172
+ }
3173
+ const provider = lookup.found ? lookup.agent : void 0;
3140
3174
  if (!provider) {
3141
3175
  return errorResult(
3142
3176
  `Provider ${params.providerNpub} not found on ${agent.network}. Refresh discovery (e.g. search_agents) or verify the npub is correct.`
@@ -3371,8 +3405,16 @@ async function executeDelegatedJob(ctx, agent, params) {
3371
3405
  `Provider ${params.providerNpub} is offline. Run search_agents to find currently-online providers.`
3372
3406
  );
3373
3407
  }
3374
- const providers = await agent.client.discovery.fetchAgents(agent.network);
3375
- const provider = providers.find((candidate) => candidate.npub === params.providerNpub);
3408
+ const lookup = findAgentByNpub(
3409
+ await agent.client.discovery.fetchAgents(agent.network),
3410
+ params.providerNpub
3411
+ );
3412
+ if (!lookup.found && lookup.reason === "nothing-payable") {
3413
+ return errorResult(
3414
+ `Provider ${params.providerNpub} prices every capability on a chain this server cannot pay (it pays on Solana). Ask for a Solana price, or pay from a client that supports that chain.`
3415
+ );
3416
+ }
3417
+ const provider = lookup.found ? lookup.agent : void 0;
3376
3418
  if (!provider) {
3377
3419
  return errorResult(
3378
3420
  `Provider ${params.providerNpub} not found on ${agent.network}. Refresh discovery (e.g. search_agents) or verify the npub is correct.`
@@ -4240,11 +4282,16 @@ ${diffResult.diff}`;
4240
4282
  `Provider ${input.provider_npub} is offline. Run search_agents to find currently-online providers.`
4241
4283
  );
4242
4284
  }
4243
- const agents = await agent.client.discovery.fetchAgents(agent.network);
4244
- const provider = agents.find((a) => a.npub === input.provider_npub);
4245
- if (!provider) {
4246
- return errorResult(`Provider ${input.provider_npub} not found on the network.`);
4285
+ const lookup = findAgentByNpub(
4286
+ await agent.client.discovery.fetchAgents(agent.network),
4287
+ input.provider_npub
4288
+ );
4289
+ if (!lookup.found) {
4290
+ return errorResult(
4291
+ lookup.reason === "nothing-payable" ? `Provider ${input.provider_npub} prices every capability on a chain this server cannot pay (it pays on Solana). Ask for a Solana price, or pay from a client that supports that chain.` : `Provider ${input.provider_npub} not found on the network.`
4292
+ );
4247
4293
  }
4294
+ const provider = lookup.agent;
4248
4295
  const card = paymentCardForCapability(provider, dTag) ?? provider.cards.find(
4249
4296
  (c) => toDTag(c.name) === dTag || c.capabilities?.some((cap) => toDTag(cap) === dTag)
4250
4297
  );
@@ -4433,9 +4480,8 @@ var dashboardTools = [
4433
4480
  const network = input.network ?? agent.network;
4434
4481
  let agents;
4435
4482
  try {
4436
- agents = await withTimeout(
4437
- agent.client.discovery.fetchAgents(network),
4438
- input.timeout_secs * 1e3
4483
+ agents = withPayableCards(
4484
+ await withTimeout(agent.client.discovery.fetchAgents(network), input.timeout_secs * 1e3)
4439
4485
  );
4440
4486
  } catch (e) {
4441
4487
  return textResult(e instanceof Error ? e.message : String(e));
@@ -4764,7 +4810,7 @@ var discoveryTools = [
4764
4810
  );
4765
4811
  }
4766
4812
  }
4767
- const agents = await agent.client.discovery.fetchAgents(agent.network);
4813
+ const agents = withPayableCards(await agent.client.discovery.fetchAgents(agent.network));
4768
4814
  let filtered = contacts_only ? agents.filter((a) => contactByPubkey.has(a.pubkey)) : agents;
4769
4815
  filtered = filtered.filter(
4770
4816
  (a) => a.cards.some(
@@ -5054,7 +5100,7 @@ var discoveryTools = [
5054
5100
  async handler(ctx) {
5055
5101
  ctx.toolRateLimiter.check();
5056
5102
  const agent = ctx.active();
5057
- const agents = await agent.client.discovery.fetchAgents(agent.network);
5103
+ const agents = withPayableCards(await agent.client.discovery.fetchAgents(agent.network));
5058
5104
  const caps = /* @__PURE__ */ new Set();
5059
5105
  for (const a of agents) {
5060
5106
  for (const card of a.cards) {
@@ -7593,6 +7639,11 @@ function resolveAssetOrThrow(chain, token, mint) {
7593
7639
  }
7594
7640
  async function setSessionLimit(amount, chain, token, mint) {
7595
7641
  const asset = resolveAssetOrThrow(chain, token, mint);
7642
+ if (asset.chain !== "solana") {
7643
+ throw new Error(
7644
+ `The session limit of ${asset.symbol} cannot be overridden yet: its built-in cap applies.`
7645
+ );
7646
+ }
7596
7647
  const trimmedAmount = amount.trim();
7597
7648
  parseAssetAmount(asset, trimmedAmount);
7598
7649
  const path = globalConfigPath();