sample-wiki-mcp-on-amazon-s3
OfficialThis server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
sample-wiki-mcp-on-amazon-s3
A shared knowledge base your AI agents can read and write, where every person sees and changes only what they've been given.
This sample is a tree of markdown articles that people reach through their AI agent,
connected to Claude as a remote MCP server. You ask Claude a question and it searches
and reads the tree for you. You ask it to record something and it writes an article,
attributed to you. Access is set per folder or per article: an owner gives someone
read, write or own on part of the tree, and that part is all they, and their
agent, can see or change.
It runs on your own AWS account (S3, DynamoDB, Lambda), with WorkOS handling sign-in. There are no servers to run, and every change is kept as a version. The sample ships with Object Lock and data retention off so it can be torn down; with both on (docs/DEPLOY.md §9), nothing can be deleted by accident.
This is sample code. It demonstrates an approach, for learning and experimenting, and is provided to you as AWS Content under the AWS Customer Agreement, or the relevant written agreement between you and AWS (whichever applies). You should not use this AWS Content in your production accounts, or on production or other critical data. Before any production use, it needs your own security testing and a review of the code and the deployment against your security, privacy and compliance requirements. Whether to use it in production is your decision, and you are responsible for testing, securing, and optimizing it as appropriate for production grade use, based on your specific quality control practices and standards. Deploying it incurs AWS charges (Cost). If you adapt this sample, docs/DEPLOY.md §9 lists what to consider.
Why
Teams and families want one shared memory their agents can use, but not everyone should see or edit all of it. Ordinary wikis make that a choice between sharing the whole wiki and sharing nothing, and they give an agent no safe way to write with the writer's identity attached. This sample makes the tree itself the permission model:
Broad read, governed write. Everyone can read the plan; only the person accountable for a part can change that part. The agent helping them has exactly their rights and nothing more.
Every version is kept and attributed to the signed-in person the agent was acting for, in metadata the agent can't rewrite.
Default deny. A new person sees nothing, not even that the tree exists, until an owner grants them something. Content they can't see and content that doesn't exist look the same to them.
Typical uses: a product team's decision records (each role owns its own section and everyone reads across), a household's records, a small business's shared knowledge. An instance starts empty; what it's for is whatever you put in it.
Related MCP server: Dexio
Using an instance
You need a Claude account (web, desktop or Claude Code), and someone who owns the instance needs to grant you access.
Connect. In Claude, go to Settings → Connectors → Add custom connector and enter
https://<instance>/mcp. Sign in with the emailed link. Do this on web or desktop; once connected it also works on your phone. In Claude Code, add the same URL as a remote MCP server.Ask an owner for access. They add you in the admin console and grant you a folder or an article.
Talk to Claude. It picks the right tools itself. For example:
You say | What happens |
"What did we decide about the storage design, and why?" |
|
"Add a row to the roadmap's open questions for the pricing question." |
|
"Draft an ADR for the new search design as proposed." |
|
"Move the old notes into /archive/2025." |
|
"What's been shared with me? Put Dana's racing folder in my tree." |
|
"What did this page say last month?" |
|
Concepts in two minutes
Tree. Folders and markdown articles with YAML frontmatter (title, description, tags, status), in the Open Knowledge Format (OKF) shape.
Grants.
read,writeorownon a folder (which covers everything beneath it) or on a single article. Grants add up; there are no deny rules. Only people holdingowngrant access, and only in the web console. No agent can grant.Versions. Every write is a new, immutable version. Archive hides an article without destroying anything. Move leaves a forwarding pointer, and since access follows position, moving something changes who can see it (a move that would widen access has to be confirmed by a person in the console).
Links. A
linkarticle points at a folder or article shared with you, so your tree becomes your own content plus the things others have shared. A link grants nothing: the target still checks your access every time.The web app at
https://<instance>/app: browse and search what you can read, view history, and, for owners, the admin console (add people, grant and revoke, the audit log, confirming moves that widen access).
What agents can do
Fourteen MCP tools. Every read is a search or a targeted fetch; results are bounded so they fit in an agent's context.
Find | Read | Write | History | Sharing |
|
|
|
|
|
|
|
|
|
|
|
Agents can't grant access, add people, read the audit log or hard-delete. Those exist only in the web console, and the role the MCP server runs under can't write grants even if a tool tried.
Running your own instance
Start with docs/SETUP.md. It walks through setting up WorkOS, deploying the four AWS stacks with CDK, and connecting the two, ending with Claude reading your tree. docs/DEPLOY.md is the full reference, including §9 on adapting this sample; docs/RUNBOOK.md covers restore, break-glass, revoking access and alarms.
You need an AWS account, a WorkOS account, a domain you control, and about a day for the first setup. Cost says what an instance bills, and Clean up how to remove one.
Security, briefly:
Each operation gets short-lived AWS credentials scoped to the one path it touches, so a bug in the storage code can't read past that path. A bug in grant resolution or in building that scope could; see Security design.
Tokens are bound to your instance's URL.
The bucket is encrypted with your own KMS key. Object Lock and retain-on-delete are off in the sample; turn them on if you adapt it (docs/DEPLOY.md §9).
Every MCP call (reads included), every page of the web console's read view, write, grant and denial is audited for 90 days, and the API keeps an access log.
The design is in docs/ARCHITECTURE.md, and a short threat model (assets, trust boundaries, threats, residual risks) in docs/SECURITY.md.
What the controls don't cover, and what's left to you as the deployer, is in Security design below.
Cost
You pay for the AWS resources an instance uses; the sample itself is free. Most of
it is billed per request, so a quiet instance costs little. Prices below are for US
West (Oregon), the region infra/config.py sets, as of October 2026. Check
AWS Pricing or the
AWS Pricing Calculator for current rates.
These are billed every month, used or not:
What | USD a month |
KMS key | 1.00. Its first and second yearly rotations each add 1.00. |
The web secret in Secrets Manager | 0.40 |
Eight CloudWatch alarms | 0.80 (0.10 each) |
The three metric filters' custom metrics, namespace | up to 0.90 (0.30 each) |
Contributor Insights rule | 0.50, plus 0.02 per million write calls it matches |
That is about 3.60 USD a month in the first year, before any CloudWatch free-tier allowance your account has left.
Billed by use:
API Gateway requests, Lambda invocations and duration (arm64), DynamoDB on-demand reads and writes and point-in-time recovery storage, S3 storage and requests (every article version is kept), KMS requests past the free 20,000 a month, Secrets Manager API calls, X-Ray traces past the free 100,000 a month (tracing is on for the stage and every function), and AWS Backup storage for the daily grant-table backups, kept 35 days.
CloudWatch Logs, at 0.50 USD per GB ingested and 0.03 USD per GB-month stored: the function logs, the API access log (one line per request) and the trail's log group. The trail's log group receives every management event in the account, from every Region, so its volume follows the account's activity, not this instance's.
API Gateway's detailed CloudWatch metrics, which the stage turns on for every method. Each of the API's eight methods publishes about five to seven metrics, and CloudWatch bills each one as a custom metric at 0.30 USD a month, prorated by the hours it receives data. If every method sees traffic every hour, that is about 12 to 17 USD a month, several times the fixed charges above.
CloudTrail. The ops stack creates a multi-Region trail of every management event in the account, plus write data events on the wiki bucket at 0.10 USD per 100,000. If it is the account's only trail, CloudTrail doesn't charge for its management events; their copy in the trail's log group is still billed as CloudWatch Logs. If the account already has a trail, for example an AWS Organizations trail, this one is a second copy at 2.00 USD per 100,000 management events, which in a busy account can outweigh everything else here.
Not on your AWS bill from these stacks: the domain and its DNS zone, the public ACM certificate (free), WorkOS (billed by WorkOS; its staging environment needs no payment method, its production environments do) and Claude plans.
The api stack's monthly budget wiki-<env>-monthly (20 USD) covers all spend in
the account, not only this instance. It emails at 80% only if you deploy with
ALERT_EMAIL=, and it never stops spend.
Clean up
make destroy deletes the four stacks. Run it from a terminal, because the CDK
CLI asks you to confirm. Pass the account and AuthKit domain you deployed with;
synth refuses to run without them:
make destroy ENV=dev ACCOUNT=<12-digit id> AUTHKIT_DOMAIN=https://<slug>.authkit.appWith the sample's defaults (retain_data off) it deletes what the stacks created,
including the bucket with every article version in it and both tables. That is
permanent. These outlive it:
The backup vault
wiki-<env>-grantscan't be deleted while it holds a recovery point, and the daily backup runs at 09:00 UTC. If the ops stack fails to delete for that reason, delete the vault's recovery points in the AWS Backup console and runmake destroyagain (docs/RUNBOOK.md §8).The KMS key behind
alias/wiki-<env>is scheduled for deletion and deleted 30 days later. There is no charge while it waits. You can cancel the deletion in that time if you still need something encrypted with it, but then the key is billed for the waiting period as if the deletion had never been scheduled.API Gateway's account-level CloudWatch Logs role setting and the role it names (
wiki-<env>-api-ApiCloudWatchRole…) are kept, because that one setting serves every REST API in the account and Region. If nothing else there logs to CloudWatch, clear the CloudWatch log role ARN in the API Gateway console's settings, then delete the role.Log groups that no stack owns, with no expiry:
API-Gateway-Execution-Logs_<api-id>/v1(the stage's error log),/aws/apigateway/welcome, and the two/aws/lambda/wiki-<env>-*-CustomS3AutoDeleteObjects*groups of the functions that empty the buckets. Delete the ones nothing else uses.DNS and the certificate. With
HOSTED_ZONE_NAME, the api stack deletes its alias record but the certificate's validation CNAME stays in the zone; delete it. With the hand-deployed certificate,make destroydoesn't touch thewiki-<env>-certificatestack. Remove it withnode_modules/.bin/cdk --app "uv run python -m infra.cert_app" destroy -c env=dev -c account=<id> -c domain=<host> -c authkitDomain=https://<slug>.authkit.app. That deletes the SSM parameter and keeps the certificate, so that a stack delete can never take a live domain's certificate; delete the certificate in ACM afterwards. Then remove the records you added at your DNS provider: the validation CNAME and the one pointing atDomainTarget.The CDK bootstrap stack
CDKToolkit, which every CDK app in that account and Region shares. If you bootstrapped only for this sample, delete the stack, then empty and delete its staging bucketcdk-hnb659fds-assets-<account-id>-us-west-2, which the stack keeps.Outside AWS: in WorkOS, delete the applications, the resource indicator and the users you created (or the whole environment); in Claude, remove the connector.
With retain_data on, make destroy also leaves the bucket, both tables, the key,
the web secret, the trail bucket, the backup vault and every log group in place,
and the grant table keeps its deletion protection
(docs/DEPLOY.md §9). Delete them yourself when you mean to. With
Object Lock on, each article version is kept until its one-year retention ends.
Security design
The bullets below cover what the built-in controls do: supply-chain pinning, per-path credential scoping, encrypted secrets with rotation and alarms, a recent AuthKit sign-in and CSRF-checked forms on admin actions, and audited writes. They also say where those controls stop, for example rate limiting, backup handling and log retention. Closing those gaps, and anything particular to how you run your instance, is on you as the deployer.
make buildinstalls the Lambda dependencies fromuv.lockwith hashes, so a file PyPI serves that doesn't match the lock fails the build.GitHub Actions are pinned to commit SHAs, the gitleaks image to a digest, and the CDK CLI to an exact version in
package-lock.json. The Makefile and CI run that CLI fromnode_modules/(installed bynpm ci, whichmake syncruns), never a fresh download of the latest.Dependabot checks the Python lock, the CDK CLI and the Actions for updates every week and opens pull requests for the ones it finds. Nothing merges them automatically, and every CI job has a read-only token: each update waits for a person to review it and for CI to pass. Branch protection on
mainis a repository setting (docs/DEPLOY.md §0).CI runs
pip-auditon the exact Lambda requirements and fails on a known vulnerability. Each run uploads a CycloneDX SBOM as thesbomartifact.Per-path isolation comes from session policies built in
app/auth/credentials.py. The storage role itself can reach all ofa/*, so IAM won't catch a bug in grant resolution (app/auth/grants.py) or in building the policy. Unit tests fuzz the path grammar and the ancestor walk on every CI run.make securityandmake aws-testsare verification you run against your own deployment, after any change toapp/authorapp/storage; a skipped test is not a pass.make aws-testsassumes the storage role, which trusts only the MCP and web functions, so to run it temporarily add your own test principal to that role's trust policy in a test account, run it, then remove the principal again (docs/DEPLOY.md step 12).Enforce MFA in WorkOS for every member, and require it for anyone holding
own. This is a dashboard setting, and WorkOS documents noamrclaim, so the app can't check it. Keep access-token lifetimes short. Web sessions last 12 hours (SESSION_HOURSininfra/stacks/compute.py).Admin actions in the console (adding a person, granting, revoking, enabling or disabling someone, moving an article) need a sign-in through AuthKit that completed in the last 5 minutes. An older session is sent back through AuthKit, and you submit again. That stops someone who has only copied your session cookie, because they can't finish the sign-in. It is not a fresh password or code prompt: AuthKit usually answers from its own session without asking, since it doesn't re-prompt Magic Auth users for
max_ageand doesn't keepauth_timecurrent, so the app can't rely on either (docs/RUNBOOK.md §9).The console templates autoescape by default and render markdown with raw HTML disabled, so article content can't inject a script tag into the page. A Content-Security-Policy header restricts where scripts and frames can come from, and every admin form carries an HMAC CSRF token that's checked before the POST runs.
Adding a person in the console takes the WorkOS subject id and the email or name you type; it doesn't check that email against the WorkOS identity. A typo or a deliberately wrong email records a profile that looks right but points at the wrong person, and other owners then grant to that profile believing it's who it says. Copy the subject id straight from WorkOS rather than retyping it.
Anyone who can read the web secret can sign in to the console as anyone. The secret is encrypted with your KMS key, and only the web role and the rotation function are granted read. Any other read, an administrator's included, raises the
wiki-<env>-websecretreadalarm.session_keyrotates every 30 days, and the previous key keeps working for one interval, so nobody is logged out. If you suspect a leak, rotate twice (docs/RUNBOOK.md §4d). That logs everyone out.Article text is untrusted input to your agent. Anyone with write on a folder you read can plant instructions. The server stops privilege changes, but it can't stop your agent copying content you can already read. Keep write grants narrow. Every MCP tool that returns article text says in its description that the text is data, not instructions, and
read_articleandsearch_and_readreturn who last wrote each article and when (actor,at). Thewiki-<env>-writeburstalarm fires when one person's agent makes 30 or more write calls in 5 minutes, and a CloudWatch Contributor Insights rule on the MCP tool-call log names who it was (docs/RUNBOOK.md §6). A few quiet writes stay under it. The rule and the alarm are listed under Cost. Nothing alerts a folder's owners when someone outside the folder writes into it; that is optional hardening for you to add.Owners are trusted. Anyone with
ownon a folder can share it, including re-delegatingown. Every grant records who made it and when. Review grants periodically on the console's Grants page. An owner of/should also check Unowned grants, which lists grants whose granter is disabled or no longer owns the place. A move that widens access shows who gains and who loses before you confirm it, and agents can't make one. Nothing alerts when someone is grantedown; adding that alert is optional hardening for you, and it isn't built.No AWS WAF is attached.
/mcpand the/appconsole share one stage throttle of 20 requests a second with a burst of 50 (infra/stacks/api.py), so an unauthenticated flood can use it up for everyone. The per-person MCP limits (60 calls a minute, 200 writes an hour,app/auth/ratelimit.py) fail open if their table errors; five such errors in 5 minutes raise thewiki-<env>-ratelimitunavailablealarm. The console has no per-user limit. If you adapt this sample, attach a web ACL with a per-IP rate-based rule and the AWS managed IP reputation rules, and keep the stage throttle. The 20 USD monthly budget emails at 80% only if you deploy withALERT_EMAIL=(-c alertEmail=), and it never stops spend.Audit logs are kept 90 days. The MCP function logs one line per tool call (who, which tool, which path, allow or deny, and the grants it relied on). The web function logs one
web_readline per page of the read view (who, which page, which path and version, allow or deny), plus grants, revokes, people changes and moves. The API stage writes an access log with the request id, time, source IP, method, path, status and size, and the token subject on/mcp. It never records headers, cookies or query strings, and the request id joins its lines to the functions' lines. These log groups have a fixed 90-day retention (APP_LOG_RETENTIONininfra/stacks/compute.py), so keeping them longer is a code change.log_retention_daysininfra/config.pysets only the CloudTrail log group and trail bucket. CloudTrail records S3 writes but not reads, so after 90 days you can't show who read what. The console's audit page shows only the MCP tool-call lines of the last 30 days for one path. Console reads and the access log aren't on it, so query them with CloudWatch Logs Insights (docs/RUNBOOK.md §8). Who wrote each article version stays in that version's metadata. If you have compliance needs, export the logs before they expire, for example to an Object Lock bucket.Backups and any exports carry no permission model, so treat them as full-tree access. Anyone who can read the bucket directly sees every article, and anyone who can restore a grant-table backup sees every grant, whatever their own grants. The bucket, the grant table, the backup vault
wiki-<env>-grantsand the trail bucket are encrypted with your KMS key, and the bucket refuses principals from other accounts (infra/stacks/storage.py,infra/stacks/ops.py). There is no snapshot-share alarm, because DynamoDB recovery points have no share call to watch (docs/RUNBOOK.md §6). A copy you take out of AWS, such as the/tmpfiles the runbook's restore steps use, is plaintext with no grants attached; delete it when you're done. Rehearse a restore once, then yearly, and record the date (docs/RUNBOOK.md §7).Reads of paths you can't see look like "not found", in MCP tools and in the console. Writes return "forbidden" when you lack write. Both answers come from the grant check before storage is touched, so neither tells you whether the path exists. Some metadata does show: a link or moved-article pointer in a folder you can read names its target even if you can't open it, and a move preview shows which folder an access change comes through but names only people you administer. Content never leaks this way.
Revocation is prospective. Content already in someone's agent history stays there, and so do their notes and anything they copied. Disabling a person in the console takes effect on their next MCP call or click: their grants resolve to nothing and their console session is refused. Their grant rows stay, so revoke those too, and deactivate them in WorkOS yourself; nothing here does that for you (docs/RUNBOOK.md §5).
Scope
The sample covers one organization per instance, with people added by an owner and every write made by an agent acting for a signed-in person.
Not in this sample: semantic search over article bodies, subscriptions (your agent tells you when something you watch changes), and multi-tenant hosting.
The design reference is docs/ARCHITECTURE.md, the spec the code is built against. Where the code and that document disagree, fix the code.
Developing
Path | What |
| API Gateway REQUEST authorizer: JWT validation, nothing else |
| MCP transport ( |
| Grant resolution, per-operation credential minting, grant administration, rate limits |
| S3 reads and conditional writes, frontmatter, the listing projection |
| The web application: login, read view, admin console |
| CDK: storage, compute, api, ops stacks |
|
|
| Unit tests, no AWS (moto) |
| The security checklist as integration tests against a deployed instance |
|
|
make sync # dependencies
make test # unit tests
make lint # ruff
make typecheck # mypy
make build # package the Lambda functions (arm64, py3.13)
make synth ENV=dev
make deploy ENV=dev # asks before new IAM permissions; REQUIRE_APPROVAL=never skips that
make security # after deploy; env contract in tests/security/README.md
make aws-tests # the storage-isolation negative tests, with real credentialsChanges go through pull requests; see CONTRIBUTING. Read docs/ARCHITECTURE.md §1, §2, §4 and §11 before touching authorization or storage.
Security
See CONTRIBUTING for more information.
License
Note: This project depends on the certifi package, which is licensed under MPL-2.0, a copyleft license. Its development and test tools also depend on hypothesis and pathspec, which are licensed under MPL-2.0.
This library is licensed under the MIT-0 License. See the LICENSE file.
This server cannot be deployed
Maintenance
Related MCP Connectors
Persistent docs and memory for AI agents — read, write, organize & search a shared workspace.
Shared docs for people and their agents: markdown docs and HTML pages with comments and history.
Read, edit and improve shared documents and knowledge with people and agents.
Shared knowledge base for AI agents. Semantic search across agents, no setup required — just a URL.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to securely read and write to an Obsidian-compatible Markdown vault with per-agent access control, audit logging, and conflict resolution.Apache 2.0
- AlicenseAqualityBmaintenanceLets AI agents from any machine list, read, search, write, edit, move and link markdown pages and store files alongside them, all in a shared wiki. People can then see what the agents know through a web app showing the link graph, every page, and the history of who changed what.165AGPL 3.0
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to create, read, update, list, restore, and share encrypted workspaces and artifacts with version-aware writes, view-only links, and optional public documents.14 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents and their human owners to browse, search (keyword, semantic, and hybrid), create, and revise a versioned personal knowledge base of Markdown documents, checkpoint summaries, and structured tasks. Access is OAuth-protected with separately grantable read and write scopes, and edits are history-tracked with conflict protection so concurrent clients don't overwrite each other.3MIT