npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@codegame.dev/careerflow-mcp

v1.9.0

Published

MCP server exposing CareerFlow tasks, CRM, HR, and workplace tools to AI assistants

Readme

CareerFlow MCP Server

Connect an AI assistant to CareerFlow so it can read and manage your tasks, track your time, message colleagues, work CRM deals, handle HR requests, and more — on your behalf.

Works with any MCP-capable client — Claude Code, Claude Desktop, and others.

The server holds no privileges of its own. It calls the same REST API the web app uses, authenticated as you, so your existing role still decides what it can do — and the token's permissions narrow that further.


Quick start

The one-command way

npx @codegame.dev/careerflow-mcp init

The setup wizard asks for your CareerFlow host and access token, detects which MCP clients you have installed, and writes the configuration into Claude Code, Claude Desktop, ZCode (Z.ai), or Cursor for you — or prints a ready-to-paste JSON block for any other client. Token input is hidden as you type; it is never passed on the command line.

Flags prefill the answers, so an onboarding page can print a one-liner per company or client — only the token is still asked for (hidden):

npx @codegame.dev/careerflow-mcp init --base-url https://careerflow.codegame.dev/site-api --name acme --client claude-code
npx @codegame.dev/careerflow-mcp init --base-url https://careerflow.codegame.dev/site-api --name acme --company-id 24 --client zcode
  • --base-url — the CareerFlow host, so it is never typed by hand
  • --name — the server's name in the client config (default careerflow); use one name per company or install, e.g. acme, acme-staging
  • --company-id — optional default company
  • --client — claude-code, claude-desktop, zcode, cursor, or other

None of these flags is secret, so the one-liner is safe to publish. The access token is never accepted as a flag — argv is readable by other processes on the machine — so the wizard always prompts for it with hidden input.

Removing it again

init is reversible. The remove command deletes the server entry it created (no token needed, so it works in scripts too):

npx @codegame.dev/careerflow-mcp remove --client claude-code --name acme
npx @codegame.dev/careerflow-mcp remove --client zcode --name acme

Without flags it asks which client to clean up. For Claude Code it runs claude mcp remove --scope user; for Claude Desktop, ZCode, and Cursor it deletes the entry from the client's JSON config, leaving everything else in the file untouched. Other clients: delete the pasted block by hand.

The manual way

  1. Create an access token.

    In CareerFlow: Settings → Access Tokens → Create access token.

    Give it a name, an expiry, and only the permissions the assistant needs.

    The token is shown once. It is stored hashed and cannot be recovered afterwards. Copy it before closing the dialog.

  2. Add it to your client.

Claude Code

claude mcp add careerflow \
  --env CAREERFLOW_BASE_URL=https://careerflow.codegame.dev/site-api \
  --env CAREERFLOW_TOKEN=cf_pat_xxxxxxxx \
  --env CAREERFLOW_COMPANY_ID=24 \
  -- npx -y @codegame.dev/careerflow-mcp

Claude Desktop — add to claude_desktop_config.json:

{
  "mcpServers": {
    "careerflow": {
      "command": "npx",
      "args": ["-y", "@codegame.dev/careerflow-mcp"],
      "env": {
        "CAREERFLOW_BASE_URL": "https://careerflow.codegame.dev/site-api",
        "CAREERFLOW_TOKEN": "cf_pat_xxxxxxxx",
        "CAREERFLOW_COMPANY_ID": "24"
      }
    }
  }
}

Config file locations:

  • macOS — ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows — %APPDATA%\Claude\claude_desktop_config.json
  • Linux — ~/.config/Claude/claude_desktop_config.json

