Design, scaffold, audit, and upgrade Model Context Protocol servers. Use when the user asks to build or migrate an MCP server, adopt MCP 2026-07-28, add dual-era support, create an MCP integration, expose an API or data source through MCP tools/resources/prompts, add OAuth or API-key auth to an MCP endpoint, run an authorization server for it, support browser-hosted MCP clients, or choose an MCP transport/auth/deployment shape.
Help design and build MCP servers. Keep the work focused on protocol primitives,
transport, authorization, validation, tests, and deployment.
Choose the operating mode before acting:
Mode
Default behavior
Build or change
Design, implement, and verify the requested server changes.
Audit or review
Inspect and report with evidence. Do not edit files or mutate external systems unless the user explicitly asks.
Migration or upgrade
Audit the current implementation first. Implement the migration only when the request includes authorization to change it.
The first decision is the protocol era. The released 2026-07-28 protocol is
stateless and materially different from revisions through 2025-11-25. Do not
mix their lifecycle or transport patterns. Read references/protocol-eras.md
before choosing an SDK or scaffold.
For an existing server, read references/migrate-2026-07-28.md and inventory
its lifecycle, transport, state, server-to-client requests, caching,
authorization, SDK entry points, and real client versions before editing it.
This skill is TypeScript-first: its ready-to-copy scaffold targets the official
TypeScript SDK v2. For Python or another SDK, verify every required modern wire
behavior in the selected release instead of transliterating TypeScript APIs.
Your first job is discovery, not code. MCP servers stay small when protocol
version, transport, authorization, and primitive shape are chosen explicitly.
Two standing rules for this work:
Assume your training data is stale on MCP. The specification moves fast
and revisions change wire behavior, not just wording. Verify every protocol
claim against the versioned specification page for the revision you target and
its changelog, and every SDK claim against the installed version.
MCP is a thin adapter over a good API, not the design center. Adapt to the
service layer that already owns validation, authorization, persistence, and
events. Never duplicate route business logic inside a tool handler.
Phase 1: Interrogate the use case
Answer these questions before scaffolding. If the request already answers them,
state the inferred choices and proceed.
1. What does the server expose?
It exposes...
Likely direction
A cloud API, SaaS app, database, or service
Remote Streamable HTTP
Local files, a local process, localhost service, or hardware
Local stdio
Desktop app with an existing in-process service or local API
Embedded loopback HTTP, optionally with a stdio shim
Pure computation with no user-local state
Remote Streamable HTTP by default
A private internal service
Remote Streamable HTTP or local stdio, based on network access
For an existing application, identify the in-process service or local API that
already owns validation, authorization, persistence, and events. MCP handlers
should adapt to that layer rather than duplicate its business logic.
2. Who connects, and which protocol era do they support?
One developer or a local automation script: local stdio is acceptable.
A team, organization, or external users: remote Streamable HTTP.
A self-hosted customer deployment: remote Streamable HTTP inside their
deployment boundary.
Name the target hosts and versions, such as Codex, Claude Code, Cursor,
ChatGPT, a browser app, or a custom client.
For a new server, target the modern 2026-07-28 era. Add 2025-era support
only when a required host needs it, and test each era independently.
Treat product-level rollout announcements as leads, not compatibility proof.
Record the exact web, desktop, CLI, connector, or embedded host version tested.
For remote OAuth servers, read
references/target-client-compatibility.md.
3. What primitives does it need?
Tools: model-invoked actions, searches, parameterized reads, and mutations.
Resources: application-controlled, read-only context identified by URI.
Prompts: user-invoked message templates or workflows.
Elicitation: additional user input needed while resolving tools/call,
resources/read, or prompts/get. In the modern era this uses a multi
round-trip input_required result, not a direct server-to-client request.
Most servers start with tools. Use resources when context is useful independent
of a single tool call. Use prompts only for a genuinely reusable user workflow.
When selecting resources, templates, or prompts, read
references/resources-and-prompts.md now. When selecting subscriptions or an
extension, read references/server-capabilities.md now.
4. How many actions are there?
Under roughly 15 actions: one tool per action.
15–30 actions: still workable, but audit near-duplicates.
Dozens to hundreds of actions: consider a discovery-plus-execution pattern.
This is product guidance, not a protocol limit.
5. Does a request need more user input?
Ordinary required input: put it in the tool/resource/prompt arguments.
Simple non-sensitive input needed mid-operation: use form elicitation through
the modern MRTR flow, with capability checks and a fallback.
Secrets, API keys, passwords, payment credentials, or third-party OAuth: use
URL-mode elicitation or a separate trusted setup flow. Never collect them in
form mode. See references/elicitation.md.
6. What authorization is required?
Separate two authorization planes:
MCP client -> MCP server: who may call the MCP endpoint.
MCP server -> upstream service: which credential the server uses for the API,
database, or service it wraps.
Do not collapse them into one vague "API key". See references/auth.md.
Then answer a second question the spec leaves open: who runs the authorization
server? Delegate to an external identity provider, act as your own, or accept
API keys and skip OAuth. Delegation is not automatically cheapest; provider
consoles need configuration nobody can do in code. If the answer is "we do", or
if browser-hosted clients must work, read references/authorization-server.md.
7. Does state span requests?
Modern MCP has no protocol session. If application state spans calls, mint an
opaque handle and pass it as an ordinary result/argument. Authorize the handle
on every use and give it a documented lifetime. For an MRTR retry, use an
integrity-protected requestState bound to the caller, operation, and expiry.
Phase 2: Recommend a server shape
Recommend one primary path and name any compatibility path separately.
Remote Streamable HTTP
Default for cloud APIs, team servers, self-hosted deployments, and anything
reachable over the network.
For 2026-07-28:
the MCP endpoint accepts POST; GET and DELETE are not part of the modern
transport
every request is self-contained and carries protocol version and client
capabilities in _meta
there is no initialize handshake, Mcp-Session-Id, session affinity, or SSE
replay
a response can be JSON or a request-scoped SSE stream
long-lived change events use subscriptions/listen
Two different things are called "SSE" and the answer differs:
HTTP+SSE, the 2024-11-05 transport with its separate SSE and POST
endpoints, is deprecated and is in the deprecated-features registry. Do not
adopt it. Migrate existing deployments to Streamable HTTP.
SSE as a response content type inside Streamable HTTP is current. A server
may answer any request POST with either application/json or a
request-scoped text/event-stream, and a client must support both. A
JSON-only server is valid; a client that only accepts JSON is not.
Do not hardcode a protocol version in product code. Let the SDK negotiate, and
keep version strings in tests and smoke scripts where a change is visible. A
version you observe a client negotiating is that client's choice, not your
server's maximum; read the maximum from server/discover.
Use references/remote-http-scaffold.md for the modern TypeScript scaffold.
Use references/deploy-cloudflare-workers.md only for a Cloudflare Workers
target.
Local stdio
Use when the server must access user-local files, processes, hardware, or
desktop state.
Keep local stdio simple:
write only MCP JSON-RPC messages to stdout; log to stderr
validate and confine filesystem paths
avoid broad shell execution
avoid plaintext secrets on disk
treat the process as a multiplexed transport, not a conversation or session
document exactly what local access the server needs
Embedded desktop listener
Use a loopback Streamable HTTP listener inside the desktop process when the app
already has an in-process service layer and HTTP is a better host boundary than
a child process. Keep one MCP registry/factory, adapt it to that existing
service, and add a stdio shim only for hosts that require stdio. Treat loopback
as a security boundary: bind locally, validate Host and Origin, authenticate the
host, and own listener startup/shutdown with the desktop lifecycle. See
references/embedded-desktop.md.
Legacy compatibility
Revisions through 2025-11-25 use initialize and older Streamable HTTP
semantics. If a target host requires that era, use an SDK-supported dual-era
entry point or an explicitly separate legacy route. Never bolt legacy GET,
DELETE, session IDs, or direct server-to-client requests onto the modern path.
The official TypeScript v2 createMcpHandler and serveStdio entries support
both eras. For a new modern-only server, explicitly set legacy: "reject";
enable the SDK's compatibility path only when a required client needs it.
Existing sessionful legacy HTTP deployments still need a deliberately isolated
legacy handler rather than session state inside the modern per-request factory.
Phase 3: Pick a tool design pattern
Tool schemas and descriptions are runtime contracts visible to models and hosts.
Keep them precise, small, and stable.
Pattern A: one tool per action
Use for small surfaces.
create_issue: Create a new issue. Params: title, body, labels[]
update_issue: Update an issue. Params: id, title?, body?, state?
search_issues: Search issues. Params: query, limit?
add_comment: Add a comment. Params: issue_id, body
Pattern B: discover + execute
Use selectively for very large API surfaces.
search_actions: Return matching actions with IDs, descriptions, safety, and schemas.
execute_action: Execute one action by ID with validated parameters.
The server owns the full catalog. Never hide whether the selected action is a
read, write, or destructive operation behind a generic annotation. Consider
promoting the most common actions to dedicated tools.
See references/tool-design.md.
Phase 4: Pick an implementation stack
Prefer the user's existing stack only if it supports the target protocol era.
Framework familiarity does not compensate for an incompatible wire protocol.
Stack
Use when
Official TypeScript SDK v2 split packages
Default for a new 2026-07-28 TypeScript/JavaScript server. Use the modern createMcpHandler or serveStdio entry points.
Official TypeScript SDK v1 @modelcontextprotocol/sdk
Maintaining a 2025-era server. Do not describe it as a current-protocol scaffold.
Python/FastMCP or another SDK
The user prefers that ecosystem and its installed version is verified to support every required 2026-07-28 behavior. Otherwise target the older era explicitly or choose a supporting SDK.
The official TypeScript v2 split packages are stable, but still confirm package
tags, imports, and supported protocol versions before implementation. Do not
mix v1 and v2 imports. See references/versions.md.
Phase 5: Scaffold and verify
Once protocol era, deployment, primitives, framework, and authorization are
chosen:
Scaffold a minimal server with one read-only tool.
Add authorization before private data or mutations.
Add resources/prompts only when they solve a concrete context problem.
Add modern-protocol checks for:
server/discover
required per-request _meta
tools/list and tools/call
required wire resultType
required ttlMs and cacheScope on cacheable results
resources/list, resources/read, resources/templates/list, or
prompts/list/prompts/get when exposed
malformed request and unsupported protocol version
a domain/input failure returned as a tool result, not a crashed transport
For Streamable HTTP, test POST request headers (MCP-Protocol-Version,
Mcp-Method, and Mcp-Name where required) on JSON-RPC requests,
header/body mismatch, Origin, unauthorized access, and every enabled server
response mode. A JSON-only server is valid; clients must support JSON and
request-scoped SSE. The current revision does not define notification-POST
header requirements.
Run the current conformance suite and MCP Inspector version that support the
target era.
Test with each actual target host.
If MCP OAuth is selected, verify login, scope step-up, reconnect/refresh
after token expiry, revoke/re-auth, and registration behavior with each
target host. Prove the auth surface with exact assertions, not a successful
login: the full WWW-Authenticate value, whole metadata documents, each CORS
header individually including the absence of allow-credentials, fixed error
strings, code burn on a wrong verifier, and revocation actually stopping
service. Red-proof those tests against the pre-change source. See
references/authorization-server.md.
If supporting both eras, run the same functional tests against modern and
legacy connections and assert that their transport behaviors stay separate.
For mutating tools, simulate a response stream failing after the operation
commits. Verify that a retry with a new JSON-RPC ID cannot silently duplicate
harmful work.
Make an explicit subscriptions/listen decision: either reject it before
opening SSE and test that behavior, or provide a real event bus, fan-out,
capacity, cancellation, and reconnect tests. Capability advertising alone
does not disable the SDK listen router.
Server primitives reference
Primitive
Controller
Use when
Tools
Model through the host
Actions, searches, parameterized reads, writes
Resources
Host application
Browsable/read-only URI-addressed context
Prompts
User
Reusable workflows or message templates
Elicitation
Server during a supported request
Additional non-secret form input or a trusted URL handoff via MRTR
Subscriptions
Client
Opt in to list/resource change notifications
Extensions
Negotiated client/server capabilities
Optional features such as MCP Apps or Tasks
Roots, Sampling, Logging, and Dynamic Client Registration were deprecated in
2026-07-28. HTTP+SSE has been deprecated since 2025-03-26 and is now carried
in the same registry. All remain available only for compatibility during their
deprecation windows; new servers should use their documented migration paths.
Client ID Metadata Documents are DCR's migration path. See
references/server-capabilities.md.
Deployment checklist
Before calling a modern server ready:
server/discover advertises supported versions, capabilities, identity,
instructions when useful, and cache hints.
Every request is processed independently; no caller identity, capability,
conversation, or application state is inferred from a connection.
Streamable HTTP exposes POST at the MCP endpoint; GET/DELETE return 405
unless they belong to a deliberately separate legacy route.
Streamable HTTP validates Origin when present and local servers bind to
localhost or validate Host.
Required JSON-RPC request POST headers are present, safely decoded, and
match the request body; unsupported versions return the specified error.
Every enabled server response mode is tested. A JSON-only server is
allowed; clients are verified to accept both JSON and request-scoped SSE.
subscriptions/listen is either explicitly rejected without opening SSE,
or backed by a tested event bus with fan-out, capacity, cancellation, and
reconnect behavior.
There are no protocol sessions, resumability, Last-Event-ID, or
server-initiated JSON-RPC requests on the modern path.
Auth precedes private data and mutations; MCP auth is separate from
upstream-service auth.
Multiple credential shapes are discriminated by prefix with no
fallthrough; a claimed-but-invalid bearer is 401, never anonymous.
If MCP OAuth is selected, Protected Resource Metadata,
authorization-server discovery, resource audience binding, PKCE,
issuer validation, and client registration behavior are tested.
If the server runs its own authorization server: CORS is on the metadata
documents, registration, and token, and on nothing else; no endpoint sends
Access-Control-Allow-Credentials; consent is shown per client and
remembered; revocation stops service and clears warm authorization codes.
The credential lane the deployment serves is set in production, not only
in staging, and the setup guide the server publishes matches it.
No protocol version is hardcoded in product code.
Tool/resource/prompt schemas reject invalid input and external $ref
fetching is disabled by default.
Tools include useful names, titles, descriptions, schemas, and accurate
annotations; annotations are never treated as authorization.
Tool lists are deterministic and cacheable results use correct ttlMs
and cacheScope values.
Expected domain/input failures return useful tool results; malformed MCP
requests return protocol errors; HTTP failures never become HTML pages.
Stateful workflows use explicit, authorized handles. MRTR state is
integrity-protected and replay-bounded.
Secrets never appear in source, results, resources, prompts, URLs, logs,
traces, exceptions, or test snapshots.
Conformance, Inspector, and real-host checks pass for every supported era.
Reference routing
Use references/protocol-eras.md as the canonical wire-invariants reference;
context-specific references should point back to it rather than inventing a
second protocol model.
Situation
Read
Any era or wire-protocol decision
references/protocol-eras.md
Audit, migration, or dual-era rollout
references/migrate-2026-07-28.md
TypeScript remote HTTP implementation
references/remote-http-scaffold.md
Pinned runnable TypeScript HTTP example
assets/typescript-http/
Embedded Electron or other desktop application
references/embedded-desktop.md
Cloudflare Workers deployment
references/deploy-cloudflare-workers.md
Tool names, schemas, annotations, or state
references/tool-design.md
MCP OAuth or upstream authorization
references/auth.md
Running the authorization server yourself
references/authorization-server.md
Browser-hosted MCP clients, OAuth CORS
references/authorization-server.md
Resources, URI templates, or prompts
references/resources-and-prompts.md
Form/URL elicitation or MRTR state
references/elicitation.md
Discovery, caching, subscriptions, extensions
references/server-capabilities.md
Real-host negotiation, OAuth, or tool UX
references/target-client-compatibility.md
Package/API/version-sensitive claim
references/versions.md
1---2name: build-mcp-server3description: Design, scaffold, audit, and upgrade Model Context Protocol servers. Use when the user asks to build or migrate an MCP server, adopt MCP 2026-07-28, add dual-era support, create an MCP integration, expose an API or data source through MCP tools/resources/prompts, add OAuth or API-key auth to an MCP endpoint, run an authorization server for it, support browser-hosted MCP clients, or choose an MCP transport/auth/deployment shape.4---56# Build an MCP Server78Help design and build MCP servers. Keep the work focused on protocol primitives,9transport, authorization, validation, tests, and deployment.1011Choose the operating mode before acting:1213| Mode | Default behavior |14| -------------------- | -------------------------------------------------------------------------------------------------------------------------- |15| Build or change | Design, implement, and verify the requested server changes. |16| Audit or review | Inspect and report with evidence. Do not edit files or mutate external systems unless the user explicitly asks. |17| Migration or upgrade | Audit the current implementation first. Implement the migration only when the request includes authorization to change it. |1819The first decision is the protocol era. The released `2026-07-28` protocol is20stateless and materially different from revisions through `2025-11-25`. Do not21mix their lifecycle or transport patterns. Read `references/protocol-eras.md`22before choosing an SDK or scaffold.2324For an existing server, read `references/migrate-2026-07-28.md` and inventory25its lifecycle, transport, state, server-to-client requests, caching,26authorization, SDK entry points, and real client versions before editing it.2728This skill is TypeScript-first: its ready-to-copy scaffold targets the official29TypeScript SDK v2. For Python or another SDK, verify every required modern wire30behavior in the selected release instead of transliterating TypeScript APIs.3132Your first job is discovery, not code. MCP servers stay small when protocol33version, transport, authorization, and primitive shape are chosen explicitly.3435Two standing rules for this work:3637- **Assume your training data is stale on MCP.** The specification moves fast38 and revisions change wire behavior, not just wording. Verify every protocol39 claim against the versioned specification page for the revision you target and40 its changelog, and every SDK claim against the installed version.41- **MCP is a thin adapter over a good API, not the design center.** Adapt to the42 service layer that already owns validation, authorization, persistence, and43 events. Never duplicate route business logic inside a tool handler.4445---4647## Phase 1: Interrogate the use case4849Answer these questions before scaffolding. If the request already answers them,50state the inferred choices and proceed.5152### 1. What does the server expose?5354| It exposes... | Likely direction |55| ------------------------------------------------------------ | -------------------------------------------------------------- |56| A cloud API, SaaS app, database, or service | Remote Streamable HTTP |57| Local files, a local process, localhost service, or hardware | Local stdio |58| Desktop app with an existing in-process service or local API | Embedded loopback HTTP, optionally with a stdio shim |59| Pure computation with no user-local state | Remote Streamable HTTP by default |60| A private internal service | Remote Streamable HTTP or local stdio, based on network access |6162For an existing application, identify the in-process service or local API that63already owns validation, authorization, persistence, and events. MCP handlers64should adapt to that layer rather than duplicate its business logic.6566### 2. Who connects, and which protocol era do they support?6768- One developer or a local automation script: local stdio is acceptable.69- A team, organization, or external users: remote Streamable HTTP.70- A self-hosted customer deployment: remote Streamable HTTP inside their71 deployment boundary.72- Name the target hosts and versions, such as Codex, Claude Code, Cursor,73 ChatGPT, a browser app, or a custom client.74- For a new server, target the modern `2026-07-28` era. Add 2025-era support75 only when a required host needs it, and test each era independently.76- Treat product-level rollout announcements as leads, not compatibility proof.77 Record the exact web, desktop, CLI, connector, or embedded host version tested.78- For remote OAuth servers, read79 `references/target-client-compatibility.md`.8081### 3. What primitives does it need?8283- Tools: model-invoked actions, searches, parameterized reads, and mutations.84- Resources: application-controlled, read-only context identified by URI.85- Prompts: user-invoked message templates or workflows.86- Elicitation: additional user input needed while resolving `tools/call`,87 `resources/read`, or `prompts/get`. In the modern era this uses a multi88 round-trip `input_required` result, not a direct server-to-client request.8990Most servers start with tools. Use resources when context is useful independent91of a single tool call. Use prompts only for a genuinely reusable user workflow.92When selecting resources, templates, or prompts, read93`references/resources-and-prompts.md` now. When selecting subscriptions or an94extension, read `references/server-capabilities.md` now.9596### 4. How many actions are there?9798- Under roughly 15 actions: one tool per action.99- 15–30 actions: still workable, but audit near-duplicates.100- Dozens to hundreds of actions: consider a discovery-plus-execution pattern.101102This is product guidance, not a protocol limit.103104### 5. Does a request need more user input?105106- Ordinary required input: put it in the tool/resource/prompt arguments.107- Simple non-sensitive input needed mid-operation: use form elicitation through108 the modern MRTR flow, with capability checks and a fallback.109- Secrets, API keys, passwords, payment credentials, or third-party OAuth: use110 URL-mode elicitation or a separate trusted setup flow. Never collect them in111 form mode. See `references/elicitation.md`.112113### 6. What authorization is required?114115Separate two authorization planes:116117- MCP client -> MCP server: who may call the MCP endpoint.118- MCP server -> upstream service: which credential the server uses for the API,119 database, or service it wraps.120121Do not collapse them into one vague "API key". See `references/auth.md`.122123Then answer a second question the spec leaves open: **who runs the authorization124server?** Delegate to an external identity provider, act as your own, or accept125API keys and skip OAuth. Delegation is not automatically cheapest; provider126consoles need configuration nobody can do in code. If the answer is "we do", or127if browser-hosted clients must work, read `references/authorization-server.md`.128129### 7. Does state span requests?130131Modern MCP has no protocol session. If application state spans calls, mint an132opaque handle and pass it as an ordinary result/argument. Authorize the handle133on every use and give it a documented lifetime. For an MRTR retry, use an134integrity-protected `requestState` bound to the caller, operation, and expiry.135136---137138## Phase 2: Recommend a server shape139140Recommend one primary path and name any compatibility path separately.141142### Remote Streamable HTTP143144Default for cloud APIs, team servers, self-hosted deployments, and anything145reachable over the network.146147For `2026-07-28`:148149- the MCP endpoint accepts POST; GET and DELETE are not part of the modern150 transport151- every request is self-contained and carries protocol version and client152 capabilities in `_meta`153- there is no `initialize` handshake, `Mcp-Session-Id`, session affinity, or SSE154 replay155- a response can be JSON or a request-scoped SSE stream156- long-lived change events use `subscriptions/listen`157158Two different things are called "SSE" and the answer differs:159160- **HTTP+SSE, the 2024-11-05 transport** with its separate SSE and POST161 endpoints, is deprecated and is in the deprecated-features registry. Do not162 adopt it. Migrate existing deployments to Streamable HTTP.163- **SSE as a response content type inside Streamable HTTP** is current. A server164 may answer any request POST with either `application/json` or a165 request-scoped `text/event-stream`, and a client must support both. A166 JSON-only server is valid; a client that only accepts JSON is not.167168Do not hardcode a protocol version in product code. Let the SDK negotiate, and169keep version strings in tests and smoke scripts where a change is visible. A170version you observe a client negotiating is that client's choice, not your171server's maximum; read the maximum from `server/discover`.172173Use `references/remote-http-scaffold.md` for the modern TypeScript scaffold.174Use `references/deploy-cloudflare-workers.md` only for a Cloudflare Workers175target.176177### Local stdio178179Use when the server must access user-local files, processes, hardware, or180desktop state.181182Keep local stdio simple:183184- write only MCP JSON-RPC messages to stdout; log to stderr185- validate and confine filesystem paths186- avoid broad shell execution187- avoid plaintext secrets on disk188- treat the process as a multiplexed transport, not a conversation or session189- document exactly what local access the server needs190191### Embedded desktop listener192193Use a loopback Streamable HTTP listener inside the desktop process when the app194already has an in-process service layer and HTTP is a better host boundary than195a child process. Keep one MCP registry/factory, adapt it to that existing196service, and add a stdio shim only for hosts that require stdio. Treat loopback197as a security boundary: bind locally, validate Host and Origin, authenticate the198host, and own listener startup/shutdown with the desktop lifecycle. See199`references/embedded-desktop.md`.200201### Legacy compatibility202203Revisions through `2025-11-25` use `initialize` and older Streamable HTTP204semantics. If a target host requires that era, use an SDK-supported dual-era205entry point or an explicitly separate legacy route. Never bolt legacy GET,206DELETE, session IDs, or direct server-to-client requests onto the modern path.207208The official TypeScript v2 `createMcpHandler` and `serveStdio` entries support209both eras. For a new modern-only server, explicitly set `legacy: "reject"`;210enable the SDK's compatibility path only when a required client needs it.211Existing sessionful legacy HTTP deployments still need a deliberately isolated212legacy handler rather than session state inside the modern per-request factory.213214---215216## Phase 3: Pick a tool design pattern217218Tool schemas and descriptions are runtime contracts visible to models and hosts.219Keep them precise, small, and stable.220221### Pattern A: one tool per action222223Use for small surfaces.224225```text226create_issue: Create a new issue. Params: title, body, labels[]227update_issue: Update an issue. Params: id, title?, body?, state?228search_issues: Search issues. Params: query, limit?229add_comment: Add a comment. Params: issue_id, body230```231232### Pattern B: discover + execute233234Use selectively for very large API surfaces.235236```text237search_actions: Return matching actions with IDs, descriptions, safety, and schemas.238execute_action: Execute one action by ID with validated parameters.239```240241The server owns the full catalog. Never hide whether the selected action is a242read, write, or destructive operation behind a generic annotation. Consider243promoting the most common actions to dedicated tools.244245See `references/tool-design.md`.246247---248249## Phase 4: Pick an implementation stack250251Prefer the user's existing stack only if it supports the target protocol era.252Framework familiarity does not compensate for an incompatible wire protocol.253254| Stack | Use when |255| ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |256| Official TypeScript SDK v2 split packages | Default for a new `2026-07-28` TypeScript/JavaScript server. Use the modern `createMcpHandler` or `serveStdio` entry points. |257| Official TypeScript SDK v1 `@modelcontextprotocol/sdk` | Maintaining a 2025-era server. Do not describe it as a current-protocol scaffold. |258| Python/FastMCP or another SDK | The user prefers that ecosystem and its installed version is verified to support every required `2026-07-28` behavior. Otherwise target the older era explicitly or choose a supporting SDK. |259260The official TypeScript v2 split packages are stable, but still confirm package261tags, imports, and supported protocol versions before implementation. Do not262mix v1 and v2 imports. See `references/versions.md`.263264---265266## Phase 5: Scaffold and verify267268Once protocol era, deployment, primitives, framework, and authorization are269chosen:2702711. Scaffold a minimal server with one read-only tool.2722. Add authorization before private data or mutations.2733. Add resources/prompts only when they solve a concrete context problem.2744. Add modern-protocol checks for:275 - `server/discover`276 - required per-request `_meta`277 - `tools/list` and `tools/call`278 - required wire `resultType`279 - required `ttlMs` and `cacheScope` on cacheable results280 - `resources/list`, `resources/read`, `resources/templates/list`, or281 `prompts/list`/`prompts/get` when exposed282 - malformed request and unsupported protocol version283 - a domain/input failure returned as a tool result, not a crashed transport2845. For Streamable HTTP, test POST request headers (`MCP-Protocol-Version`,285 `Mcp-Method`, and `Mcp-Name` where required) on JSON-RPC requests,286 header/body mismatch, Origin, unauthorized access, and every enabled server287 response mode. A JSON-only server is valid; clients must support JSON and288 request-scoped SSE. The current revision does not define notification-POST289 header requirements.2906. Run the current conformance suite and MCP Inspector version that support the291 target era.2927. Test with each actual target host.2938. If MCP OAuth is selected, verify login, scope step-up, reconnect/refresh294 after token expiry, revoke/re-auth, and registration behavior with each295 target host. Prove the auth surface with exact assertions, not a successful296 login: the full `WWW-Authenticate` value, whole metadata documents, each CORS297 header individually including the absence of allow-credentials, fixed error298 strings, code burn on a wrong verifier, and revocation actually stopping299 service. Red-proof those tests against the pre-change source. See300 `references/authorization-server.md`.3019. If supporting both eras, run the same functional tests against modern and302 legacy connections and assert that their transport behaviors stay separate.30310. For mutating tools, simulate a response stream failing after the operation304 commits. Verify that a retry with a new JSON-RPC ID cannot silently duplicate305 harmful work.30611. Make an explicit `subscriptions/listen` decision: either reject it before307 opening SSE and test that behavior, or provide a real event bus, fan-out,308 capacity, cancellation, and reconnect tests. Capability advertising alone309 does not disable the SDK listen router.310311---312313## Server primitives reference314315| Primitive | Controller | Use when |316| ------------- | ------------------------------------- | ------------------------------------------------------------------ |317| Tools | Model through the host | Actions, searches, parameterized reads, writes |318| Resources | Host application | Browsable/read-only URI-addressed context |319| Prompts | User | Reusable workflows or message templates |320| Elicitation | Server during a supported request | Additional non-secret form input or a trusted URL handoff via MRTR |321| Subscriptions | Client | Opt in to list/resource change notifications |322| Extensions | Negotiated client/server capabilities | Optional features such as MCP Apps or Tasks |323324Roots, Sampling, Logging, and Dynamic Client Registration were deprecated in325`2026-07-28`. HTTP+SSE has been deprecated since `2025-03-26` and is now carried326in the same registry. All remain available only for compatibility during their327deprecation windows; new servers should use their documented migration paths.328Client ID Metadata Documents are DCR's migration path. See329`references/server-capabilities.md`.330331---332333## Deployment checklist334335Before calling a modern server ready:336337- [ ] `server/discover` advertises supported versions, capabilities, identity,338 instructions when useful, and cache hints.339- [ ] Every request is processed independently; no caller identity, capability,340 conversation, or application state is inferred from a connection.341- [ ] Streamable HTTP exposes POST at the MCP endpoint; GET/DELETE return 405342 unless they belong to a deliberately separate legacy route.343- [ ] Streamable HTTP validates `Origin` when present and local servers bind to344 localhost or validate Host.345- [ ] Required JSON-RPC request POST headers are present, safely decoded, and346 match the request body; unsupported versions return the specified error.347- [ ] Every enabled server response mode is tested. A JSON-only server is348 allowed; clients are verified to accept both JSON and request-scoped SSE.349- [ ] `subscriptions/listen` is either explicitly rejected without opening SSE,350 or backed by a tested event bus with fan-out, capacity, cancellation, and351 reconnect behavior.352- [ ] There are no protocol sessions, resumability, `Last-Event-ID`, or353 server-initiated JSON-RPC requests on the modern path.354- [ ] Auth precedes private data and mutations; MCP auth is separate from355 upstream-service auth.356- [ ] Multiple credential shapes are discriminated by prefix with no357 fallthrough; a claimed-but-invalid bearer is 401, never anonymous.358- [ ] If MCP OAuth is selected, Protected Resource Metadata,359 authorization-server discovery, `resource` audience binding, PKCE,360 issuer validation, and client registration behavior are tested.361- [ ] If the server runs its own authorization server: CORS is on the metadata362 documents, registration, and token, and on nothing else; no endpoint sends363 `Access-Control-Allow-Credentials`; consent is shown per client and364 remembered; revocation stops service and clears warm authorization codes.365- [ ] The credential lane the deployment serves is set in production, not only366 in staging, and the setup guide the server publishes matches it.367- [ ] No protocol version is hardcoded in product code.368- [ ] Tool/resource/prompt schemas reject invalid input and external `$ref`369 fetching is disabled by default.370- [ ] Tools include useful names, titles, descriptions, schemas, and accurate371 annotations; annotations are never treated as authorization.372- [ ] Tool lists are deterministic and cacheable results use correct `ttlMs`373 and `cacheScope` values.374- [ ] Expected domain/input failures return useful tool results; malformed MCP375 requests return protocol errors; HTTP failures never become HTML pages.376- [ ] Stateful workflows use explicit, authorized handles. MRTR state is377 integrity-protected and replay-bounded.378- [ ] Secrets never appear in source, results, resources, prompts, URLs, logs,379 traces, exceptions, or test snapshots.380- [ ] Conformance, Inspector, and real-host checks pass for every supported era.381382---383384## Reference routing385386Use `references/protocol-eras.md` as the canonical wire-invariants reference;387context-specific references should point back to it rather than inventing a388second protocol model.389390| Situation | Read |391| ---------------------------------------------- | ------------------------------------------- |392| Any era or wire-protocol decision | `references/protocol-eras.md` |393| Audit, migration, or dual-era rollout | `references/migrate-2026-07-28.md` |394| TypeScript remote HTTP implementation | `references/remote-http-scaffold.md` |395| Pinned runnable TypeScript HTTP example | `assets/typescript-http/` |396| Embedded Electron or other desktop application | `references/embedded-desktop.md` |397| Cloudflare Workers deployment | `references/deploy-cloudflare-workers.md` |398| Tool names, schemas, annotations, or state | `references/tool-design.md` |399| MCP OAuth or upstream authorization | `references/auth.md` |400| Running the authorization server yourself | `references/authorization-server.md` |401| Browser-hosted MCP clients, OAuth CORS | `references/authorization-server.md` |402| Resources, URI templates, or prompts | `references/resources-and-prompts.md` |403| Form/URL elicitation or MRTR state | `references/elicitation.md` |404| Discovery, caching, subscriptions, extensions | `references/server-capabilities.md` |405| Real-host negotiation, OAuth, or tool UX | `references/target-client-compatibility.md` |406| Package/API/version-sensitive claim | `references/versions.md` |
Run npx skillmds@latest add backnotprop/build-mcp-server in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Design, scaffold, audit, and upgrade Model Context Protocol servers. Use when the user asks to build or migrate an MCP server, adopt MCP 2026-07-28, add dual-era support, create an MCP integration, expose an API or data source through MCP tools/resources/prompts, add OAuth or API-key auth to an MCP endpoint, run an authorization server for it, support browser-hosted MCP clients, or choose an MCP transport/auth/deployment shape. It is listed under AI & ML on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
backnotprop (@backnotprop) published this skill. Their other Agent Skills are listed on their SkillMD profile.