{
  "markdown": "# secureFlows MCP Server\n\n[![secureFlows](https://img.shields.io/badge/secureFlows-www.secure--flows.com-1a73e8)](https://www.secure-flows.com) [![CI](https://github.com/michal-lefler/secureflows-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/michal-lefler/secureflows-mcp/actions/workflows/ci.yml)\n\nCloud-deployable MCP server that wraps the [secureFlows](https://www.secure-flows.com) OpenAPI\nsurface tagged `ai-safe` and `ai-optional`.\n\n> This repo is a public mirror, published periodically from the private secureFlows monorepo\n> where development actually happens. Issues and PRs are welcome; large changes may take a\n> release cycle to land upstream first.\n\n## What is an MCP server?\n\nAn **MCP server** is a small HTTP service that exposes a set of “tools” an AI client can call in a standard way.\n\nIn this repo:\n- The **secureFlows MCP server** exposes tools that are auto-generated from your OpenAPI YAML specs.\n- When a client calls a tool, the MCP server **forwards** the call to your real secureFlows backend (`connection.host`)\n  and returns the response in a normalized tool result.\n\nThis lets an AI client:\n- discover available secureFlows operations via `listTools`\n- call them via `callTool`\n- without hardcoding the API surface or manual auth/header wiring\n\n## What it does\n\nTwo kinds of tools, registered together in `src/server.ts`:\n\n**Generated tools** (`src/tools/build-tools.ts`) — one per OpenAPI operation:\n- Loads:\n  - `docs/openapi/session/secure-flows-session-api.yaml`\n  - `docs/openapi/user/secure-flows-user-api.yaml`\n  - `docs/openapi/docs/secure-flows-docs-api.yaml`\n- Exposes only operations tagged `ai-safe` or `ai-optional` as MCP tools\n- Forwards requests to a caller-provided secureFlows host — a thin, generic HTTP wrapper with no\n  secureFlows-specific judgment. Every one of these requires a live `auth.*` token, so they're\n  only useful once a session already exists (see **Runtime model** below).\n- Maps secureFlows auth headers from MCP tool inputs:\n  - `auth.firebaseToken`\n  - `auth.sessionToken`\n  - `auth.userToken`\n\n**Static tools** (`src/tools/static-tools.ts`) — hand-written, not generated from the spec:\n- `secureflows_build_login_url` / `secureflows_build_logout_url` — build the hosted-login and\n  redirect-logout URLs correctly by construction (always `/app/sessions/login`, never the legacy\n  `/app/login`; refuses a post-logout `redirect_uri` that points at `/callback` or leaks\n  `session_token`). No secureFlows token required.\n- `secureflows_lint_integration` — checks generated app source against the integration rules and\n  reports structured findings instead of leaving them as prose the agent has to self-police. No\n  secureFlows token required. Two kinds of finding:\n  - **`scope: \"file\"`** — a forbidden construct is *present*, at an exact `file:line`: env-var\n    config constants, token in `localStorage`, legacy `/app/login`, `fetch`/XHR logout, client-side\n    JWT decode, revoke-on-sign-out, empty `catch {}`, restore `setSession(null)` on non-auth errors,\n    Continue CTA gated on `session === null`, …\n  - **`scope: \"project\"`** — required handling is *absent* across every file passed in: detecting\n    `401`/`410` but never clearing the token, never handling `403`, or handling `403` without the\n    `BILLING_GRACE_LOCK` carve-out.\n\n  The absence checks exist because the pattern rules structurally could not catch the defect class\n  that dominates real generated apps. Measured: on a real trial's app that the eval harness's LLM\n  judge scored **4/10** — citing \"stale token never cleared on signed-out\", \"403 variants\n  unhandled\", \"no error handling\" — the pattern rules alone produced **zero** findings, because\n  every one of those bugs is an *absence*, and a regex can only see what is present. With the\n  absence checks it produces 3, including the `error`-severity token-clearing one. Both check\n  kinds are validated against the canonical `templates/web-app-secureflows` starter, which must\n  stay at zero findings.\n\n  Still heuristic text analysis, not a parser or type checker: it misses what it has no rule for,\n  a project check can be satisfied by the right keyword in the wrong place, and it cannot cover\n  the checks that need a running app (auth-guard mount races, the fresh-reload check). A fast\n  first pass — not a replacement for the Agent implementation checklist in SKILL.md.\n\nThese static tools exist because the generated tools can't help with the part of an integration\nthat happens *before* a session exists — scaffolding the redirect/callback/token-lifecycle code —\nwhich is exactly where most secureFlows integration mistakes happen.\n\nUses a stateless HTTP MCP transport, so the server does not persist tenant config or secrets.\n\n## Runtime model\n\nEach tool call receives:\n\n- `connection.host`: secureFlows base URL\n- `connection.workspaceName`: optional default workspace\n- `connection.appId`: optional default application id\n- `auth.*`: whichever token the selected endpoint needs\n\n`workspaceName` and `appId` are treated as stable app config. The server injects them into known secureFlows request shapes when omitted by the caller.\n\n## For agents (the only supported client path)\n\nPoint the MCP client at the **hosted** URL — same host as the product, path `/mcp` (not a subdomain):\n\n| Environment | MCP URL |\n|---|---|\n| Production | `https://www.secure-flows.com/mcp` |\n| Staging | `https://secure-flows-staging.onrender.com/mcp` |\n| Health | `…/mcp/health` → `{\"ok\":true}` |\n\n```json\n{\n  \"mcpServers\": {\n    \"secureflows\": {\n      \"url\": \"https://www.secure-flows.com/mcp\"\n    }\n  }\n}\n```\n\nDo **not** tell agents to run `npx` or use `localhost` — that splits the story and breaks anyone who never starts a local process. Wired in the web Docker image (Node on `127.0.0.1:8787`, nginx `location = /mcp`; see `docs/ROUTING.md`). The Node process installs `uncaughtException` / `unhandledRejection` guards so a single bad request does not exit the process; `docker/entrypoint.sh` also restarts MCP if the process still exits.\n\n## Local development (maintainers of this package)\n\n```bash\ncd mcp-server\nnpm install\nnpm run build\nnpm test\nnpm run dev\n```\n\nThe server starts on `http://0.0.0.0:8787` by default (`POST /mcp`, `GET /health`). This is for\nchanging the MCP server itself — not the path product agents should configure.\n\n## Environment variables\n\n- `PORT`: HTTP port, default `8787` (in the web container, entrypoint sets `PORT=8787` only for the MCP child so nginx keeps Render’s public `$PORT`)\n- `HOST`: bind host, default `0.0.0.0` (web container uses `127.0.0.1`)\n- `ALLOWED_HOSTS`: optional comma-separated host allowlist for MCP host header validation\n- `MCP_ALLOWED_HOSTS`: entrypoint override for `ALLOWED_HOSTS` when starting the in-image process\n\n## Endpoints\n\n- `POST /mcp`: MCP Streamable HTTP endpoint\n- `GET /health`: health check (publicly exposed as `GET /mcp/health` via nginx)\n## Embedding secureFlows in an application\n\nProduct apps integrate **directly** with secureFlows HTTP APIs and hosted login. Start from:\n\n- `docs/integration/quickstart.md` — provisioning (workspace + application) and runtime hosted login\n- `docs/integration/CONCEPT.md` — baseline order: **login → create workspace** before advanced features\n- `docs/openapi/integration-auth.yaml` — **`/app/sessions/login`** (session apps) vs `/app/login` (legacy/console)\n\nProduct apps still integrate directly with the HTTP APIs above, not through this server. The\n**generated** tools here are for agents/automation that already have a token (testing, scripted\nverification). The **static** tools (`secureflows_build_login_url`, `secureflows_build_logout_url`,\n`secureflows_lint_integration`) need no token and are meant to be called by a coding agent while\nit's still scaffolding the integration — see **What it does** above.\n\n## Testing this MCP server\n\n1. `npm test` in `mcp-server/` — unit tests **plus** HTTP smoke (`test/http-smoke.test.ts`):\n   starts the Express app on an ephemeral port, checks `GET /health`, `GET /mcp` → 405, and a\n   real Streamable-HTTP client `listTools` + `callTool(secureflows_build_login_url)`.\n2. After deploy: Playwright `tests/smoke/mcp-health.spec.ts` hits public `GET /mcp/health` and\n   `GET /mcp` on the target host (production smoke job).\n3. Local maintainer loop: `npm run dev`, then `curl -sS http://127.0.0.1:8787/health`.\n4. Optional: MCP client against `POST /mcp` with `connection.host` + `auth.*` for generated tools.\n\n## Deployment\n\nShipped inside the web Docker image and proxied at `/mcp` on `www.secure-flows.com` / staging\n(see **For agents** above). No separate subdomain.\n\nThe npm package `secureflows` is how CI publishes a versioned artifact (and how a\nstandalone container can be built from `mcp-server/Dockerfile`); it is **not** the agent-facing\nsetup path. Publish on `v*.*.*` tags via `.github/workflows/publish-secureflows-mcp-server.yml`.\n\n```bash\ndocker build -f mcp-server/Dockerfile -t secureflows-mcp-server .\ndocker run --rm -p 8787:8787 secureflows-mcp-server\n```\n\n## Notes\n\n- Hosted login / redirect endpoints are exposed only if they are tagged `ai-safe` or `ai-optional` in the OpenAPI specs.\n- **Documentation search** (`get_docs_search`) is `ai-safe`, requires **no** `auth.*` — only `connection.host` and query `q`.\n- Human-only admin console APIs are intentionally excluded.\n- The response payload from each tool includes:\n  - `status`\n  - `ok`\n  - `url`\n  - `headers`\n  - `data`\n",
  "bytes": 9472,
  "sha": "e870c315fd904e393fbf6227cbc231b7f1dd1bc0994296d606b569074a3de605",
  "repo_slug": "michal-lefler/secureflows-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_michal_lefler_secureflows_mcp_590f11fb/readme"
}