system_import_account
Import a NEAR account into the local keystore using a private key or a JSON file. Allows subsequent tools to use the account for transactions.
Instructions
Import an account into the local keystore. This will allow the user to use this account with other tools. Remember mainnet accounts are created with a .near suffix, and testnet accounts are created with a .testnet suffix.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| args | Yes |
Implementation Reference
- src/services.ts:486-681 (registration)The tool 'system_import_account' is registered via mcp.tool() with its name, description, schema, and handler.
mcp.tool( 'system_import_account', noLeadingWhitespace` Import an account into the local keystore. This will allow the user to use this account with other tools. Remember mainnet accounts are created with a .near suffix, and testnet accounts are created with a .testnet suffix.`, { args: z.union([ z.object({ op: z.literal('import_from_private_key'), accountId: z.string(), networkId: z.enum(['testnet', 'mainnet']).default('mainnet'), privateKey: z .string() .describe( 'The private key for the account. If provided, this will be used to import the account.', ), }), z.object({ op: z.literal('import_from_file'), filePath: z.string().describe( noLeadingWhitespace` The path to the file containing the account id, public key, and private key. The file should be in JSON format and the filename should be something like \`<accountId>.<networkId>.json\`.`, ), }), ]), }, async (args, _) => { switch (args.args.op) { case 'import_from_private_key': const connection = await connect({ networkId: args.args.networkId, nodeUrl: getEndpointsByNetwork(args.args.networkId)[0]!, }); const serializedPrivateKeyResult: Result<KeyPair, Error> = (() => { if (args.args.privateKey) { try { return { ok: true, value: KeyPair.fromString( args.args.privateKey as KeyPairString, ), }; } catch (e) { return { ok: false, error: new Error(e as string) }; } } return { ok: false, error: new Error('No private key provided') }; })(); if (!serializedPrivateKeyResult.ok) { return { content: [ { type: 'text', text: `Failed to import private key. Error: ${serializedPrivateKeyResult.error}`, }, ], }; } const accountResult: Result<Account, Error> = await getAccount( args.args.accountId, connection, ); if (!accountResult.ok) { return { content: [ { type: 'text', text: `Error: ${accountResult.error}` }, ], }; } // at this point we know the account exists, so we can import the private key // ensure that the private key being imported matches a full access key const accessKeys = await accountResult.value.getAccessKeys(); if ( !accessKeys.some( (key) => key.public_key === serializedPrivateKeyResult.value.getPublicKey().toString(), ) ) { return { content: [ { type: 'text', text: `Error: Account ${args.args.accountId} does not have matching access key for private key being imported.`, }, ], }; } // we found a matching access key, so we can import the account await keystore.setKey( args.args.networkId, args.args.accountId, serializedPrivateKeyResult.value, ); return { content: [ { type: 'text', text: `Account imported: ${args.args.accountId}`, }, ], }; case 'import_from_file': const filePath = args.args.filePath; const readKeyFileResult: Result<[string, KeyPair], Error> = await (async () => { try { return { ok: true, value: await readKeyFile(filePath) }; } catch (e) { return { ok: false, error: new Error(e as string) }; } })(); if (!readKeyFileResult.ok) { return { content: [ { type: 'text', text: `Error: ${readKeyFileResult.error}`, }, ], }; } const [accountId, keypair] = readKeyFileResult.value; const networkIdResult: Result<string, Error> = getNetworkFromAccountId(accountId); if (!networkIdResult.ok) { return { content: [ { type: 'text', text: `Error: ${networkIdResult.error}`, }, ], }; } const networkId = networkIdResult.value; const fromFileConnection = await connect({ networkId, nodeUrl: getEndpointsByNetwork(networkId)[0]!, }); const fromFileAccountResult: Result<Account, Error> = await getAccount(accountId, fromFileConnection); if (!fromFileAccountResult.ok) { return { content: [ { type: 'text', text: `Error: ${fromFileAccountResult.error}`, }, ], }; } const fromFileAccessKeys = await fromFileAccountResult.value.getAccessKeys(); if ( !fromFileAccessKeys.some( (key) => key.public_key === keypair.getPublicKey().toString(), ) ) { return { content: [ { type: 'text', text: `Error: Account ${accountId} does not have matching access key for private key being imported.`, }, ], }; } await keystore.setKey(networkId, accountId, keypair); return { content: [ { type: 'text', text: `Account imported: ${accountId}`, }, ], }; default: return { content: [{ type: 'text', text: 'Invalid operation' }], }; } }, ); - src/services.ts:493-515 (schema)Input schema for system_import_account: a discriminated union between 'import_from_private_key' (accountId, networkId, privateKey) and 'import_from_file' (filePath).
{ args: z.union([ z.object({ op: z.literal('import_from_private_key'), accountId: z.string(), networkId: z.enum(['testnet', 'mainnet']).default('mainnet'), privateKey: z .string() .describe( 'The private key for the account. If provided, this will be used to import the account.', ), }), z.object({ op: z.literal('import_from_file'), filePath: z.string().describe( noLeadingWhitespace` The path to the file containing the account id, public key, and private key. The file should be in JSON format and the filename should be something like \`<accountId>.<networkId>.json\`.`, ), }), ]), }, - src/services.ts:516-681 (handler)Handler function for system_import_account. Supports two modes: import_from_private_key (parses the private key, verifies it matches a full access key on-chain, then stores it in keystore) and import_from_file (reads a key file, validates the account exists and the key matches, then stores it).
async (args, _) => { switch (args.args.op) { case 'import_from_private_key': const connection = await connect({ networkId: args.args.networkId, nodeUrl: getEndpointsByNetwork(args.args.networkId)[0]!, }); const serializedPrivateKeyResult: Result<KeyPair, Error> = (() => { if (args.args.privateKey) { try { return { ok: true, value: KeyPair.fromString( args.args.privateKey as KeyPairString, ), }; } catch (e) { return { ok: false, error: new Error(e as string) }; } } return { ok: false, error: new Error('No private key provided') }; })(); if (!serializedPrivateKeyResult.ok) { return { content: [ { type: 'text', text: `Failed to import private key. Error: ${serializedPrivateKeyResult.error}`, }, ], }; } const accountResult: Result<Account, Error> = await getAccount( args.args.accountId, connection, ); if (!accountResult.ok) { return { content: [ { type: 'text', text: `Error: ${accountResult.error}` }, ], }; } // at this point we know the account exists, so we can import the private key // ensure that the private key being imported matches a full access key const accessKeys = await accountResult.value.getAccessKeys(); if ( !accessKeys.some( (key) => key.public_key === serializedPrivateKeyResult.value.getPublicKey().toString(), ) ) { return { content: [ { type: 'text', text: `Error: Account ${args.args.accountId} does not have matching access key for private key being imported.`, }, ], }; } // we found a matching access key, so we can import the account await keystore.setKey( args.args.networkId, args.args.accountId, serializedPrivateKeyResult.value, ); return { content: [ { type: 'text', text: `Account imported: ${args.args.accountId}`, }, ], }; case 'import_from_file': const filePath = args.args.filePath; const readKeyFileResult: Result<[string, KeyPair], Error> = await (async () => { try { return { ok: true, value: await readKeyFile(filePath) }; } catch (e) { return { ok: false, error: new Error(e as string) }; } })(); if (!readKeyFileResult.ok) { return { content: [ { type: 'text', text: `Error: ${readKeyFileResult.error}`, }, ], }; } const [accountId, keypair] = readKeyFileResult.value; const networkIdResult: Result<string, Error> = getNetworkFromAccountId(accountId); if (!networkIdResult.ok) { return { content: [ { type: 'text', text: `Error: ${networkIdResult.error}`, }, ], }; } const networkId = networkIdResult.value; const fromFileConnection = await connect({ networkId, nodeUrl: getEndpointsByNetwork(networkId)[0]!, }); const fromFileAccountResult: Result<Account, Error> = await getAccount(accountId, fromFileConnection); if (!fromFileAccountResult.ok) { return { content: [ { type: 'text', text: `Error: ${fromFileAccountResult.error}`, }, ], }; } const fromFileAccessKeys = await fromFileAccountResult.value.getAccessKeys(); if ( !fromFileAccessKeys.some( (key) => key.public_key === keypair.getPublicKey().toString(), ) ) { return { content: [ { type: 'text', text: `Error: Account ${accountId} does not have matching access key for private key being imported.`, }, ], }; } await keystore.setKey(networkId, accountId, keypair); return { content: [ { type: 'text', text: `Account imported: ${accountId}`, }, ], }; default: return { content: [{ type: 'text', text: 'Invalid operation' }], }; } }, );