Engineering documents from the cMCP pilot build (October 2026). Statuses here are engineering states, not product claims: see cMCP for what is available. All documents
Status 2026-10-11. The ports and folders below are those of the pilot server. Stages 1a–1t of Build Phase 1 are built and tested (1l–1s on 2026-10-11, M-109; 1t, M-111). The pilot company has not adopted cMCP, so its account is now a test account with its company data cleared. Next, on hold until the owner resumes it (M-112): the web console moves to cmcp.it-labs.in and the API, sign-in, database and local AI model to a GPU server, so the addresses on this page will change. See the build plan, section 15.

cMCP Features and Stack

All features of the cMCP hardware and software, one tab per part. Phase 1: internal company use on one shared server. Facts taken from the repo docs, deploy files and manual; no secrets are shown.

Overview and end-to-end flow

cMCP is the company's shared cognitive memory layer: AI apps (Claude Code, Claude Desktop, bots) and people read and write governed memory through one permission service, one audit log and one search index. Phase 1 is internal use on one shared server.

How it works

  1. Person or AI appbrowser / MCP client
  2. Apache 443only public port
  3. Router edgeCaddy, 127.0.0.1:5080
  4. Web 5580 / Login 5570 / MCP-API 5550by host name
  5. Permission check + auditPostgres RLS
  6. Postgres + Hindsight indexmemory record + search
  7. Workerextract, index, jobs

Features

FeatureWhat it doesWho uses itWhere
Memory scopesEight layers of memory: Account, Organization, Project, Client, Team, User, Agent, Personal.EveryoneMemory model tab
Context packWhat an AI app gets at the start of a task: inherited memory for its place, with a manifest for cheap refresh.AI appsMCP tool memory_get_context
Hybrid searchMeaning (Hindsight) plus keyword (Postgres), re-checked under row-level security.AI apps, peoplememory_search, /v1/search
Governed writesNothing reaches a shared scope without a role, a time-limited grant or an approval.Leads, adminsPermissions tab
Audit logEvery allow and deny recorded with caller, place, app and model.Auditors, org adminsAudit screen, /v1/audit
ConnectorsJira, database views and mailboxes feed facts into staging for approval.Org admins, leadsConnectors tab
Web console15 screens for memory, approvals, places, grants, settings, audit.Everyoneconsole.pilot.example
Local fact extractionA small CPU model on this server turns text into facts in the background.WorkerOllama, port 5560

Usage and knowledge

Parts and ports (all 127.0.0.1)

Typical life of a memory

Phase 1 in one line

Gotchas

Hardware and server

The shared production host that runs cMCP in Docker, with per-container CPU and memory caps, localhost-only ports and Apache 443 as the only public way in.

How it works

  1. Hardware firewallopens 443 only
  2. Apache 443 (ISPConfig)3 sites, Let's Encrypt
  3. Container edge127.0.0.1:5080
  4. Stack on 127.0.0.1Postgres, Valkey, Hindsight, Ollama, Keycloak, OpenBao
  5. Host processesAPI, worker, web UI
  6. Backups 04:20age-encrypted, 14 days

Features

FeatureWhat it doesWho uses itWhere
HostEPYC 16 cores / 32 threads, 125 GB RAM (about 113 GB free), 1.2 TB NVMe free on RAID 1, no GPU, Ubuntu 26.04. Shared with mail, DNS, VPN, 14 sites and carfax.Operatortodo.md section 7
Capacity planInternal use for up to about 200 people plus a few bots: roughly 22 to 34 GB RAM, 12 to 16 threads, 160 to 260 GB disk including local backups.Operatortodo.md section 7
postgrespgvector/pgvector:pg18, 127.0.0.1:5532, 4 CPU, 12 GB, shm 1 GB. Databases cmcp, hindsight, keycloak. Volume cmcp_pgdata.All partsdeploy/compose.yaml
hindsight0.10.2, 127.0.0.1:5540, 2 CPU, 4 GB, API key required, CPU embeddings and reranker.API, workercompose.yaml
ollama0.35.0, 127.0.0.1:5560, 8 CPU, 10 GB, one model loaded, keep-alive 30 min. Volume cmcp_models.Workercompose.yaml
keycloak26.7.4 production mode, 127.0.0.1:5570, 1.5 CPU, 2 GB.Loginscompose.yaml
valkey8.1.10, 127.0.0.1:5534, 1 CPU, 384 MB (maxmemory 256 MB), no persistence, read-only root, ACL users.API, webcompose.yaml
openbao2.5.5, 127.0.0.1:5536, 0.5 CPU, 256 MB, capabilities dropped, no-new-privileges, sealed after each start.API, workercompose.yaml
edgecmcp-edge 2.11.4 (Caddy + rate limits), host network, binds 127.0.0.1:5080 only, read-only, user 65534, 0.5 CPU, 256 MB.Apachecompose.yaml, deploy/edge/Caddyfile
fixture-dbTest profile only: synthetic Postgres on 127.0.0.1:5577, 0.5 CPU, 256 MB.Testscompose.yaml
Backups and cron/etc/cron.d/cmcp-backup runs deploy/backup/backup.sh daily at 04:20; 14 days kept in /srv/cmcp/backups; monthly restore test.Operatordeploy/backup

