serverless-wiki-on-aws MCP Server
MCP server that provides secure access to a serverless Markdown wiki on AWS, enabling AI assistants to read, search, and edit pages with space-level permission checks and Bedrock-powered semantic search.
README
serverless-wiki-on-aws
English | 日本語
A Markdown wiki that runs on AWS serverless services. Spaces carry their own permissions, an Amazon Bedrock assistant answers from the pages you wrote, and Obsidian and MCP clients read and write the same content through the same permission checks.
There are no EC2 instances, containers, or database clusters to keep running: the deployed stack is Lambda, API Gateway, DynamoDB, S3, CloudFront, Cognito, SQS, and Bedrock.

Reading a page. The pages shown here are sample content.
Features
- Markdown pages arranged in a folder-and-page tree, one tree per space
- Space-level permissions resolved on every request in the API layer — the UI, the AI assistant, the MCP server, and the sync API all pass the same check
- AI assistant on Amazon Bedrock: it searches the wiki, answers from what it finds, and edits pages only after you approve the change. Amazon Nova 2 Lite answers by default;
AI_MODEL_IDswaps in another Bedrock model - Semantic search with Bedrock Knowledge Bases, S3 Vectors, and Titan Text Embeddings V2
- MCP (Model Context Protocol) server at
POST /mcp, authenticated with OAuth 2.1 through Cognito, for Claude and other MCP clients - Obsidian plugin that syncs a vault and a space in both directions
- Attachments delivered through presigned URLs; the bucket blocks all public access
- Japanese and English UI, switched in the header
- Infrastructure defined with AWS Blocks, an Infrastructure-from-Code framework
Screens

The space list. The badge on each card is the permission the signed-in account holds on that space — a space you cannot read never appears here.

