MCP Server Scaffold
A production-ready, security-first starting point for building Model Context Protocol servers, enforcing safe defaults like dry-run and tenant isolation.
README
MCP Server Scaffold
A production-ready, security-first starting point for building Model Context Protocol
servers. Clone this repo to start every new MCP server — don't start from a blank npm init.
This is opinionated on purpose. Every default here exists because of a real gap or incident
pattern observed across MCP servers in the wild (see MCP-SCAFFOLD-REFERENCE.md), and the
goal is that the secure path is the only easy path — unsafe behavior requires an explicit,
reviewable override, not just theoretical avoidance.
Start here
| I want to... | Read |
|---|---|
| Understand the mandatory architecture and why it's shaped this way | SPEC.md |
| Add a tool to an existing server | docs/ADDING-A-TOOL.md |
| Add or understand presets | docs/ADDING-A-PRESET.md |
| Wire up auth, tenancy, and credentials | docs/AUTHENTICATION.md |
| Understand every security control this scaffold ships with | docs/SECURITY.md |
| Know what a host must support for write approvals to actually work | docs/HOST-INTEGRATION-CONTRACT.md |
| Deploy to Docker / Azure Container Apps / locally | docs/DEPLOYMENT.md |
| Avoid known footguns | docs/KNOWN-GOTCHAS.md |
| Run the full checklist from scaffold to production | DEVELOPMENT-CHECKLIST.md |
| Change the scaffold itself (not a server built from it) | CONTRIBUTING.md |
| See what real-world MCP repos this scaffold's decisions are based on | MCP-SCAFFOLD-REFERENCE.md |
Working in this repo with Claude Code
This repo ships its own Claude Code operating layer, not just docs a human has to remember to open:
CLAUDE.md— the always-loaded cockpit placard: authority, required commands, non-negotiables, a task-to-doc map..claude/skills/nucleus-mcp-builder/— a Skill that routes "add a tool" / "add a vendor" / "review this server" requests to the right doc instead of requiring the whole spec read every time..claude/agents/mcp-security-reviewer.mdandmcp-protocol-reviewer.md— narrow review agents scoped to exactly the concerns indocs/SECURITY.mdand the MCP protocol respectively. Dispatch them before merging any change tosrc/auth/,src/safety/,src/tools/, orsrc/server/..claude/commands/— explicit slash commands into the same playbook, for when you'd rather type a command than rely on the skill inferring intent:/mcp-new-server <vendor-name>,/mcp-add-tool <what it should do>,/mcp-review.
Quickstart
cp .env.example .env # set MOCKVENDOR_API_KEY to any value for the demo
npm ci
npm run dev # runs the example server over stdio
Smoke-test it with MCP Inspector:
npx @modelcontextprotocol/inspector npm run dev
You should see three demo tools (mockvendor_search_open_high_priority_tickets,
mockvendor_list_tickets, mockvendor_close_ticket + its preview_ companion) backed by an
in-memory fake vendor (examples/vendor/mock-vendor-client.ts) — this is what
docs/ADDING-A-TOOL.md and DEVELOPMENT-CHECKLIST.md walk you through replacing with your
real vendor integration.
npm run verify # typecheck + lint + test (with coverage) + build + catalogue generation
What's in here
src/
auth/ AuthenticatedPrincipal, TenantResolver, CredentialProvider, AuthorizationPolicy
tools/ tool definition contract (defineTool), ToolContext, risk levels
safety/ dry-run + operation tokens + human approval + redaction + rate limiting
vendor/ VendorClient interface, controlled errors, bounded pagination, shared HTTP client
observability/ structured logging, audit log, correlation IDs, metrics
server/ tool registry, presets, stdio/HTTP transports, the composition root
config/ env schema + fail-fast loader
index.ts demo entrypoint — swap examples/ for your real tools
examples/ working read tool, write tool, paginated tool, prompt, mock vendor
tests/ contract, security, tenant-isolation, tool unit tests, integration
docs/ task-specific how-tos (see table above)
deploy/ Docker, Azure Container Apps, local — reference deployment targets
scripts/ tool-catalogue / permission-manifest generation
Nearly everything here is framework code shared by every server cloned from this template.
src/vendor/ and the tools you add under (a real server's) src/tools/read/ and
src/tools/write/ are the ~20% that's genuinely yours per project — see SPEC.md §3.
Why this architecture (the short version)
- One template, many vendors. A competent engineer, with no prior scaffold knowledge, should get from a documented REST API + sandbox credentials to a working read-only server with tests passing in under a day. If it takes three, that's a scaffold bug — see SPEC.md §1.
- Tenant identity is never trusted from model input. A
tenantIdargument in a tool call is a hint, not an authorization — resolution happens against the authenticated principal. - Writes are a different lifecycle from reads, not a flag bolted onto the same one.
mediumrisk requires a dry run and a digest-bound single-use operation token;highrisk (deletes, by definition) additionally requires a distinct human approver. The platform enforces the floor per risk tier — a tool can request stricter, never weaker. - Every tool response is minimized to its declared schema. Whatever the vendor API
actually returns, only the fields your
outputSchemadeclares leave the tool — structurally, viazod's parse-strips-unknown-keys behavior, not by developer discipline. - Presets before discovery. Explicit, named tool bundles (
MCP_PRESETS=service-desk) are the v1 tool-surface-scoping mechanism — simpler than full search-based dynamic discovery, and derived from each tool's own declaration rather than a second hand-maintained list.
Full reasoning for every one of these: SPEC.md.
Toolchain & dependency baseline
Language/runtime: TypeScript on Node.js 22+ (LTS, 22.12.0 or later — see .nvmrc). This is the mainstream choice for MCP
servers today — the official TypeScript SDK is the most mature, the type system pays for
itself directly in this scaffold's schema-driven design (a tool's inputSchema/outputSchema
are its TypeScript types via z.infer), and it's what most MCP tooling (Inspector, the
registry, most reference servers) assumes first. Python is the better call if your team's
domain is data/ML-adjacent and Python is already the house language; C#/.NET if you're
Azure/Microsoft-ecosystem-first end to end. This scaffold doesn't hedge across languages — pick
one and get the full benefit of a single well-typed contract, rather than a lowest-common-
denominator design that works passably in three languages.
| Concern | Choice | Why |
|---|---|---|
| Schema validation | zod |
The MCP TypeScript SDK's native schema story; z.infer gives you types for free from the same declaration that drives runtime validation — one source of truth, not two to keep in sync. |
| Logging | pino |
Structured JSON by default, fast, straightforward formatters/mixin hooks — exactly what's needed for the redaction and correlation-ID wiring in src/observability/. |
| HTTP transport | express |
Minimal, well-understood, and all this scaffold needs it for is a few health routes plus mounting the MCP SDK's own StreamableHTTPServerTransport — not a case for a heavier framework. |
| Test runner | vitest |
Fast, native ESM/TypeScript support without a separate ts-jest config layer, Jest-compatible API so it's not a new mental model. |
| Lint/format | ESLint (flat config) + Prettier | eslint.config.js in this repo also encodes two safety rules as lint errors, not just style: no bare fetch() (bypasses the shared timeout/retry/circuit-breaker client) and no console.* (bypasses log redaction). |
| CI | GitHub Actions | .github/workflows/ci.yml — typecheck, lint, format check, test with coverage, build, catalogue generation, dependency audit, Docker build. Adapt the YAML to your CI system; the stages are what matter. |
None of these choices are load-bearing for the architecture — swap express for fastify,
pino for winston, if your organization has a strong existing preference. What is
load-bearing: schema-driven tool definitions, structured logging with automatic redaction, and
routing every vendor call through one shared HTTP client. Keep those properties whatever
libraries you pick.
License
Add your organization's license here before treating this as a template repo others clone.
推荐服务器
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 模型以安全和受控的方式获取实时的网络信息。