Usage and knowledge

Rules for this shared host

Memory budget of the caps

When a new server is needed

Backups

Network and sign-in

Three public sites on Apache 443 are routed by host name through one local router to the web console, the login server (Keycloak) and the MCP endpoint.

How it works

  1. Browser / AI appHTTPS 443
  2. Apache vhostcmcp, cmcp-auth, cmcp-api
  3. Router edge :5080host routing, allow-lists, limits
  4. cmcp → Web 5580console
  5. cmcp-auth → Keycloak 5570realm cmcp
  6. cmcp-api → API 5550/mcp only

Features

FeatureWhat it doesWho uses itWhere
Site console.pilot.exampleWeb console. Limit 1,200 requests per minute per address.PeopleISPConfig → router → 5580
Site auth.pilot.exampleKeycloak login: realm cmcp, static files and the realm admin console for super-users. Master realm, admin root, health and metrics return 404. Limit 30 per minute.People, apps, super-users→ 5570
Site api.pilot.exampleMCP for AI apps: only /mcp and the OAuth metadata. REST under /v1 returns 404. No dynamic client registration. Limit 600 per minute.AI apps, bots→ 5550
Router rulesOther hosts 404; encoded or dotted paths 400; over limit 429; X-Forwarded-For replaced by Apache's client address; Forwarded, X-Real-IP, x-middleware-* removed.Operatordeploy/edge/Caddyfile
One-time code sign-inReal people (accounts in CMCP_REAL_ACCOUNTS, default pilot) sign in with password plus authenticator code; a password alone never yields a token.PeopleKeycloak flow 'cmcp browser'
Test loginsTest users hold role cmcp-dev-cli and may use the password grant on cmcp-cli, only for test accounts.Testskeycloak_golive.py
Super-usersAccount admins of CMCP_SUPERUSER_ACCOUNTS (default pilot) get role cmcp-superuser and the realm admin console (users, sessions, unlock, read events). No realm, client or flow changes, no impersonation.Operatorkeycloak_golive.py superusers
Session lifetimesSessions 2 h idle / 8 h max, access token 15 min, refresh rotation, no offline_access; events kept 90 days (login) and 365 days (admin).AllRealm settings
Go public switchgo-public.sh sets public URLs, restarts services, checks the sites; 'off' returns to 127.0.0.1.Operatordeploy/dev/go-public.sh

Usage and knowledge

Sign in as a person

Admin console

Lockout

Dev access from a PC

ISPConfig gotchas

Never change by hand

Memory model

Memory is stored as governed rows in Postgres, layered in eight scopes, walled per client, labelled by audience, versioned and kept in step downward to every connected app.

How it works

  1. Save (fact or text)by person, app or bot
  2. Scope + audience labelwhere, who may see
  3. Status: staged → currentapproval where needed
  4. Version keptsuperseded on change
  5. Scope version bumpschange notice sent
  6. Apps re-read packdelta by manifest

Features

