mcpbeat

Azure Storage File Share Ts

microsoft/azure-storage-file-share-ts

|

3k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
2857
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/microsoft/skills --skill azure-storage-file-share-ts

The instruction itself

49 sections, as written by the author

@azure/storage-file-share (TypeScript/JavaScript)

SDK for Azure File Share operations — SMB file shares, directories, and file operations.

Installation

npm install @azure/storage-file-share @azure/identity

Current Version: 12.x

Node.js: >= 18.0.0

Environment Variables

AZURE_STORAGE_ACCOUNT_NAME=<account-name>
AZURE_STORAGE_ACCOUNT_KEY=<account-key>
# OR connection string
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production

Authentication

Connection String (Simplest)

import { ShareServiceClient } from "@azure/storage-file-share";

const client = ShareServiceClient.fromConnectionString(
  process.env.AZURE_STORAGE_CONNECTION_STRING!
);

StorageSharedKeyCredential (Node.js only)

import { ShareServiceClient, StorageSharedKeyCredential } from "@azure/storage-file-share";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY!;

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
const client = new ShareServiceClient(
  `https://${accountName}.file.core.windows.net`,
  sharedKeyCredential
);

Microsoft Entra Token Credential

import { ShareServiceClient } from "@azure/storage-file-share";
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";

// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
const credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]});
// Or use a specific credential directly in production:
// See https://learn.microsoft.com/javascript/api/overview/azure/identity-readme?view=azure-node-latest#credential-classes
// const credential = new ManagedIdentityCredential();

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const client = new ShareServiceClient(
  `https://${accountName}.file.core.windows.net`,
  credential
);

SAS Token

import { ShareServiceClient } from "@azure/storage-file-share";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const sasToken = process.env.AZURE_STORAGE_SAS_TOKEN!;

const client = new ShareServiceClient(
  `https://${accountName}.file.core.windows.net${sasToken}`
);

Client Hierarchy

ShareServiceClient (account level)
└── ShareClient (share level)
    └── ShareDirectoryClient (directory level)
        └── ShareFileClient (file level)

Share Operations

Create Share

const shareClient = client.getShareClient("my-share");
await shareClient.create();

// Create with quota (in GB)
await shareClient.create({ quota: 100 });

List Shares

for await (const share of client.listShares()) {
  console.log(share.name, share.properties.quota);
}

// With prefix filter
for await (const share of client.listShares({ prefix: "logs-" })) {
  console.log(share.name);
}

Delete Share

await shareClient.delete();

// Delete if exists
await shareClient.deleteIfExists();

Get Share Properties

const properties = await shareClient.getProperties();
console.log("Quota:", properties.quota, "GB");
console.log("Last Modified:", properties.lastModified);

Set Share Quota

await shareClient.setQuota(200); // 200 GB

Directory Operations

Create Directory

const directoryClient = shareClient.getDirectoryClient("my-directory");
await directoryClient.create();

// Create nested directory
const nestedDir = shareClient.getDirectoryClient("parent/child/grandchild");
await nestedDir.create();

List Directories and Files

const directoryClient = shareClient.getDirectoryClient("my-directory");

for await (const item of directoryClient.listFilesAndDirectories()) {
  if (item.kind === "directory") {
    console.log(`[DIR] ${item.name}`);
  } else {
    console.log(`[FILE] ${item.name} (${item.properties.contentLength} bytes)`);
  }
}

Delete Directory

await directoryClient.delete();

// Delete if exists
await directoryClient.deleteIfExists();

Check if Directory Exists

const exists = await directoryClient.exists();
if (!exists) {
  await directoryClient.create();
}

File Operations

Upload File (Simple)

const fileClient = shareClient
  .getDirectoryClient("my-directory")
  .getFileClient("my-file.txt");

// Upload string
const content = "Hello, World!";
await fileClient.create(content.length);
await fileClient.uploadRange(content, 0, content.length);

Upload File (Node.js - from local file)

import * as fs from "fs";
import * as path from "path";

const fileClient = shareClient.rootDirectoryClient.getFileClient("uploaded.txt");
const localFilePath = "/path/to/local/file.txt";
const fileSize = fs.statSync(localFilePath).size;

await fileClient.create(fileSize);
await fileClient.uploadFile(localFilePath);

Upload File (Buffer)

const buffer = Buffer.from("Hello, Azure Files!");
const fileClient = shareClient.rootDirectoryClient.getFileClient("buffer-file.txt");

await fileClient.create(buffer.length);
await fileClient.uploadRange(buffer, 0, buffer.length);

Upload File (Stream)

import * as fs from "fs";

const fileClient = shareClient.rootDirectoryClient.getFileClient("streamed.txt");
const readStream = fs.createReadStream("/path/to/local/file.txt");
const fileSize = fs.statSync("/path/to/local/file.txt").size;

await fileClient.create(fileSize);
await fileClient.uploadStream(readStream, fileSize, 4 * 1024 * 1024, 4); // 4MB buffer, 4 concurrency

Download File

const fileClient = shareClient
  .getDirectoryClient("my-directory")
  .getFileClient("my-file.txt");

const downloadResponse = await fileClient.download();

// Read as string
const chunks: Buffer[] = [];
for await (const chunk of downloadResponse.readableStreamBody!) {
  chunks.push(Buffer.from(chunk));
}
const content = Buffer.concat(chunks).toString("utf-8");

Download to File (Node.js)

const fileClient = shareClient.rootDirectoryClient.getFileClient("my-file.txt");
await fileClient.downloadToFile("/path/to/local/destination.txt");

Download to Buffer (Node.js)

