MCP Server

The @air/mcp package connects MCP-compatible AI clients to an Air workspace. It exposes tools for finding and previewing assets, organizing boards, applying tags and custom fields, importing files from URLs, and uploading local files.

The server supports:

  • STDIO for clients that launch the package as a local child process. This is the recommended setup for desktop and coding clients.
  • Streamable HTTP for local HTTP-capable clients and development.

Prerequisites

  • Node.js 18 or newer
  • An Air API key and workspace ID. See Getting Started for credential setup.

Configuration

The server reads these environment variables:

VariableRequiredDescription
AIR_API_KEYYesAPI key used to authenticate with Air
AIR_WORKSPACE_IDYesWorkspace that all MCP tools operate on
AIR_API_URLNoAPI base URL override for non-production environments

Credentials stay in the MCP server process. Do not place them in prompts or tool arguments.

Command-line options

OptionDescription
--httpUse Streamable HTTP instead of STDIO
--port <number>Set the initial HTTP port. The default is 3000; if occupied, the server tries up to 10 subsequent ports.
--debugIn HTTP mode, log parsed MCP requests and responses to stderr

HTTP mode binds to 127.0.0.1 and serves MCP requests at /mcp.

Set up a client

Claude Desktop

Add the server to your Claude Desktop config. On macOS, the file is ~/Library/Application Support/Claude/claude_desktop_config.json.

{
  "mcpServers": {
    "air": {
      "command": "npx",
      "args": ["-y", "@air/mcp"],
      "env": {
        "AIR_API_KEY": "your-api-key",
        "AIR_WORKSPACE_ID": "your-workspace-id"
      }
    }
  }
}

If Claude Desktop does not load the Node.js version from your shell profile, set command to the full path of a Node 18+ npx executable. See the Claude Desktop MCP guide.

Claude Code

claude mcp add \
  --env AIR_API_KEY=your-api-key \
  --env AIR_WORKSPACE_ID=your-workspace-id \
  --transport stdio \
  air \
  -- npx -y @air/mcp

See the Claude Code MCP documentation.

Codex

Add the server to ~/.codex/config.toml:

[mcp_servers.air]
command = "npx"
args = ["-y", "@air/mcp"]

[mcp_servers.air.env]
AIR_API_KEY = "your-api-key"
AIR_WORKSPACE_ID = "your-workspace-id"

Or use the CLI:

codex mcp add air \
  --env AIR_API_KEY=your-api-key \
  --env AIR_WORKSPACE_ID=your-workspace-id \
  -- npx -y @air/mcp

See the Codex MCP documentation.

Cursor

Add the server to .cursor/mcp.json in a project or ~/.cursor/mcp.json globally:

{
  "mcpServers": {
    "air": {
      "command": "npx",
      "args": ["-y", "@air/mcp"],
      "env": {
        "AIR_API_KEY": "your-api-key",
        "AIR_WORKSPACE_ID": "your-workspace-id"
      }
    }
  }
}

See the Cursor MCP documentation.

Windsurf

Add the server to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "air": {
      "command": "npx",
      "args": ["-y", "@air/mcp"],
      "env": {
        "AIR_API_KEY": "your-api-key",
        "AIR_WORKSPACE_ID": "your-workspace-id"
      }
    }
  }
}

See the Windsurf MCP documentation.

VS Code with GitHub Copilot

Add the server to .vscode/mcp.json, or open the user-level file with MCP: Open User Configuration:

{
  "servers": {
    "air": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@air/mcp"],
      "env": {
        "AIR_API_KEY": "your-api-key",
        "AIR_WORKSPACE_ID": "your-workspace-id"
      }
    }
  }
}

Use Copilot in Agent mode to call MCP tools. See the VS Code MCP documentation.

Zed

Add the server to ~/.config/zed/settings.json:

{
  "context_servers": {
    "air": {
      "command": "npx",
      "args": ["-y", "@air/mcp"],
      "env": {
        "AIR_API_KEY": "your-api-key",
        "AIR_WORKSPACE_ID": "your-workspace-id"
      }
    }
  }
}

See the Zed context server documentation.

Run with Streamable HTTP

Start a local HTTP server with credentials in the process environment:

AIR_API_KEY=your-api-key \
AIR_WORKSPACE_ID=your-workspace-id \
npx -y @air/mcp --http

Connect a local HTTP-capable MCP client to:

http://localhost:3000/mcp

For example, add --port 4000 to choose another initial port or --debug to inspect MCP traffic.

Do not expose this endpoint directly to the internet. It binds to loopback and does not authenticate incoming MCP connections. Remote products such as ChatGPT custom apps require a remotely reachable MCP server; use a secure, authenticated deployment or proxy if adapting this package for remote access. See OpenAI's MCP documentation.

Tool reference

The server registers 23 tools in six categories. A parameter followed by ? is optional.

List tools return a JSON object with data, pagination, and total. To request another page, pass the returned pagination cursor into the next call.

Assets

