d7eeem

MCP Dockhand

Community d7eeem
Updated

MCP Server for Dockhand Docker Management - exposes 130+ API endpoints as MCP tools

MCP Dockhand

CILicense: MITDocker

An MCP (Model Context Protocol) server that exposes the Dockhand API as MCP tools. Manage your entire Docker infrastructure through AI assistants.

API coverage: 88.7% of in-scope Dockhand endpoints (282/318) have an MCP tool — see docs/coverage.md for the full, auto-updated breakdown by area.

Dockhand is a Docker management server that connects to multiple Docker hosts via Hawser agents. This MCP server provides full programmatic access to all Dockhand features.

Features

  • 280+ MCP Tools covering the Dockhand API — see docs/coverage.md for exact, auto-updated coverage
  • Streamable HTTP Transport (MCP Spec 2025-03-26) for Docker container hosting
  • Session-based Auth with auto-relogin on 401
  • SSE Support for deploy operations (start, stop, down, restart)
  • Environment Filter enforced on all container/stack/image/network/volume endpoints
  • Docker Ready with multi-stage build, non-root user, and health checks

Quick Start

Docker (recommended)

docker run -d \
  --name mcp-dockhand \
  -p 8080:8080 \
  -e DOCKHAND_URL=https://your-dockhand-server.com \
  -e DOCKHAND_USERNAME=your-username \
  -e DOCKHAND_PASSWORD=your-password \
  ghcr.io/strausmann/mcp-dockhand:latest

Docker Compose

services:
  mcp-dockhand:
    image: ghcr.io/strausmann/mcp-dockhand:latest
    container_name: mcp-dockhand
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - DOCKHAND_URL=https://your-dockhand-server.com
      - DOCKHAND_USERNAME=your-username
      - DOCKHAND_PASSWORD=your-password

From Source

git clone https://github.com/strausmann/mcp-dockhand.git
cd mcp-dockhand
npm install
npm run build
DOCKHAND_URL=https://your-server.com DOCKHAND_USERNAME=admin DOCKHAND_PASSWORD=secret npm start

Configuration