const fileClient = shareClient.rootDirectoryClient.getFileClient("my-file.txt");
const buffer = await fileClient.downloadToBuffer();
console.log(buffer.toString());

Delete File

const fileClient = shareClient.rootDirectoryClient.getFileClient("my-file.txt");
await fileClient.delete();

// Delete if exists
await fileClient.deleteIfExists();

Copy File

const sourceUrl = "https://account.file.core.windows.net/share/source.txt";
const destFileClient = shareClient.rootDirectoryClient.getFileClient("destination.txt");

// Start copy operation
const copyPoller = await destFileClient.startCopyFromURL(sourceUrl);
await copyPoller.pollUntilDone();

File Properties & Metadata

Get File Properties

const fileClient = shareClient.rootDirectoryClient.getFileClient("my-file.txt");
const properties = await fileClient.getProperties();

console.log("Content-Length:", properties.contentLength);
console.log("Content-Type:", properties.contentType);
console.log("Last Modified:", properties.lastModified);
console.log("ETag:", properties.etag);

Set Metadata

await fileClient.setMetadata({
  author: "John Doe",
  category: "documents",
});

Set HTTP Headers

await fileClient.setHttpHeaders({
  fileContentType: "text/plain",
  fileCacheControl: "max-age=3600",
  fileContentDisposition: "attachment; filename=download.txt",
});

Range Operations

Upload Range

const data = Buffer.from("partial content");
await fileClient.uploadRange(data, 100, data.length); // Write at offset 100

Download Range

const downloadResponse = await fileClient.download(100, 50); // offset 100, length 50

Clear Range

await fileClient.clearRange(0, 100); // Clear first 100 bytes

Snapshot Operations

Create Snapshot

const snapshotResponse = await shareClient.createSnapshot();
console.log("Snapshot:", snapshotResponse.snapshot);

Access Snapshot

const snapshotShareClient = shareClient.withSnapshot(snapshotResponse.snapshot!);
const snapshotFileClient = snapshotShareClient.rootDirectoryClient.getFileClient("file.txt");
const content = await snapshotFileClient.downloadToBuffer();

Delete Snapshot

await shareClient.delete({ deleteSnapshots: "include" });

SAS Token Generation (Node.js only)

Generate File SAS

import {
  generateFileSASQueryParameters,
  FileSASPermissions,
  StorageSharedKeyCredential,
} from "@azure/storage-file-share";

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);

const sasToken = generateFileSASQueryParameters(
  {
    shareName: "my-share",
    filePath: "my-directory/my-file.txt",
    permissions: FileSASPermissions.parse("r"), // read only
    expiresOn: new Date(Date.now() + 3600 * 1000), // 1 hour
  },
  sharedKeyCredential
).toString();

const sasUrl = `https://${accountName}.file.core.windows.net/my-share/my-directory/my-file.txt?${sasToken}`;

Generate Share SAS

import { ShareSASPermissions, generateFileSASQueryParameters } from "@azure/storage-file-share";

const sasToken = generateFileSASQueryParameters(
  {
    shareName: "my-share",
    permissions: ShareSASPermissions.parse("rcwdl"), // read, create, write, delete, list
    expiresOn: new Date(Date.now() + 24 * 3600 * 1000), // 24 hours
  },
  sharedKeyCredential
).toString();

Error Handling

import { RestError } from "@azure/storage-file-share";

try {
  await shareClient.create();
} catch (error) {
  if (error instanceof RestError) {
    switch (error.statusCode) {
      case 404:
        console.log("Share not found");
        break;
      case 409:
        console.log("Share already exists");
        break;
      case 403:
        console.log("Access denied");
        break;
      default:
        console.error(`Storage error ${error.statusCode}: ${error.message}`);
    }
  }
  throw error;
}

TypeScript Types Reference

import {
  // Clients
  ShareServiceClient,
  ShareClient,
  ShareDirectoryClient,
  ShareFileClient,

  // Authentication
  StorageSharedKeyCredential,
  AnonymousCredential,

  // SAS
  FileSASPermissions,
  ShareSASPermissions,
  AccountSASPermissions,
  AccountSASServices,
  AccountSASResourceTypes,
  generateFileSASQueryParameters,
  generateAccountSASQueryParameters,

  // Options & Responses
  ShareCreateResponse,
  FileDownloadResponseModel,
  DirectoryItem,
  FileItem,
  ShareProperties,
  FileProperties,

  // Errors
  RestError,
} from "@azure/storage-file-share";

Best Practices

  • Use connection strings for simplicity — Easiest setup for development
  • Use DefaultAzureCredential for local development; use ManagedIdentityCredential or WorkloadIdentityCredential for production
  • Set quotas on shares — Prevent unexpected storage costs
  • Use streaming for large filesuploadStream/downloadToFile for files > 256MB
  • Use ranges for partial updates — More efficient than full file replacement
  • Create snapshots before major changes — Point-in-time recovery
  • Handle errors gracefully — Check RestError.statusCode for specific handling
  • Use *IfExists methods — For idempotent operations

Platform Differences

| Feature | Node.js | Browser |

|---------|---------|---------|

| StorageSharedKeyCredential | ✅ | ❌ |

| uploadFile() | ✅ | ❌ |

| uploadStream() | ✅ | ❌ |

| downloadToFile() | ✅ | ❌ |

| downloadToBuffer() | ✅ | ❌ |

| SAS generation | ✅ | ❌ |

| DefaultAzureCredential | ✅ | ❌ |

| Anonymous/SAS access | ✅ | ✅ |

How to use it

Copy the folder

Take microsoft/azure-storage-file-share-ts from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npm. Without those the skill loads but fails at the first command.