MCP server for centrally distributing multiple projects context to coding agents.
cakemcp stands for a multi-layered but simple architecture and approach. Like a piece of cake.
This project is intended to distribute a centralized knowledge base for multiple projects written in multiple languages. It is designed to provide a single source of truth for all AI agents in a company without duplicating or scattering core rules across many repositories.
The knowledge base itself is collected from either a git repository (public or private), or a local directory.
The knowledge base is split into layers:
- global agreements
- language-specific rules
- framework-related instructions and agreements
- project-level specifics
Layers are stored together to make de-duplication and sharing easier across projects, including AI-assisted maintenance workflows.
cakemcp MCP server can be used locally over stdio as well as remotely over the network, including authenticated
deployments.
The service is designed to run safely in Kubernetes environments and is also suitable for Docker-based deployments, including setups exposed to the public internet.
Stack:
- TypeScript
- Bun runtime
punkpeye/fastmcp
The demo-data folders are intended to show example usage for three projects:
- frontend, written in TypeScript + MeteorJS
- backend, written in TypeScript + Bun + Elysia
- billing service, written in C#
Project manifests contain the list of knowledge layers used by each project. Some knowledge is shared across projects, for example global agreements used everywhere or language-specific rules reused by both frontend and backend services.
Adding a new project, such as an auth backend service, typically requires creating a project manifest file and, if needed, adding project-specific knowledge layers.
Projects do not need to share any knowledge at all. This also supports cases where multiple unrelated company products are stored in the same centralized registry.
TODO: The demo-data content is currently marked as TODO and will be synced soon.
"All data available once authorized". There is no scope-based access control within the knowledge base itself.
Any developer or AI agent in the company may access any included project knowledge once they are authorized to use
cakemcp.
This means you need to:
- configure proper IAM access for entry into
cakemcp - avoid storing keys, tokens, or secrets inside the knowledge repository (as usual)
If it is truly necessary, sensitive data can be placed in AGENTS.md within the corresponding project code
repository instead.
- no database required, vector DB, or embeddings
- no UI/admin/auth platform
- no heavy enterprise abstractions
- tool output is returned as a JSON string (MCP-client friendly)
bun install
cp .env.example .env
bun run startBy default, the server starts with stdio transport.
For remote mode:
MCP_TRANSPORT=httpStream PORT=8080 bun run startCONTEXT_REGISTRY(required)- local path to the registry
- or git URL (
https://...,ssh://...,git@...,*.git)
REGISTRY_DIR(optional)- directory inside
CONTEXT_REGISTRYthat containsprojects/andlayers/ - defaults to
contexts - use
.when the registry lives at the repo root
- directory inside
REGISTRY_KEY(optional)- key/token for private HTTPS git registry access
- if it contains
:, it is treated as Basic auth (username:password) - otherwise it is treated as a token for HTTPS git authentication
REGISTRY_KEY_FILE(optional)- path to a file containing the private registry token/key
- used only when
REGISTRY_KEYis not set
CACHE_EXPIRY(optional)- repository cache TTL in seconds (default
300)
- repository cache TTL in seconds (default
MCP_TRANSPORT(optional)stdio(default) orhttpStream
PORT,HOST(optional)- used for
httpStream
- used for
DEBUG_MCP(optional)- set to
1to enableresolve_contextdebug traces. Saves ouput summaries toDEBUG_MCP_OUTPUTfile
- set to
DEBUG_MCP_OUTPUT(optional)- output file path for debug traces (default
./output.log)
- output file path for debug traces (default
projects/*.yaml - project manifests
layers/ - layer markdown files
layers/global/*.md
layers/language/*.md
layers/framework/*.md
layers/project/*.md
Prefer level-2 headings (##) inside layer markdown files, because the merged output already uses a top-level layer
header (# Layer: ...) per block.
name: billing-service
layers:
global:
- formatting
- engineering
language:
- typescript
framework:
- nextjs
- bun
project:
- billing-service # This is actually redundant, layers/project/billing-service.md is auto-added
- payment-rulesRules:
nameis optional (defaults toproject_idif missing)layers.*are optional- project manifest is resolved by project_id from
projects/${project_id}.yaml - auto-layer is always attempted as
layers/project/${name}.md(even if not specified inmanifest.project)
Input:
project_id: stringtask_type?: stringpath?: stringchanged_files?: string[]
Behavior:
- Loads
projects/${project_id}.yaml - Applies layers in strict order:
globallanguageframeworkproject(from manifest)
- Always tries to append
layers/project/${projectName}.md - Merges markdown into
merged_contentwith layer separators
Output (JSON string):
project_idproject_nameresolved_layers[](type,name,path,priority,revision)merged_contentwarnings[](if any)
merged_content example fragment:
# Layer: global/formatting
...content...
# Layer: language/typescript
...content...Returns available project IDs.
Input: project_id.
Returns parsed manifest.
Input: type, name.
Returns raw layer content.
resolve_context does not fail because of a missing optional layer from the manifest:
- missing layer is added to
warnings
resolve_context fails only when:
- project is not found
- registry is unavailable and no cache is available
- manifest is invalid
Git provider behavior:
- stores a local checkout in a temp cache directory
- does not perform a full clone on every request
- refreshes no more often than
CACHE_EXPIRY - resolves the registry under
REGISTRY_DIRinside the cloned repo - if refresh fails but local copy exists, stale cache is used and an error is logged
JSON structured logs include:
- startup summary (without secrets)
- provider type (
local/git) - cache hit / refresh events
- project lookup
- warnings for missing layers
- git refresh failures
bun testCovered scenarios:
- local
resolve_context - strict layer order
- auto-add
layers/project/${projectName}.md - missing optional layer does not break resolve
- project not found
- manifest parsing
- basic cache behavior
Set DEBUG_MCP=1 to append per-request resolve_context traces to ./data/output.log.
Example format:
request_id=...
time=...
tool=resolve_context
project_id=billing-service
manifest=projects/billing-service.yaml
layers=[
global/formatting.md,
language/typescript.md,
framework/nextjs.md,
project/payment-rules.md,
project/billing-service.md
]
warnings=[...]
merged_size=18423
cache=hit
duration_ms=47
To debug the actual output of resolve_context and other tools, use official SDK inspector:
npx @modelcontextprotocol/inspector