Policy engine and review console for Model Context Protocol (MCP) tool traffic
TsInterceptor hosts an MCP interceptor server (interceptors/list, interceptor/invoke) that runs tenant policies on tools/call request and response phases, persists messages and alerts, and provides a web UI to triage traffic and tune rules.
You need Node.js 20 or newer.
npm install -g @teamsparkai/tsinterceptorSet a session secret (not required, but strongly advised if exposing to public internet):
export TSINTERCEPTOR_SESSION_JWT_SECRET="$(openssl rand -base64 48)"Start the server (web UI + HTTP MCP interceptor):
interceptor --port 3000Open http://localhost:3000/. If this is a fresh install, create the admin account; otherwise sign in.
Point your MCP interceptor client at http://<host>:3000/mcp/interceptor with Authorization: Bearer <keyLookupId>.<secret> on every HTTP request. Create the API key under Settings → API keys. The hosted policy interceptor is named tsinterceptor-policy.
For a stdio sidecar (no web UI), use:
export TSINTERCEPTOR_API_KEY="<keyLookupId>.<secret>"
interceptor --mcp-stdioSee the in-app Help tab for a step-by-step setup guide.
If the server is not publicly reachable, use a tunnel (e.g. ngrok) and set the public host in Settings so the MCP interceptor URL reflects your external base URL.
| Option | Description |
|---|---|
--port <n> |
Listen on TCP port n (1–65535). |
--log-level <level> |
One of: error, warn, info, debug, trace. Overrides TSINTERCEPTOR_LOG_LEVEL when both apply. |
--mcp-stdio |
Run MCP interceptor on stdin/stdout only (no Next.js UI or HTTP). |
--api-key <token> |
Tenant API key for --mcp-stdio (keyLookupId.secret). |
--clean |
Delete the TsInterceptor app data directory (SQLite, logs, api.json, etc.) and exit. |
--admin-reset |
Delete all users for the default tenant and exit. Stop the server first. Afterward, /login offers creating the first admin again. Does not remove API keys or other data. |
--help, -h |
Print help and exit. |
If neither --port nor TSINTERCEPTOR_PORT is set, the server uses port 0 (the OS picks a free port). Read the startup log for the URL.
Set variables in your environment, or use .env / .env.local. For interceptor, values are read from the install directory and then from your current working directory (later wins for the same key). .env.local overrides .env within each directory.
| Variable | Role |
|---|---|
TSINTERCEPTOR_SESSION_JWT_SECRET |
Signs and verifies the httpOnly session cookie (JWT) for the web UI. Not a user password or API key. Use a long random value in production. |
TSINTERCEPTOR_PORT |
Default HTTP port (1–65535). Ignored if --port is passed. |
TSINTERCEPTOR_LOG_LEVEL |
error, warn, info, debug, or trace. Default info. Ignored if --log-level is passed. |
TSINTERCEPTOR_API_KEY |
Tenant API key for --mcp-stdio (keyLookupId.secret). Alternative to --api-key. |
NODE_ENV |
Standard Node/Next value (e.g. production vs development) — affects cookie Secure, SQLite driver verbosity in development, and similar behavior. |
Generate a value (use either command, then set the output as the variable or paste it after = in .env — no quotes unless you want them in the secret):
openssl rand -base64 48node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"If TSINTERCEPTOR_SESSION_JWT_SECRET is unset, the app still starts with a development default and logs a warning or error once per process (when the interceptor server starts). Do not rely on that outside quick local use.
- Node.js 20+ and npm
- Git
- macOS, Windows, or Linux — native modules (
sqlite3,argon2,sharp) may require a working build toolchain on your platform (e.g. Xcode CLI tools on macOS, build-essential on Debian).
git clone https://github.com/TeamSparkAI/tsinterceptor.git
cd tsinterceptor
npm installFull distribution (Next.js production build + bundled server.ts → dist/):
npm run build
npm run start:prodSame as node dist/server.js or ./dist/interceptor after a successful build.
Iterating locally: npm run start:dev runs build:next then tsx server.ts -- --port 3000.
For start:dev only, .env / .env.local are read from the repository root (next to server.ts), not from cwd.
| Script | Purpose |
|---|---|
npm run build |
Full dist/ (Next .next, interceptor binary, appData, public). Use this (or prepack) before publish. |
npm run build:next |
next build (writes .next/ in the repo). |
npm run build:bundle |
esbuild server.ts → repo dist/server.js. |
npm run build:prod |
build:next + build:bundle (what scripts/build.js runs for the first half). |
npm run start:prod |
node dist/server.js. |
npm run start:dev |
Next build + tsx server on port 3000. |
npm run start:server |
./dist/interceptor (after npm run build). |
npm test |
Jest unit tests. |
npm run test:watch / npm run test:coverage / npm run test:e2e |
Test variants. |
npm run clean |
Wipe TsInterceptor app data (same effect as interceptor --clean; uses tsx scripts/clean.ts). |
npm run load-sample-data |
Load optional sample messages (development). |
npm run migrate |
Standalone migration helper (lib/models/sqlite/runMigration.ts). |
- github.com/TeamSparkAI/tsinterceptor.
- Design:
docs/mcp-interceptor-design.md
This project is licensed under the MIT License.
