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

@qeekai/ide-client

v0.5.3

Published

Qeek IDE integration client library + Claude Desktop MCP server (QEEK-87 Phase 2).

Readme

@qeekai/ide-client

Client library + MCP server for the qeek IDE Integration.

Two consumers:

  • MCP-aware IDEs — Claude Code, Claude Desktop, Cursor, VS Code (1.95+). Run the registry-pinned npx command below as an MCP server; the IDE picks up eleven tools (list-briefs, get-brief, list-specs, search-specs, get-spec, list-spec-questions, check-spec-implementation, update-spec, ask-spec-question, check-spec-answer, get-repo-context).
  • Custom IDE extensions — import the lib and wire IdeApiClient
    • IdeNotificationListener into your extension surface (~30 lines).

If you just want to use the integration from your IDE, the two steps below are all you need. The rest of this README is for library / extension authors and people deploying the MCP server.

Why the --@qeekai:registry=… flag? This package is published to the public npm registry. Several QEEK repos ship an .npmrc that routes @qeekai/* to GitHub Packages for private workspace packages, so a bare npx -y @qeekai/ide-client … 404s when run from those folders. Pinning the scope makes login and MCP work from any cwd.

Step 1 — sign in (once)

npx -y --@qeekai:registry=https://registry.npmjs.org @qeekai/ide-client login

Opens your browser to my.qeek.ai to sign in, then saves credentials to ~/.qeek/credentials.json. Every IDE config below picks these up automatically — no tokens or env vars needed. Re-run this if you ever need to switch accounts; append logout instead of login to clear it.

If you'd rather use a static long-lived token instead (e.g. for CI or a shared machine), skip this step and see "Alternative: static token" below.

Step 2 — configure your IDE

Claude Code

claude mcp add qeek -- npx -y --@qeekai:registry=https://registry.npmjs.org @qeekai/ide-client

The eleven MCP tools become available in every Claude Code session after the next reload. Claude Code's CLI, desktop app, and VS Code extension are expected to share this same config (same underlying product) — if the tools don't show up in one of them, check that surface's own MCP settings before assuming a separate config is needed.

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (on macOS — Windows/Linux paths in Anthropic's docs):

{
  "mcpServers": {
    "qeek": {
      "command": "npx",
      "args": [
        "-y",
        "--@qeekai:registry=https://registry.npmjs.org",
        "@qeekai/ide-client"
      ]
    }
  }
}

Restart Claude Desktop. Ask it "What qeek specs do I have?" — it should call list-specs and reply with your specs.

Cursor

npx -y --@qeekai:registry=https://registry.npmjs.org @qeekai/ide-client setup-cursor

Writes (or merges) the qeek server into ~/.cursor/mcp.json with the registry pin already in the generated args. Pass --local to write .cursor/mcp.json in the current project instead (per-workspace, takes precedence over the global file). Re-run after upgrading if your existing entry still lacks the registry flag.

Reload Cursor (Cmd+Shift+P → "Reload Window"). The qeek server should show up under MCP tools in the agent panel.

VS Code (native MCP, 1.95+)

This is VS Code's own built-in MCP client (used by Copilot Chat and other MCP-aware extensions) — a different integration path from the Claude Code extension above, which shares the CLI's config instead.

Per-workspace config (preferred — keeps env out of global settings): .vscode/mcp.json in your project root:

{
  "servers": {
    "qeek": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "--@qeekai:registry=https://registry.npmjs.org",
        "@qeekai/ide-client"
      ]
    }
  }
}

Or global: Cmd+Shift+P → "MCP: Add server" → fill in the same command / args. Stored in User Settings.

Alternative: static token (no login, e.g. CI or a shared machine)

Generate a token from qeek-ui at /settings/api-tokens, then set it instead of running login. Config style depends on which quick start you followed above:

Claude Desktop, VS Code (JSON config) — add an env block:

"env": {
  "QEEK_IDE_TOKEN": "<qek_live_...>",
  "QEEK_IDE_ACCOUNT": "<your-account-id>",
  "QEEK_IDE_CHAT_SESSION": "<chat-session-id-for-clarifications>"
}

Cursor — run setup-cursor first (see above), then add the same env block to the generated qeek entry in ~/.cursor/mcp.json (or .cursor/mcp.json if you used --local):

"qeek": {
  "command": "npx",
  "args": [
    "-y",
    "--@qeekai:registry=https://registry.npmjs.org",
    "@qeekai/ide-client"
  ],
  "env": {
    "QEEK_IDE_TOKEN": "<qek_live_...>",
    "QEEK_IDE_ACCOUNT": "<your-account-id>"
  }
}

Claude Code (CLI) — pass --env flags instead:

claude mcp add qeek \
  --env QEEK_IDE_TOKEN=<qek_live_...> \
  --env QEEK_IDE_ACCOUNT=<your-account-id> \
  --env QEEK_IDE_CHAT_SESSION=<chat-session-id-for-clarifications> \
  -- npx -y --@qeekai:registry=https://registry.npmjs.org @qeekai/ide-client
  • QEEK_IDE_TOKEN — long-lived qeek API token. Treat as a password; revoke from /settings/api-tokens if leaked.
  • QEEK_IDE_ACCOUNT — your account ID, visible in qeek-ui URLs (https://my.qeek.ai/<accountId>/…).
  • QEEK_IDE_CHAT_SESSION — the chat session id where clarification answers should land (…/chat/<sessionId>). Optional — if unset, the ask-spec-question tool requires chatSessionId in the call args.

~/.qeek/credentials.json (from login) takes priority over QEEK_IDE_TOKEN if both are present.

Custom IDE extensions (advanced)

import {
  IdeApiClient,
  IdeNotificationListener,
} from "@qeekai/ide-client";
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getAuth, signInWithCustomToken } from "firebase/auth";

const app = initializeApp({ /* your Firebase config */ });
const auth = getAuth(app);
const db = getFirestore(app);

