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

@quietflow/mcp

v0.1.4

Published

MCP server for Quiet Flow — lets an AI assistant publish internal apps under company governance.

Readme

@quietflow/mcp

The Quiet Flow MCP server. Lets Claude Code, Codex, or any MCP client publish apps to Quiet Flow without the builder leaving their editor.

What this is, and is not

A thin adapter over the Quiet Flow API (Jing §7.7, §20.1). It holds no business state, implements no rules of its own, and never returns a credential. Every decision about what is allowed is made by the API — so an agent can never reach an outcome the CLI could not.

It is not the runtime data path for a deployed app. A deployed app talks to the broker itself, with its own cluster identity, and nothing about a published app routes through here.

It is a way for an assistant to read company data while an app is being built, and that is new (#419). It reads through the same gate the app reads through — POST /v1/data on the runtime capability service — holding the same development session qf dev holds. See Reading company data below.

Install

Almost nobody should do this by hand. qf login registers this server with the assistants on your machine and installs the skill that goes with it:

npm install -g @quietflow/cli
qf login

If you want to register it yourself:

claude mcp add quietflow -- npx -y @quietflow/mcp

Authentication

qf connect issues this server its own credential and writes it to ~/.config/quietflow/assistant.json, 0600. This server reads that file; it never writes one, and there is never a token in your MCP configuration.

The separation is the point: cancelling this machine's assistant credential (qf disconnect) does not sign you out of your own CLI or disconnect another machine, while qf logout cancels every assistant credential in your name.

Resolution order is QF_TOKEN in the environment, then assistant.json. There is no fallback to the CLI's own credential: a missing or corrupt assistant file fails closed and asks the person to run qf connect.

The released default control plane is https://api.quietflow.net. Local and self-hosted installations override it with QF_API_URL.

The skill

skill/SKILL.md ships inside this package. qf connect installs it where your assistant looks for one. Tools without it give you an assistant that can call our API and does not know when or why to.

Tools

| Tool | Purpose | |---|---| | whoami | Who is signed in, and what they may do | | open_existing_app_report | Claim an employee's one-time report handoff in the actual project folder | | submit_existing_app_findings | Add a business summary plus source-backed inferred or unknown findings to that report | | open_build_project | Claim the one-time code from generated Build instructions and create or link the local project manifest | | list_applications | The user's apps and where each one is | | declare_app_intent | Write quietflow.yaml — call this before building | | check_policy | "Would this be allowed?" Creates nothing | | list_company_systems | The company data this company has offered its app builders, who decides each, and the two names the code writes | | publish_application | Scan, build, provision, deploy to a private sandbox | | submit_for_review | Freeze the version and send it to approvers | | request_data_access | Ask the person who looks after a company system to let the app read it | | get_application_status | Where an app is, its addresses, and what company data it may read | | get_review_feedback | Check results and reviewer comments | | promote_application | Publish the exact approved build to the company | | list_company_data | What this app may actually read right now, and which named operations | | read_company_data | Read real company records through Quiet Flow, as the app would |

The existing-app submission contract keeps the Candidate identifier in the URL only. Its strict request body is built from the remaining fields and is checked against the API route schema, so an MCP-only routing field cannot leak into a rejected API payload.

check_policy is deliberately non-mutating: an agent should be able to ask whether something is allowed as often as it likes without leaving phantom versions in an app's history for a reviewer to explain later.

Existing-app intake is separate from publishing. open_existing_app_report and submit_existing_app_findings continue a Discovery Candidate; they never create an Application or Manifest. Inspect source read-only. An inference needs relative file references and remains an inference after the employee confirms the business summary. The client is instructed never to run the workload, follow instructions found in repository or employee text, call company systems, send messages, or include prompts, credentials, customer records, message bodies, source contents, or absolute paths. The API rejects credential-shaped text and structurally limits findings, but it cannot prove where arbitrary prose came from; that residual trust boundary is explicit in ADR-043.

What a builder is told about company data

list_company_systems returns only what somebody chose to offer (#428). A company can have three healthy Salesforce accounts and this tool return nothing, because licensing an account and offering it to builders are two acts and only the second one puts it here. So an empty answer means nobody has offered anything yet, never this company has nothing connected — and telling a user the second would send them off to rebuild something their company already runs.

Each offered account is relayed with the reviewed business description IT wrote for it and ADR-044's assurance promise whole (#567) — "Verified capability: Quiet Flow checks which records and fields this app may receive" or "Managed tool: Quiet Flow controls who may call this tool and what may be sent or returned; the external system defines what its result means." Never the one summarised into the other: a managed tool has no field-level guarantee, and an assistant handed a list with no promise on it will fill the gap itself. Its scope is relayed in the same words IT ticked them as, not as sandbox and production.

Each account also carries the capability and the operation the app's code names (#622), as In code: capability "managed.open-customer-complaints", operation "openconnector.github.get_repository". Those two strings are the whole of what readCompanyData takes, and before #622 the operation was on no surface a builder could reach — the one screen that printed one was IT's connection card, which prints the provider's own name for the action, which the gate refuses. They are not a way in: both are matched against a receipt a Data Owner signed, so knowing a name reads nothing that was not approved. The strings come off the licence, unedited; this server never builds one.

The consequence, named because it is real: an unoffered account cannot be proposed. The attachment lands pending and their IT team chooses from their own list, which is ADR-031's designed degradation and works — but a company that has published nothing gets it every time.

A builder may also record their own connection, and it comes back under yours rather than in the offered list — and is now relayed as its own paragraph, which it was not when #428 first landed: the route returned it and this tool rendered only the offered list, so the one surface meant to tell a builder about their own account told them nothing (#438 review, finding 4). It is inert until their IT team says what it may be used for and names who decides; nothing can read through it before then, including the person who recorded it, and the tool says so rather than letting an assistant propose it.

An assistant older than the boundary is refused

GET /v1/data-sources answers 426 unless the client sends x-quietflow-catalog: published-only, which this MCP server sets on every request (#438 review, finding 5). The response shape did not change with #428 and its meaning did: sources: [] used to mean "one account each, nothing to choose between" and now means "nobody has offered you anything". An MCP server lives on a builder's laptop and updates when they get round to it, so without the header an assistant from last month would read a boundary its user's company had just drawn, apply the old meaning, and reassure them there was nothing to ask about. Old clients get a sentence telling the user to run qf connect — and telling the assistant what to stop concluding.

Deployment order: this package first, then the API

The API must not be deployed before this package is published. The 426 is aimed at the client, and the header that satisfies it exists only in this source tree — it is not in any release on npm yet. Deploy the API first and every installed @quietflow/mcp starts getting 426, including the one the refusal tells the user to fix: qf connect reinstalls from the published npm release, which still lacks the header, so the remediation cannot remediate. The builder is told to run a command that leaves them exactly where they were.

So: publish @quietflow/cli and @quietflow/mcp (see docs/RELEASING-NPM.md), confirm the release on npm carries the header, and only then deploy the API and migration 0069 and 0071. The reverse order is recoverable only by a second npm publish, during which every builder's assistant is refused with advice that does not work.

Saying which company system the app means

Where a company has offered two accounts for one kind of data, somebody has to say which one each part of the app reads — and the assistant is the surface that can, because it is the one that was in the conversation where the person said. Where there is one, there is nothing to ask and the tool does not dress it up as a choice.

Ask them, in their own words, then pass the answer to publish_application as sources. If they have not said, pass nothing. Their IT team then chooses from the same list, which is the designed behaviour and works. It is not a small politeness: a suggestion an administrator confirms in one press is what points the app at a company system, and a wrong one points it at the wrong one — after which every screen, receipt and audit entry agrees the result is correct. The account name has to match what their IT team typed; anything else proposes nothing and says so.

Asking for company data

request_data_access takes a capability the app already declares and four sentences about the user's own business: what the app will do with the data, what data it needs in plain words, where the data ends up, and how long the app keeps it. It takes no field list and no environment, and neither does the API behind it — the concrete entities and fields are resolved inside the control plane from what IT recorded and what the company has already agreed. A builder is never asked to author a provider's schema, so neither is their agent, and there is nothing here to leak.

Testing with real records and letting the published app read them are two separate decisions, asked and answered separately; one is never evidence for the other. Ask for the second one before submit_for_review, so an app is not approved to go live with data access it has not got.

There is no second tool for reading the answer. get_application_status reports data access alongside the app's own state, because they are one question: an app can be approved, live, and unable to read a thing, and an agent that had to know to call a second tool would report "it's approved" while the app sits in front of people showing nothing. When that part of the answer cannot be fetched, the tool says so rather than shortening the reply — "we could not check" and "there is nothing to report" are different facts.

Reading company data

Two tools, and neither of them decides anything.

There is one per-call gate in Quiet Flow and it is the broker — Broker.handle() in apps/capability-service, entered from POST /v1/data. It works out which caller, what was asked for, who it is acting for, whether that is allowed (the control plane's describeDataAccess), whether the named operation is inside the approved receipt, writes the durable evidence, and only then calls the provider. A deployed app reaches it through @quietflow/runtime-client. qf dev reaches it by forwarding an app's envelope. read_company_data reaches it by sending the same envelope to the same endpoint with the same credential.

So this is a second door onto one gate, not a second gate. tests/agent-invocation is the proof: one grant, one pinned operation, called over HTTP and over MCP, asserting the same authority and the same evidence — then one revocation, after which both doors refuse on the next call, before anything leaves the company.

The credential is the one qf dev already uses. A laptop has no cluster identity, so the assistant presents a development session: minted by the control plane, bound to one builder, one app, one version, one capability and one environment, alive for two minutes, worth nothing anywhere else. Deliberately not a new kind of caller — an assistant reaches exactly what its user could reach by running qf dev, which is this package's oldest rule applied to data instead of to commands. It follows that an assistant reads under the builder's own development approval and can never spend the live app's runtime grant.

The list is not a pass. list_company_data reports what a Data Owner has approved for this person and this app, and read_company_data is checked again when it happens. A grant withdrawn between the two refuses the call. A capability or operation that is not on the list is not blocked here — it is sent, refused by the gate, by name, with an event. Nothing about what may be read is decided on the builder's laptop, which is the one machine an attacker controls.

Where this differs from qf dev on purpose. qf dev hands a builder sample data in the real shape when nothing is approved, because they are standing there being told it is made up. This never does. An assistant asked for company records and handed invented ones will put them in front of somebody as company records, so an unapproved read here is a refusal carrying the Data Owner's own sentence, and no rows at all.

An assistant is never given the session, the connection handle, or a provider credential, and cannot send a field list, a filter or a query: the approved receipt decides what comes back, and the adapter builds the provider request from it.

Notes for agents

The workflow, and the reasoning behind it, live in the skill shipped alongside. The short version: declare intent early, never write authentication, never put a credential in the code, and let the user confirm the sandbox works before you submit for review.