AI integration / Open source

saas-mcp-connector: a safe MCP server for a SaaS API

An MCP server that lets Claude Desktop, Claude Code and other MCP clients use a SaaS product's API safely. Every call is scoped to one user's workspace, writes need explicit confirmation, and the HTTP transport is rate limited.

Our role: Open source, written by App369 founder Simon Dziak and released under the MIT license. It is a reference build that runs against an in-memory fake SaaS, not a client project and not a production deployment.

The Problem

What saas-mcp-connector Needed to Solve

Customers are starting to ask whether a product works with their AI assistant. The easy way to build that is to expose the API as tools and hope the model behaves. The harder questions are the ones this build answers. Can a tool reach another customer's data? Can the model change something without asking? What happens when a client floods the server with requests, or when the upstream API fails with a message that should not reach the model?

The Build

How We Built It

A TypeScript server on the official MCP SDK. Each token is resolved to an API client that is already bound to one workspace, and no tool takes a workspace argument, so cross-workspace access cannot be expressed. Write tools do nothing without confirm: true, and READ_ONLY=true blocks them completely. The same server runs over stdio for Claude Code and Claude Desktop, or over stateless Streamable HTTP with bearer-token auth and a per-token rate limit. The API client is an interface, so swapping the fake SaaS for a real REST API does not change the server.

Features

What the Product Does

Six tools

list_projects, list_tasks (with filters and cursor pagination), get_task and search are read tools. create_task and update_task_status are write tools.

Per-user scoping

The token chooses the workspace. Tests cover reads, search, listing and writes across workspaces.

Read-only mode

READ_ONLY=true makes every write tool return an error, even with confirm: true.

Explicit confirmation

A write without confirm: true does nothing and tells the model to ask the user first.

Rate limiting

A token bucket per token on the HTTP transport. Over the limit, the server returns 429 with Retry-After. Buckets are keyed by a hash of the token.

Safe errors

Known failures come back as MCP tool errors with a readable message. Unexpected exceptions are logged to stderr and returned as a generic message, with no stack traces or upstream details.

Architecture

The Stack, Layer by Layer

Server
Node 22 or newer, TypeScript, the official @modelcontextprotocol/sdk and zod for input validation. Read tools carry readOnlyHint so clients can treat them differently.
API layer
An ApiClient interface in src/api.ts, an in-memory multi-workspace fake in src/fake-saas.ts, and a client factory that maps a token to a client.
Transports
stdio, and Streamable HTTP built fresh per request from the caller's token, so no session state can leak between users.
Tests
vitest suites that run offline: server logic, the HTTP transport and a stdio smoke test.
By the Numbers

Verifiable Facts

Oct 2026
Published on GitHub (single commit, October 12)
6
Tools: 4 read and 2 write
18
Test cases across 3 test files
MIT
License

Counted from the public GitHub repository on October 13, 2026. This page makes no claims about stars, adoption or production use.

Lessons

What We Learned Shipping It

Make the unsafe call impossible to write

The server does not check that a tool is allowed to name a workspace. No tool has the argument at all. Removing the option is easier to test than policing it.

Gate writes twice

Confirmation protects against a model that acts too fast. Read-only mode protects against a deployment that should never write. They answer different questions, so both exist.

Stay stateless on HTTP

Building a fresh server per request from the caller's token means there is no session to leak, and the process can be restarted or scaled without a sticky session.

Keep the API as the authority

The README says your own API must still enforce authorization. This layer is defense in depth, not the only lock.

Say what is not built

OAuth sign-in is described in the README as an optional extension and is not implemented. A short list of what is missing is more useful to the next reader than a long list of claims.

Technologies Used
TypeScript•Node.js•MCP•zod•vitest•Claude
Timeline
Published October 2026

Planning Something Similar?

We build Flutter and Firebase apps for startups and small businesses. Get a ballpark with our app cost calculator, see Flutter development, or tell us about your project.

More Case Studies

SaaS / Business software

Workspace369: a Flutter and Firebase SaaS for client work

An all-in-one workspace for freelancers and small service businesses: CRM, proposals, invoicing and payments, scheduling, a shared email/SMS/voice inbox, accounting and AI, in one Flutter app on iOS and the web.

Read Case Study →
Consumer / Music

3693: a private music app in Flutter and Firebase

A private music app built with Flutter: search, a now-playing screen with lyrics, a queue, playlists, liked songs, a cloud library, listening stats and light and dark themes, on a typed Firebase backend.

Read Case Study →
AI / Image processing

Deep Dream: a Flutter app and a PyTorch queue behind it

A Flutter app sends a photo to a Python API. A Redis queue hands the job to a PyTorch worker that runs DeepDream on a convolutional neural network, and the dreamed image comes back to save to the gallery.

Read Case Study →
Consumer / Collectibles

DG Card: scan a trading card and match it on the device

A Flutter app for trading card players. Point the camera at a card, on-device text recognition reads it, and the app matches it against a synced card database. From there you track a collection, build decks and trade with other players.

Read Case Study →
Automotive / Security hardware

Bull Horn GPS Alarm: one-tap SMS commands for an alarm

A Flutter app that works as a remote control for GPS vehicle and asset alarms. Each alarm is saved once with its phone number and password, and every command after that is one tap.

Read Case Study →
Landscaping / Field sales

Artificial Grass Masters: a field estimator and job sign-off app

A Flutter app for an artificial-turf installer. A rep measures a yard on a map, prices the grass, delivery and dumpster on the spot, and closes the job with photos, a customer signature and a rating. The company gets a text message when a new rating comes in.

Read Case Study →