// 1. Sign in (your extension handles this however — paste, OAuth,
//    PAT exchange via api_tokens).
await signInWithCustomToken(auth, "<custom-token-from-your-flow>");

// 2. REST client
const api = new IdeApiClient({
  baseUrl: "https://qeek-ide-service-bg2lz2topa-uc.a.run.app",
  token: () => auth.currentUser!.getIdToken(),
  accountId: "<account-id>",
  toolType: "vscode",
  toolVersion: "0.1.0",
});

const { specs } = await api.listSpecs();

// 3. Notification listener (Firestore push)
const listener = new IdeNotificationListener({
  db,
  userId: auth.currentUser!.uid,
  accountId: "<account-id>",
  handlers: {
    onSpecUpdated: (notif, payload) => {
      vscode.window.showInformationMessage(
        `Spec "${payload.specTitle}" updated to v${payload.newVersion}`,
        "Refresh",
      );
    },
    onClarificationAnswered: (notif, payload) => {
      vscode.window.showInformationMessage(
        `qeek answered: ${payload.answer.slice(0, 80)}…`,
      );
    },
  },
});
listener.start();

// Cleanup on extension deactivation
context.subscriptions.push({ dispose: () => listener.stop() });

MCP tools

| Tool | What | |---|---| | list-briefs | The "what should we build / what's left?" entrypoint. List the briefs (work-items) you can access in a project — id, title, specCount, updatedAt, access (owned|shared), and a url to open it in QEEK. Requires projectId. Then get-brief to drill in. | | list-specs | List specs in the user's account. Filters: projectId, status, limit. | | search-specs | Free-text search across the account's specs — terms are AND-matched over title + body (title hits first), returning id/title/type/scope + a match snippet. Use it to discover specs when you don't know their ids, then get-spec. Args: query (required), projectId, status, limit. | | get-brief | Pull a whole brief (a qeek chat session) and summaries of ALL its specs in one call — per spec: id, title, type, a short preview, word count — plus the brief's title, projectId, repositoryNames, tickets (linked Jira/Linear issue(s), or empty = none), and a url to open it in QEEK. Then get-spec a spec id for the full body. Arg: briefId. | | get-spec | Fetch one spec's full content by id. Also returns version (use as baseVersion for update-spec), tickets (the Jira/Linear issue(s) the spec's brief is linked to; empty = no ticket attached), and a url to open it in QEEK. Optional saveTo: true writes to .qeek/specs/<id>.md, or a string path (cwd-relative, path-traversal guarded). When set, the assistant can re-read the file across later turns without another API call. | | list-spec-questions | A spec's clarification questions labeled open / answered·authoritative / answered·inferred / failed, with counts — the "what's still undecided" view. Arg: specId. | | check-spec-implementation | "What's left to build." Fetches a spec + its repo context in one call and asks the assistant to label each acceptance criterion implemented / partial / missing with repo evidence. Args: specId, optional depth/repoName/repoNames. | | update-spec | Write a new version of a spec after you and the user agree on a change — the spec body is updated in QEEK and the change is recorded in version history with your rationale (a trail of why it changed; reversible). Read the spec first (get-spec) for its version, pass it as baseVersion; a concurrent edit returns 409 VERSION_CONFLICT (re-read and retry). Args: specId, chatSessionId (the brief id), baseVersion, content, changeDescription. | | ask-spec-question | Submit a clarification question. The qeek agent answers; the answer threads into the user's qeek chat session. The tool long-polls up to 45s for the answer and returns it inline; on timeout returns a questionId for check-spec-answer. Answers are labeled authoritative (grounded in the spec) or inferred (reasoned beyond it). | | check-spec-answer | Poll an in-flight question for its answer. Used when ask-spec-question timed out. | | get-repo-context | Fetch spec-scoped repo context — per-file summaries, dependency edges, and (when present) project architecture overview + directory structure. Optional saveTo writes a directory of markdown + json files (.qeek/context/<specId>/) the assistant can re-read across turns. Args: depth (minimal | related), includeWiki, repoName, forceRefresh. |