FeatureWhat it doesWho uses itWhere
ScopesAccount, Organization, Project, Client, Team, User, Agent, Personal. Wide to narrow; teams nest up to 5 levels and you also read parent and child teams.EveryoneGlossary
Client wallClient memory is returned only while the place is that client or a project linked to it. Never reaches another client, bots never use it.Client leadsauthz.py wall_client
Audience labelsinternal (default), restricted (named people only, bots never read), external_ok (safe for outside replies; set by a lead).Leadsenum cmcp.audience
Must-applyA rule the AI must always follow in a place; only leads or org admins set it.Leadsmemory field mandatory
Kindsfact, decision, preference, policy, procedure, contact, event.EveryoneSave dialog
Statusescurrent, superseded, deleted, staged (waiting for approval).Systemenum cmcp.memory_status
VersionsEvery update keeps the previous version; old versions kept 365 days by default (applied in Phase 2).Everyone/v1/memories/{id}/versions
Context pack and manifestInherited memory: Org → project (or team) → User → Personal if allowed → the app's Agent memory. The manifest lists scope versions; send it back to get up_to_date=true or only the changes.AI appscontext.py
Downward syncA pack is stale when a live scope version differs from the manifest. Subscribed apps get a notice on cmcp://context/<app_id> (URI only, no content).AI appssync.py
Place resolutionApp names a place you belong to → app default → repo/Jira mapping (git_repo:<remote>) → home team.AI appsConnect AI apps
Token budgetThe pack is cut to the app's budget (500 to 100,000 tokens); must-apply items are always kept.AI appsApp preferences
Data not instructionsMemory is returned labelled as data; text that looks like instructions is flagged and cannot be bulk-approved.AllDD-08

Usage and knowledge

Limits

Who may write where

Personal memory

Deleting a client

Gotcha

Permissions and audit

One permission service decides every read and write, deny by default; AI apps get only the smaller of the person's rights and a time-limited grant; every decision is audited.

How it works

  1. Request + verified tokenprincipal, acting-for, client app
  2. Permission servicedeny by default, error = deny
  3. Row-level securityPostgres per account
  4. Allow / denywith reason
  5. audit_eventsappend-only

Features

FeatureWhat it doesWho uses itWhere
Rolesorg admin, account admin, auditor (reads, never writes), team / project / client lead, member.Adminsauthz.py
AI apps vs peopleAn app install is the verified OAuth client; only cmcp-web counts as the person directly. Declared app name is only a label.AllADR 0001
Delegation grantsA lead grants an app or bot read and/or write on places they lead. Max 8 h for apps, 90 days for bots (adjustable). Never more than the grantor holds, not passed on, stops when the grantor loses the role, owner of the app accepts first.LeadsGrants and apps
BotsOwn login (client credentials), AI badge, sponsor, purpose (internal or outside_reply), hourly call limit (default 500). Read home team and organization; need a grant to write. Never see Personal, restricted or Client memory, never approve or grant.Org admins, sponsorsPeople and bots
Kill switchesSuspend now (sponsor or org admin), Resume (org admin), disable login client (super-user).Sponsors, adminscmcp-admin.py suspend / bot-disable
In-person actionsSettings, switches, solo mode, resources, approvals, grants decisions are made by a person in the web console, never by an AI app or bot.Admins, leadsWeb console
Row-level securityEvery table is tenant-isolated; isolation tests seed two accounts, organizations and clients and assert nothing crosses.Developerstests/isolation
Feature switchesOn/off per level (account, org, project, team, client, user, bot) with locks and 'allow switching on below'; lower levels can only restrict.AdminsSwitches screen
Audit logEvery read, write and admin decision with place, app and declared model; refused bot logins, rate limits, failed imports. Never edited by users (migration 0007 append-only).Auditors, org admins/audit, /v1/audit
What the AI knewAn audit entry for a read lists the exact memory versions in that context pack.AuditorsAudit screen

Usage and knowledge

Find why someone was refused

Typical admin commands (person login)

Limits

Accepted Phase 1 gap

MCP and REST API

The same single API sources drive both channels: 11 MCP tools for AI apps under /mcp and REST under /v1 for the web console and admin scripts.

How it works

  1. Claude Code / DesktopMCP over HTTP
  2. cmcp-api site or 127.0.0.1:5550/mcp
  3. Token checkOAuth, verified client
  4. Tool → permission → auditsame code as REST
  5. Result as labelled datamanifest included

Features

FeatureWhat it doesWho uses itWhere
memory_get_contextGet the company memory for the current place.AI apps/mcp
memory_searchSearch by meaning and keywords across what you may read.AI apps/mcp
memory_saveSave a fact or free text.AI apps/mcp
memory_updateChange one memory you may write; the previous version is kept.AI apps/mcp
memory_deleteDelete one memory you may write.AI apps/mcp
memory_refreshRebuild context from scratch.AI apps/mcp
memory_request_changeAsk the owner of a higher scope to correct, add, remove or explain.AI apps/mcp
memory_request_statusSee state and answer of your requests.AI apps/mcp
memory_save_session_summaryPropose an end-of-session summary; the person confirms first.AI apps/mcp
memory_list_scopesWhat you may read, writable shared scopes, grants.AI apps/mcp
resource_lookupFind where git repos, databases, mailboxes, folders, services live.AI apps/mcp
REST groups (63 paths)context, memories (+versions), search, sources, requests, approvals (+bulk), principals (suspend/resume), apps, teams, projects, clients (+erase), places and members, place-mappings, grants (accept/revoke), switches, connectors (+run, approval, reextract), notifications, me, settings, places, access-requests, account (+solo), resources, app-prefs, audit, metrics.Web console, scriptsdocs/api/openapi.yaml

Usage and knowledge

Connect Claude Code

How an app should behave (server instructions v1.4.0)

Common parameters

Tests

Adding a tool

Connectors and secrets

Connectors bring facts from other tools into staging, where the lead approves them; their passwords live only as ciphertext, with keys in OpenBao.

How it works

  1. Connector on schedule15 to 1,440 min
  2. Allow-listed hostchecked address
  3. Worker importread-only
  4. Staged factsApprovals → Imports
  5. Lead decidesapprove / edit / reject
  6. Memory in placeraw text purged after 30 d

Features

