AgentStack
MCP verified Apache-2.0 Self-run

GetMCP

mcp-rayenbabdallah-getmcp · by Rayenbabdallah

Zero Trust for AI agents. Generates and protects MCP servers for both internal copilots and customer-facing agents. Apache 2.0, self-hosted.

No reviews yet
0 installs
14 views
0.0% view→install

Install

$ agentstack add mcp-rayenbabdallah-getmcp

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of GetMCP? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

GetMCP Zero Trust for AI agents. Generates the MCP servers your customers' agents need, then enforces who can do what — per request, per agent, per tenant.

Quickstart → · Threat model · Operations · Changelog


> TL;DR. Point GetMCP at any OpenAPI spec. It generates two runnable MCP servers (Internal "god mode" and External "customer-safe"), then runs in front of them as a policy proxy with a tamper-evident audit log. Self-hosted, Apache 2.0, no telemetry.

What is GetMCP?

A policy proxy + audit log that sits between AI agents (Claude, ChatGPT, Cursor, your bots) and your existing API.

It does two things:

  1. Generates Internal + External MCP servers from any OpenAPI spec, so your customers' AI agents can safely call your API.
  2. Enforces Zero Trust on every call — per-agent identity, 5 policy rule types, Slack-mediated approval for sensitive mutations, and a tamper-evident audit log you can verify with one HTTP request.
   ┌─────────┐     ┌──────────────────────────────┐     ┌──────────┐
   │  AI     │ ──► │ GetMCP — auth · policy ·     │ ──► │ Your API │
   │  agent  │     │ approval · audit · stream    │     │          │
   └─────────┘     └──────────────────────────────┘     └──────────┘

Built for: B2B SaaS companies whose customers are starting to wire AI agents into their APIs and need a Zero Trust layer they can self-host.

Not built for: routing internal traffic between microservices (use a service mesh) or rate-limiting public APIs (use a CDN / WAF). GetMCP is specifically the AI-agent → enterprise-API path.

Why not roll your own?

| You'd need to build | What GetMCP gives you on day 1 | |---|---| | Auth + per-tenant isolation, with regression tests proving Org A can't read Org B | Apache-2.0, working, tested | | A streaming proxy with header filtering (no leaking caller Authorization to the upstream) | Real, with 502 / 504 mapped correctly, never 500 | | A policy engine with deterministic priority order and a dry-run endpoint | 5 rule types, property-tested, POST /policies/simulate | | A tamper-evident audit log your auditors will accept | sha256 hash chain, one-call GET /audit/verify, NDJSON export | | A Slack approval flow with HMAC-signed callbacks | Idempotent state machine, replay-on-approve through the proxy | | All of the above as a Helm chart with rolling deploys | Bundled, pre-install migration hook, no bundled DB |

About 6 months of work for one engineer. GetMCP is one bash command:

./deploy/scripts/bootstrap.sh

Prerequisites

  • Docker & Docker Compose
  • Node.js 20+ (for local development) — see .nvmrc
  • pnpm 9+
  • PostgreSQL (if running outside of Docker)

Documentation

Full operator + auditor docs in [docs/](docs/). Start with [docs/quickstart.md](docs/quickstart.md) — zero to a proxied request in 10 minutes. Live Swagger UI at /docs when the API is running in dev or with ENABLE_DOCS=true.

Quick Start (one command)

git clone https://github.com/Rayenbabdallah/GetMCP
cd GetMCP
./deploy/scripts/bootstrap.sh

The bootstrap script generates .env with fresh POSTGRES_PASSWORD + KEY_ENCRYPTION_KEY, brings up Postgres, runs migrations, starts API + Web, and seeds a demo org. Re-runnable safely. Output prints a working API key (saved exactly once) and curl commands.

Defaults: dashboard at http://localhost:8080, API at http://localhost:3000. Kubernetes deploy via Helm chart in deploy/helm/getmcp/. Full operations runbook in docs/operations.md.

