Skip to main content
Glama

account_sign_data

Sign data strings using a local account's private key. Outputs the signature encoded in base58 or base64.

Instructions

Cryptographically sign a piece of data with a local account's private key, then encode the result with the specified encoding. Outputs the curve, encoded signature, and encoding used.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
accountIdYesThe account id of the account that will sign the data. This account must be in the local keystore.
networkIdNomainnet
dataYesThe data to sign as a string.
signatureEncodingNoThe encoding to use for signature creation.base58

Implementation Reference

  • The handler function for the 'account_sign_data' tool. It retrieves the key pair from the keystore, signs the provided data using the account's private key, encodes the signature in base58 or base64, and returns the curve, encoded signature, and encoding used.
      async (args, _) => {
        const keyPairResult: Result<KeyPair, Error> = await getAccountKeyPair(
          args.accountId,
          args.networkId,
          keystore,
        );
        if (!keyPairResult.ok) {
          return {
            content: [{ type: 'text', text: `Error: ${keyPairResult.error}` }],
          };
        }
        const keyPair = keyPairResult.value;
        const signatureRaw = keyPair.sign(new TextEncoder().encode(args.data));
        const signatureEncodingResult: Result<string, Error> = (() => {
          try {
            switch (args.signatureEncoding) {
              case 'base64':
                return {
                  ok: true,
                  value: Buffer.from(signatureRaw.signature).toString('base64'),
                };
              case 'base58':
                return {
                  ok: true,
                  value: base58.encode(Buffer.from(signatureRaw.signature)),
                };
              default:
                throw new Error(
                  `Unsupported encoding: ${String(args.signatureEncoding)}`,
                );
            }
          } catch (e) {
            return { ok: false, error: new Error(e as string) };
          }
        })();
        if (!signatureEncodingResult.ok) {
          return {
            content: [
              { type: 'text', text: `Error: ${signatureEncodingResult.error}` },
            ],
          };
        }
    
        return {
          content: [
            {
              type: 'text',
              text: stringify_bigint({
                signerAccountId: args.accountId,
                curve: keyTypeToCurvePrefix(keyPair.getPublicKey().keyType),
                signature: signatureEncodingResult.value,
                encoding: args.signatureEncoding,
              }),
            },
          ],
        };
      },
    );
  • Input schema for the 'account_sign_data' tool. Defines parameters: accountId, networkId (testnet/mainnet), data (string to sign), and signatureEncoding (base58/base64).
    {
      accountId: z
        .string()
        .describe(
          'The account id of the account that will sign the data. This account must be in the local keystore.',
        ),
      networkId: z.enum(['testnet', 'mainnet']).default('mainnet'),
      data: z.string().describe('The data to sign as a string.'),
      signatureEncoding: z
        .enum(['base58', 'base64'])
        .default('base58')
        .describe('The encoding to use for signature creation.'),
    },
  • Registration of the 'account_sign_data' tool via mcp.tool() call within the createMcpServer function.
    mcp.tool(
      'account_sign_data',
      noLeadingWhitespace`
      Cryptographically sign a piece of data with a local account's private key, then encode the result with the specified encoding.
      Outputs the curve, encoded signature, and encoding used.`,
      {
        accountId: z
          .string()
          .describe(
            'The account id of the account that will sign the data. This account must be in the local keystore.',
          ),
        networkId: z.enum(['testnet', 'mainnet']).default('mainnet'),
        data: z.string().describe('The data to sign as a string.'),
        signatureEncoding: z
          .enum(['base58', 'base64'])
          .default('base58')
          .describe('The encoding to use for signature creation.'),
      },
      async (args, _) => {
        const keyPairResult: Result<KeyPair, Error> = await getAccountKeyPair(
          args.accountId,
          args.networkId,
          keystore,
        );
        if (!keyPairResult.ok) {
          return {
            content: [{ type: 'text', text: `Error: ${keyPairResult.error}` }],
          };
        }
        const keyPair = keyPairResult.value;
        const signatureRaw = keyPair.sign(new TextEncoder().encode(args.data));
        const signatureEncodingResult: Result<string, Error> = (() => {
          try {
            switch (args.signatureEncoding) {
              case 'base64':
                return {
                  ok: true,
                  value: Buffer.from(signatureRaw.signature).toString('base64'),
                };
              case 'base58':
                return {
                  ok: true,
                  value: base58.encode(Buffer.from(signatureRaw.signature)),
                };
              default:
                throw new Error(
                  `Unsupported encoding: ${String(args.signatureEncoding)}`,
                );
            }
          } catch (e) {
            return { ok: false, error: new Error(e as string) };
          }
        })();
        if (!signatureEncodingResult.ok) {
          return {
            content: [
              { type: 'text', text: `Error: ${signatureEncodingResult.error}` },
            ],
          };
        }
    
        return {
          content: [
            {
              type: 'text',
              text: stringify_bigint({
                signerAccountId: args.accountId,
                curve: keyTypeToCurvePrefix(keyPair.getPublicKey().keyType),
                signature: signatureEncodingResult.value,
                encoding: args.signatureEncoding,
              }),
            },
          ],
        };
      },
    );
  • Helper function getAccountKeyPair used by the handler to retrieve the key pair from the keystore by accountId and networkId.
    const getAccountKeyPair = async (
      accountId: string,
      networkId: string,
      keystore: UnencryptedFileSystemKeyStore,
    ): Promise<Result<KeyPair, Error>> => {
      try {
        const keyPair = await keystore.getKey(networkId, accountId);
        return { ok: true, value: keyPair };
      } catch (e) {
        return { ok: false, error: new Error(e as string) };
      }
    };
  • Helper function keyTypeToCurvePrefix used by the handler to convert the key type (ED25519/SECP256K1) to a human-readable curve name.
    export const keyTypeToCurvePrefix = (keyType: KeyType) => {
      switch (keyType) {
        case KeyType.ED25519:
          return 'ed25519';
        case KeyType.SECP256K1:
          return 'secp256k1';
      }
    };
Behavior2/5

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

With no annotations provided, the description bears full responsibility for disclosing behavioral traits. It mentions that the account must be local and that the output includes curve and encoding, but omits critical details like whether the operation is irreversible, what happens if the account is missing, or any security implications.

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?

The description is extremely concise, consisting of two short sentences that front-load the action and immediately follow with the output. Every sentence contributes meaningful information without redundancy or unnecessary detail.

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 the moderate complexity of a signing tool, the description covers the core operation and output. However, it lacks explicit mention of common failure modes (e.g., invalid account, unsupported curve) and does not reference the sibling verification tool for context. Still, it is mostly complete for its purpose.

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?

The schema already provides detailed descriptions for three out of four parameters (75% coverage). The description adds minimal extra meaning beyond restating the encoding process and output structure, so it meets the baseline but does not significantly enhance parameter understanding.

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?

The description clearly states the tool's primary action: cryptographically signing data with a local private key and encoding the result. It specifies the verb 'sign' and the resource 'data with a local account's private key', and implicitly distinguishes from the sibling 'account_verify_signature' tool by focusing on signing rather than verification.

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

Usage Guidelines2/5

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

The description does not provide explicit guidance on when to use this tool versus alternatives such as 'account_verify_signature'. It does not mention prerequisites, edge cases, or situations where this tool should not be used, leaving the agent without clear decision criteria.

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/nearai/near-mcp'

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