synamcps-server
Universal corporate AI-tools memory and MCP proxy server to store data and proxy external MCP sources on role-based model
Documentation
Synamcps (SynaMCPs) — MCP + Knowledge Storage Gateway
`Synamcps` is a server that provides:
- An MCP server for LLM clients (Cursor / Claude Desktop / Claude Code / etc.)
- An HTTP API to create/search/read knowledge items
- A Web Admin UI to manage users/groups/storages/tokens, view status, and do basic diagnostics
- Token-based access to storages (tokens only *narrow* permissions), with ACL/RBAC, rate limiting, and usage/metrics
The server supports multiple auth methods (OIDC/Keycloak/Google/Teleport Proxy JWT) and an internal login for the Admin UI.
Quick start (Docker Compose)
Requirements:
- Docker + Docker Compose
Run:
cp .env.example .env
make compose-upOpen:
- Login: `http://localhost:8080/login`
- Admin UI: `http://localhost:8080/admin`
- User app: `http://localhost:8080/app`
- MCP endpoint (streamable): `http://localhost:8080/mcp`
- HTTP API: `http://localhost:8080/api/*`
Stop:
make compose-downLocal run (without Docker)
Requirements:
- Go 1.23+
- Postgres, Redis, S3/MinIO available (or use Docker Compose as your infrastructure)
export CONFIG_PATH=configs/config.local.yaml
go run ./cmd/serverFeatures (high level)
Storages, ACL and tokens
- Storage is a logical entity tied to:
- records in the metadata catalog (Postgres)
- an S3 prefix (`storage.S3Prefix`)
- search scoping (vector backend: pgvector/qdrant)
- ACL bindings define user/group access to a storage (read/write/admin/owner).
- Access tokens:
- belong to a user (owner)
- do not expand permissions — they *narrow* the owner's access (intersection of user ACL and token scopes)
- can restrict: `storageIds`, `maxMode` (read/read_write), `toolAllowlist`, rate limits.
- Document visibility (`personal`/`group`/`public`) is enforced on top of storage access: being able to read a storage is necessary but not sufficient — a `personal` document is visible only to its owner, a `group` document only to its owner or members of its groups.
Knowledge items
- You can add an item as:
- Text (via the standard `POST /api/knowledge`)
- File (upload → raw stored to S3 → best-effort extraction → summary+embeddings → item saved to storage)
- Link (download → raw stored to S3 → extraction → summary+embeddings → item saved to storage)
- Link ingestion only accepts `http`/`https` URLs and refuses to fetch internal addresses (loopback, link-local incl. cloud metadata `169.254.169.254`, and private ranges) — SSRF protection that also applies across redirects.
MCP
- MCP exposes a dynamic `tools/list` based on the bearer token (only allowed tools/storages are visible).
- Supports Streamable HTTP transport (`/mcp`) and optional legacy SSE.
- MCP tool names use `_` (underscore) to avoid filtering/warnings in some clients.
- MCP proxy: register upstream HTTP/SSE MCP servers in Admin UI (`MCP Servers` tab), discover tools/resources/prompts, restrict by ACL and per-token scopes. Proxied identifiers:
- tools/prompts: `{slug}__{upstream_name}`
- resources: `syna-mcp/{slug}/{upstream_uri}`
- the `slug` is generated automatically from the server name (no manual entry).
- Upstream auth secrets are stored encrypted in Postgres (`MCP_PROXY_SECRETS_KEY` in `.env`).
Usage / Rate limit / Metrics
- Rate limiting per token (minute/hour/day + burst), enforced for both MCP calls and the REST API (`429 Too Many Requests` when exceeded).
- Request bodies are capped by `limits.max_upload_bytes` (`413` when exceeded).
- Usage events (and status/errors) can be written to Redis TimeSeries (when enabled).
- `/metrics` exposes Prometheus-format metrics (label values are sanitized and series cardinality is bounded).
Web Admin UI
The built-in admin UI (server-rendered HTML) lets you:
- Users / Groups / Group members
- Storages + Storage details (ACL, keys/tokens, items list)
- Tokens + MCP Connect wizard + delete
- Add item (Text/File/Link)
- Search (by token / by storage)
- Status (Postgres/Redis/S3/LLMs + error counters)
Forms pick entities from name dropdowns (storages/groups/users/tokens/MCP servers) with refresh buttons instead of typing raw IDs. Slugs are no longer entered by hand — a storage defaults its slug to its id and an MCP server derives a unique slug from its name.
Configuration
Default config: `configs/config.example.yaml`
Override: `CONFIG_PATH=/path/to/config.yaml`
Key sections:
- `web.default_admin`: Admin UI username/password (password via env ref)
- `oauth.providers`: OIDC providers (issuer/audience/jwks_url; optional client_id for AS login)
- `oauth_as`: MCP OAuth 2.1 Authorization Server for Claude Desktop Connectors
- `teleport`: Teleport Proxy JWT (issuer/audience)
- `redis`: sessions + usage/time-series (when enabled)
- `s3`: endpoint/bucket + large document threshold
- `embedding`, `summarization`: LLMs (provider/model/api/api_key_env_ref)
- `vector_backend.active`: `pgvector` or `qdrant`
- `metadata_catalog.dsn`: Postgres DSN
- `api.allowed_origins`: strict CORS allowlist
- `usage`: accounting and time series, retention, exporters
Example `.env` for local development: `.env.example`.
HTTP API
Authentication:
- cookieAuth: web UI session (`session_id` cookie)
- bearerAuth: `Authorization: Bearer `
Common error codes:
- `401` — missing token/session
- `403` — forbidden (insufficient permissions for the storage/operation)
- `404` — not found
- `413` — request body exceeds `limits.max_upload_bytes`
- `422` — invalid request
- `429` — rate limit exceeded (per-token limits)
Knowledge API
`GET /api/knowledge`
List items with pagination and filters.
Query params:
- `page` (int)
- `pageSize` (int)
- `storageId` (string) — limit to a specific storage
- `source` (string) — exact match
- `sourceUrl` (string)
- `sourceUrlMode` (`exact` | `partial`) — `partial` works only when `search.filters.source_url.allow_partial_match=true`
Response: `models.PaginatedKnowledgeList` (items + total + hasNext + page/pageSize).
`POST /api/knowledge`
Create an item from text.
Body:
{
"storageId": "storage-id-optional",
"title": "Runbook",
"text": "Long knowledge text...",
"mimeType": "text/plain",
"visibility": "personal",
"groupIds": [],
"source": "api",
"sourceUrl": "https://docs.example.com/runbook"
}Notes:
- if `storageId` is empty and access-service is enabled, the server uses/creates the user's personal storage
- `visibility` defaults to `personal`
- `groupIds` must be an array (not `null`)
`GET /api/knowledge/{docId}`
Return a single document.
`DELETE /api/knowledge/{docId}`
Delete a document (and associated embeddings in the vector store).
`POST /api/knowledge/search`
Embedding-based search.
Body:
{
"query": "kubernetes ingress timeout",
"topK": 10,
"filters": {
"storageId": "storage-id-optional",
"source": "api",
"sourceUrl": "https://...",
"sourceUrlMode": "exact"
}
}Response: an array of search hits (including snippet/title/source/sourceUrl).
Ingest API (File/Link)
`POST /api/knowledge/ingest/file` (multipart)
Upload a file as an item:
- raw content is stored in S3
- best-effort text extraction is performed
- the pipeline produces summary + embeddings
- the final result is saved as a normal knowledge item
Multipart fields:
- `storageId` (string, optional)
- `title` (string, optional)
- `visibility` (`personal`|`group`|`public`, optional)
- `source` (string, optional)
- `sourceUrl` (string, optional)
- `mimeType` (string, optional)
- `file` (required)
Example:
curl -X POST http://localhost:8080/api/knowledge/ingest/file \
-H "Authorization: Bearer $TOKEN" \
-F "storageId=..." \
-F "title=Spec" \
-F "visibility=personal" \
-F "file=@./spec.txt"`POST /api/knowledge/ingest/link` (json)
Downloads a URL, stores raw content to S3, extracts text, and saves an item.
Body:
{
"storageId": "storage-id-optional",
"title": "Optional title",
"url": "https://example.com/docs",
"visibility": "personal",
"source": "link"
}Admin API (`/api/admin/*`)
All endpoints require authentication (cookie or bearer), and many require `platform_admin`.
Users
- `GET /api/admin/me`
- `GET /api/admin/users` (platform_admin)
- `POST /api/admin/users` (platform_admin)
- `GET /api/admin/users/{id}` (admin или сам пользователь)
- `PATCH /api/admin/users/{id}` (admin или сам пользователь)
- `POST /api/admin/users/{id}/password` (admin или сам пользователь)
- `DELETE /api/admin/users/{id}` (platform_admin)
Groups
- `GET /api/admin/groups` (platform_admin)
- `POST /api/admin/groups` (platform_admin)
- `DELETE /api/admin/groups/{id}` (platform_admin)
- `GET /api/admin/groups/{id}/members` (platform_admin)
- `PUT /api/admin/groups/{id}/members/{userId}` (platform_admin)
- `DELETE /api/admin/groups/{id}/members/{userId}` (platform_admin)
Storages
- `GET /api/admin/storages` (storages available to the current user)
- `POST /api/admin/storages`
- `DELETE /api/admin/storages/{id}` (requires `storage.delete`: storage owner/admin or platform_admin)
- `GET /api/admin/storages/{id}` (storage details: storage + acl + tokens; requires read access)
- `GET /api/admin/storages/{id}/acl` (requires `acl.manage`)
- `PUT /api/admin/storages/{id}/acl` (requires `acl.manage`)
Tokens
Mutating token endpoints require the caller to be the token owner or platform_admin; `GET /api/admin/tokens` lists only the caller's own tokens (platform_admin sees all).
- `GET /api/admin/tokens`
- `POST /api/admin/tokens`
- `DELETE /api/admin/tokens/{id}` (owner/platform_admin)
- `PATCH /api/admin/tokens/{id}/rate-limit` (owner/platform_admin)
- `POST /api/admin/tokens/{id}/revoke` (owner/platform_admin)
- `POST /api/admin/tokens/{id}/rotate` (owner/platform_admin)
- `PATCH /api/admin/tokens/{id}/mcp-scopes` (owner/platform_admin)
- `GET/POST /api/admin/tokens/{id}/connect-options` (wizard for MCP clients)
Usage / Status
- `GET /api/admin/usage/series`
- `GET /api/admin/usage/summary`
- `GET /api/admin/status` — component status + error counters (Redis TimeSeries)
MCP
Transport
- Streamable HTTP: `POST /mcp` (JSON-RPC) + `GET /mcp` (SSE stream по `Mcp-Session-Id`)
- Legacy SSE (если включено): `/sse` + `/messages`
Minimal flow (streamable)
1) Obtain a bearer token (OIDC/Teleport/or internal)
2) `initialize`:
curl -X POST http://localhost:8080/mcp \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{}}'3) Save `Mcp-Session-Id` from headers/response (clients do this automatically)
4) Open the stream (the bearer token is required and must match the session owner):
curl -N http://localhost:8080/mcp \
-H "Authorization: Bearer $TOKEN" \
-H "Mcp-Session-Id: "`GET /mcp` and `DELETE /mcp` are authenticated; a session can only be read/closed by the principal that created it.
Dynamic tools/list
`tools/list` returns only the tools allowed by the current bearer token and its storage scopes.
tools/call
`tools/call` routes calls to the corresponding internal methods (knowledge_* etc.).
MCP Connect (Web UI)
The Admin UI (`/admin`) includes an MCP Connect page that generates:
- config file name
- `configBody` (JSON)
- step-by-step instructions
You can copy `configBody` by clicking it.
Installation and operations
Docker Compose
cp .env.example .env
make compose-upHelpful:
- `make compose-down`
- `make seed-dev` (if used in your environment)
Config and secrets
- `configs/config.example.yaml` — example config
- `configs/config.local.yaml` — local compose config (used in `docker-compose.yml`)
- `.env` — secrets (passwords/keys), example in `.env.example`
CORS
`api.allowed_origins` is a strict allowlist. Unknown origins are rejected.
Web UI routes (`/`, `/login`, `/logout`, `/app*`, `/admin*`) bypass the origin check.
Troubleshooting
Documentation in this repo
- `docs/marketing.md` — product overview + corporate RAG / agentic pipeline scenarios
- `docs/setup.md` — installation and run
- `docs/api.md` — basic knowledge endpoints
- `docs/mcp-connection.md` — MCP connection
- `docs/auth-setup.md` — auth providers
- `docs/openapi.yaml` — baseline OpenAPI stub
Frequently asked questions
What is synamcps-server?
synamcps-server is Universal corporate AI-tools memory and MCP proxy server to store data and proxy external MCP sources on role-based model
How do I install synamcps-server?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is synamcps-server open source?
Yes — it is hosted on GitHub at https://github.com/synamcps/synamcps-server and has 4 stars.
Related MCP tools
The missing open-source Kubernetes UI with a built-in MCP server for AI agents. See what's broken, why, and what changed. Issues, Topology, event timeline, Helm, GitOps, live service traffic, and cluster audits - all in one Go binary.
mcp-language-server gives MCP enabled clients access semantic tools like get definition, references, rename, and diagnostics.
Run MATLAB® using AI applications with the official MATLAB MCP Server from MathWorks®. This MCP server for MATLAB supports a wide range of coding agents like Claude Code® and Visual Studio® Code.
One place to manage & connect to all your MCP servers
eBPF-powered network observability for Kubernetes. Indexes L4/L7 traffic with full K8s context, decrypts TLS without keys. Queryable by AI agents via MCP and humans via dashboard.
GOWA - WhatsApp REST API with support for UI, Multi Account, Webhooks, and MCP, and Chatwoot. Built with Golang for efficient memory use.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP