Skip to main content
kodexa-api exposes its workflow surface — activities, tasks, and task-groups, plus assignment, status, and membership actions — as a Model Context Protocol (MCP) connector. You add the endpoint to claude.ai as a remote OAuth connector, and Claude can then query and manage your workflow in natural language, acting as you.
The connector is served by the Kodexa platform itself over HTTP — there is nothing to install on your machine. Every call is authenticated and every result is scoped to what the calling user is permitted to see, exactly like the REST API.

What The Connector Exposes

The MCP server registers as kodexa-workflow and presents 19 tools:
  • Discovery — resolve who you are and the organizations, projects, teams, and members you can act on.
  • Workflow queries — list and read activities, tasks, task-groups, and task statuses (read-only).
  • Workflow actions — assign and unassign tasks and task-groups, move tasks between statuses, and add or remove tasks from a group.
Reads reuse the platform’s registry handlers; writes replay through the existing REST handlers. As a result access control (FGAC), optimistic locking, task-group cascades, audit, and domain events are identical to the REST surface — no logic is duplicated.
Workflow-model caveats the tools enforce:
  • Activities are read-only over MCP. You can list and inspect them, but not mutate them.
  • A grouped task’s assignee is managed via its group. assign_task / unassign_task targeting the user (assignee) fail on a task that belongs to a task-group — assign the group with assign_task_group instead, and the assignment cascades to every member task. (A team-only assignment through assign_task is not blocked for grouped tasks, since a group owns the assignee, not the team.)
  • Access is FGAC-scoped to the calling user. Claude sees and changes only what you could see and change yourself.

Enabling The Connector

The connector is off by default. A platform administrator enables it in the platform configuration:
SettingPurpose
mcp.enabledTurns the connector on. When false, the /mcp route is not mounted.
mcp.publicUrlThe canonical, publicly reachable URL of the MCP endpoint. This value must equal the Auth0 API identifier (audience) for the OAuth flow, and it anchors the protected-resource metadata document.
For the claude.ai OAuth flow, api.security.auth0.domain must also be set. On startup the platform builds an Auth0 token validator bound to mcp.publicUrl as the audience.
If mcp.enabled is set but mcp.publicUrl is empty, the connector is disabled. If the Auth0 domain is not configured (or the validator fails to initialize), the connector still works with the X-API-Key fallback but does not advertise the claude.ai OAuth flow.
The connector is mounted at <basePath>/mcp over the Streamable HTTP transport (stateless — each request is a self-contained, independently authenticated JSON-RPC message).

Adding It To claude.ai

Add the MCP endpoint (https://<your-mcp-publicUrl>/mcp) as a remote connector in claude.ai. The OAuth handshake is automatic:
  1. claude.ai calls the endpoint with no token and receives an RFC 9728 401 with a WWW-Authenticate: Bearer resource_metadata="…" header.
  2. It fetches /.well-known/oauth-protected-resource from the endpoint’s origin, which points at your Auth0 authorization server.
  3. It performs Dynamic Client Registration (DCR) and an OAuth authorization-code + PKCE flow against Auth0, obtaining an access token whose audience matches mcp.publicUrl.
  4. Every subsequent MCP call carries that bearer token, which the platform validates against Auth0’s JWKS (signature, issuer, expiry, audience) before landing an authenticated user in context.
The protected-resource metadata advertises the openid, profile, email, and offline_access scopes.

Programmatic And Local Clients

Clients that cannot run the OAuth flow can authenticate with an API key by sending it in the X-API-Key header instead of a bearer token. This is the fallback path used for local development and programmatic access.

Tool Reference

All list tools share a common set of optional parameters: filter (an advanced SpringFilter expression, ANDed with the other filters), query (free-text search), sort (e.g. created_on:desc), page (1-indexed, default 1), and pageSize (default 20, max 1000).

Discovery

ToolPurposeKey arguments
whoamiReturn the authenticated user’s identity (id, email, roles, groups, job title). Call this first.
list_organizationsOrganizations you can access.list params
list_projectsProjects, optionally scoped to an organization.organizationId
list_teamsTeams in an organization (assignment targets).organizationId
list_organization_membersMembers of an organization (assignment targets).organizationId (required)

Workflow Queries (read-only)

ToolPurposeKey arguments
list_activitiesActivities (runtime instances of activity plans).projectId, lifecycleState (PENDING, RUNNING, COMPLETED, FAILED, CANCELLED, REPLANNED)
get_activityA single activity, including its materialized steps.id (required)
list_tasksTasks, with rich filtering.projectId, assigneeId, unassigned, statusType (OPEN, IN_PROGRESS, DONE, BLOCKED, PENDING), taskGroupId
get_taskA single task.id (required)
list_task_groupsTask-groups (batch tasks for shared assignment and lifecycle).projectId, teamId, assigneeId, statusType
get_task_groupA single task-group.id (required)
list_task_statusesTask statuses for an organization (optionally bound to a project). Use a status slug with update_task_status.organizationId, projectId

Workflow Actions (write)

ToolPurposeKey arguments
assign_taskAssign a task to a user and/or team. A user assignment fails if the task belongs to a task-group (assign the group instead) or the task is locked; a team-only assignment is allowed on grouped tasks.taskId (required), userId, teamId, changeSequence
unassign_taskClear a task’s user and/or team assignment. Clearing the user fails if the task belongs to a task-group.taskId (required), target (user, team, or both; default user)
assign_task_groupAssign a task-group to a user; cascades to every member task. Fails if any member is locked.taskGroupId (required), userId (required), changeSequence
unassign_task_groupClear a task-group’s user assignment, cascading the clear to all members.taskGroupId (required)
update_task_statusMove a task to a status by slug. Applies the status’s lock behavior and any group auto-complete/reopen.taskId (required), status (slug, required), changeSequence, lockTask, lockDocumentFamily
add_tasks_to_groupAdd tasks to a group; the group’s assignee (if set) cascades to the new members.taskGroupId (required), taskIds (required)
remove_task_from_groupRemove a single task from a group, ungrouping it.taskGroupId (required), taskId (required)

Optimistic Concurrency

Tasks carry a changeSequence. The write tools that accept a changeSequence argument (assign_task, assign_task_group, update_task_status) use it for optimistic-concurrency safety: pass the sequence you last read, and the write fails cleanly if the task changed underneath you. It is optional — omit it to skip the check.

A Typical Session

A natural place to start is discovery, then narrow to the work you care about, then act:
Who am I, and which projects can I see?
Show me the unassigned tasks in the Invoices project that are still OPEN.
Assign the "Review BoL #1428" task to me.
Claude calls whoami and list_projects, then list_tasks with projectId, unassigned: true, and statusType: OPEN, then resolves your user id via list_organization_members and calls assign_task. Because everything runs through the platform’s normal access-control path, it can only ever do what you are permitted to do.