ZCode (Z.ai) — add to ~/.zcode/cli/config.json (note the nested mcp.servers, different from most clients' mcpServers):

{
  "mcp": {
    "servers": {
      "careerflow": {
        "type": "stdio",
        "command": "npx",
        "args": ["-y", "@codegame.dev/careerflow-mcp"],
        "env": {
          "CAREERFLOW_BASE_URL": "https://careerflow.codegame.dev/site-api",
          "CAREERFLOW_TOKEN": "cf_pat_xxxxxxxx",
          "CAREERFLOW_COMPANY_ID": "24"
        }
      }
    }
  }
}

For a project-shared server use <repo>/.zcode/config.json instead — but the token would then sit in a versioned file; prefer user scope.

Restart the client. Ask it "what are my tasks?" to confirm the connection.

Configuration

| Variable | Required | Description | | --- | --- | --- | | CAREERFLOW_BASE_URL | yes | API root, e.g. https://api.example.com | | CAREERFLOW_TOKEN | yes | Your personal access token (cf_pat_…) | | CAREERFLOW_COMPANY_ID | no | Default company, so tools need no company_id per call | | CAREERFLOW_TIMEOUT_MS | no | Request timeout, default 30000 | | CAREERFLOW_GROUPS | no | Register only these comma-separated tool groups | | CAREERFLOW_EXCLUDE_GROUPS | no | Register everything except these comma-separated groups | | CAREERFLOW_ALL_TOOLS | no | Set to 1 to register every tool, even ones your role or token cannot reach | | CAREERFLOW_KEEP_READ_TOOLS | no | Set to 1 to keep the read-only tools run_company_sql otherwise replaces |

The token is read only from the environment, never from command-line arguments — argv is readable by other processes on the same machine.


What you can ask for

Daily work

  • "What am I working on today?" · "Anything overdue?"
  • "Mark the login-bug task done."
  • "Start a timer on task 412." · "Log 45 minutes on the report task."
  • "Add a comment on task 88 saying the API is now deployed."
  • "Add a checklist to task 12 with three items." · "Attach this link to task 40."

Supervising a team

  • "What is Sara working on?" · "Show everything pending review."
  • "Create a task 'Prepare Q3 report' in Sprint 12, assign it to Ali, due Friday, high priority."
  • "Move task 91 to Done." · "Accept task 77 and score it 4.5."
  • "Create a project called 'Website Redesign' and add Sara as manager."

Sales & CRM

  • "Show my open deals." · "Create a lead for Acme Corp from the website form."
  • "Move the Acme deal to Negotiation and set the amount to $12,000."
  • "Log a call with the Beta Inc contact." · "What's in my pipeline this month?"

HR & people ops

  • "Show my latest payroll slip." · "Accept my performance review."
  • "List open job applications for the Backend Engineer posting."
  • "Am I registered for the current loan lottery?" · "Check in my mood: 4, feeling good today."
  • "Reserve lunch for tomorrow."

Around the work

  • "Any new announcements?" · "Message Reza that the deploy finished."
  • "Create a chat group for the launch team with Sara, Ali, and Reza."
  • "Open a support ticket about the slow dashboard load."

Naming: the API vs the UI

The tools keep the backend API's names, and the UI names the same things differently — easy to trip over when relaying what a user asked for:

| API (and these tools) | UI | | --- | --- | | project of type special | "project" (پروژه) | | project of type normal — or any non-special type | "board" (تابلو) | | board — a column of tasks inside a project | "list" (لیست) |

So when a user asks for a "board", they usually mean an API project (find it with list_projects, checking each row's type); when they ask for a "list", they mean an API board (list_boards). The server's instructions string spells this out to the model too.

Tools

167 tools. The everyday surface (only part of it can be registered):

| Group | Tools | | --- | --- | | Identity & structure | whoami, list_companies, list_projects, list_boards, list_project_members, find_user | | Tasks | list_my_tasks, search_tasks, get_task, create_task, update_task, complete_task, assign_task, move_task, review_task, list_task_comments, add_task_comment | | Kanban (boards, labels, checklists, attachments) | create_board, edit_board, archive_board, list_labels, create_label, delete_label, add_task_checklist, add_checklist_item, complete_checklist_item, delete_checklist, add_task_link_attachment, delete_task_attachment, archive_task, duplicate_task, list_recurring_tasks, create_recurring_task, delete_recurring_task, list_kanban_activity | | Projects | create_project, update_project, archive_project, project_stats, invite_project_member, authorize_project_member | | Time | start_timer, stop_timer, log_time, list_task_time | | Chat | list_chats, read_messages, send_message, create_chat_group, edit_chat_group, manage_chat_group_members, list_chat_group_members, leave_chat_group, mute_chat, edit_chat_message, delete_chat_message, mark_message_seen | | Workplace | list_announcements, list_surveys, list_my_attendance | | Company & user admin | create_user, update_user, set_user_status, set_user_role, get_user, list_roles, get_organization_chart, get_company, list_organization_units | | CRM — contacts, deals, activities | crm_search_contacts, crm_get_contact, crm_create_contact, crm_update_contact, crm_delete_contact, crm_contact_timeline, crm_search_deals, crm_get_deal, crm_create_deal, crm_update_deal, crm_delete_deal, crm_deal_stage_summary, crm_add_deal_next_step, crm_list_deal_line_items, crm_add_deal_line_item, crm_delete_deal_line_item, crm_search_activities, crm_create_activity, crm_complete_activity, crm_delete_activity, crm_dashboard_summary, crm_dashboard_pipeline | | CRM — pipelines & config | crm_list_pipelines, crm_create_pipeline, crm_delete_pipeline, crm_list_stages, crm_create_stage, crm_delete_stage, crm_list_lead_sources, crm_create_lead_source, crm_list_tags, crm_create_tag, crm_assign_tag, crm_list_custom_fields, crm_create_custom_field, crm_settings | | HR — payroll, discipline, careers, onboarding, cafeteria | list_my_payrolls, respond_to_payroll, list_my_performance_reviews, respond_to_performance_review, list_disciplinary_notes, estimate_disciplinary_penalty, create_disciplinary_note, list_administrative_notes, get_administrative_note, create_administrative_note, list_careers, list_career_requests, update_career_request_status, get_onboarding_checklist, set_onboarding_stage, list_food_schedules, reserve_food, list_my_food_reservations, mood_checkin | | Benefit fund (loans & lotteries) | benefit_fund_my_dashboard, benefit_fund_hr_dashboard, list_benefit_fund_loan_types, list_benefit_fund_loans, request_benefit_fund_loan, update_benefit_fund_loan_status, pay_benefit_fund_loan_installment, list_benefit_fund_lotteries, register_for_lottery, respond_to_lottery_win, benefit_fund_settings, list_benefit_fund_membership_requests, request_benefit_fund_membership, review_benefit_fund_membership_request | | Forms | list_forms, get_form, list_form_submissions, update_form_submission_status, message_form_submission | | CMS | list_posts, get_post, create_post, update_post, delete_post, list_custom_pages, get_custom_page | | Dev tickets (support) | list_dev_tickets, get_dev_ticket, create_dev_ticket, reply_to_dev_ticket | | Misc (addresses, surveys, announcements, billing) | list_my_addresses, add_address, create_survey, delete_survey, list_survey_answers, answer_survey, create_announcement, delete_announcement, list_transactions, list_payment_orders | | Company SQL (reporting views) | list_company_sql_schema, run_company_sql |


Registering only the tool groups you need

Every registered tool's schema lands in the model's context, so a client that loads all 167 tools spends real tokens on descriptions before you ask anything. If the assistant only works one domain — a sales assistant, a task bot — register just that slice:

{
  "mcpServers": {
    "careerflow": {
      "command": "npx",
      "args": ["-y", "@codegame.dev/careerflow-mcp"],
      "env": {
        "CAREERFLOW_BASE_URL": "https://careerflow.codegame.dev/site-api",
        "CAREERFLOW_TOKEN": "cf_pat_xxxxxxxx",
        "CAREERFLOW_GROUPS": "workspace,tasks,time"
      }
    }
  }
}

Group names (matching rows in the table above, crm covering both CRM rows, chat both chat modules):

workspace, tasks, kanban, projects, time, chat, workplace, admin, crm, hr, benefit-funds, forms, cms, dev-tickets, misc, company-sql

CAREERFLOW_GROUPS is an allowlist; CAREERFLOW_EXCLUDE_GROUPS removes the named groups from the full set. An unknown name fails at startup with the valid list. Group filtering is a context-size control only — the token's scopes still decide what actually works.


Tools you cannot use are not registered

On top of the group filter, the server asks the API at startup what your role in the company and your token's scopes actually allow (GET users/capabilities), and registers only the tools that pass. A sales rep never sees the payroll tools; a token scoped to tasks:read never sees create_task. The startup line on stderr says how many were hidden:

careerflow-mcp connected (api: …, groups: …, tools: 57 registered / 110 hidden by role + token scopes)

This is a context-size and clarity measure, not a security boundary — the API enforces the same rules on every call either way. It degrades safely: an older API without the endpoint, an unreachable host, or a company that cannot be resolved (no CAREERFLOW_COMPANY_ID and no company on your account) registers everything, exactly as before. Set CAREERFLOW_ALL_TOOLS=1 to opt out.

Because the filter is computed once at startup, a role or token change takes effect when the client restarts the server.

If you can run company SQL, the read-only tools step aside

run_company_sql answers any question the v_ai_* views cover — with filters, joins and aggregates no fixed tool offers — so for the users who have it (the company owner, a full-access role, CareerFlow staff) the 54 read-only tools that duplicate it are not registered. On an owner account that is 167 tools down to 113, and "which projects have the most overdue tasks" becomes one query instead of a listing tool that cannot answer it at all.

That includes the listings a write uses to resolve an id — list_projects, list_boards, search_tasks, find_user, crm_list_pipelines, crm_search_contacts and the rest. Each is backed by a view, so for these users looking up an id is simply another query, and the assistant is told which views to use for it.

What stays, SQL or no SQL:

  • everything the views do not cover — payroll and performance rows (only their groups are exposed), the whole benefit fund, dev tickets, billing, addresses, CRM settings
  • chat, which is a live conversation rather than a report
  • whoami, and the SQL tools themselves

Users who cannot run SQL keep every read tool. Set CAREERFLOW_KEEP_READ_TOOLS=1 to keep them anyway.


Permissions

Each token carries an explicit permission list. A tool call that needs a permission the token lacks fails with a message naming the missing one — create a new token with it added. The full list is shown on the token creation screen in Settings → Access Tokens → Create access token; it's summarized here too.

Every scope comes in a :read/:write pair; some also accept a :own suffix (e.g. tasks:write:own) that narrows the write to records the token's owner created, owns, or is assigned to — ask CareerFlow support or check the token creation screen if you want that narrower grant.

| Group | Scopes | Covers | | --- | --- | --- | | Personal | profile, files | your own profile, sessions, addresses, onboarding; file/image/video uploads | | Work | tasks, projects, time, chat | kanban boards/tasks/checklists/labels, projects & membership, time tracking, chat & groups | | CRM | crm_contacts, crm_deals, crm_activities, crm_settings | contacts/leads, deals, activities, and CRM configuration (pipelines, stages, tags, custom fields) | | Company | company, users, roles, attendance | company profile & org chart, user admin, roles, attendance | | HR | surveys, announcements, forms, payroll, performance, benefit_fund, notes, careers | surveys, announcements, form builder, payroll/performance slips, benefit fund loans & lotteries, disciplinary/administrative notes, recruiting | | Content | cms | posts, custom pages, categories | | Billing | billing, dev_tickets | payment/product orders, transactions, support tickets | | Platform (staff-only) | admin | charts, logs, and other platform-admin surfaces — only issuable to CareerFlow staff accounts |

Grant the narrowest set that does the job. A read-only assistant needs only profile:read, tasks:read, and projects:read.

The Company SQL tools are gated on top of scopes: the API re-authorizes each call and only a company owner or a full-access user can run one.

Security notes

  • A token acts as you, limited to its permissions. Treat it like a password.
  • It cannot exceed your own role — the API enforces the same checks as the web app.
  • A token cannot create, edit, or manage another token — token management is a session-only action in the web app, so a leaked token cannot widen itself.
  • Revoke any token you no longer use: Settings → Access Tokens → Revoke. Revocation takes effect immediately.
  • Several tools deliver something real and cannot be undone from inside the tool call — send_message, create_administrative_note, message_form_submission send to real people; create_user, set_user_status, set_user_role change real accounts; request_benefit_fund_loan, update_benefit_fund_loan_status, pay_benefit_fund_loan_installment, and respond_to_lottery_win touch real money. Their descriptions ask the assistant to confirm details with you first — grant the underlying :write scope only if you want that capability at all.

Running from source

git clone https://gitlab.com/dev.codegames/careerflow-mcp
cd careerflow-mcp
npm install
npm run build

Point your client at the built entry point:

{
  "mcpServers": {
    "careerflow": {
      "command": "node",
      "args": ["/absolute/path/to/careerflow-mcp/dist/index.js"],
      "env": { "CAREERFLOW_BASE_URL": "…", "CAREERFLOW_TOKEN": "…" }
    }
  }
}

Docker

docker build -t careerflow-mcp .
{
  "mcpServers": {
    "careerflow": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "CAREERFLOW_BASE_URL",
        "-e", "CAREERFLOW_TOKEN",
        "-e", "CAREERFLOW_COMPANY_ID",
        "careerflow-mcp"
      ],
      "env": {
        "CAREERFLOW_BASE_URL": "https://careerflow.codegame.dev/site-api",
        "CAREERFLOW_TOKEN": "cf_pat_xxxxxxxx",
        "CAREERFLOW_COMPANY_ID": "24"
      }
    }
  }
}

