MCP Workstation
Provides web search and extraction capabilities using the Brave Search API.
Provides tools for interacting with GitHub, including repository management, issues, pull requests, files, commits, branches, releases, Actions, and rate limit information.
Provides tools for interacting with Jira, including issue search with JQL, issue creation and updates, comments, worklogs, projects, boards, sprints, issue types, and assignable users.
Provides tools for interacting with Notion, including searching, retrieving pages, listing block children, creating pages, and appending blocks.
Provides tools for interacting with Slack, including posting messages, listing channels, viewing channel history, and listing users.
Provides tools for interacting with SQLite databases, including listing tables, running queries, and executing SQL statements.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Workstationlist my enabled servers and their tools"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
π₯οΈ MCP Workstation
One MCP endpoint. Every MCP server. Your own multi-user platform.
MCP Workstation is a single MCP server that acts as an aggregator: your AI client connects to it once and gets every tool from every MCP server you've registered β plus a dense set of built-in tools β behind one connection.
Run it in platform mode (set BETTER_AUTH_SECRET) and it becomes a full product:
Sign-in with Google or GitHub (Better Auth) at a built-in dashboard (
/)Per-user MCP servers β each user registers their own stdio/HTTP MCP servers, with secrets stored encrypted (AES-256-GCM), and toggles them on/off
API tokens per user; every
/mcprequest must carryAuthorization: Bearer <token>Per-user catalogs β tool lists are built per request from that user's enabled servers and module prefs. Users only ever see their own servers.
Categorized modules & tools β everything ships on by default, grouped by category (Development, Data, Finance & Crypto, β¦), with per-tool toggles: turn off a whole module or a single tool (e.g. keep
crypto_pricebut hidecrypto_trending).A Skills Hub β reusable agent instruction sets (debugging, code review, security audits, β¦) shipped alongside the MCP tools, browsable in the dashboard and loadable by any connected client via
skills_list/skills_get. One hub, MCP + skills together.
It speaks the 2026-07-28 MCP specification (the newest release): a stateless
protocol core. There is no initialize handshake, no Mcp-Session-Id, no connection
state β every request is self-contained and independently authenticated, so the server
scales behind a plain round-robin load balancer. Tools are namespaced
(github_create_issue, mybox_read_file, β¦) so nothing collides and routing is automatic.
ββββββββββββββββ Bearer token + stateless request βββββββββββββββββββββββββββββββββββ
β Claude / β ββββββββββββββββββββββββββββββββββββΆ β MCP Workstation β
β Cursor / β http://localhost:3125/mcp β βββββββββββββββββββββββββββββ β
β VS Code β ββββββββββββββββββββββββββββββββββββ β β Built-in modules (shared) β β
ββββββββββββββββ β β time uuid memory githubβ¦ β β
ββββββββββββββββ β βββββββββββββββββββββββββββββ β
β Browser β / (dashboard) β βββββββββββββββββββββββββββββ β
β Google / β βββββββββββββββββββββββββββββββββββΆ β β Per-user proxy engine β β
β GitHub β /api/auth/*, /api/* β β βΆ user's stdio servers β β
ββββββββββββββββ β β βΆ user's HTTP servers β β
β βββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββQuick start
Requires Node.js β₯ 22.5 (for the built-in node:sqlite).
1. Run with platform mode (recommended):
npm install
npm run build
cp .env.example .env # then set BETTER_AUTH_SECRET + OAuth keys (see below)
npm start2. Or run single-user, no auth (everything is open):
npm start # platform mode stays off without BETTER_AUTH_SECRETYou'll see a startup report listing active modules, connected upstream servers, and whether platform mode is on:
[mcp-workstation] β time: 2 tools
[mcp-workstation] β github: GITHUB_TOKEN not set
[mcp-workstation] 22 tools available
[mcp-workstation] platform mode: ON (multi-user auth)
[mcp-workstation] dashboard: http://localhost:3125/Related MCP server: MCPGate
Platform mode β turning it on
Add to .env:
BETTER_AUTH_SECRET=$(openssl rand -base64 32) # REQUIRED β turns platform mode on
# Google OAuth (redirect URI: {BETTER_AUTH_URL}/api/auth/callback/google)
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
# GitHub OAuth (callback URL: {BETTER_AUTH_URL}/api/auth/callback/github)
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...Then open http://localhost:3125/ and sign in with Google or GitHub. Email/password
sign-in is on by default for development (ALLOW_EMAIL_AUTH=false to disable).
From the dashboard you can:
Add MCP servers β pick
stdio(a local command) orhttp(a remote endpoint), name it (tools appear asname_*), and set env vars / headers. Secrets are encrypted at rest and never returned by the API.Toggle servers on/off β disabled servers stop appearing in your endpoint instantly.
Mint API tokens β name a token (e.g. "Claude Code"), copy it once, revoke anytime.
Toggle modules & individual tools β everything is on by default; drill into any module and switch off single tools, or hide whole categories you don't use.
Browse the Skills Hub β enable/disable skills, read their full instructions, and let your clients pull them over MCP.
Connect your AI client
First create an API token in the dashboard. Then point your client at the endpoint with the token as a Bearer header:
Client | Configuration |
Claude Code |
|
Cursor | Settings β MCP β Add new MCP server β Type: |
VS Code / Copilot |
|
The endpoint serves the 2026-07-28 stateless protocol, falls back to serving
2025-era streamable-HTTP requests automatically, and still bridges the deprecated
legacy HTTP+SSE transport for older clients (in platform mode its message POSTs are
authenticated too). Requests without a valid token get a proper 401 + WWW-Authenticate
challenge.
Local apps can also use stdio (single-user mode):
npm run stdioWhat's new β 2026-07-28 features wired in
Stateless core β no handshake, no sessions. Each request carries its protocol version, client identity, and capabilities in a
_metaenvelope. The old session-recovery/session-reaping code is gone entirely; the server is just a handler.server/discoverβ clients can probe capabilities up front (optional).Cacheable list results β
tools/listandserver/discoverreturnttlMs+cacheScopehints (tool catalogs only change on reload).Header-based routing β requests carry
Mcp-Method/Mcp-Nameheaders, so gateways, rate limiters, and WAFs can route and meter without parsing JSON bodies (missing headers are rejected with a spec-compliant error).resultType: "complete"results withio.modelcontextprotocol/serverInfoin_meta.Built on SDK v2 (
@modelcontextprotocol/server+@modelcontextprotocol/client), web-standards based, with the client auto-negotiating protocol era against upstreams.
MCP Registry integration
Discover & import: the dashboard Directory searches the official MCP Registry (
registry.modelcontextprotocol.io) live β one click adds any remote server to your account as a namespaced upstream (/api/registryis a read-only, session-gated proxy; no keys leave the server side).Publish our hub:
registry/server.jsonis a valid entry (io.github.anshace/mcp-workstation, validated offline against the vendored official schema vianpm run validate:registry). To list it publicly: point the remoteurlat your deployed instance, claim the namespace via GitHub, and submit with the officialmcp-publisherCLI.
Built-in tools (no API keys needed for the core set)
In platform mode the key-gated modules (
github,jira,search,notion,slack) are per-user: each account can store its own credentials on the dashboard's Credentials page (API:/api/secrets, encrypted at rest, never displayed back) and those shadow the server's process env β so one user'sgh_*calls never run with another's token.
Module | Tools | Enabled by |
|
| always |
|
| always |
|
| always |
|
| always |
|
| always |
|
| always |
|
| always |
| 27 tools β |
|
| 15 tools β |
|
|
| any of |
|
| always |
|
| always |
|
| always |
Lite catalog β search-first, token-frugal (on by default for new users)
Every agent pays for tools/list in its context window β a full workstation
catalog is 60+ tools β tens of thousands of tokens. Lite mode lists only
five Tier-0 tools and keeps everything else fully reachable behind them:
Tool | Role |
| BM25 search over the whole hidden catalog (name + description + module synonyms) |
| fetch the exact input schema of any catalog tool |
| invoke any catalog tool by name β rate limits and audit apply identically |
| introspection + reload |
Toggle per user on the dashboard (Modules & Tools β Lite catalog) or via
PUT /api/prefs {"liteCatalog":false} for clients that want the full static
list. Retrieval reuses our tool-index work (src/toolsearch.ts, unit-tested
against a 20-probe intent set at β₯90% accuracy).
Oversized tool results (default >200KB, MAX_RESULT_BYTES) are spilled to a
file in the workspace and replaced by a preview + fs_read pointer, so one
chatty upstream never floods the agent's context.
| skills | skills_list, skills_get β pull your enabled skills' instructions over MCP | always |
GitHub and Jira both support enterprise/self-hosted instances via
GITHUB_API_URLandJIRA_BASE_URL. Jira accepts an API token (Basic auth withJIRA_EMAIL) or a PAT. |postgres|pg_list_tables/describe_table/query|DATABASE_URL| |notion|notion_search/get_page/list_block_children/create_page/append_blocks|NOTION_TOKEN| |slack|slack_post_message/list_channels/channel_history/list_users|SLACK_BOT_TOKEN| |workstation|workstation_status,workstation_reload| always |
Copy .env.example to .env, fill in the keys you have, and restart. Missing keys simply
disable that module β everything else keeps working.
π§ Knowledge base β full-text + vector search (zero config)
The knowledge module gives your AI a searchable memory, out of the box:
Full-text search β SQLite FTS5 with BM25 ranking (
knowledge_fts_search)Semantic vector search β local embeddings (
all-MiniLM-L6-v2, 384-dim), downloaded once and cached; runs fully offline afterwards (knowledge_vector_search)Hybrid search β FTS + vector merged and ranked (
knowledge_search)Auto-fallback β if the embedding model can't load, a TF-IDF vectorizer takes over, so search always works
Workspace indexing β
knowledge_index_workspacecrawls the sandboxed filesystem roots and indexes text/code files in chunks
# add documents, then search
knowledge_index { "text": "...", "title": "...", "source": "..." }
knowledge_search { "query": "feline companions that purr" } # semantic
knowledge_fts_search { "query": "javascript server" } # exact/BM25The embedding model downloads on first vector-search use (one-time, ~23 MB), stored in the local HuggingFace cache. No API keys required.
π‘ Skills Hub β instructions your agents can follow
The workstation ships a library of skills: markdown playbooks for recurring work
(debugging, code-review, git-workflow, sql-querying, web-research,
documentation, deployment-checklist, security-audit β each with a description,
category and version). They sit next to the MCP tools in one hub:
Everything is on by default β no setup.
The dashboard has a dedicated Skills page: browse by category, read any skill's full instructions in a preview, and toggle skills on/off per user.
Connected clients pull them over MCP:
skills_list(names, descriptions, categories) thenskills_get { "name": "debugging" }for the full content.Skills live in
skills/*.mdβ add one with the same frontmatter (name, description, category, version) and rebuild.
Adding your own MCP servers (the aggregator part)
Copy config/servers.example.json to config/servers.json and list the servers you want
aggregated. The workstation connects to each at startup (via the v2 client, which
auto-negotiates with both modern and legacy upstream servers) and merges their tools
into its own list, prefixed with the server's key.
{
"servers": [
{
"key": "myfiles", // β tools appear as myfiles_*
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "C:/path/to/folder"],
"env": { "SOME_TOKEN": "..." } // optional extra env for the child process
},
{
"key": "remote",
"type": "http", // remote Streamable HTTP / SSE servers
"url": "https://your-mcp-server.example.com/mcp",
"headers": { "Authorization": "Bearer ..." }
}
]
}enabled: false(or a bad entry) skips the server; a server that fails to start is reported inworkstation_statusinstead of crashing the workstation.After editing
servers.json, call theworkstation_reloadtool β because every HTTP request builds a fresh tool catalog from the live registry, the new tools appear on the very nexttools/list.
Operations
workstation_statusβ which modules are active (and why others aren't), which upstream servers are connected, total tool count, protocol version.workstation_reloadβ re-readsservers.json, reconnects upstreams, refreshes the tool list.Endpoint path and port are configurable:
MCP_PATH(default/mcp),PORT(default3125).
Security notes
Every
/mcprequest is authenticated in platform mode. No token, no tools. Tokens are stored as SHA-256 hashes, never plaintext; per-user server secrets (env vars, headers) are encrypted with AES-256-GCM usingBETTER_AUTH_SECRETand never returned by the API.Multi-tenant isolation. Each request builds the tool catalog from that user's enabled servers and prefs β a user can never see or call another user's servers.
Filesystem is sandboxed.
fs_*tools refuse paths outsideFILESYSTEM_ROOTS(default./data/workspace).Databases are read-only by default.
pg_queryandsqlite_queryblock write statements unless you explicitly setPG_ALLOW_WRITE=true/SQLITE_ALLOW_WRITE=true.fetch_urlcan be restricted to specific domains withallowed_domains.Every key-gated module is off unless you set the key. Nothing phones home.
In single-user mode (no
BETTER_AUTH_SECRET) there is no auth β bind to localhost or put a reverse proxy in front. Sessions usesecurecookies automatically when the public URL is HTTPS.
Development
npm run check # typecheck + web typecheck + dead-code gate + unit tests
npm run typecheck # fast type check (backend)
npm run typecheck:web # type check (React dashboard)
npm run test:unit # fast unit tests for core modules (no build needed)
npm test # builds + unit tests + the core end-to-end smoke test
npm run test:platform # platform mode: signup β tokens β per-user /mcp β isolation
npm run test:integrations # GitHub + Jira modules against a local mock API (no real credentials)
npm run dev # run the backend from source (serves the built dashboard at /)
npm run dev:web # Vite dev server for the dashboard (proxies /api + /mcp to the backend)
npm run build:web # rebuild the dashboard into public/ (served by the backend)See CONTRIBUTING.md (how to add a module) and docs/ARCHITECTURE.md (how the pieces fit together).
Project layout
src/
index.ts entry point: boots workstation + platform (auth, DB, dashboard)
server.ts per-request McpServer built for the authenticated user,
shared registry + per-user upstream aggregators
http.ts node:http front-end: /api/auth/*, /api/*, static UI, /mcp
(Bearer-gated in platform mode, legacy SSE bridge kept)
config.ts .env + config/servers.json loading
registry.ts mutable tool registry + module registration
platform/
auth.ts Better Auth instance (Google + GitHub, cookies)
db.ts SQLite: auth tables (auto-migrated) + servers/tokens/prefs
tokens.ts API-token mint/verify + the /mcp Bearer verifier
api.ts dashboard REST API (servers CRUD, tokens, prefs, skills,
secrets, registry import proxy)
oauth.ts OAuth 2.1 authorization server for /mcp (RFC 9728/7591:
DCR, consent, PKCE S256 β mcw_ bearer)
serverConfig.ts encrypted server-row codec (shared by core + REST)
toolsearch.ts ephemeral BM25 tool index + module synonym table
descli.ts tool-description quality linter
serverConfig β platform/serverConfig.ts server-row β runtime codec
skills.ts loads skills/*.md (frontmatter) into the skills hub
crypto.ts AES-256-GCM secret encryption + SHA-256 token hashing
proxy/
upstream.ts v2 client connection to one stdio/HTTP MCP server, namespacing
aggregator.ts connect-all / list-all / route-calls across upstreams
builtins/ time, uuid, fetch, memory, filesystem, knowledge, github,
jira, search, postgres, sqlite, notion, slack, crypto, hn,
weather (+ the skills module)
skills/ *.md β the skills hub library (one markdown file per skill)
public/
index.html built React dashboard (emitted by `npm run build:web`)
assets/ hashed JS/CSS bundles (React + Astryx + Tailwind)
web/ the dashboard source β React 19 + Vite + Tailwind CSS v4
(layout utilities only), Meta's Astryx design system
(@astryxdesign/core + theme-neutral, forced dark),
lucide-react (icons)
src/
App.tsx root: session gate + view router + toast viewport
main.tsx Astryx Theme provider (neutral theme, dark mode)
lib/api.ts REST client + types
lib/store.tsx app state: session, data, routing, toasts
lib/catalog.ts MCP Directory catalog + connect-guide client configs
components/ Shell (AppShell + TopNav + SideNav), ui primitives
views/ Auth, Dashboard, Directory, Connect, Servers, Tokens,
Credentials, Modules, Skills, Settings
registry/
server.json official MCP Registry entry (publish-ready)
server.schema.json vendored registry schema (offline validation)
scripts/
smoke.mjs core end-to-end test (npm test)
smoke-platform.mjs platform-mode end-to-end test (npm run test:platform)
smoke-ghjira.mjs GitHub + Jira mock-API test
test-upstream.mjs tiny stdio MCP server used by the platform test
tests/
*.test.ts unit tests for core modules (npm run test:unit) β
utils/config/ratelimit/audit, run via node --test + tsx
docs/
ARCHITECTURE.md how the pieces fit togetherRoadmap ideas
MRTR (Multi Round-Trip Requests) β tools that ask the user to confirm mid-call (e.g. before creating a GitHub issue), via
input_requiredresultsPer-user keys for built-in modules (currently server-level env keys are shared)
Tasks extension for long-running agent work
Resource + prompt aggregation from upstreams (currently tools only)
This server cannot be deployed
Maintenance
Related MCP Connectors
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
- UnifAPIOAuthcom.unifapi
Hosted MCP server for live public-data APIs and Skills for AI agents.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
One connector for 15,000+ MCP servers plus your team's private MCPs, from any AI client.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA centralized management platform that aggregates multiple Model Context Protocol (MCP) servers into a single unified endpoint for AI agents. It provides a web interface for hot-swappable tool management, proxying of existing servers, and AI-powered generation of custom MCP plugins.1-
- AlicenseNot gradedqualityDmaintenanceMCPGate aggregates multiple MCP servers into a single unified endpoint, enabling centralized tool management with granular filtering, automatic namespacing, and observability. Features a real-time web dashboard and optional PostgreSQL-backed audit trails for monitoring and controlling AI tool access across local and remote deployments.5 npmApache 2.0
- FlicenseNot gradedqualityBmaintenanceAggregates multiple MCP servers and custom Python tools behind a single endpoint, with intelligent context and tool discovery for AI agents.-
- AlicenseNot gradedqualityAmaintenanceUnified AI gateway that aggregates MCP tools from multiple servers and routes LLM requests with provider combos and fallback, all managed through a web UI.1MIT