ToolInputsDescription
list_assetsparentBoardId?, includeNestedAssets?, tag?, customField?, search?, limit?, cursor?, includeThumbnails?List assets with board, tag, custom-field, and search filters. tag and customField accept one string or an array. includeThumbnails adds inline images for up to the first 10 results.
list_nested_assetsboardId, limit?, cursor?, includeThumbnails?List assets in a board and all nested sub-boards. Can include up to 10 inline thumbnails.
get_assetassetIdGet asset details, cover version, metadata, custom fields, and a canonical Air web app url.
get_asset_download_urlassetId, versionId?Get a temporary download URL. If versionId is omitted, the cover version is used.
get_asset_boardsassetId, limit?, cursor?List every board that contains an asset.
get_asset_imageassetId, size?Return an inline base64 image content block. size is thumbnail (default) or preview.
rename_assetassetId, title, versionId?Update only the display title. Defaults to the cover version and does not change the underlying file name.
update_assetassetId, title?, description?, versionId?Update the display title and/or description. Defaults to the cover version.
add_tag_to_assetassetId, tagId, versionId?Add a tag to an asset version. Defaults to the cover version.
remove_tag_from_assetassetId, tagId, versionId?Remove a tag from an asset version. Defaults to the cover version.
update_asset_custom_fieldassetId, customFieldId, value?, values?Set or clear a custom field value. Field-specific rules are described below.

Boards

ToolInputsDescription
list_boardsname?, parentBoardId?, limit?, cursor?List boards, optionally filtered by name or parent.
get_boardboardIdGet board details and a canonical Air web app url.
create_boardtitle, description?, parentBoardId?Create a root board or a board nested under another board. Returns a canonical url.
update_boardboardId, title?, description?, parentBoardId?Update a board. Pass parentBoardId: null to move it to the workspace root.
add_asset_to_boardboardId, assetIdsAdd one or more asset IDs to a board.

Tags

ToolInputsDescription
list_tagsname?, limit?, cursor?List tags, optionally filtered by name.
create_tagnameCreate a tag in the workspace.

Custom fields

ToolInputsDescription
list_custom_fieldslimit?, cursor?List custom fields defined in the workspace.
get_custom_fieldcustomFieldIdGet a field's type and its possible select options.

Imports

ToolInputsDescription
create_importsourceUrl, fileName?, ext?, recordedAt?, parentBoardId?, assetId?, description?, title?, customFields?, tags?Import an asset from a URL. Optionally place it in a board, add it as a new version, and set metadata. Returns an import task ID, asset ID, version ID, and canonical url.
get_import_statusimportIdPoll an import task. Status is pending, inProgress, succeeded, or failed; failures include an error object.

Uploads

ToolInputsDescription
upload_assetfilePath, parentBoardId?, assetId?, customFields?, tags?Upload a local file. The SDK detects its type and upload strategy. Optionally place it in a board or add it as a new asset version. Returns the asset ID, version ID, and canonical url.

filePath must be an absolute path that the MCP server process can read. For STDIO, this is normally the same machine as the client. For HTTP, the path refers to the server machine, not the machine running the remote client.

Tool behavior

Canonical Air URLs

get_asset, get_board, create_board, create_import, and upload_asset return a canonical url when applicable. Agents should use this field instead of constructing Air URLs from asset, version, or board IDs.

Asset images and thumbnails

get_asset_image returns an MCP image content block that supported clients can render directly. list_assets and list_nested_assets can include image content blocks by setting includeThumbnails: true.

For list calls, thumbnail fetching is limited to the first 10 returned assets. Images are fetched only from trusted Air or Imgix HTTPS hosts.

Custom-field values

update_asset_custom_field fetches the custom-field definition and validates values before updating the asset:

  • For plain-text and date fields, pass value. Pass null to clear it.
  • For single-select and multi-select fields, pass values as an array of { "id": "option-uuid" } objects. Pass null to clear the selection.
  • A select field also accepts one option ID through value; the server validates the ID and converts it to values.
  • Do not pass both value and values.
  • Select option IDs are validated against the field's available options.

The customFields parameter accepted by create_import and upload_asset uses an array of objects with this shape:

[
  {
    "id": "text-or-date-field-id",
    "value": "text-or-date-value"
  },
  {
    "id": "select-field-id",
    "values": [{ "id": "select-option-id" }]
  }
]

Use the member appropriate for the field type. The tags parameter for imports and uploads is an array of { "id": "tag-id" } objects.

Imports and uploads

URL imports are asynchronous. After create_import, call get_import_status with the returned import task ID until the status is succeeded or failed.

Pass assetId to create_import or upload_asset to add the new file as a version of an existing asset. Pass parentBoardId to place a newly created asset in a board.

For create_import, fileName excludes the extension, ext excludes the leading dot, and recordedAt is an ISO 8601 date string.

Errors

Air API failures are returned as MCP tool errors containing the HTTP status and API error message. Invalid custom-field input is returned as a tool error with guidance about the expected value shape or valid select options.