A common flow: get-brief <briefId> (or search-specs) to load the specs, review them, then ask-spec-question for anything unclear.

ask-spec-question routes through the existing qeek chat agent (same model, same cost line). The conversation persists in the user's qeek chat session — the Q and the answer show up in qeek-ui alongside normal chat turns for anyone looking at that chat, tagged with the answer's authoritative / inferred source.

Auth model

The MCP server (registry-pinned npx … @qeekai/ide-client mcp, the default subcommand) supports two auth paths, checked in this order:

  1. ~/.qeek/credentials.json, written by npx -y --@qeekai:registry=https://registry.npmjs.org @qeekai/ide-client login — a long-lived qeek API token (qek_live_…), minted by the browser at login time and revoked automatically the next time you log in (or on logout). No hourly expiry. The MCP server re-reads this file on each request (token and account id) and retries once on 401 when the token changed, so re-login does not require restarting the IDE (QEEK-355). This is the path every quick-start above uses.
  2. QEEK_IDE_TOKEN — the same kind of long-lived API token, set manually via the qeek-ui /settings/api-tokens page instead of login. Used when there's no login session (e.g. CI, a shared machine). Env-only setups do not reload from disk — update the env var and restart the MCP server after rotating.

IdeApiClient.config.token (the library's REST client, for custom IDE extensions — see below) accepts either a string or a getter function — the getter is called before every request, so an extension can plumb its own refresh loop in without touching this package.

Configuration

| Env var | Purpose | Default | |---|---|---| | QEEK_IDE_URL | ide-service base URL | prod URL | | QEEK_IDE_CHAT_SESSION | Default chat session id for ask-spec-question | optional — if unset, tool call must pass chatSessionId |

QEEK_IDE_TOKEN / QEEK_IDE_ACCOUNT aren't listed here — normal use is login (Step 1 above). See "Alternative: static token" if you need them for CI or a shared machine.

Development

# Build (from repo root or this package)
pnpm -C ide-client build

# Test
pnpm -C ide-client test

# Run the MCP server locally with stdio (for poking via @modelcontextprotocol/inspector)
QEEK_IDE_TOKEN=... QEEK_IDE_ACCOUNT=... pnpm -C ide-client start:mcp

Behaviour notes

  • get-spec tool results are ephemeral. The MCP tool returns the spec as a JSON tool-result block; the assistant reads it for the current turn, but the IDE's context window may compact it away on later turns. Use saveTo (see the table above) when you want the spec available to re-read across turns / sessions.
  • No streaming responses. MCP tool calls are request-response; long answers come back as a single text block when the agent finishes generating.
  • Notification listener is for IDE extensions, not the MCP server. MCP prefers synchronous tool responses, so the MCP server uses the REST polling endpoint (/v1/ide/questions/:id) instead of opening a Firestore listener. The IdeNotificationListener export is for the VS Code / Cursor extension surface.

Architecture

MCP-aware IDE (Claude Code / Desktop / Cursor / VS Code 1.95+)
      │  (stdio MCP protocol)
      ▼
┌─────────────────────────────────────────┐
│  npx … @qeekai/ide-client (this package) │
│  ┌───────────────────────────────────┐  │
│  │  createMcpServer (11 tools)       │  │
│  │       │                           │  │
│  │       ▼                           │  │
│  │  IdeApiClient (REST wrapper)      │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘
      │  HTTPS + Bearer token
      ▼
┌─────────────────────────────────────────┐
│  ide-service (Cloud Run)                │
└─────────────────────────────────────────┘

IDE extensions skip the MCP server and use IdeApiClient + IdeNotificationListener directly.