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

@unfoldit/mcp-server

v0.9.1

Published

MCP server for Unfold It (https://unfoldit.ai) -- create goals with AI-generated plans, agent-assisted clarification, plan import with enrichment, progress tracking, cohort analytics, and skill assessments via AI assistants

Downloads

634

Readme

Unfold It MCP Server

Connect AI assistants to Unfold It -- create goals with AI-generated plans, agent-assisted clarification, plan import with enrichment, individual progress tracking, cohort analytics, and skill assessments.

Built for platforms (academies, LMS tools, coaching apps) that want to use Unfold It as their execution layer. Three autonomy tiers: fully autonomous, semi-auto with review, or import your own steps with AI enrichment. Generate skill assessments with AI-validated MCQs, score them, and automatically create targeted learning paths from the results. Tag goals with custom metadata to track and analyze entire cohorts.

Quick Start

npx @unfoldit/mcp-server

Or install globally:

npm install -g @unfoldit/mcp-server

Configuration

Set the following environment variables:

| Variable | Required | Description | |----------|----------|-------------| | UNFOLD_API_KEY | Yes | Org-scoped API key. Generate at app.unfoldit.com -> Organization -> API Keys | | UNFOLD_API_URL | No | API base URL. Defaults to https://api.unfoldit.com |

Claude Desktop / Claude Code

Add to your MCP config (claude_desktop_config.json or .mcp.json):

{
  "mcpServers": {
    "unfoldit": {
      "command": "npx",
      "args": ["@unfoldit/mcp-server"],
      "env": {
        "UNFOLD_API_KEY": "unfold_sk_..."
      }
    }
  }
}

Cursor

Add to .cursor/mcp.json in your project:

{
  "mcpServers": {
    "unfoldit": {
      "command": "npx",
      "args": ["@unfoldit/mcp-server"],
      "env": {
        "UNFOLD_API_KEY": "unfold_sk_..."
      }
    }
  }
}

API Key Scopes

Your API key needs specific scopes depending on which tools you use:

| Scope | Tools | Included by default? | |-------|-------|---------------------| | goals:create | create_goal, unfold_goal, submit_clarification, import_plan, delete_goal | Yes | | goals:read | get_goal_status, list_goals, get_analytics, get_clarification | Yes | | claims:manage | revoke_claim | Yes | | assessment:generate | generate_skill_assessment | No -- must be granted explicitly | | assessment:score | score_skill_assessment | No -- must be granted explicitly | | assessment:read_capabilities | get_assessment_capabilities | No -- must be granted explicitly |

Assessment scopes are opt-in. Ask your org owner to enable them in the API Key settings.

Available Tools (13)

create_goal

Create a goal with an AI-generated plan. The agent auto-answers clarification questions using the context you provide. Set auto_respond=false to review agent suggestions before the plan generates. Tag goals with metadata to group and analyse entire cohorts.

Input:

  • title (required) -- Goal title

  • description -- Goal description. More detail produces a better AI plan

  • context -- Rich context for the agent:

    • tech_stack -- e.g. ["Python", "React"]
    • team_size -- e.g. 3
    • timeline -- e.g. "3 months", "Q3 2026"
    • constraints -- e.g. "2 hours per week"
    • experience_level -- e.g. "beginner", "advanced"
    • industry -- e.g. "fintech"
    • additional_notes -- Any other context
  • auto_respond -- true (default): agent answers all questions. false: returns questions with suggestions for review

  • clarification_answers -- Pre-set answers by question ID (agent skips these)

  • goal_context -- "personal" or "professional" (default: "professional")

  • priority -- "low", "medium", or "high" (default: "medium")

  • claim_expires_in_days -- Claim link validity (default: 30)

  • progress_share -- Generate embeddable progress link (default: true)

  • metadata -- Custom key-value tags for analytics grouping, e.g. { cohort: "spring-2026", track: "frontend" }

  • category -- Resource category hint: "learning", "health_adhd", or "general". Auto-detected from goal title and description if not provided. Determines which sources and search strategies are used when attaching resources to substeps.

  • resource_world -- Override resource discovery for this goal:

    • preferred_sources -- Source domains to prioritise, e.g. ["coursera.org", "docs.python.org"]
    • excluded_sources -- Source domains to suppress
    • youtube_playlists -- YouTube playlist IDs to draw resources from
    • lms_search_endpoint -- Custom LMS search endpoint URL
    • content_policies -- { require_verified_sources, show_disclaimer, disclaimer_text }
  • assessment (since v0.7.0) -- Structured assessment input the planner uses to bias step selection. Discriminated by assessment_type:

    • skill_proficiency v1 -- Drop the score_skill_assessment response straight in. The planner prioritises weak facets, compresses strong ones, and anchors steps in work_item_context.
    • clinical_intake v1 -- ADHD / coaching / clinical context. Wire shape is locked; the prompt builder is currently stubbed and returns assessment_type_not_supported until a real partner drives it. Sensitive type -- requires superadmin enablement per org.
    • general v1 -- Catch-all for assessment data that does not fit either typed shape. Treated as soft hints; only constraints honoured as hard limits.

    See GUIDE_ASSESSMENT_TO_PLAN_MCP for the canonical end-to-end walkthrough.

  • request_id (since v0.8.0, optional, idempotency key) -- Within a 5-minute window, two create_goal calls with the same request_id return the SAME goal and claim link instead of creating a new one. See Idempotency below for the rules. Omit to get a fresh goal on every call (default).

Returns: goalId, claimLink, claimToken, progressLink, planGenerationStatus, questions (if auto_respond=false), agentAnswersUsed, idempotentReplay (since v0.8.0), claimStatus (since v0.8.0), warnings (always present, empty when none)

get_goal_status

Get the current status and full step-by-step detail of a goal. Returns individual step data (timestamps, time spent, blocker count, substep progress) when the plan is ready.

Input:

  • goal_id (required) -- The goal ID from create_goal

Returns: Goal status, progress, resourceCategory, steps[] (with per-step detail when plan is ready), metadata, claimCreatedAt, claimedAt, assignedTo, agentAnswersUsed

get_analytics

Aggregated cohort analytics across all API-created goals. Returns KPIs, at-risk learners, a step-level drop-off funnel, and optional breakdowns by metadata dimension or resource type.

Input:

  • group_by -- Metadata key to break down completion rates by (e.g. "track", "cohort", "department")
  • inactive_days -- Flag goals with no step activity in this many days as at-risk (default: 7)
  • include_funnel -- Include step-by-step completion funnel (default: true)
  • include_resources -- Include resource engagement by type and source (default: false)
  • metadata -- Filter to a specific cohort or segment, e.g. { cohort: "spring-2026" }
  • date_from -- ISO date (YYYY-MM-DD). Only include goals created on or after this date
  • date_to -- ISO date (YYYY-MM-DD). Only include goals created on or before this date

Returns:

  • totalGoals, activeGoals, completedGoals, blockedGoals, completionRate, avgDaysToComplete
  • claimsTotal, claimsClaimed, claimsPending, claimsExpired, avgHoursToClaim
  • atRiskCount, atRiskGoals[] (goalId, title, metadata, daysInactive, progressPercent)
  • completionByDimension[] (when group_by is set)
  • stepFunnel[] (stepOrder, stepTitle, completionRate, avgHoursToComplete)
  • resourceEngagement[] (when include_resources=true)

get_clarification

Get pending clarification questions with agent-suggested answers and confidence levels. Use after create_goal with auto_respond=false.

Input:

  • goal_id (required) -- The goal ID from create_goal

Returns: Questions with agentAnswer, agentConfidence (high/medium/low/fallback), agentSource

submit_clarification

Submit answers to clarification questions and trigger plan generation. Provide your own answers for questions you want to override. Agent suggestions are kept for the rest.

Input:

  • goal_id (required) -- The goal ID from create_goal
  • answers -- Your answers keyed by question ID (only include overrides)
  • accept_agent_answers -- Accept agent suggestions for unoverridden questions (default: true)

Returns: goalId, status, planGenerationStatus, agentAnswersUsed

import_plan

Import a pre-formulated plan with steps and substeps. Skips clarification entirely. AI enriches steps with dependencies, critical path, duration estimates, severity, complexity, and quick-win flags.

Input:

  • title (required) -- Goal title
  • description -- Goal description
  • steps (required) -- Array of steps, each with:
    • title (required) -- Step title
    • description -- Step description
    • substeps -- Optional array of substeps with title, description, type (research/work/decision/verification)
  • enrich -- Run AI enrichment (default: true). Set false for 0 credits
  • enrich_options -- Control which enrichment features to run:
    • dependencies, critical_path, duration_estimates, severity, complexity, quick_wins, resources
  • goal_context -- "personal" or "professional" (default: "professional")
  • priority -- "low", "medium", or "high" (default: "medium")
  • claim_expires_in_days -- Claim link validity (default: 30)
  • progress_share -- Generate embeddable progress link (default: true)
  • metadata -- Custom key-value tags for analytics grouping, e.g. { cohort: "spring-2026", track: "backend" }

Returns: goalId, planId, enriched steps[] with metadata, claimLink

list_resource_categories

List available resource categories for goal classification. Returns each category's active providers, content safety policies, and disclaimer text. Use this to build adaptive UIs or to discover which categories are available before creating goals.

Input: None

Returns: Array of categories, each with id, name, description, activeProviders, showDisclaimer, disclaimerText

list_goals

List all goals in your org with optional filters. Use metadata to filter to a cohort, category to segment by goal type, assigned_email to look up a specific learner, or inactive_days to find at-risk goals without pulling full analytics.

Input:

  • status -- Filter by goal status (draft, in_progress, completed, blocked, paused)
  • claim_status -- Filter by claim status (unclaimed, claimed, expired, revoked)
  • category -- Filter by resource category (learning, health_adhd, general). Use this to segment ADHD goals from learning goals in a mixed cohort.
  • metadata -- Filter by metadata tag(s) in "key=value" format, e.g. ["track=frontend", "cohort=spring-2026"]
  • assigned_email -- Return only the goal assigned to this learner email
  • inactive_days -- Return only goals with no step activity in the last N days (1-365)
  • include_steps (since v0.9.1) -- Include per-step details (steps[]) for each goal whose plan is ready. Off by default to keep list payloads lean; set true to render step lists without a get_goal_status call per goal.
  • limit -- Max results (default: 50, max: 100)
  • offset -- Pagination offset

Returns: Array of goal statuses with progress, resourceCategory, metadata, claimCreatedAt, claimedAt. When include_steps=true, each goal whose plan is ready also carries steps[] -- the same per-step shape as get_goal_status (timestamps, time spent, blocker count, substep counts). Goals still generating return steps: null. Steps are not paginated; the full step list is returned per goal.

revoke_claim

Invalidate a claim link so it can no longer be used.

Input:

  • claim_token (required) -- The token from the claim link URL

delete_goal

Delete a goal created via the API. Main use case: after a learner retakes a skill assessment, call create_goal with the new suggested_goal_seed and then delete_goal on the obsolete goal so the dashboard shows the current goal instead of duplicates. Soft delete by default (recoverable); set hard_delete=true to remove the row permanently. Scoped to api-created goals -- cannot delete goals a user created in the webapp UI.

Input:

  • goal_id (required) -- UUID of the goal (the goalId returned by create_goal)
  • hard_delete -- If true, permanently delete the row instead of soft-deleting. Default false.

generate_skill_assessment

Generate a skill-proficiency assessment (MCQs) for a learner. Questions are AI-generated and validated (structural + semantic checks) before being returned. Returns a signed assessment_token that the learner's answers are scored against.

Input:

  • work_item_context (required) -- The work item the learner is preparing for:
    • title (required) -- Work item title
    • description -- Work item description (max 2000 chars)
    • domain_tags -- Tags for question anchoring
  • skill (required) -- Skill to assess (e.g. "Python", "SQL", "Project Management")
  • target_proficiency (required) -- Band the learner should reach: "beginner", "low", "medium", "high"
  • num_questions (required) -- Number of MCQs to generate (3-20)
  • difficulty_mix -- Distribution as {easy, medium, hard} floats summing to 1.0. Default: {easy: 0.2, medium: 0.5, hard: 0.3}
  • band_thresholds -- Custom proficiency band ranges. Default: beginner [0,10], low [11,50], medium [51,85], high [86,100]
  • language -- ISO language code (default: "en")
  • request_id (required) -- Idempotency key. Same request_id returns the same assessment.

Returns: assessment_token, questions[] (stem, options, difficulty, skill_facet), band_map, max_raw_score, target_band, model_meta

Requires scope: assessment:generate

score_skill_assessment

Score a submitted assessment using the signed assessment_token from generate_skill_assessment. Returns the learner's proficiency band, gap vs target, and per-question results. When the learner falls short, includes a suggested_goal_seed you can pass to create_goal to create a targeted learning path.

Input:

  • assessment_token (required) -- The signed token from generate_skill_assessment
  • answers (required) -- Array of {question_id, selected_option_id} (at least one)
  • band_thresholds -- Optional override of proficiency band ranges (defaults to the thresholds embedded in the token)
  • request_id (required) -- Idempotency key

Returns: raw_score, max_raw_score, raw_pct, band, target_band, gap_bands, per_question[], per_facet[] (server-side aggregation per sub-skill with total, correct, raw_pct, classification: weak | strong | mixed), weak_facets[], strong_facets[], facet_coverage (full | partial | difficulty_fallback), recommended_action (none / create_unfold_goal), suggested_goal_seed

Chaining tip: This response is shape-compatible with create_goal's new assessment field (skill_proficiency v1). Drop it in with three header fields added (assessment_type: "skill_proficiency", schema_version: "v1", assessed_at: <ISO timestamp>) and the planner uses it directly. No client-side join logic, no threshold tuning.

Requires scope: assessment:score

get_assessment_capabilities

Get supported parameters for skill assessments. Use this to introspect before calling generate_skill_assessment. No input parameters required.

Returns: schema_version, supported_languages, min_questions, max_questions, supported_proficiency_bands, default_band_thresholds, default_difficulty_mix, open_domain, token_ttl_seconds

Requires scope: assessment:read_capabilities

Idempotency

Available since v0.8.0.

create_goal accepts an optional request_id so a partner can retry safely without producing duplicate goals.

The rules

  1. Scope the key to one logical operation. A "logical operation" is one learner / one enrollment. Construct the key from your own per-learner identifier, for example:
    request_id = "enrollment:42:learner:7"
    request_id = "course:python-101:user:abc-123"
  2. Reuse the key on retries, not on new learners. If a network blip or process restart makes you re-send the same call for the same learner, use the same request_id. If you are creating a goal for a DIFFERENT learner, generate a NEW key.
  3. Do NOT derive the key from the body. Two learners enrolled in the same course will produce identical title / description / assessment payloads. If you reuse a body-derived key, the second learner will receive a claim link the first learner already claimed.
  4. Without a request_id, every call creates a fresh goal. This is the default and is always safe.

Cache window

Two calls with the same tenant + request_id within 5 minutes return the same response. After 5 minutes the key falls out of cache and a fresh call creates a new goal. Best-effort across pod restarts and horizontal scaling today; treat the window as a retry helper, not a deduplication guarantee.

Detecting a replay

Two new fields on the response tell you what happened:

  • idempotentReplay: true -- this response was served from cache. A prior call with the same request_id produced this goal.
  • claimStatus: "unclaimed" | "claimed" | "expired" | "revoked" -- current state of the underlying claim token, refreshed from the DB on every replay. null on a fresh create (implicitly "unclaimed").

Branch on this when handling retries:

const result = await create_goal({ title, request_id: enrollmentKey });

if (result.idempotentReplay && result.claimStatus && result.claimStatus !== "unclaimed") {
  // The link was already consumed by the original recipient. Don't
  // forward it again -- prompt the human or open a support ticket
  // depending on your flow.
} else {
  // Safe to forward the claimLink to the learner.
}

How It Works

Tier 1 -- Semi-Auto (Review agent suggestions)

  1. Call create_goal with auto_respond=false and your context
  2. Get back questions with agent-suggested answers and confidence levels
  3. Review suggestions, override any you disagree with
  4. Call submit_clarification to trigger plan generation
  5. Poll get_goal_status until planGenerationStatus is "completed"

Tier 2 -- Full-Auto (Agent handles everything)

  1. Call create_goal with context (auto_respond defaults to true)
  2. Agent answers all clarification questions using your context + user history
  3. Plan generates in the background (15-30s)
  4. Get a claim link immediately -- send it to your user
  5. Poll get_goal_status for completion and agentAnswersUsed transparency

Tier 3 -- Import (Bring your own steps)

  1. Call import_plan with your steps and substeps
  2. AI enriches with dependencies, durations, severity, critical path
  3. Plan is ready immediately (no clarification needed)
  4. Get a claim link and enriched step metadata

Assess-then-Learn (Assessment to goal) [updated v0.7.0]

The canonical chain that turns a scored assessment into a personalised plan, with no client-side join logic:

  1. Call generate_skill_assessment with the skill, target proficiency, and work item context
  2. Present questions to the learner in your UI
  3. Call score_skill_assessment with the token and the learner's answers. Response includes per_facet, weak_facets, strong_facets, facet_coverage (server-side aggregation).
  4. Call create_goal with the score response dropped into the new assessment field (skill_proficiency v1). The planner uses weak/strong facets to bias steps and anchors them in work_item_context.
  5. Send the claim link to the learner.

Full walkthrough with payload examples for skill_proficiency, general, and clinical_intake lives at GUIDE_ASSESSMENT_TO_PLAN_MCP.

Legacy path. Pre-v0.7.0 integrations stuffed the score into additional_context.unfold_assessment per the payload convention. That still works on POST /api/v1/ext/goals for backwards compat; behind the scenes both paths now route through the same prompt-builder registry. New integrations should use the structured assessment field on create_goal.

Example Prompts

"Create a Python certification learning path for a beginner with 2 hours per week for 3 months."

"Import our Jira sprint backlog as a goal with dependencies and time estimates."

"Create a coaching plan for Sarah but let me review the questions before generating the plan."

"Create an ADHD morning routine coaching plan with category health_adhd for a patient who struggles with time blindness."

"List all health_adhd goals in the spring cohort and show me which ones are at risk."

"Show me all goals where the claim link hasn't been used yet."

"What's the progress on goal abc-123? Has the learner started?"

"Generate a Python assessment with 8 questions for someone who needs medium proficiency to work on the ML pipeline."

"Score this assessment and create a goal from the results if the learner didn't reach the target."

Getting an API Key

  1. Go to app.unfoldit.com
  2. Create or switch to your organization
  3. Go to Organization settings
  4. Scroll to API Keys section
  5. Click + Create Key, give it a name, and copy the key

Typed errors and warnings (v0.7.0+)

When a tool fails with a typed error, the response is a structured JSON envelope rather than a stringified message. Branch on error_code:

| error_code | When | Notes | |---|---|---| | models_not_configured | BYO provider role is not configured | Response includes settings_url | | provider_unauthorized | BYO provider key rejected | Includes settings_url and switch_to_unfold_ai CTA | | provider_quota_exceeded | BYO provider returned quota/billing error | Includes switch_to_unfold_ai CTA | | provider_unavailable | BYO provider 5xx or circuit breaker open | Transient; retry later | | assessment_type_not_supported | assessment_type recognised but builder not yet wired | Response includes supported list | | assessment_type_not_enabled_for_org | Tenant has not opted into this assessment type | Sensitive types (clinical_intake) need superadmin enablement | | token_invalid / assessment_expired | Assessment token tampered or past TTL | Regenerate via generate_skill_assessment | | idempotency_conflict | Same request_id used with different request body | Pick a new request_id | | validation_failed | Generation output failed validation after retry budget | Retry with different request_id |

Successful responses on goal creation also carry warnings: ApiWarning[] (always present, empty when none). Known warning codes:

| code | When | |---|---| | category_assessment_type_mismatch | category and assessment.assessment_type disagree. Plan was generated using assessment_type. | | duplicate_assessment_input | Both structured assessment field and legacy additional_context.unfold_assessment envelope sent. Structured won. |

Both branches preserve the structured envelope so AI coding agents can deterministically branch on the error_code or warning code strings. See the versioning policy for stability guarantees on these codes.

Versioning

This package follows semver. Pin a minor version range ("@unfoldit/mcp-server": "^0.8.0") -- you will get fixes and additive features automatically; breaking changes require a major version bump. We support the latest two minor versions; older minors receive security fixes only.

Note: in the pre-1.0 era, each minor bump (e.g. 0.7.x -> 0.8.0) may include additive surface changes such as new optional request fields or new response fields. Existing code keeps working; opt in to new behaviour as you need it.

See GUIDE_MCP_VERSIONING for the full policy. See CHANGELOG.md for what changed in each release.

Learn More

License

MIT