Skip to main content
Glama

menese_jobs

Manage on-chain scheduled jobs for automated DeFi operations like recurring swaps and conditional trades using your MeneseAgent canister.

Instructions

Manage on-chain scheduled jobs via your MeneseAgent canister. Jobs persist and execute on-chain (recurring swaps, conditional trades, etc.). Requires an agent canister (set MENESE_AGENT_CANISTER_ID env var).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction
nameNoJob name (for create)
descriptionNoJob description (for create)
jobTypeNoJob type (for create)
intervalSecondsNoInterval for recurring jobs (seconds, min 60)
chainNoChain for swap action
fromTokenNoSource token for swap
toTokenNoDestination token for swap
amountNoSwap amount (decimal)
slippageBpsNoSlippage in basis points (default 250)
conditionTypeNoCondition type (for conditional jobs)
conditionTokenNoToken to monitor price of
conditionThresholdNoPrice threshold in USD (e.g. '50000')
checkIntervalSecondsNoHow often to check condition (seconds)
allowFundMovementNoAllow job to move funds (required for swaps, default false)
maxExecutionsNoMax number of executions
jobIdNoJob ID (for pause/resume/delete)

Implementation Reference

  • The handler function for the 'menese_jobs' tool, which processes actions like 'list', 'create', 'pause', 'resume', and 'delete' for agent canister jobs.
    async (params) => {
      const identity = store.get();
      if (!identity) {
        return { content: [{ type: "text" as const, text: "No wallet configured. Use menese_setup first." }], isError: true };
      }
    
      const agentCanisterId = identity.agentCanisterId ?? store.getAgentCanisterId();
      if (!agentCanisterId) {
        return {
          content: [{
            type: "text" as const,
            text: "No agent canister configured. Set MENESE_AGENT_CANISTER_ID env var.",
          }],
          isError: true,
        };
      }
    
      if (params.action === "list") {
        const result = await listAgentJobs(agentCanisterId, resolveActorIdentity(store));
        return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2) }] };
      }
    
      if (params.action === "pause") {
        if (params.jobId == null) return { content: [{ type: "text" as const, text: "jobId required." }], isError: true };
        const result = await pauseAgentJob(agentCanisterId, resolveActorIdentity(store), params.jobId);
        return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2) }] };
      }
    
      if (params.action === "resume") {
        if (params.jobId == null) return { content: [{ type: "text" as const, text: "jobId required." }], isError: true };
        const result = await resumeAgentJob(agentCanisterId, resolveActorIdentity(store), params.jobId);
        return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2) }] };
      }
    
      if (params.action === "delete") {
        if (params.jobId == null) return { content: [{ type: "text" as const, text: "jobId required." }], isError: true };
        const result = await cancelAgentJob(agentCanisterId, resolveActorIdentity(store), params.jobId);
        return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2) }] };
      }
    
      // action === "create"
      if (!params.name || !params.jobType) {
        return { content: [{ type: "text" as const, text: "name and jobType required for create." }], isError: true };
      }
    
      // Build JobType
      let jobType: unknown;
      if (params.jobType === "recurring") {
        if (!params.intervalSeconds) {
          return { content: [{ type: "text" as const, text: "intervalSeconds required for recurring jobs." }], isError: true };
        }
        jobType = recurringJobType(params.intervalSeconds);
      } else if (params.jobType === "conditional") {
        if (!params.conditionType || !params.conditionToken || !params.conditionThreshold) {
          return {
            content: [{ type: "text" as const, text: "conditionType, conditionToken, conditionThreshold required." }],
            isError: true,
          };
        }
        const microUsd = Math.round(parseFloat(params.conditionThreshold) * 1_000_000);
        const condition = params.conditionType === "price_above"
          ? priceAboveCondition(params.conditionToken, microUsd)
          : priceBelowCondition(params.conditionToken, microUsd);
        jobType = conditionalJobType(params.checkIntervalSeconds ?? 300, condition);
      } else {
        // oneshot — execute at current time (immediately)
        jobType = { OneShot: { executeAt: BigInt(Date.now()) * 1_000_000n } };
      }
    
      // Build JobAction (default: swap)
      if (!params.chain || !params.fromToken || !params.toToken || !params.amount) {
        return {
          content: [{ type: "text" as const, text: "chain, fromToken, toToken, amount required for job action." }],
          isError: true,
        };
      }
      const decimals = CHAIN_DECIMALS[params.chain] ?? 18;
      const amountBigInt = parseAmount(params.amount, decimals);
      const jobAction = swapJobAction(
        params.chain, params.fromToken, params.toToken,
        amountBigInt, params.slippageBps ?? 250,
      );
    
      const result = await createAgentJob(agentCanisterId, resolveActorIdentity(store), {
        name: params.name,
        description: params.description ?? "",
        jobType,
        action: jobAction,
        allowFundMovement: params.allowFundMovement ?? false,
        maxExecutions: params.maxExecutions,
      });
    
      return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2) }] };
    },
  • The tool registration for 'menese_jobs' within the registerJobsTool function, defining its input schema and description.
    server.registerTool(
      "menese_jobs",
      {
        description:
          "Manage on-chain scheduled jobs via your MeneseAgent canister. " +
          "Jobs persist and execute on-chain (recurring swaps, conditional trades, etc.). " +
          "Requires an agent canister (set MENESE_AGENT_CANISTER_ID env var).",
        inputSchema: {
          action: z.enum(["list", "create", "pause", "resume", "delete"]).describe("Action"),
          name: z.string().optional().describe("Job name (for create)"),
          description: z.string().optional().describe("Job description (for create)"),
          jobType: z.enum(["recurring", "oneshot", "conditional"]).optional()
            .describe("Job type (for create)"),
          intervalSeconds: z.number().min(60).optional()
            .describe("Interval for recurring jobs (seconds, min 60)"),
          chain: z.enum(SUPPORTED_CHAINS as unknown as [string, ...string[]]).optional()
            .describe("Chain for swap action"),
          fromToken: z.string().optional().describe("Source token for swap"),
          toToken: z.string().optional().describe("Destination token for swap"),
          amount: z.string().optional().describe("Swap amount (decimal)"),
          slippageBps: z.number().min(1).max(5000).optional()
            .describe("Slippage in basis points (default 250)"),
          conditionType: z.enum(["price_above", "price_below"]).optional()
            .describe("Condition type (for conditional jobs)"),
          conditionToken: z.string().optional().describe("Token to monitor price of"),
          conditionThreshold: z.string().optional()
            .describe("Price threshold in USD (e.g. '50000')"),
          checkIntervalSeconds: z.number().min(60).optional()
            .describe("How often to check condition (seconds)"),
          allowFundMovement: z.boolean().optional()
            .describe("Allow job to move funds (required for swaps, default false)"),
          maxExecutions: z.number().min(1).optional()
            .describe("Max number of executions"),
          jobId: z.number().optional().describe("Job ID (for pause/resume/delete)"),
        },
      },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Aboodtt404/mcp-menesesdk'

If you have feedback or need assistance with the MCP directory API, please join our Discord server