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)"),
        },
      },
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full disclosure burden. Adds valuable context about persistence ('Jobs persist and execute on-chain') and infrastructure requirements. However, omits safety-critical behavioral traits: no warning about destructive delete action, automatic fund movement risks (despite schema parameter 'allowFundMovement'), or failure modes for conditional triggers.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, optimally structured: [1] Core function, [2] Behavioral characteristics with examples, [3] Prerequisites. Zero redundancy; every sentence conveys unique operational information not available in structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 17 parameters with 100% schema coverage, the description appropriately focuses on high-level operational context (persistence, canister requirements) rather than parameter details. Deducted one point for missing output behavior description and lack of safety warnings regarding automatic fund transfers, which are critical for this financial automation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% description coverage, establishing baseline 3. Description provides helpful examples ('recurring swaps, conditional trades') that map to jobType enum values, adding illustrative context. However, does not explain parameter relationships (e.g., which fields are required for 'create' vs 'conditional' actions) or complex semantics beyond schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clear specific verb ('Manage') + resource ('on-chain scheduled jobs') + mechanism ('via your MeneseAgent canister'). Explicitly distinguishes from sibling tools by focusing on persistent scheduling ('recurring swaps, conditional trades') versus immediate operations like menese_swap or menese_send.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States critical prerequisite ('Requires an agent canister') and setup requirement (env var), implying this is for automated/recurring workflows. However, lacks explicit guidance on when to choose this over menese_swap for immediate execution, or warnings about fund management implications.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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-menese-sdk'

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