FeatureWhat it doesWho uses itWhere
JiraRead-only Jira Cloud account; open issues first (or all); issues with a security level and restricted comments never imported; Re-extract issues.Org admins, leadsConnectors screen
Database viewsPostgreSQL views only (up to 20), read-only user, at most 500 rows per run, own cMCP databases always refused.Account admins enable, org admins useconnector_database switch
MailboxesTLS port 993 only, up to 10 folders, sender domains allow-list, DKIM/DMARC pass required unless turned off, attachments never read, never bulk-approved.Account admins enable, people useconnector_imap switch
Personal connectionYour own mailbox or Jira; feeds only your User memory after you approve.EveryoneMy connections
Client connectionFeeds one client's memory; a client lead other than the person who set it up approves; any change withdraws approval.Client leadsPlaces screen
Place mappingsGit repo or Jira key → project or team.Org adminsConnectors screen
ApprovalsTabs: Requests, Promotions, Synthesis, Imports, Access. Edit before approving; items that look like instructions need rewriting; bulk approve/reject with preview.Leads, adminsApprovals screen
Resource catalogueWhere things live: repo, database, mailbox, folder, web link, document, service. Address only; text that looks like a password, token or key is refused. Internal or Restricted.Everyone reads, writers addResources, resource_lookup
OpenBao secret storeOne Transit key per account; Postgres holds only ciphertext bound to its connector. API token can only encrypt, worker token only decrypt. Write-only for users.System127.0.0.1:5536
Host allow-listsCMCP_CONNECTOR_HOSTS (default https://*.atlassian.net), CMCP_DB_CONNECTOR_HOSTS, CMCP_IMAP_HOSTS. Name resolved once; on this host only the cMCP dev block 5533 to 5580 is reachable, never port 5532 or production services.Super-usersnetguard.py

Usage and knowledge

Jira pilot setup

OpenBao after any restart

Tokens

Keep safe

Gotchas

Web console

A Next.js console (Node 24) at console.pilot.example for everyone; admin screens show only to those allowed. Every screen links to its manual page at /help.

How it works

  1. Browsercookie session
  2. Web server :5580holds tokens, Valkey sessions
  3. REST /v1as the person
  4. Permission checkevery call
  5. Screenwith Help link

Features

FeatureWhat it doesWho uses itWhere
My memoryContext for a place, search, save a memory, Re-sync, up-to-date badge.Everyone/
My requestsMemory requests you made and answers.Team members/requests
ApprovalsInbox for leads: Requests, Promotions, Synthesis, Imports, Access.Leads, admins/approvals
PlacesYour teams, projects, clients; greyed ones allow Request access; admins create places and add members.Everyone/places
Grants and appsGrants received/given, my app installs, default place, token budget, Personal access, app preferences.Everyone, leads/grants
ResourcesResource catalogue.Everyone/resources
My connectionsPersonal Jira and mailbox.Everyone/connections
NotificationsBell, mark read, daily reminder mail.Everyone/notifications
People and botsList, add bot, suspend/resume, sponsor change, view bot Agent memory (read only).Org admins/people
SwitchesFeature on/off per level with locks.Admins, leads/switches
ConnectorsConnector types, connections, place mappings.Admins/connectors
Times and limitsSettings with ranges, defaults and reasons.Admins, auditors read/settings
UsageTiles, calls, tokens saved, p95 times against targets, trends.Everyone (admins: account)/usage
AuditFilterable log, What the AI knew; Export is Phase 2.Auditors, org admins/audit
AccountAccount details and solo mode.Account admins/account
HelpManual in three groups: users, admins, super (server guide for account admins).Everyone/help

Usage and knowledge

Rules for changes

Build and run

Solo mode

Notifications and mail

Valkey

Operations

Run commands from /home/cMCP/repo. Check health after every start, restart or change; change one thing at a time.

How it works

  1. stack.sh up -dcontainers
  2. run-services.shAPI, worker, web, OpenBao unseal
  3. healthzok, engine, valkey, secrets
  4. host-guard checknothing else affected
  5. testsunit, isolation, e2e

Features

FeatureWhat it doesWho uses itWhere
Startdeploy/dev/stack.sh up -d, stack.sh ps, deploy/dev/run-services.sh, curl 127.0.0.1:5550/healthz.Operatorstart-stop
Stoprun-services.sh stop; stack.sh down keeps data. Never add -v.Operatorstart-stop
After a rebootsystemctl start docker, stack up, run-services.sh. Docker is not enabled at boot yet.OperatorRUNBOOK
Restart onestack.sh restart keycloak (names: postgres, valkey, hindsight, ollama, keycloak, openbao, edge).Operatorstart-stop
Logs/srv/cmcp/dev/logs/api.log, worker.log, web.log; containers via stack.sh logs --tail 100 keycloak.Operatorhealth-and-logs
Scheduled jobsConnector import every 60 min; promotion daily/weekly/off; synthesis off by default; client purge; bot counter trim daily; raw text purge; OpenBao token renewal twice a day; daily reminders; mailer about once a minute. Postgres is the queue.Systemscheduled-jobs
Migrations38 SQL files in db/migrations (0001_core to 0038_login_bound_volatile), applied in order by uv run python ../../db/migrate.py from services/api.Operatorupgrades-migrations
UpgradesVersions pinned in compose.yaml; read release notes, host-change snapshot, change one component, stack.sh up -d, host check, health, tests.Operatorupgrades-migrations
BackupsDaily 04:20 age-encrypted, 14 days; backup.sh, forget-key; monthly restore-test.sh into a throwaway container.Operatorbackups-encrypted
Restore orderStop services and stack, restore volume and secrets files, start stack, apply missing migrations, start services, health check, look at the console. Valkey starts empty and everyone signs in again.Operatorbackups-restore
Troubleshooting tableHealthz fails; keyword only; slow search; console not opening; app unauthorized; bot refused; 503 on secrets; connection paused; allow-list refusals; login loops.Operatortroubleshooting

Usage and knowledge

Health meanings

Check nothing is public

Safe-output rule

Test and retrieval checks

Login loops

Keys and secrets files

Security and limits

Phase 1 is internal and deliberately relaxed on one shared host. Each stage has a threat model; what is not done yet is listed so nobody assumes it.

How it works

  1. Threat modelper stage
  2. Phase 1 control + testin code
  3. Accepted residual riskwritten down
  4. Phase 2 itemscheduled

Features

FeatureWhat it doesWho uses itWhere
Threat modelsdocs/threat-models: go-live, stage 1b projects and sync, 1c grants/bots/Jira, 1d account/client/promotion, 1e web UI and settings, 1f integration hub.Developersdocs/threat-models
Deny by defaultAny error in a permission check means deny; every decision audited.Systemauthz.py
NetworkLocalhost-only ports, one public entry, router allow-lists and rate limits, HSTS one year without includeSubDomains.Operatorgo-live threat model
Prompt-injection guardMemory returned as data; instruction-like items cannot be approved until rewritten or rejected.ApproversDD-08
SecretsOpenBao ciphertext, write-only; credential patterns refused in resources and memory text.Allstage 1f
Cloud policyNo company text to cloud models unless the account is explicitly allowed.OperatorM-46, M-81
BackupsEncrypted with age; key offline.OperatorG10

Usage and knowledge

Deliberately not done in Phase 1

Phase 2 list (todo.md section 8)

When to leave this server

Reporting rule