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

apic-mcp

v0.4.2

Published

MCP server for Apic — let AI tools read, run, and create/edit your API requests locally

Readme

apic-mcp

An MCP server for Apic — lets AI tools (Claude Code, Claude Desktop, Cursor, …) read your Apic API collections and run requests locally on your machine (so they reach localhost services you're building).

It connects to your Apic cloud workspace with a Personal Access Token, pulls the collection tree, and executes requests with Apic's own engine (variable resolution, pre-request/test scripts, auth) — execution stays on your machine; nothing is proxied through the cloud.

1. Mint a token

In the Apic app: Settings → MCP access → Generate token, then copy it (shown once). Tokens act as you and are read-only by default; mint a read-write token to use the write tools (create_request, update_request, create_folder, delete_request). Optionally pin one to a single workspace.

2. Configure your AI tool

All transports are stdio via npx. Set three env vars:

| Var | Meaning | |---|---| | APIC_API_URL | Your Apic backend, e.g. https://api.yourapic.com (default http://localhost:4000) | | APIC_TOKEN | The apic_pat_… token | | APIC_WORKSPACE_ID | Optional — the default organization (workspace). Falls back to a per-directory .apic.json binding, then your only workspace, or pass workspaceId per call | | APIC_PROJECT_ID | Optional — the default project/collection. Same fallback chain; the recommended way to pin a project on Claude Desktop (which has no project directory) | | APIC_PROJECT_DIR | Optional — explicit project-root override for locating .apic.json when the client doesn't expose one (e.g. set to ${workspaceFolder} in Cursor) |

Claude Desktopclaude_desktop_config.json:

{
  "mcpServers": {
    "apic": {
      "command": "npx",
      "args": ["-y", "apic-mcp"],
      "env": {
        "APIC_API_URL": "https://api.yourapic.com",
        "APIC_TOKEN": "apic_pat_…",
        "APIC_WORKSPACE_ID": "ws_…"
      }
    }
  }
}

Claude Code — one command:

claude mcp add apic \
  -e APIC_API_URL=https://api.yourapic.com \
  -e APIC_TOKEN=apic_pat_… \
  -e APIC_WORKSPACE_ID=ws_… \
  -- npx -y apic-mcp

Cursor~/.cursor/mcp.json uses the same mcpServers shape as Claude Desktop.

Tools

| Tool | Does | |---|---| | list_workspaces | Workspaces this token can access | | list_requests | Collection/folder tree (id, name, method, url) | | search_requests | Find requests by name / method / url | | get_request | Full request definition + a resolved method/url/headers preview | | run_request | Execute a request locally → status, headers, body, tests, console | | list_environments | A project's environments | | list_variables | Variables in scope (secret values returned as null) | | create_request | Create a saved request in a folder (read-write token) | | update_request | Update fields of an existing request (read-write token) | | create_folder | Create a top-level folder (read-write token) | | delete_request | Delete a saved request (read-write token) | | whoami | Show the resolved org + project (and where each came from) for this directory | | bind_project | Write a .apic.json binding this directory to an org + project | | unbind_project | Remove the org/project keys from this directory's .apic.json |

get_request / run_request accept environmentId and a variableOverrides map.

create_request / update_request accept preScript, postScript and testScript — JavaScript run in Apic's sandbox via the apic.* API (e.g. apic.variables.setRuntime('accessToken', apic.response.json().accessToken) in a post-response script, or apic.test(name, () => apic.expect(apic.response.status).toBe(200)) in a test script). On update_request, pass an empty string to clear a script; omit the field to leave it unchanged.

bodyType can be none / json / raw / form (multipart/form-data) / urlenc (x-www-form-urlencoded). For form pass a formData array, for urlenc a urlencoded array — [{ key, value }], keys used literally. Handy for an OAuth token request: bodyType:"urlenc", urlencoded:[{key:"grant_type",value:"client_credentials"}, …]. A formData row can be a file field via file: {key:"upload", file:{name:"invoice.pdf", mime:"application/pdf"}} — this authors the field structure (type=File + metadata), but the MCP can't attach the bytes: pick the actual file in the Apic app, and run_request via MCP skips file fields.

Per-directory binding (.apic.json)

So an agent always targets the right org/project without being told the ids every time, each working directory can be bound to one organization + project. Ask the agent to run bind_project (grab the org id and project id from Apic → Settings → MCP access — both are copyable there); it writes a small .apic.json at the project root:

{ "workspaceId": "ws_…", "workspaceName": "Acme", "projectId": "proj_…", "projectName": "Billing API" }

Commit it to share the binding with your team, or add it to .gitignore to keep it local. Run whoami any time to see what's resolved and where it came from. Resolution precedence:

  1. an explicit workspaceId / projectId tool argument (always wins)
  2. the .apic.json binding for the current directory
  3. the APIC_WORKSPACE_ID / APIC_PROJECT_ID env vars
  4. the sole workspace / project if there's exactly one (else you're asked to choose)

A .apic.json binding is re-verified against your token on use (the org id must still resolve to the same name), so a stale or cloned file can't silently point writes at the wrong org. Secrets and apiUrl are never read from .apic.json.

Finding the directory differs by client — the server tries, in order: the MCP roots/list (when the host supports it), then APIC_PROJECT_DIR, then CLAUDE_PROJECT_DIR (Claude Code sets this), then the process cwd:

  • Claude Code — works out of the box (CLAUDE_PROJECT_DIR = the project root).
  • Cursor — add "cwd": "${workspaceFolder}" (or "env": { "APIC_PROJECT_DIR": "${workspaceFolder}" }) to the server in .cursor/mcp.json, otherwise the cwd isn't your project.
  • Claude Desktop — has no project directory, so .apic.json can't be located; pin the project with APIC_WORKSPACE_ID / APIC_PROJECT_ID in the config env instead.

Secrets

Secret variable values are never synced to the Apic cloud (the server stores blanks), so the MCP server supplies them locally, from two sources (later wins):

  1. ~/.apic/secrets.json{ "<workspaceId>" | "default": { "<var key>": "<value>" } } (chmod 600)
  2. the per-call variableOverrides tool argument

All known secret values are redacted from the console output returned to the model.

Limitations (v1)

  • File uploads (binary body / form-data file fields) are not executed — run_request returns a warnings[] note; run those in the Apic app.
  • The per-phase network timeline is desktop-only (absent here).

Develop

pnpm install
pnpm build           # tsup → dist/index.js (bundles Apic's engine from ../src)
pnpm typecheck

# drive it with the MCP Inspector:
APIC_API_URL=http://localhost:4000 APIC_TOKEN=apic_pat_… APIC_WORKSPACE_ID=ws_… \
  npx @modelcontextprotocol/inspector node dist/index.js

The request engine, variable resolution and script runtime are imported directly from the Apic SPA (../src/engine, ../src/data/types) and bundled in — single source of truth, no duplication.