Variable Required Default Description
DOCKHAND_URL Yes - Dockhand server URL
DOCKHAND_USERNAME Yes - Dockhand username
DOCKHAND_PASSWORD Yes - Dockhand password
MCP_PORT No 8080 Port for the MCP server
MCP_SESSION_TTL_SECONDS No 1800 Inactivity timeout before a retained MCP session is expired
MCP_SESSION_CLEANUP_INTERVAL_SECONDS No 300 Interval for removing expired sessions (clamped to the session TTL)
MCP_MAX_SESSIONS No 0 Maximum retained sessions; 0 keeps the existing unlimited behavior
MCP_HOST No 0.0.0.0 Listen address. Kept as the wildcard address by default so the published Docker port (-p 8080:8080 / docker-compose.yml) keeps working; see Securing the transport for the recommended way to protect the endpoint instead of binding loopback-only
MCP_ALLOWED_HOSTS No (unset — Host check disabled) Comma-separated Host header allowlist for /mcp (DNS-rebinding protection). Opt-in: unset means no Host check at all (pre-existing behavior, so existing deployments aren't broken by an update). Recommended once you set it up — see Securing the transport
MCP_ALLOWED_ORIGINS No (unset — Origin check disabled) Comma-separated Origin header allowlist for /mcp. Opt-in, same as above. Only enforced when a caller actually sends an Origin header at all (non-browser MCP clients typically don't)
MCP_AUTH_TOKEN No (unset — endpoint unauthenticated) Shared secret required as Authorization: Bearer <token> on every /mcp request. Opt-in; recommended once the endpoint is reachable beyond your own loopback — see Securing the transport
LOG_LEVEL No info error, warn, info or debug. debug adds one line per Dockhand request (method, endpoint template, status, duration). For requests through the client the duration spans the full response body and a bytes body-size field is added; the login and self-check probes (which bootstrap the client and so can't route through it) log time-to-headers without a bytes field. Never a path segment or a parameter value. An unrecognised value warns and falls back to info.
TRUSTED_PROXIES No (empty) Comma-separated addresses or CIDRs allowed to set X-Forwarded-For / X-Real-IP, e.g. 10.0.0.0/8, 100.64.0.0/10. Empty means the headers are ignored and the peer address is used.

Securing the transport

/mcp binds 0.0.0.0:8080 by default (see MCP_HOST above), and out of the box — with none ofMCP_ALLOWED_HOSTS, MCP_ALLOWED_ORIGINS, or MCP_AUTH_TOKEN set — it accepts any requestwith no Host/Origin check and no authentication. This is the same behavior mcp-dockhandhas always had, kept as the default deliberately: enabling a check by default would rejectrequests from any client that doesn't reach the server as localhost/127.0.0.1 (a LAN IP, areverse proxy, a Docker network alias), breaking existing deployments on a routine update.

You should turn this on once /mcp is reachable beyond your own machine's loopback interface— the server holds one Dockhand admin credential and every tool call acts with that identity, soanyone who can open an MCP session controls Docker (container exec, host bind-mounts viacreate_container, file read/write, stored git credentials). With no protection configured, theserver logs a [security] WARNING at startup as a reminder. Three independent, all-opt-in layersare available:

  1. Host allowlist (MCP_ALLOWED_HOSTS). Once set to a non-empty value, every request to/mcpPOST, GET, and DELETE — is rejected with 403 unless its Host header matchesthe allowlist. This is the primary defense againstDNS-rebinding: a malicious web page cannot makethe operator's browser reach the server under a Host value the allowlist accepts. Set it tohowever your client actually reaches the server — localhost:8080/127.0.0.1:8080 for thedocumented local setup, or, if you connect directly by address rather than throughlocalhost (including the mcp-proxy remote-server setup below), the exact host:port yourclient sends, e.g. 100.100.50.40:8222. Get this wrong and every request is rejected with403 Invalid Host header — check the message, it echoes the Host value it saw.
  2. Origin allowlist (MCP_ALLOWED_ORIGINS). Once set, any request that does send anOrigin header not in the list is rejected with 403. A missing Origin header always passes(the SDK's own MCP client and most non-browser tooling never send one), so this is only usefulif a browser-based client talks to /mcp directly; the Host allowlist above is what actuallystops DNS-rebinding.
  3. Bearer token (MCP_AUTH_TOKEN). Once set, every /mcp request must carryAuthorization: Bearer <token> or is rejected with 401; the comparison is constant-time.Recommended alongside the Host allowlist for any deployment reachable from more than theoperator's own machine.
# .env — recommended configuration once /mcp is reachable beyond loopback
MCP_ALLOWED_HOSTS=dock-mcp.internal.example.com
# or, connecting directly by address instead of a hostname:
#MCP_ALLOWED_HOSTS=100.100.50.40:8222
MCP_AUTH_TOKEN=<a long random secret, e.g. `openssl rand -hex 32`>

Securing the server with CrowdSec

The server writes an nginx-format access line to stdout for every request,including the ones it rejects, while the structured application log goes tostderr. CrowdSec parses the access lines with its stock collections — no customparser required.

Add an acquisition file on the host running your CrowdSec agent:

source: docker
container_name:
  - mcp-dockhand
labels:
  type: docker
  program: nginx-mcp

Both labels are required, and neither fails loudly if you forget it.type: docker enables crowdsecurity/docker-logs, which unwraps Docker's JSONenvelope. program: nginx-mcp enables crowdsecurity/nginx-logs, which matches onprogram starting with nginx — the -mcp suffix keeps this source distinguishablefrom your other nginx sources. With one label missing the chain simply producesnothing, and nothing reports it.

Once wired up, the stock scenarios apply:

Scenario What it means here
LePresidente/http-generic-401-bf Repeated 401 on /mcp — someone is guessing MCP_AUTH_TOKEN
crowdsecurity/http-dos-swithcing-ua Request floods with rotating user agents

A 403 is worth watching too: it means a request failed the MCP_ALLOWED_HOSTS orMCP_ALLOWED_ORIGINS check, which is what a DNS-rebinding attempt looks like fromhere.

The stock 401 scenario only counts POST. Its filter isevt.Parsed.verb == 'POST' — one literal, not a list. This server serves POST, GETand DELETE on /mcp, and the bearer check runs ahead of all three, so a wrong tokenon GET /mcp or DELETE /mcp returns 401 exactly like POST does — andLePresidente/http-generic-401-bf never counts those. Someone guessingMCP_AUTH_TOKEN over GET /mcp is invisible to it.

This is a property of the upstream scenario, shared with every nginx deployment thatuses it — not something this server's log format can fix. To close it, add a localscenario that drops the verb filter, or matches the three methods this serveranswers on. Until then, treat the row above as "repeated 401 on POST /mcp".

Set TRUSTED_PROXIES before you enable this.Behind a reverse proxy every request arrives from the proxy's address. WithoutTRUSTED_PROXIES that address is what gets logged — so the first ban CrowdSecissues takes out the proxy, and with it every user behind it. Set it to theaddress or subnet your proxy talks from.

The setting is equally deliberate in the other direction: the forwarding headersare only honoured from a peer on that list. Trusting them unconditionally would letany direct caller name an arbitrary third party and have them banned.

One expected side effect: the structured JSON lines share the container's logstream and carry the same program label, so they fail the nginx pattern and countas unparsed in cscli metrics. That is noise, not a fault — no alert, no decision.

MCP Client Configuration

Claude Desktop / Claude Code

Add to your MCP settings:

{
  "mcpServers": {
    "dockhand": {
      "url": "http://localhost:8080/mcp"
    }
  }
}

If the server enforces a bearer token (MCP_AUTH_TOKEN set — seeSecuring the transport), the client must send it as anAuthorization header, or every request is rejected with 401. In Claude Code's.mcp.json, add a headers block — reference an environment variable so the tokennever lives in the (often version-controlled) config file:

{
  "mcpServers": {
    "dockhand": {
      "type": "http",
      "url": "http://your-server:8080/mcp",
      "headers": { "Authorization": "Bearer ${DOCKHAND_MCP_TOKEN}" }
    }
  }
}

Send the token only over an encrypted transport. A bearer over plain http:// on ashared network can be sniffed — terminate TLS at a reverse proxy, or reach the server overa WireGuard/Tailscale/VPN link (the app-layer HTTP is then encrypted by the tunnel).

Export DOCKHAND_MCP_TOKEN in the environment Claude Code is launched from (e.g. from agitignored .env you source before starting). The Host/host:port you connect tomust also be in the server's MCP_ALLOWED_HOSTS if that allowlist is set. For ClaudeDesktop (native config has no headers field), pass the token through the mcp-proxyworkaround below — mcp-proxy forwards an Authorization header via its ownenvironment/args.

Claude Desktop with a remote server (mcp-proxy)

Claude Desktop can fail to connect to a remote mcp-dockhand server (notlocalhost) using the native "url" config above, even though the endpointitself is reachable. The symptom is a generic "not a valid MCP server" errorin Claude Desktop, while a plain browser/curl request to the same URLcorrectly returns {"error":"Invalid or missing session ID"}. This is a knownlimitation of Claude Desktop with remote Streamable HTTP servers, not amcp-dockhand bug.

Workaround: wrap the connection withmcp-proxy, which translatesStreamable HTTP to stdio — a transport Claude Desktop handles reliably:

{
  "mcpServers": {
    "dockhand": {
      "command": "/path/to/mcp-proxy",
      "args": ["--transport", "streamablehttp", "http://your-server:8080/mcp"]
    }
  }
}

All tools load and work correctly through the proxy. Thanks to@deadrubberboy for reporting this andsharing the workaround (#90).

Tool Reference

Containers (27 tools)

Tool Description
list_containers List all containers in an environment
get_container Get container details
inspect_container Docker inspect (full details)
get_container_logs Get container logs
get_container_stats Get resource usage stats
get_container_top Get running processes
start_container Start a container
stop_container Stop a container
restart_container Restart a container
pause_container Pause a container
unpause_container Unpause a container
rename_container Rename a container
update_container Update container settings
create_container Create a new container
get_container_shells List available shells
exec_container Create a terminal exec session (execId + WS connectionInfo); does NOT run a one-shot command or return output — no such endpoint exists in the Dockhand API
list_container_files Browse files inside container
get_container_file_content Read file from container
create_container_file Create an empty file or directory in container (no content — use write_container_file_content for that)
delete_container_file Delete file in container
rename_container_file Rename file in container
chmod_container_file Change file permissions
check_container_updates Check for image updates
get_pending_updates Get pending updates
batch_update_containers Batch update containers
execute_batch Run a bulk lifecycle operation (start/stop/restart/remove/etc.) across containers, images, volumes, networks, or stacks
get_container_sizes Get container disk sizes
get_containers_stats Get aggregated stats

Stacks (21 tools)

Tool Description
list_stacks List all stacks
get_stack Get stack details
create_stack Create and optionally deploy a stack
start_stack Start a stack (compose up)
stop_stack Stop a stack (compose stop)
restart_stack Restart a stack
down_stack Take down a stack (compose down)
delete_stack Delete a stack
get_stack_compose Read compose file
update_stack_compose Update compose file
get_stack_env Read environment variables
update_stack_env Update environment variables (merge by default — safe for partial updates; use mode="replace" to overwrite all)
get_stack_env_raw Read raw .env file
validate_stack_env Validate env variables
scan_stacks Scan filesystem for stacks
adopt_stack Adopt an untracked stack
relocate_stack Move stack to new path
get_stack_sources Get stack sources
get_stack_base_path Get base path
get_stack_path_hints Get path suggestions
validate_stack_path Validate a stack path

Images (9 tools)

Tool Description
list_images List all images
get_image Get image details
get_image_history Get image layer history
tag_image Tag an image
remove_image Remove an image
pull_image Pull an image
push_image Push an image
scan_image Vulnerability scan (Trivy/Grype)
export_image Export image as tarball

Environments (18 tools)

Tool Description
list_environments List all environments
get_environment Get environment details
create_environment Create an environment
update_environment Update an environment
delete_environment Delete an environment
test_environment Test connection
test_environment_connection Test without saving
detect_docker_socket Auto-detect socket
get_environment_timezone Get timezone
set_environment_timezone Set timezone
get_environment_update_check Get update-check settings
set_environment_update_check Set update-check settings
get_environment_image_prune Get image prune settings
set_environment_image_prune Set image prune settings
list_environment_notifications List notifications
create_environment_notification Create notification
get_environment_notification Get notification
delete_environment_notification Delete notification

Networks (7 tools)

Tool Description
list_networks List all networks
get_network Get network details
inspect_network Inspect network
create_network Create a network
remove_network Remove a network
connect_container_to_network Connect container
disconnect_container_from_network Disconnect container

Volumes (9 tools)

Tool Description
list_volumes List all volumes
get_volume Get volume details
inspect_volume Inspect volume
browse_volume Browse files in volume
get_volume_file_content Read file from volume
release_volume_browse Release browse session
clone_volume Clone a volume
export_volume Export volume
remove_volume Remove volume (destructive)

Git Stacks (15 tools)

Tool Description
list_git_stacks List Git-based stacks
get_git_stack Get Git stack details
deploy_git_stack Deploy a Git stack (SSE)
sync_git_stack Sync with remote repo
test_git_stack Test Git connection
get_git_stack_env_files Get env files
trigger_git_webhook Trigger webhook
get_git_webhook Get webhook details
list_git_credentials List Git credentials
create_git_credential Create Git credential
get_git_credential Get credential details
update_git_credential Update credential
delete_git_credential Delete credential
list_git_repositories List Git repositories
create_git_repository Create repository config

Dashboard & Activity (8 tools)

Tool Description
get_dashboard_stats Get dashboard statistics
get_dashboard_preferences Get display preferences
set_dashboard_preferences Set display preferences
get_activity_feed Get activity feed
get_container_activity Container activity
get_activity_events Activity events
get_activity_stats Activity statistics
get_merged_logs Merged logs from containers

Auth & Hawser (12 tools)

Tool Description
get_auth_session Check session status
get_auth_providers List auth providers
get_auth_settings Get auth settings
create_oidc_provider Create OIDC provider
get_oidc_provider Get OIDC provider
test_oidc_provider Test OIDC provider
create_ldap_provider Create LDAP provider
get_ldap_provider Get LDAP provider
test_ldap_provider Test LDAP provider
list_hawser_tokens List Hawser tokens
create_hawser_token Create Hawser token
revoke_hawser_token Revoke Hawser token

Audit (4 tools)

Tool Description
get_audit_log Get audit log
get_audit_events Get audit event types
get_audit_users Audit data by user
export_audit_log Export audit log

Notifications (8 tools)

Tool Description
list_notifications List notifications
create_notification Create notification
get_notification Get notification
update_notification Update notification
delete_notification Delete notification
test_notification Test notification
test_notification_config Test without saving
trigger_test_notification Trigger a real test event for a given event type + payload

Registries (10 tools)

Tool Description
list_registries List registries
create_registry Add registry
get_registry Get registry details
update_registry Update registry
delete_registry Delete registry
set_default_registry Set as default
search_registry Search registry
get_registry_catalog Get catalog
get_registry_image Get image from registry
get_registry_tags Get image tags

System & Settings (19 tools)

Tool Description
health_check Server health
health_check_database Database health
get_host_info Host information
get_system_info System information
get_system_disk Disk usage
list_system_files List system files
get_system_file_content Read system file
get_changelog Changelog
get_dependencies Dependencies
get_general_settings General settings
update_general_settings Update settings
get_theme_settings Theme settings
update_theme_settings Update theme
get_scanner_settings Scanner settings
update_scanner_settings Update scanner
get_license License info
activate_license Activate license by name and key
get_prometheus_metrics Prometheus metrics
prune_all Prune all resources

Users, Roles & Preferences (20 tools)

Tool Description
list_users List users
create_user Create user
get_user Get user details
update_user Update user
delete_user Delete user
get_user_mfa_status MFA status
enable_user_mfa Enable MFA
disable_user_mfa Disable MFA
get_user_roles Get user roles
add_user_role Assign one role to a user (no bulk-replace)
remove_user_role Unassign one role from a user
list_roles List roles
create_role Create role with name + permissions object
get_role Get role
update_role Update role
delete_role Delete role
get_profile Get own profile
update_profile Update own profile
get_favorites Get favorites
set_favorites Set favorites
list_config_sets List config sets

Schedules (9 tools)

Tool Description
list_schedules List schedules
get_schedule_settings Get settings
update_schedule_settings Update settings
get_schedule_executions Execution history
get_schedule_execution Execution details
get_schedule Get schedule
run_schedule_now Run immediately
toggle_schedule Enable/disable
toggle_system_schedule Toggle system schedule

Auto-Update (3 tools)

Tool Description
get_auto_update_settings Get all auto-update settings
get_container_auto_update Get container auto-update
set_container_auto_update Set auto-update policy

Self-help / meta tools (6 tools)

Diagnostics for this MCP server itself, distinct from the Dockhand API tools above —useful for a client or operator asking "is this server healthy and correctly configured?"rather than "is Dockhand healthy?". None of these six take any input arguments, and none ofthem wrap a single Dockhand endpoint the way the tables above do (get_tool_manifest andget_runtime_stats call no Dockhand endpoint at all) — see src/tools/meta.ts.

Tool Description
get_server_info This server's own version, git SHA, build date, uptime, MCP protocol version, and the Dockhand URL/server version it's connected to
check_for_update Compares this server's running version against the latest GitHub release (TTL-cached)
get_tool_manifest Lists every registered tool with its Dockhand {method, path}, plus the pinned Dockhand OpenAPI commit/version this server's tools were generated against
self_check End-to-end diagnostic: Dockhand reachability, credential validity, and a live, per-environment reachability check (POST /api/environments/{id}/test, run in parallel with a 5s per-environment timeout) plus Hawser-agent-connected status, in one call
validate_config Checks that the required DOCKHAND_URL/DOCKHAND_USERNAME/DOCKHAND_PASSWORD env vars are present and that they authenticate successfully
get_runtime_stats In-process counters for this server: total/per-tool call and error counts, uptime, and the last error's tool/message/timestamp

Notes:

  • check_for_update needs outbound network access to api.github.com (GitHub's releasesAPI) — it will degrade to updateAvailable: null rather than fail if that's unreachable.
  • No meta tool exposes any secret value. validate_config reports only whether therequired env vars are present (booleans) and whether they authenticate (a boolean +the raw HTTP status code, e.g. 200/401) — never the credential values themselves.self_check reports auth validity the same way. get_runtime_stats' lastError carriesonly a tool name, an error message, and a timestamp — never call arguments or responsepayloads. That error message is not fully opaque, though: for a failed Dockhand APIcall it can embed a slice of the upstream HTTP status and response body (viaDockhandClient's own Dockhand API error: ... returned <status>: <body> message), andit is echoed to whichever MCP client next calls get_runtime_stats — not necessarily theone that hit the original error. It never includes request bodies or credential values,and it is truncated to 500 characters (with an ellipsis marker) before being stored, so anoversized upstream response is never echoed wholesale.

Important Notes

update_stack_env — Merge vs Replace Semantics

The Dockhand REST endpoint PUT /api/stacks/{name}/env has replace-semantics: submitting a partial list of variables silently deletes all other variables from the stack. A single-variable update would wipe everything else.

To prevent accidental data loss, this MCP tool defaults to merge mode:

  1. It fetches the current variable list via GET /api/stacks/{name}/env.
  2. It merges the incoming variables by key (new values overwrite existing ones on key collision).
  3. It writes the full combined list back via PUT.
# Safe partial update — only MY_VAR changes, all others preserved
update_stack_env(environmentId=1, name="my-stack", variables=[{key: "MY_VAR", value: "new"}])

# Explicit full replacement — all other variables are deleted
update_stack_env(environmentId=1, name="my-stack", variables=[...], mode="replace")

Use mode="replace" only when you intentionally want to replace the entire variable set.

Environment ID is Required

Most Docker resource endpoints (containers, stacks, images, networks, volumes) require an environmentId parameter. This maps to the ?env=<id> query parameter in the Dockhand API. Without it, endpoints return empty arrays.

SSE Responses

Deploy operations (start, stop, down, restart, compose update with restart) return Server-Sent Events. The MCP server automatically parses these and returns the final result.

Authentication

The server uses session-based cookie authentication. It automatically:

  • Logs in on first request
  • Stores the session cookie in memory
  • Re-authenticates on 401 responses
  • Handles session timeout (24h)

Troubleshooting

Start with LOG_LEVEL=debug. Every Dockhand request then appears with its endpoint,status code and duration, and every line of a single call shares onecall identifier — grep for it to get the whole sequence. The req identifierties those lines back to the access line that started them, and sid coverseverything one client did across its whole session. For requests through the client, ms is the full requestduration — it spans the response body being read, not just the time until theresponse headers arrived, so it reflects what a slow or stalled streamedresponse (e.g. a deploy's SSE output) actually cost — and bytes is the size of thebody that was actually read. (The login and self-check probes bootstrap the client and can't route through it, so their lines log time-to-headers without a bytes field.) A failed Dockhand request additionally logs awarn line carrying errType — the exception name (e.g. TimeoutError, TypeError),a bounded vocabulary rather than free text — so you can filter failures by errortype. That warn line fires both when the request itself failed before anyresponse arrived, and when a response body's read failed partway through (e.g.an SSE stream hitting its timeout mid-stream) — either way ms reflects howlong it took to fail.

Development

# Install dependencies
npm install

# Type check
npm run typecheck

# Build
npm run build

# Run in development mode
DOCKHAND_URL=https://your-server.com \
DOCKHAND_USERNAME=admin \
DOCKHAND_PASSWORD=secret \
npm run dev

Linting

npm run lint lints src/ and tests/ with two rules: no-unused-vars andno-explicit-any. Because typescript-eslint does not support the pinnedtypescript@^7.0.2 compiler — it hard-throws on TS 7.0, not just a peer warning: seetypescript-eslint#10940— the lint runs inside a throwaway node:22 container with pinned TypeScript 5 (thelanguage is identical across TS 5/6/7; only the compiler differs). It mounts src/,tests/ and eslint.config.js read-only, so Docker is required to run it. The samescript runs as a hard gate in CI. Unused imports/locals are additionally caught natively onTS 7 by tsc (noUnusedLocals/noUnusedParameters in tsconfig.tests.json, vianpm run typecheck:tests).

License

MIT

MCP Server · Populars

MCP Server · New

    mobbin

    Official Mobbin MCP server

    Official Mobbin MCP server repository

    Community mobbin
    frankchu91

    MindBase — Karpathy's LLM Wiki, as a product

    Karpathy's LLM Wiki idea as a product — an AI that builds and maintains a markdown wiki from your notes and sources. MCP server + web UI, runs on free local models (Ollama), no API key needed. MIT.

    Community frankchu91
    aakarim

    📜 OpenLore

    A minimal, extensible, agent-native knowledge base that keeps shared context current and inspectable

    Community aakarim
    sv-grid

    @svgrid/mcp

    Native Svelte 5 data grid. Headless-first engine + drop-in render component. Row + column virtualization (1M rows), Excel-style filters, inline editing, grouping, pivot, server-side data. MIT core (@svgrid/grid), MCP server for Claude / Cursor. https://svgrid.com

    Community sv-grid
    cinderline

    NorthCinder

    Buyer-run, ad-neutral shopping-agent MCP software with deterministic ranking, signed purchase mandates, and a local audit trail.

    Community cinderline