Search. Results are filtered by the same space permissions before they are returned.
Prerequisites
- Node.js 24 and pnpm 11 (npm is not supported;
mise installpicks up both frommise.toml) - To deploy: an AWS account, AWS CLI 2.32.0+, and Bedrock model access for Amazon Nova 2 Lite and Titan Text Embeddings V2
- The CloudFormation stack CDK builds goes to whichever region your AWS profile names. It has been run against
ap-northeast-1(Tokyo); any region you pick has to offer S3 Vectors and the two Bedrock models above
Quick Start
No AWS account is needed. Every Building Block runs mocked on your machine, and the mock data lands in .bb-data/.
pnpm install
pnpm run dev
Open your browser: Navigate to http://localhost:3000.
Sign-up is open against the local mock, so create an account there and sign in. Permissions are not mocked, though: a brand-new account belongs to no group and therefore sees no spaces. Make yourself an administrator the same way a real deployment does — the local store is a file the running server rewrites, so stop it first.
# Ctrl-C the dev server, then
pnpm run seed-admin -- --local --email you@example.test
pnpm run dev
One thing does not run locally: the assistant talks to a mock model that replies with fixed text, so the conversation is only good for exercising the flow. Everything else — pages, permissions, search, attachments — behaves like the deployed system.
Deploy to AWS
aws login --profile <profile>
pnpm run deploy # on the very first deploy, run this twice
The first run creates the CloudFront distribution, so its address does not exist yet while that same run is configuring the Lambda. The second run reads the address from the stack output and passes it in. After that, one run per deploy is enough.
The first account
Sign-up is closed, so a fresh deployment has nobody who can sign in. Create the first account yourself in the Cognito user pool. The password has to be 12 characters or longer and carry an upper-case letter, a lower-case letter, a digit, and a symbol.
# The pool whose name starts with your stack id
aws cognito-idp list-user-pools --max-results 10 --profile <profile> --region <region>
aws cognito-idp admin-create-user \
--user-pool-id <user-pool-id> \
--username you@example.com \
--user-attributes Name=email,Value=you@example.com Name=email_verified,Value=true \
--message-action SUPPRESS \
--profile <profile> --region <region>
# Set the password permanently, so the first sign-in is not a password-change challenge
aws cognito-idp admin-set-user-password \
--user-pool-id <user-pool-id> \
--username you@example.com \
--password '<password>' \
--permanent \
--profile <profile> --region <region>
The first administrator
Sign in once in the browser. That sign-in writes your profile record and fixes the Cognito sub the next step points at, so it has to come first. Then find the permission table — its name starts with the stack id and ends in -permissions — and seed yourself.
aws dynamodb list-tables --profile <profile> --region <region>
AWS_PROFILE=<profile> pnpm run seed-admin -- --table <table-name> --email you@example.com
Nothing in the API raises anyone's own permissions, which is why this step is a script and not a button. Every administrator after the first one is added by an administrator, from the admin screens.
Sandbox
pnpm run sandbox puts the backend on AWS and leaves the frontend on your machine. It does not resolve the origin for you, so name it yourself.
CORS_ALLOWED_ORIGINS=http://localhost:3000 pnpm run sandbox
Teardown
pnpm run sandbox:destroy # the sandbox stack, data and all
pnpm run destroy # the deployed stack
A sandbox is disposable: its tables and buckets are destroyed with it. A real deployment is not. The DynamoDB table, the content bucket, and the search corpus bucket are retained on purpose, so pnpm run destroy leaves them — and their storage charges — behind for you to delete deliberately.
Configuration
| Variable | Default | Purpose |
|---|---|---|
CORS_ALLOWED_ORIGINS |
read from the stack output by pnpm run deploy |
Comma-separated origins the S3 bucket accepts presigned-URL requests from. Without a match, attachments fail in the browser. Set it explicitly when a custom domain sits in front of CloudFront or several origins serve the app. Wildcards are rejected. |
MCP_PUBLIC_ORIGIN |
read from the stack output by pnpm run deploy |
The origin the MCP OAuth metadata advertises. Set it explicitly for a custom domain. |
AI_MODEL_ID |
global.amazon.nova-2-lite-v1:0 |
The Bedrock model the assistant talks to. Amazon Nova 2 Lite through its Global inference profile is the default. jp.amazon.nova-2-lite-v1:0 keeps inference inside Japan; global.anthropic.claude-sonnet-4-6 and global.anthropic.claude-sonnet-5 select tools better and cost more. Whichever you name, enable model access for it in Bedrock first — passing the variable does not grant it. Read at run time, so an unset or empty value lands on the default rather than failing. |
MCP clients
Copy .mcp.json.example to .mcp.json and fill in the CloudFront domain and the McpClientId stack output.
aws cloudformation describe-stacks --stack-name <stack-name> --profile <profile> \
--query 'Stacks[0].Outputs[?OutputKey==`McpClientId`].OutputValue' --output text
Obsidian sync
The bundled plugin in clients/obsidian/ syncs an Obsidian vault with the spaces you can read. When the two sides disagree, the wiki wins: the plugin sets your local copy aside and writes the wiki's version over it. Setup and usage are in clients/obsidian/README.md.
Project Structure
serverless-wiki-on-aws/
├── aws-blocks/ # Backend
│ ├── index.cdk.ts # Stack definition (AWS Blocks + CDK)
│ ├── index.ts # API surface the frontend calls
│ ├── access.ts # Permission resolution
│ ├── wiki-ops.ts # Page, tree, and search operations
│ ├── mcp.ts # MCP server (POST /mcp)
│ ├── ext.ts # Sync-client API (POST /ext/*)
│ └── scripts/ # deploy, sandbox, seed-admin, destroy
├── src/ # Frontend (React 19 + Vite + Cloudscape)
│ ├── views/ # Space, page, folder, search, and admin screens
│ ├── components/ # Page tree, editor, assistant drawer, search box
│ └── i18n/ # Japanese and English dictionaries
├── clients/obsidian/ # Obsidian sync plugin
├── test/e2e.test.ts # End-to-end test across the whole API
├── assets/ # Screenshots used by this README
└── README.md # This file
Limitations
- Search is semantic only. There is no keyword or full-text search, so an exact string or a rare identifier may not surface the page that contains it.
- Search lags a save. Re-ingestion is debounced by 30 seconds and then re-reads the whole corpus, so a page you just wrote takes a moment to become findable.
- Markdown is a deliberate subset. Headings, lists, blockquotes, code, links, images, and inline marks render; GFM tables do not. Assistant replies and search excerpts are shown as plain text, so any Markdown in them appears as written.
- Sign-up is closed. Accounts are created in the Cognito user pool by an operator, and no API raises anyone's own permissions.
- No audit log, request rate limiting, or enforced MFA.
Learn More
- AWS Blocks — the Infrastructure-from-Code framework this project is built on
- Amazon Bedrock Knowledge Bases — the semantic search backend
- Model Context Protocol — the protocol the
/mcpendpoint speaks - Cloudscape Design System — the UI components
License
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。