Nanostores Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Nanostores Mcp (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<img align="right" width="92" height="92" title="Nano Stores logo" src="https://nanostores.github.io/nanostores/logo.svg">
Model Context Protocol server for Nanostores — analyze, debug and monitor your nanostores in AI assistants like Claude Desktop.
@nanostores/logger, performance metrics, activity trackingnpx nanostores-mcpAsk your AI: _"Analyze my store architecture"_ or _"Which stores update most frequently?"_
<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" /> Made at <b><a href="https://evilmartians.com/devtools?utm_source=nanostores-mcp&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.
Understand your nanostores architecture without running your app:
.subscribe() / .listen() calls and component bindings across React, Vue, Svelte, and Angular<script> and <script setup> blocks in .vue files (requires @vue/compiler-sfc)<script context="module"> and instance <script> blocks, auto-subscriptions ($storeName in templates), and filters out Svelte 5 runes ($state, $derived, $effect, etc.) so they are not mistaken for store references (requires svelte)@nanostores/angular NanostoresService constructor injections and detects this.nanostores.useStore(...) call patterns in TypeScript component filesReal-time insights into your running application:
@nanostores/loggerSearch and browse Nanostores documentation directly from your AI assistant:
nanostores in your node_modules automatically| Requirement | Version | ||
|---|---|---|---|
| Node.js | `^20.0.0 \ | \ | >=22.0.0` |
Required peer dependency (for static analysis):
npm install nanostoresOptional peer dependencies — install only if you use the corresponding file format:
| Package | When needed |
|---|---|
@vue/compiler-sfc | Vue SFC (.vue) file scanning |
svelte | Svelte (.svelte) file scanning |
@nanostores/logger | Runtime monitoring (attachMcpLogger) |
Without these optional packages the server still works — it silently skips unsupported file types.
npm install -g nanostores-mcp
# or
pnpm add -g nanostores-mcpOr run directly without installation:
npx nanostores-mcpAdd to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"nanostores": {
"command": "npx",
"args": ["-y", "nanostores-mcp"],
"env": {
"NANOSTORES_MCP_ROOT": "/path/to/your/project"
}
}
}
}Requires GitHub Copilot extension (VS Code 1.99+). Create .vscode/mcp.json in your project:
{
"servers": {
"nanostores": {
"type": "stdio",
"command": "npx",
"args": ["-y", "nanostores-mcp"]
}
}
}Tools are available in Copilot's Agent mode (select "Agent" in the Copilot Chat dropdown).
Create .cursor/mcp.json in your project root (or ~/.cursor/mcp.json for global):
{
"mcpServers": {
"nanostores": {
"command": "npx",
"args": ["-y", "nanostores-mcp"]
}
}
}Add to your Zed settings.json:
{
"context_servers": {
"nanostores": {
"command": "npx",
"args": ["-y", "nanostores-mcp"],
"env": {
"NANOSTORES_MCP_ROOT": "/path/to/your/project"
}
}
}
}The server appears in Zed's Agent Panel settings.
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"nanostores": {
"command": "npx",
"args": ["-y", "nanostores-mcp"],
"env": {
"NANOSTORES_MCP_ROOT": "/path/to/your/project"
}
}
}
}You can also open this file from the MCP icon in the Cascade panel → "Configure".
Add via CLI:
claude mcp add --transport stdio nanostores -- npx -y nanostores-mcpOr create .mcp.json in your project root (shared with the team):
{
"mcpServers": {
"nanostores": {
"command": "npx",
"args": ["-y", "nanostores-mcp"],
"env": {
"NANOSTORES_MCP_ROOT": "/path/to/your/project"
}
}
}
}| Variable | Default | Description |
|---|---|---|
NANOSTORES_MCP_ROOT | cwd | Project root path |
NANOSTORES_MCP_ROOTS | — | Platform-delimited roots (: on Unix, ; on Windows) for multi-project setup |
WORKSPACE_FOLDER | — | Alias for NANOSTORES_MCP_ROOT — set automatically by VS Code and some editors |
WORKSPACE_FOLDER_PATHS | — | Alias for NANOSTORES_MCP_ROOTS — set automatically by some editors |
NANOSTORES_MCP_LOGGER_ENABLED | true | Set to false or 0 to disable runtime event collection and the logger bridge |
NANOSTORES_MCP_LOGGER_PORT | 3999 | HTTP port for logger bridge |
NANOSTORES_MCP_LOGGER_HOST | 127.0.0.1 | Host to bind. Allowed values: 127.0.0.1, localhost, ::1 |
NANOSTORES_DOCS_ROOT | auto-detect | Path to documentation directory |
NANOSTORES_DOCS_PATTERNS | **/*.md | Comma-separated glob patterns for docs |
The server picks workspace roots in priority order:
NANOSTORES_MCP_ROOTS / NANOSTORES_MCP_ROOT / WORKSPACE_FOLDER_PATHS / WORKSPACE_FOLDERroots/list capability (set automatically by some editors)process.cwd() used as fallback when neither env nor client roots are configuredWhen a tool is called without an explicit projectRoot argument the server uses the first configured root. In a multi-root setup always pass projectRoot to avoid ambiguity.
Works out of the box — just point at your project and ask:
Auto-detected from nanostores in your node_modules:
Requires logger integration in your app. See Runtime Monitoring below.
Run these four tools in order to confirm everything is working:
nanostores_ping → should return server status and logger bridge state
nanostores_scan_project → should list your stores and subscribers
nanostores_docs_search → should return documentation results (requires nanostores in node_modules)
nanostores_runtime_overview → should return overview (or "no runtime data" if logger is disabled — that's fine)If nanostores_scan_project returns zero stores, check that NANOSTORES_MCP_ROOT points to the correct project directory.
| Resource | Description |
|---|---|
nanostores://graph | Full dependency graph (text + Mermaid) |
nanostores://store/{key} | Store details by name or id |
nanostores://docs | Documentation index — all pages and tags |
nanostores://docs/page/{id} | Full content of a documentation page |
Static Analysis
| Tool | Description |
|---|---|
nanostores_scan_project | Scan project for all stores, subscribers, and dependencies |
nanostores_store_summary | Detailed summary of a specific store |
nanostores_project_outline | High-level overview: store kinds, top directories, hub stores |
nanostores_store_subgraph | BFS-expanded dependency neighborhood of a store |
nanostores_store_impact | Downstream causal chain — what recomputes/re-renders if X changes |
Runtime Monitoring
| Tool | Description |
|---|---|
nanostores_runtime_overview | Overall health report with statistics for all stores |
nanostores_store_activity | Activity timeline for a specific store (filterable by kind/action) |
nanostores_find_noisy_stores | Identify stores with high change frequency or error rates |
nanostores_runtime_coverage | Compare static graph with runtime events to find coverage gaps |
Documentation
| Tool | Description |
|---|---|
nanostores_docs_search | Search docs by query (full-text), storeKind (atom, map, computed, persistentAtom, etc.), or both. Optional: limit (default 10), tags |
Use nanostores://docs/page/{id} resource to read the full content of pages returned by search.
Utilities
| Tool | Description |
|---|---|
nanostores_ping | Server health check and logger bridge status |
nanostores_clear_cache | Clear project index cache to force rescan |
| Prompt | Parameters | Description |
|---|---|---|
explain-project | focus _(optional)_ | AI-guided explanation of your project's store architecture. focus narrows to a feature/domain (e.g. "cart", "auth") |
explain-store | store_name _(required)_ | Deep dive into a specific store's implementation and usage |
debug-store | store_name _(required)_ | Comprehensive analysis combining static + runtime data |
debug-project-activity | — | Project-wide performance analysis and optimization |
docs-how-to | task _(required)_ | Step-by-step guidance for a Nanostores task, backed by docs (e.g. "How do I sync a map store to localStorage?") |
Most tools accept these optional arguments that significantly change their behavior:
| Argument | Type | Used in | Description |
|---|---|---|---|
storeId | string | store_summary, store_subgraph, store_impact | Exact store identifier — format: store:src/stores.ts#$counterName. Takes priority over name when both are provided. |
name | string | store_summary, store_subgraph, store_impact | Store name (e.g. "$user"). Used when storeId is not provided. |
radius | number (0–10, default 2) | nanostores_store_subgraph | BFS hops around the store. 1 = direct deps only; 2 = deps of deps. Warning: on highly-connected hub stores (hub score > 5) radius ≥ 2 may return most of the project — start with 1. |
projectRoot | string | most tools | Which project root to analyze in multi-root setups. Omit to use the first configured root. Always specify this in multi-root projects. |
windowMs | number | store_activity, find_noisy_stores, runtime_overview | Look-back window in milliseconds (e.g. 60000 = last 60 s). Filters events to that time range. |
kinds | string[] | nanostores_store_activity | Filter events by type. Values: "mount", "unmount", "change", "action-start", "action-end", "action-error". |
actionName | string | nanostores_store_activity | Filter events to a specific action (e.g. "increment"). |
compact | boolean | scan_project, find_noisy_stores, runtime_overview | Return a compressed token-efficient table instead of full text. Useful for large projects to reduce context usage. |
For runtime analysis, integrate the MCP Logger client into your application.
1. Install in your app and enable the logger bridge:
npm install nanostores-mcpThe logger bridge starts automatically — no extra config needed. To disable it, set NANOSTORES_MCP_LOGGER_ENABLED=false in your MCP server config.
2. Define stores with logger attached (src/stores.ts):
import { atom, map, computed } from "nanostores";
import { initMcpLogger, attachMcpLogger } from "nanostores-mcp/mcpLogger";
// Automatically disabled in production (checks NODE_ENV / import.meta.env.DEV)
initMcpLogger();
// Stores
export const $count = atom(0);
export const $user = map({ name: "", role: "guest" });
export const $greeting = computed($user, user => `Hello, ${user.name}`);
// Attach logger — each call returns a cleanup function
attachMcpLogger($count, "$count");
attachMcpLogger($user, "$user");
attachMcpLogger($greeting, "$greeting");3. Use stores normally — events (mount, unmount, change, actions) are captured automatically and batched to the MCP server every second.
4. Ask your AI assistant:
nanostores_find_noisy_storesnanostores_store_activitynanostores_runtime_overviewinitMcpLogger({
url: "http://127.0.0.1:3999/nanostores-logger", // default; change if using a custom port
batchMs: 1000, // default; lower for faster delivery (e.g. 200)
projectRoot: "/absolute/path/to/project", // link runtime events with static analysis
// Mask sensitive data — return null to skip event entirely
maskEvent: event => {
if (event.storeName === "authToken") return null;
return event;
},
});import { getMcpLogger } from "nanostores-mcp/mcpLogger";
window.addEventListener("beforeunload", async () => {
await getMcpLogger()?.forceFlush();
});`nanostores_runtime_overview` health summary
The overview groups stores into three categories:
action-error events. High error counts indicate failing async actions.`nanostores_runtime_coverage`
Compares your static store graph against observed runtime events:
| Term | Meaning |
|---|---|
| static-only | Store found by AST scan but no runtime events observed. Possible dead code, deferred initialization, or missing attachMcpLogger call. |
| runtime-only | Events received for a store not found by the scanner. Common for dynamically-created stores, factory patterns, or stores in node_modules. |
| Coverage by kind | E.g. atom: 3/5 (60%) — 3 out of 5 atom stores received runtime events. 0% for a kind usually means attachMcpLogger was not called for those stores. |
`nanostores_find_noisy_stores`
Returns stores ranked by total activity (changes + actions combined) within the windowMs period. A store is considered "noisy" when its change frequency is disproportionately high relative to visible UI updates — use this to find re-render hotspots or thrashing computed chains.
The runtime logger is designed to stay on your local machine:
127.0.0.1, localhost, or ::1. Binding to 0.0.0.0 is explicitly blocked. Data never leaves your machine.maskEvent to filter or redact events client-side before they are batched and sent:initMcpLogger({
maskEvent: event => {
if (event.storeName === "$authToken") return null; // drop entirely
if (event.storeName === "$paymentInfo") return { ...event, newValue: undefined }; // strip value
return event;
},
});Ask your AI assistant natural language questions:
Static Analysis:
Runtime Debugging:
With [Playwright MCP](https://github.com/microsoft/playwright-mcp):
Documentation:
┌──────────────────────┐
│ Your Application │
│ │
│ @nanostores/logger │
│ events │
└──────────┬───────────┘
│ HTTP POST (localhost:3999)
▼
┌──────────────────────┐
│ nanostores-mcp │
│ │
│ ┌──────────────┐ │
│ │ Logger Bridge │ │ ← HTTP server for runtime events
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Event Store │ │ ← Ring buffer (5000 events) + stats
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ AST Scanner │ │ ← ts-morph static analysis
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Docs Index │ │ ← Auto-detected from node_modules
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ MCP Interface│ │ ← Resources, Tools, Prompts
│ └──────────────┘ │
└──────────┬───────────┘
│ MCP Protocol (stdio)
▼
┌──────────────────────┐
│ LLM Client │
│ (Claude, VS Code, …) │
└──────────────────────┘Multi-root: same store name in multiple projects
In multi-root mode a store named $user can exist in two different projects. The runtime event store uses a composite key (projectRoot + storeName) to keep them separate, but summary views may show the same name twice with no project label. Always specify projectRoot when querying tools in a multi-root setup to get unambiguous results.
Static analysis only covers discovered files
The AST scanner follows TypeScript/JavaScript imports from your project root. Stores created dynamically at runtime, generated by factories, or living in node_modules will not appear in static results — they may show up as "runtime-only" in coverage reports.
Vue and Svelte parsing requires optional dependencies
If @vue/compiler-sfc or svelte are not installed, .vue / .svelte files are silently skipped during scanning. Install them as dev dependencies if you want full coverage for those file types.
Event ring buffer is capped at 5 000 events
Older events are dropped when the buffer is full. For high-frequency stores use windowMs to narrow your queries to recent data, or lower batchMs in initMcpLogger to deliver events more frequently and reduce the chance of buffer overflow during bursts.
`radius` on hub stores can be very large
Stores with many dependencies (hub score > 5) can return most of the project graph at radius=2. Start with radius=1 and increase only if you need broader context.
git clone https://github.com/Valyay/nanostores-mcp.git
cd nanostores-mcp
pnpm install
pnpm dev # Run dev server
pnpm build # TypeScript compile
pnpm test # Run vitest
pnpm lint # ESLint
pnpm check # All checks: lint + format + test + build
# Test with MCP Inspector
npx @modelcontextprotocol/inspector pnpm run devLogger not receiving events:
ping tool to verify logger bridge is enabled and running[nanostores-mcp] warnings about connection issuesNANOSTORES_MCP_LOGGER_PORT) and client URLPort conflicts:
# Change server port
NANOSTORES_MCP_LOGGER_PORT=4000 npx nanostores-mcp
# Update client
initMcpLogger({ url: "http://127.0.0.1:4000/nanostores-logger" });TypeScript errors:
// Import from the mcpLogger subpath export
import { initMcpLogger, attachMcpLogger } from "nanostores-mcp/mcpLogger";Documentation not found:
nanostores in your node_modulesnanostores is installed: npm install nanostoresNANOSTORES_DOCS_ROOT to point at a docs directory manuallyNanostores ecosystem:
MCP:
MIT
Contributions are welcome! Please open an issue or PR.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.