Testing

  • Strategy + claim → test mapping: [docs/testing.md](docs/testing.md)
  • Per-file coverage gates on the 12 correctness-critical files (apps/api/package.json#jest.coverageThreshold); CI blocks merge on regression
  • Property tests for the audit chain: 200 random inserts verified end-to-end, 50 random tampers all detected at the right seq
  • Cross-rule combination tests for the policy engine — priority interactions, source filters, bypass behavior

Performance

  • Targets and tuning knobs: [docs/performance.md](docs/performance.md)
  • Load tests: deploy/load/k6-baseline.js asserts SLA thresholds (p95

Classify (cached on second call for the same spec — no LLM cost)

curl -X POST http://localhost:3000/generator/classify \ -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{"openapiUrl":"https://petstore3.swagger.io/api/v3/openapi.json"}'

Flip an endpoint manually (or clear with "exposeExternally": null)

curl -X POST http://localhost:3000/generator/override \ -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{"specHash":"...","path":"/admin/users","method":"delete","exposeExternally":true,"reason":"audited"}'

Generate the Two-MCP split (uses cached classifications + overrides)

curl -X POST http://localhost:3000/generator/generate \ -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{"openapiUrl":"https://petstore3.swagger.io/api/v3/openapi.json"}'

Download the runnable scaffold (zip)

curl -G "http://localhost:3000/generator/export" \ -H "Authorization: Bearer $KEY" --data-urlencode "openapiUrl=..." -o getmcp.zip


The exported zip contains real, runnable Node MCP servers — pinned `@modelcontextprotocol/sdk@1.0.4`, one tool per (method, path), reads `schema.json` at startup, forwards calls to `UPSTREAM_BASE_URL` via fetch. `cd internal-mcp && npm install && UPSTREAM_BASE_URL=... npm start` works out of the box.

Set `ANTHROPIC_API_KEY` to enable the LLM classifier. Without it, the generator falls back to keyword heuristics (deterministic, no network call, lower accuracy).

## Operability

- **Logs**: structured JSON via pino, one line per request. Each line carries `req.id` (sourced from `x-request-id` header or generated). Override level with `LOG_LEVEL=debug|info|warn|error|silent`.
- **Health**: `GET /health/live` (process up), `GET /health/ready` (DB reachable). Both `@Public`.
- **Metrics**: `GET /metrics` exposes Prometheus text. Series:
  - `getmcp_proxy_requests_total{action,source,upstream_status}` — proxy outcomes
  - `getmcp_proxy_request_duration_ms_bucket{action,source}` — controller-entry to response-finish latency histogram
  - `getmcp_policy_decisions_total{kind}` — engine outcome distribution
  - `getmcp_audit_writes_total{result}` — `ok` vs `failed` audit writes (the headline reliability metric)
  - `getmcp_approval_events_total{event}` — created / approved / denied / expired
  - Plus `getmcp_*` Node defaults (CPU, heap, event loop lag).
- **Migrations**: `prisma migrate` is the deploy path; `db push` is gone. Initial migration committed under `apps/api/prisma/migrations/20260515000000_init`.
- **Shutdown**: `enableShutdownHooks()` on SIGINT/SIGTERM drains in-flight requests, closes Prisma, stops the approval sweeper.

## Authentication

Every API endpoint (except `/health`) requires an `Authorization: Bearer ` header scoped to an Organization. Keys are minted by the seed script and via the `/orgs` endpoints (see `apps/api/src/auth`). All Prisma queries are filtered by the authenticated organization — see the tenant-isolation tests in `apps/api/src/auth/auth.spec.ts`.

## Configuring an upstream

The proxy forwards requests to a per-organization downstream API. Set it via:

```bash
KEY=
curl -X PATCH http://localhost:3000/orgs/me \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "upstreamBaseUrl": "https://api.stripe.com",
    "upstreamAuthHeader": "Bearer sk_test_...",
    "upstreamTimeoutMs": 10000
  }'

upstreamAuthHeader is encrypted at rest with KEY_ENCRYPTION_KEY (AES-256-GCM) and never returned by the API. Then call:

curl -X POST http://localhost:3000/proxy/execute \
  -H "Authorization: Bearer $KEY" \
  -H "x-agent-source: internal_mcp" \
  -H "Content-Type: application/json" \
  -d '{"method":"GET","path":"/v1/charges"}'

The upstream's status code, headers, and body stream through faithfully. Upstream timeouts return 504, connection errors return 502.

Agents

POST /proxy/execute requires the caller to assert which agent they're acting as via the x-agent-id header. The agent must belong to the authenticated org and not be revoked or disabled.

KEY=
# create an agent
AGENT_ID=$(curl -s -X POST http://localhost:3000/agents \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"name":"my-bot","source":"internal_mcp"}' | jq -r .id)

# use it
curl -X POST http://localhost:3000/proxy/execute \
  -H "Authorization: Bearer $KEY" \
  -H "x-agent-id: $AGENT_ID" \
  -H "x-agent-source: internal_mcp" \
  -H "Content-Type: application/json" \
  -d '{"method":"GET","path":"/v1/charges"}'

# revoke (takes effect within 5s on this instance)
curl -X DELETE http://localhost:3000/agents/$AGENT_ID -H "Authorization: Bearer $KEY"

Policy engine

Five rule types, evaluated in priority asc, createdAt asc order. First terminal decision wins.

| ruleType | What it does | actionConfig | |---|---|---| | ALLOWLIST | Short-circuits to allow; skips later BLOCK/RATE_LIMIT for this match. | — | | BLOCK | Terminal deny → 403. | — | | AUDIT | Rejects requests whose x-agent-reasoning is missing,

Full CRUD

curl http://localhost:3000/policies -H "Authorization: Bearer $KEY" curl -X POST http://localhost:3000/policies -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" \ -d '{"name":"block deletes","ruleType":"BLOCK","targetMethod":"DELETE","targetPath":"/v1/*","priority":10}' curl -X PATCH http://localhost:3000/policies/ID -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" -d '{"isActive":false}' curl -X DELETE http://localhost:3000/policies/ID -H "Authorization: Bearer $KEY"

Dry-run: shows which rules fire and why, without forwarding upstream

curl -X POST http://localhost:3000/policies/simulate -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" \ -d '{"method":"DELETE","path":"/v1/refunds/abc","source":"external_mcp","tenantId":"t-1","reasoning":"customer #321 requested rollback"}'


## Slack approval flow

A `MUTATION_APPROVAL` rule holds the request, posts an interactive Approve/Deny card to Slack, and returns `202` with a `pendingId`. The original caller polls `GET /approvals/:id` until status leaves `PENDING`.

**Configure once per org:**

```bash
curl -X PATCH http://localhost:3000/orgs/me \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{
    "slackBotToken": "xoxb-...",
    "slackSigningSecret": "abc123...",
    "slackDefaultChannel": "#approvals"
  }'

Both Slack secrets are AES-256-GCM encrypted at rest. Point your Slack app's Interactivity Request URL at https://your-getmcp/slack/interactions — the endpoint verifies signatures (v0 HMAC-SHA256, ±5min replay window).

Lifecycle:

  1. Caller POST /proxy/execute → policy fires MUTATION_APPROVAL → response is 202 { pendingId, pollUrl, expiresAt }. Default TTL 15 min.
  2. Slack message has Approve/Deny buttons. The clicker's identity is recorded in the audit log.
  3. On Approve: request is replayed through the proxy with bypassApproval=true (other rules — BLOCK / RATE_LIMIT / AUDIT — still apply). Upstream response is captured (status + headers + body up to 256KB).
  4. On Deny / Expire: a BLOCKED audit row is written, no upstream call is made.
  5. Caller polls GET /approvals/:id → eventually receives {status, responseStatus, responseHeaders, responseBody}.

A background sweeper expires PENDING rows past their TTL every 30s.

Audit ledger

Every proxy call writes one tamper-evident AuditLog row to a per-organization hash chain. Quick checks:

KEY=
curl -H "Authorization: Bearer $KEY" http://localhost:3000/audit | jq
curl -H "Authorization: Bearer $KEY" http://localhost:3000/audit/verify
curl -H "Authorization: Bearer $KEY" http://localhost:3000/audit/export -o audit.ndjson

Schema, hash construction, and integrity guarantees are documented in docs/audit.md.

Roadmap

Tracked publicly as design-discussion issues — comment if you have a take, PRs welcome:

See [CHANGELOG.md](CHANGELOG.md) for what shipped in v0.1.0. Roadmap is tracked in GitHub Issues and Discussions.

Contributing

PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for the dev loop, coverage policy, and what kinds of changes we're looking for. Discussion before code on anything touching auth, the audit chain, or migrations. Be a good neighbour: [CODE_OF_CONDUCT.md](CODEOFCONDUCT.md).

For security issues, do not file public issues — see [SECURITY.md](SECURITY.md) for the disclosure SLA.

License

GetMCP is licensed under the [Apache License 2.0](LICENSE). © 2026 Rayen Babdallah and GetMCP contributors. See [NOTICE](NOTICE).

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.