-i is required: the server speaks MCP over stdin/stdout.


Troubleshooting

"CareerFlow rejected the access token" — the token is revoked, expired, or mistyped. Check it in Settings → Access Tokens, and create a new one if needed.

"The access token does not carry the scope this action needs" — the token is missing a permission. Create a new one with that permission added.

"Company ID is not valid" — your role does not permit that read, or CAREERFLOW_COMPANY_ID points at a company you do not belong to. Run whoami to see which company you are in.

Tools do not appear — restart the client after editing its config. Verify the server starts on its own:

CAREERFLOW_TOKEN=cf_pat_xxx CAREERFLOW_BASE_URL=https://host npx @codegame.dev/careerflow-mcp

It should print careerflow-mcp connected (api: …) to stderr and wait. Ctrl-C to exit.


Requirements

  • Node.js 18 or newer
  • A CareerFlow instance with personal access tokens enabled (migration 99 applied)

Development

npm run dev          # tsc --watch
npm run typecheck    # types only
npm run format       # prettier
npm run smoke        # boot the built server and verify tool registration

Publishing

npm run prepublishOnly (typecheck, build, smoke) runs automatically on npm publish. On GitLab, the publish job in .gitlab-ci.yml publishes when a v* tag is pushed and the job is confirmed manually; it needs NPM_TOKEN (set it as a masked CI/CD variable under Settings > CI/CD > Variables):

git tag v1.1.0 && git push origin v1.1.0
# then confirm the `publish` job in CI/CD > Pipelines

Or publish from a machine that is already verified with npm: npm publish.

Compatibility

This client tracks the CareerFlow REST API. Behaviours it deliberately works around, worth knowing before changing a tool:

  • kanbans/tasks/edit, crm/deals/edit, and users/edit all replace the whole row — a field left out falls back to a default (or null) rather than keeping its current value. update_task, crm_update_deal, and update_user each read the record first and merge onto it, so a partial change cannot silently clear untouched fields. Apply the same read-then-merge pattern to any other endpoint discovered to have this behavior.
  • Several endpoints reject an unscoped company-wide read unless the caller holds an admin role, so tools pass the caller's own user id to mean "mine".
  • A few search endpoints require a filter the API otherwise has no "all" value for — e.g. careers/requests/search requires status. list_career_requests reflects that by making the field required rather than optional.