{
  "markdown": "<p>\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"site/public/icon-dark.svg\">\n    <img src=\"site/public/icon.svg\" width=\"32\" height=\"32\" align=\"absmiddle\" alt=\"\" aria-hidden=\"true\">\n  </picture>\n  &nbsp;<strong>SafeSelect</strong> <code>MCP</code>\n</p>\n\n<h1>Agents can look.<br>They cannot mutate.</h1>\n\n**Read-only PostgreSQL & MongoDB access for coding agents.**\n\nDebug with real database context, without exposing write tools—even when your\nexisting credentials allow writes. SafeSelect puts local, project-scoped policy\nbetween your agent and your data.\n\n[**Get started →**](#quick-start) ·\n[Website](https://antonillos.github.io/safeselect/) ·\n[Compare approaches](docs/compare.md) ·\n[DBeaver → Codex guide](docs/guides/dbeaver-codex.md)\n\n[![CI](https://github.com/antonillos/safeselect/actions/workflows/verify.yml/badge.svg)](https://github.com/antonillos/safeselect/actions/workflows/verify.yml)\n[![CRAP](https://img.shields.io/endpoint?url=https%3A%2F%2Fantonillos.github.io%2Fsafeselect%2Fcrap-badge.json)](https://github.com/antonillos/safeselect/actions/workflows/verify.yml)\n[![License](https://img.shields.io/badge/License-MIT-225b42)](LICENSE)\n\n[![Listed on mcpservers.org](https://mcpservers.org/badge.svg)](https://mcpservers.org/servers/antonillos/safeselect)\n[![Indexed on TensorBlock MCP Index](https://mcp-index.tensorblock.co/v1/servers/github-antonillos-safeselect-4c99dff4/badge.svg)](https://www.tensorblock.co/mcp/servers/github-antonillos-safeselect-4c99dff4)\n[![MCP Badge](https://lobehub.com/badge/mcp/antonillos-safeselect?style=flat)](https://lobehub.com/mcp/antonillos-safeselect)\n\n<details>\n<summary>Runtime and distribution</summary>\n\n[![Security](https://img.shields.io/badge/Security-fail--closed-success?logo=trustpilot&logoColor=white)]()\n[![Rust](https://img.shields.io/badge/Rust-1.85%2B-dea584?logo=rust&logoColor=white)]()\n[![Java](https://img.shields.io/badge/Java-17%2B-5382a1?logo=openjdk&logoColor=white)]()\n[![MCP](https://img.shields.io/badge/MCP-stdio%20tools-7b68ee)]()\n[![Homebrew](https://img.shields.io/badge/Homebrew-tap-FBB040?logo=homebrew&logoColor=white)](https://github.com/antonillos/homebrew-tap)\n[![asdf](https://img.shields.io/badge/asdf-plugin-8A2BE2)](https://github.com/antonillos/asdf-safeselect)\n\n</details>\n\nDiscover structure, inspect bounded rows, explain queries, and diagnose\nconnectivity—without giving the agent write-capable tools or database credentials.\nStart with development data or a sanitized replica, then review the policy and\neffective database permissions before connecting to a more sensitive environment.\n\n> [!NOTE]\n> SafeSelect is a safety boundary for agent access, not a replacement for database permissions. Use least-privilege database users when you can; SafeSelect still constrains overpowered credentials when agents connect through it.\n\nCurrent backend support: PostgreSQL and MongoDB.\n\n## Where It Helps\n\n- Debug an application against realistic data without exposing mutation tools.\n- Let an agent inspect schemas, indexes, query plans, and bounded rows during development.\n- Explore MongoDB collections through bounded reads and sampled schema inference.\n- Reuse existing DBeaver, Docker Compose, or MongoDB Compass connections.\n- Give coding agents database context while keeping policy, limits, secrets, and audit under your control.\n\n## Why SafeSelect?\n\nSafeSelect is intentionally narrower than general-purpose database MCP servers. It is not a tool builder, SQL workbench, or remote database gateway. It is a local safety boundary for agents that need database visibility, not database power.\n\n| SafeSelect prioritizes | What this means |\n|---|---|\n| Local stdio transport | No network listener or open MCP port |\n| Read-only tools | Agents do not receive write-capable database tools |\n| Credential-independent safety | Even DBA credentials are constrained to SafeSelect's read-only tool surface |\n| Fail-closed enforcement | Policy violations terminate the process |\n| Secret isolation | Passwords stay in Keychain or environment variables |\n| Project-scoped policy | Each repository defines its own allowed data surface |\n| Embedded sidecar | One installed binary reaches JDBC and MongoDB drivers behind Rust policy |\n\n## What Makes It Different?\n\nThe combination matters: PostgreSQL **and** MongoDB inspection, a fixed database\nread surface, local stdio, project policy, connection import and reproducible\nsecurity evidence. Read-only modes and layered controls also exist in other\nprojects; they are not exclusive to SafeSelect.\n\nSee the [dated comparison](docs/compare.md) for DBHub, MongoDB MCP Server,\nPostgres MCP Pro and SchemaBrain—including when each is a better fit.\n\n**Agents can look, but they cannot mutate through SafeSelect's database tools.**\nThis boundary does not cover a shell, another MCP server or direct credentials\nalso available to the agent. Use least-privilege database users and review the\n[threat model and limits](docs/security-proof.md).\n\n## Backend Support\n\n| Backend | Status | Tools |\n|---|---|---|\n| PostgreSQL | Supported | Discovery, indexes/statistics, `select`, and `explain` |\n| MongoDB | Supported | Discovery, find, aggregation, distinct/count, explain, profiling, schema inference, and anonymized fixtures |\n\n## Architecture\n\n<p align=\"center\">\n  <img src=\"docs/safeselect-architecture.svg\" alt=\"SafeSelect Architecture\" width=\"800\">\n</p>\n\nThe agent talks to SafeSelect through MCP stdio. SafeSelect enforces policy in Rust, stores secrets outside project files, and reaches databases through an embedded Java sidecar: JDBC for SQL backends and the MongoDB driver for MongoDB. The Rust to Java channel is JSON-lines over stdin/stdout: no sockets, no open ports.\n\n## See it in action\n\n### Complete onboarding: from Homebrew to a protected agent\n\n<p align=\"center\">\n  <img src=\"docs/recordings/onboarding-full-local.gif\" alt=\"SafeSelect onboarding: Homebrew, DBeaver SSH import, Keychain and OpenCode\" width=\"900\">\n</p>\n\nInstall SafeSelect from Homebrew, import an SSH-backed DBeaver connection,\nkeep the password in macOS Keychain, install the OpenCode integration, and see\nthe agent read a paid order while its `DELETE` attempt is rejected. Focused\nagent and backend clips remain in the [complete demo gallery](demo/README.md).\n\n## Quick Start\n\nInstall SafeSelect with one of the following methods:\n\n### Prebuilt binaries (macOS & glibc Linux)\n\nDownload a platform-specific, prebuilt binary for macOS or glibc-based Linux\nfrom the [latest GitHub release](https://github.com/antonillos/safeselect/releases/latest).\nThe verified installer selects the matching macOS or glibc Linux architecture,\nchecks the published SHA-256 digest, and installs to `~/.local/bin`:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/antonillos/safeselect/main/packaging/install/install-release.sh | sh\n```\n\nSet `PREFIX` to choose another installation directory. SafeSelect still needs\na Java 17+ runtime at execution time.\n\n### Homebrew (macOS)\n\n```bash\nbrew install antonillos/tap/safeselect\n```\n\n### asdf (macOS & Linux)\n\n```bash\nasdf plugin add safeselect https://github.com/antonillos/asdf-safeselect.git\nasdf install safeselect latest\nSAFESELECT_VERSION=\"$(asdf latest safeselect | sed -n '$p')\"\nasdf set -u safeselect \"${SAFESELECT_VERSION}\"\nasdf reshim safeselect \"${SAFESELECT_VERSION}\"\n```\n\nAfter installing the binary, configure a project database and its MCP entry:\n\n```bash\n# Import a project database\nsafeselect import-dbeaver ~/Downloads/dbeaver-export.zip\n# or:\n# safeselect import-compose\n# safeselect import-compass --path \"$HOME/.config/MongoDB Compass\"\n\n# Verify the environment\nsafeselect check --environment testing\n\n# Install the MCP entry. If this is the only environment, its name is inferred.\nsafeselect agent install opencode\n\n# Verify exactly what was installed and where.\nsafeselect agent status\n```\n\nSafeSelect uses any available Java 17+ runtime rather than requiring a specific\npackage-manager formula. If Java is missing or too old, install or select a\nJava 17+ runtime before running database commands. On macOS with Homebrew, you\ncan install one with `brew install openjdk@17`.\n\nThe generated MCP name defaults to `safeselect-<project>-<environment>`.\n\nThe generated MCP entry is a stdio server scoped to one project and environment:\n\n```json\n{\n  \"mcpServers\": {\n    \"safeselect-myapp-testing\": {\n      \"command\": \"safeselect\",\n      \"args\": [\"serve\", \"--project\", \"/path/to/myapp\", \"--environment\", \"testing\"]\n    }\n  }\n}\n```\n\nSafeSelect uses each client's official MCP configuration contract, pins the\nabsolute repository path, and defaults to user scope. Add `--local` for a\nproject-scoped entry where the client supports it. See\n[AI agent integration](docs/agents.md) for exact paths, scopes, and manual\nconfiguration.\n\n## Guided MCP Context\n\nClients that support MCP prompts can invoke `read_only_database_debugging` for a\nsafe investigation checklist. Clients can also read\n`safeselect://guide/read-only-database-debugging` for the same static workflow\nand boundary notes. Neither capability exposes database data, credentials, or\nwrite access; use the database tools below for discovery and bounded reads.\n\n## Agent Workflow\n\nAgents should use SafeSelect in this order:\n\n1. `database_info`\n2. `list_tables` then `describe_table`; inspect `list_table_indexes` or bounded statistics when useful for SQL\n3. `list_databases`, `list_collections`, then `discover_document_schema` for NoSQL\n4. `select` / `explain`, or the bounded MongoDB read tool that matches the task\n5. `check`, `connect`, or `reconnect` when connectivity is stale\n\nAgents must discover relation or collection structure before querying unfamiliar data and use each discovery response's `next_suggestion` instead of guessing column or field names. SQL descriptions are catalog metadata; MongoDB schemas are inferred from a bounded, non-exhaustive sample.\n\nMongoDB query documents must remain complete nested JSON values. Clients that\nflatten nested tool arguments can pass `filter`, `projection`, and `sort` as\nJSON-encoded object strings and `pipeline` as a JSON-encoded array string.\n`redact_fields` also accepts a JSON-encoded string array. Flattened keys are\nrejected so a lost filter or redaction can never become a less constrained\nfallback.\n\nMongoDB server-side JavaScript is never available: `$where`, `$function`, and\n`$accumulator` are rejected recursively in filters, projections, sorts, and\naggregation pipelines before the MongoDB driver receives them. When rejected,\nrebuild the request with declarative MQL operators; SafeSelect has no setting\nthat enables JavaScript.\n\nQuery responses include `row_count`, `byte_count`, `elapsed_ms`, and a human-readable `elapsed` value so agents can reason about result size and latency.\n\nEvery MCP success and error includes one contextual `next_suggestion`. Agents\nshould follow that single safe action, never blindly repeat an invalid request,\nand stop when the suggestion is terminal. For clients that only show an MCP\nerror summary, SafeSelect also includes the trusted next suggestion in that\nsummary without exposing database-derived detail.\n\n## Security Model\n\n- **Fail closed**: security violations terminate the MCP process.\n- **Read only**: SQL allows `SELECT`, `EXPLAIN`, and `WITH`; NoSQL backends allow discovery and read-only document reads.\n- **No server-side JavaScript**: MongoDB `$where`, `$function`, and `$accumulator` are rejected in Rust and again in the Java sidecar.\n- **Scoped access**: schemas, relations, databases, and collections can be allowed or denied.\n- **Hard limits**: row count, result bytes, and timeouts are enforced; MongoDB read commands receive the same timeout as `maxTimeMS`.\n- **Secret isolation**: passwords live in macOS Keychain or environment variables, never in project config.\n- **Driver verification**: JDBC drivers are checked by SHA-256 before use.\n- **Audit trail**: query text is hashed before being recorded; the current session exposes bounded audit metadata through `audit_status` and `audit_recent`.\n\n### Deliberate Limits\n\n- SafeSelect does not expose database writes, migrations, administration, or arbitrary command execution.\n- PostgreSQL and MongoDB are the supported backends today; broad connector count is not the goal.\n- MCP transport is local stdio. SafeSelect is not a remote database gateway.\n- MongoDB schema discovery is sampled and bounded, not an exhaustive schema guarantee.\n- SafeSelect complements database-native least privilege; it does not replace it.\n\n## MCP Tools\n\n| Area | Tools |\n|---|---|\n| SQL | `list_tables`, `describe_table`, `list_table_indexes`, `list_table_partitions`, `get_database_stats`, `get_table_stats`, `select`, `explain` |\n| MongoDB reads | `list_databases`, `list_collections`, `find_documents`, `aggregate_documents`, `distinct_documents`, `count_documents`, `explain_documents` |\n| MongoDB analysis | `profile_document_field`, `discover_document_schema`, `generate_document_fixture`, `list_collection_indexes`, `get_database_stats`, `get_collection_stats` |\n| Connection | `database_info`, `check`, `connect`, `disconnect`, `reconnect` |\n| Audit | `audit_status`, `audit_recent` |\n| Config | `config_validate`, `config_show`, `config_set_password`, `config_rename_environment`, `config_delete_environment`, `config_reset` |\n| Setup | `import_compose`, `driver_list`, `driver_add`, `driver_download`, `agent_detect`, `agent_install`, `agent_status`, `agent_uninstall` |\n\nWhen no `.safeselect/` directory exists, `safeselect serve --environment <env>` enters setup mode automatically and exposes only the setup-safe tools.\n\n> [!IMPORTANT]\n> Setup mode does not expose query tools. Agents can help import and validate configuration before any database inspection tools become available.\n\n## CLI Essentials\n\n| Command | Purpose |\n|---|---|\n| `safeselect serve --environment <env>` | Start the MCP server |\n| `safeselect check --environment <env>` | Verify config, secrets, tunnels, sidecar, and backend connectivity |\n| `safeselect doctor --environment <env>` | Print deeper diagnostics with stable codes |\n| `safeselect import-dbeaver <zip>` | Import DBeaver connections |\n| `safeselect import-compose [--path <path>]` | Import from docker-compose |\n| `safeselect import-compass [--path <path>]` | Import MongoDB Compass connections |\n| `safeselect agent install <client> --environment <env>` | Install an MCP entry |\n| `safeselect config set-password --environment <env>` | Store the database password |\n| `safeselect config set-ssh-password --environment <env>` | Store the SSH password |\n| `safeselect uninstall` | Remove installed binaries, global state, audit data, and Keychain entries |\n| `safeselect uninstall --binary-only` | Remove only user-local binaries and preserve configuration |\n\nUse `safeselect --help` or a command-specific `--help` for the full CLI.\n\nUninstall checks both release-installer and Cargo binary locations.\nMongoDB Compass imports support SSH-tunneled `mongodb+srv://` connections by resolving\nthe SRV target and rewriting the local endpoint with the required TLS and direct-connection\noptions.\n\n## Configuration\n\nGlobal state lives in `~/.config/safeselect/` by default. Project policy lives in `.safeselect/` at the repository root:\n\n```text\n<repo-root>/\n└── .safeselect/\n    ├── project.toml\n    └── environments/\n        └── <env>.toml\n```\n\nSafeSelect walks upward from the current directory to find `.safeselect/`. Use `--project <path>` when an agent or script should target a specific repository.\n\n## Supported Agents\n\n| Client | User scope | Project scope | Integration |\n|---|---:|---:|---|\n| OpenCode | Yes | Yes | JSON/JSONC `mcp` |\n| OpenAI Codex | Yes | Yes | lossless TOML `mcp_servers` |\n| Claude Code | Yes | Yes | native `claude mcp` scopes |\n| Cursor | Yes | Yes | `.cursor/mcp.json` |\n| Windsurf | Yes | No | global Windsurf MCP config |\n| GitHub Copilot | Yes | Yes | `servers` in MCP JSON |\n| Gemini CLI | Yes | Yes | `.gemini/settings.json` |\n\nSafeSelect never silently falls back to a broader scope. In particular,\n`--local` for Windsurf fails with a clear correction because Windsurf does not\ndocument a project-scoped MCP configuration.\n\n## Build From Source\n\n```bash\n# Installs makevn through Homebrew or asdf only when it is missing.\n./install.sh --install-makevn\n\"$HOME/.local/bin/safeselect\" --version\n```\n\nRequirements: Rust 1.85+ and Java 17+. The bootstrap requires Homebrew or\nasdf; otherwise install `makevn` first. `sshpass` is optional for\npassword-based SSH tunnels. Add `~/.local/bin` to your `PATH` before invoking\n`safeselect` without its full path.\n\n## Documentation\n\n- [Installation guide](docs/install.md)\n- [AI agent integration](docs/agents.md)\n- [On-demand Codex code review](docs/code-review.md)\n- [Security model](docs/security.md)\n- [Security Proof](docs/security-proof.md)\n- [Security test suite](docs/security-test-suite.md)\n- [Security policy](SECURITY.md)\n- [Distribution](docs/distribution.md)\n- [Changelog](CHANGELOG.md)\n\nRelease notes are generated from `CHANGELOG.md`.\n\n## License\n\nMIT - see [LICENSE](LICENSE).\n",
  "bytes": 17116,
  "sha": "c182cf09dcf09f1b81fa065008405a7329df6639d22152436f1a6f45e5589a73",
  "repo_slug": "antonillos/safeselect",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_antonillos_safeselect_e604b329/readme"
}