This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# Build the project (uses esbuild)
npm run build
# Run in development mode with ts-node (requires Node.js 18-22, fails on v24+)
npm run dev
# Start the built server
npm start
# Watch mode for TypeScript compilation
npm run watch
# Test with MCP Inspector UI (opens client on port 5173, server on port 3000)
npm run inspector
# Use custom ports if defaults are taken
CLIENT_PORT=5009 SERVER_PORT=3009 npm run inspector- Node.js 18-22: Required for
npm run dev(ts-node ESM loader) - Node.js 22+: Required for MCP Inspector CLI mode
- Build/Start: Works on all modern Node.js versions
Use nvm to switch versions: nvm use 22
ASANA_ACCESS_TOKEN- Required. Your Asana personal access tokenREAD_ONLY_MODE- Optional. Set to'true'to disable all write operations
This is an MCP (Model Context Protocol) server that exposes Asana functionality to AI assistants like Claude.
src/index.ts- Entry point. Creates the MCP Server instance, initializes the Asana client, and registers all handlers (tools, prompts, resources)src/asana-client-wrapper.ts- Wraps theasananpm package, providing typed methods for all Asana API operationssrc/tool-handler.ts- Defines thelist_of_toolsarray,READ_ONLY_TOOLSarray, and the maintool_handlerfunction that routes tool calls to the appropriate Asana client methodssrc/prompt-handler.ts- Defines MCP prompts (task-summary, task-completeness, create-task). Prompts are pre-built conversation starterssrc/resource-handler.ts- Exposes Asana workspaces and projects as MCP resources (readable viaasana://workspace/{gid}andasana://project/{gid}URIs)src/asana-validate-xml.ts- Validates HTML/XML content for Asana'shtml_notesandhtml_textfields
Individual tool definitions are in src/tools/:
workspace-tools.ts- List workspacesproject-tools.ts- Search projects, get project details/sections/task countsproject-status-tools.ts- CRUD for project status updatestask-tools.ts- Search/get/create/update tasks, create subtasks, get multiple taskstask-relationship-tools.ts- Dependencies, dependents, parent relationshipsstory-tools.ts- Get/create task commentstag-tools.ts- CRUD for tags, add/remove tags from tasks
Each tool file exports a Tool object with name, description, and inputSchema following the MCP SDK types.
When adding a new tool, ensure you complete ALL of these steps:
-
Define the tool in
src/tools/<category>-tools.ts:- Export a
Toolobject withname,description,inputSchema - Use
asana_prefix for the tool name
- Export a
-
Add API method in
src/asana-client-wrapper.ts:- Add the method that calls the Asana SDK
-
Register the tool in
src/tool-handler.ts:- Import the tool from the tools file
- Add to
all_toolsarray - If it's a READ-ONLY tool: Add tool name to
READ_ONLY_TOOLSarray - Add the
casehandler in the switch statement
-
Update documentation in
README.md:- Add tool to the numbered list with description and parameters
-
Test the tool:
- Build:
npm run build - Test using the helper script (see Testing section)
- Build:
When READ_ONLY_MODE=true:
- Only tools listed in
READ_ONLY_TOOLSarray are available - Write tool calls return an error
- The
create-taskprompt is filtered out
Important: When adding a new read-only tool, you MUST add its name to the READ_ONLY_TOOLS array in tool-handler.ts.
Source the helper script to get testing functions:
source scripts/test-mcp.sh
# List all available tools
mcp_list_tools
# Call a tool and get JSON result
mcp_call asana_list_workspaces '{}'
# Call a tool and parse the result
mcp_call_json asana_search_tasks '{"workspace":"YOUR_WORKSPACE_GID","completed":false}'
# Test a tool with expected result
mcp_test asana_list_workspaces '{}' 'length > 0'
# Run tag operations test suite
mcp_test_tags YOUR_WORKSPACE_GID
# Health check
mcp_health_checkMCP servers communicate via JSON-RPC 2.0 over stdio. You can test manually:
# Build first
npm run build
# Send JSON-RPC messages (requires jq)
echo '{"jsonrpc":"2.0","method":"initialize","id":0,"params":{"capabilities":{},"clientInfo":{"name":"test","version":"1.0"},"protocolVersion":"2024-11-05"}}' | node dist/index.js 2>/dev/nullThe Asana API uses dot notation for filter parameters (e.g., assignee.any, sections.all), but MCP tool schemas use underscore notation (e.g., assignee_any, sections_all) for JSON compatibility.
The searchTasks method in asana-client-wrapper.ts automatically maps underscore parameters to dot notation. If adding new search parameters, ensure they're included in the keyMappings object.
If search filters appear to be ignored:
- Check the parameter is in the
keyMappingsobject insearchTasks() - Verify the parameter name matches the Asana API documentation
- Test with an impossible filter value to confirm filtering is working
Uses esbuild (build.js) to bundle TypeScript into a single ESM file. The version is injected at build time from package.json via __VERSION__ define.