# MCP Server Specification: [Server name]

> Specification for a Model Context Protocol (MCP) server: what it exposes
> to AI applications (tools, resources, prompts), over which transport,
> with which authorization, and how it is secured, tested and versioned.
> Written against MCP specification revision **2026-07-28** (the latest
> revision on modelcontextprotocol.io when this template was written;
> previous revision 2025-11-25). Check the current revision before you
> start. Replace every `[bracketed]` value and every row marked *Example*.

<!--
Guidance: How to use this template
- Confirm the protocol revision you target in the metadata table. The
  2026-07-28 revision is stateless: there is no `initialize` handshake and
  no protocol session; every request carries its protocol version and
  client capabilities in `_meta`, and servers implement `server/discover`.
  If you must support older clients, say which revisions in section 2.
- Write tool descriptions for the model, not for humans: say when to use
  the tool, when not to, and what the side effects are.
- Every tool is code the model can trigger. Section 6 must say which tools
  change state and how the host should ask the user before calling them.
- Related documents: [AI agent specification] for the agent that uses the
  server, [API specification] for the backend it wraps.
-->

| Field | Value |
|---|---|
| Document ID | [MCP-SPEC-001] |
| Server name and version | [`example-billing-mcp`] [1.0.0] |
| Target MCP revision | [2026-07-28]; backward compatible with [2025-11-25 / none] |
| Status | [Draft / In review / Approved] |
| Owner | [@owner] |
| Reviewers | [@security-reviewer], [@platform-engineer] |
| Repository | [URL] |
| Last updated | YYYY-MM-DD |

## 1. Purpose and context

<!-- Guidance: Say what the server gives an AI application access to, which hosts will use it, and what it deliberately does not expose. -->

[Describe the system the server wraps and who will connect to it.]
*Example:* Exposes read access to invoices and a limited credit operation
from the billing service, for use by the internal support assistant and by
engineers in their IDE assistants. It does not expose payment card data,
refunds or account deletion.

| Item | Value |
|---|---|
| Wrapped system | *Example:* Billing API v4 |
| Intended hosts | *Example:* Support assistant (remote), IDE assistants (local) |
| Users | *Example:* Support staff and billing engineers |
| Data classification | *Example:* Confidential (customer billing data) |

## 2. Transport and protocol

<!-- Guidance: Choose stdio for a local process launched by the host, Streamable HTTP for a remote or shared server. Record the security requirements that apply to the chosen transport. -->

| Aspect | Choice |
|---|---|
| Transport | [stdio / Streamable HTTP / both] |
| Endpoint (HTTP) | [`https://mcp.example.com/mcp`] single MCP endpoint accepting POST |
| Response modes | [JSON object / request-scoped SSE stream] per request |
| Discovery | `server/discover` returns supported versions, capabilities and server identity |
| Change notifications | [`subscriptions/listen` for list changes / not used] |
| Older clients | [Fallback to `initialize`-based revisions: yes or no] |

Transport requirements to verify:

- **stdio:** newline-delimited JSON-RPC on stdin and stdout; logs go to
  stderr only; credentials come from the environment, not from MCP
  authorization.
- **Streamable HTTP:** validate the `Origin` header on every request and
  answer 403 when it is present and invalid (DNS rebinding protection);
  bind to 127.0.0.1 when running locally; require the
  `MCP-Protocol-Version`, `Mcp-Method` and (for `tools/call`,
  `resources/read`, `prompts/get`) `Mcp-Name` headers and reject
  header-body mismatches with 400.
- **Statelessness:** no per-connection state. Where a tool needs state
  across calls, return an explicit opaque handle and accept it as an
  argument, checking authorization on every call.

## 3. Capabilities

<!-- Guidance: List the capabilities the server declares. Declare only what you implement. -->

| Capability | Declared | Notes |
|---|---|---|
| `tools` | [Yes] | `listChanged`: [true / false] |
| `resources` | [Yes / No] | Subscriptions to updates: [yes / no] |
| `prompts` | [Yes / No] | `listChanged`: [true / false] |
| `completions` | [Yes / No] | Argument completion for prompts and resource templates |
| Extensions | [None / list] | *Example:* Tasks extension for long-running exports |
| Deprecated features | Not used | Roots, Sampling and Logging are deprecated in 2026-07-28; avoid in new servers |

## 4. Tools

<!-- Guidance: One row per tool, then a full definition for each. Annotations are hints that clients must treat as untrusted unless the server is trusted, so never rely on them as the only safety control. -->

| Name | Title | Side effects | readOnlyHint | destructiveHint | idempotentHint | openWorldHint |
|---|---|---|---|---|---|---|
| `get_invoice` | *Example:* Get invoice | None | true | n/a | n/a | false |
| `search_invoices` | *Example:* Search invoices | None | true | n/a | n/a | false |
| `apply_credit` | *Example:* Apply account credit | Writes a ledger entry | false | false | false | false |

Defaults in the schema, if a hint is omitted: `readOnlyHint` false,
`destructiveHint` true, `idempotentHint` false, `openWorldHint` true. Set
every hint explicitly so clients do not assume the worst or the best.

### 4.1 Tool definition: `apply_credit`

```json
{
  "name": "apply_credit",
  "title": "Apply account credit",
  "description": "Add a credit in USD to a customer account. Use only after confirming the charge is a duplicate or caused by an outage. Maximum 50 USD. Creates a ledger entry that finance can reverse within 30 days.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "account_id": {"type": "string", "pattern": "^acc_[a-z0-9]{12}$"},
      "amount_usd": {"type": "number", "minimum": 0.01, "maximum": 50},
      "reason_code": {"type": "string", "enum": ["DUPLICATE_CHARGE", "SERVICE_OUTAGE"]}
    },
    "required": ["account_id", "amount_usd", "reason_code"],
    "additionalProperties": false
  },
  "outputSchema": {
    "type": "object",
    "properties": {"credit_id": {"type": "string"}, "balance_usd": {"type": "number"}},
    "required": ["credit_id", "balance_usd"]
  },
  "annotations": {"readOnlyHint": false, "destructiveHint": false, "idempotentHint": false, "openWorldHint": false}
}
```

Results with an `outputSchema` return `structuredContent` that conforms to
it, plus the same JSON serialised in a text content block for older
clients.

## 5. Resources and prompts

<!-- Guidance: Resources are context the host or user selects; prompts are user-invoked templates. List each with its URI or name and content type. -->

### 5.1 Resources

| URI or template | Name | MIME type | Description | Cache hint |
|---|---|---|---|---|
| `billing://policy/credits` | *Example:* Credit policy | text/markdown | Current credit rules | `ttlMs` 3,600,000, public |
| `billing://invoices/{invoice_id}` | *Example:* Invoice | application/json | One invoice | `ttlMs` 60,000, private |

List and read results carry `ttlMs` and `cacheScope`; use `private` for
anything user-specific.

### 5.2 Prompts

| Name | Arguments | Purpose |
|---|---|---|
| `explain_invoice` | *Example:* `invoice_id` (required), `language` (optional) | Produces a customer-friendly explanation of each line item |

## 6. Authorization

<!-- Guidance: HTTP servers that need authorization should follow the MCP authorization specification (OAuth 2.1 based). stdio servers should take credentials from the environment instead. -->

| Aspect | Design |
|---|---|
| Model | MCP server acts as an OAuth 2.1 resource server |
| Protected Resource Metadata | *Example:* `https://mcp.example.com/.well-known/oauth-protected-resource` (RFC 9728) listing the authorization server |
| Authorization server | *Example:* Corporate identity provider with RFC 8414 or OpenID Connect discovery |
| Client registration | Client ID Metadata Documents preferred; pre-registration for internal hosts; Dynamic Client Registration only for compatibility (deprecated) |
| Token validation | Audience must be this server's canonical URI (RFC 8707 resource indicator); reject other tokens; no token passthrough to the billing API |
| Scopes | *Example:* `invoices:read`, `credits:write`; 401 and 403 responses carry the required `scope` in `WWW-Authenticate` |
| Tool visibility | *Example:* `tools/list` returns `apply_credit` only to tokens with `credits:write` |
| Downstream calls | *Example:* Server uses its own service credentials with per-user audit fields |

## 7. Security considerations

<!-- Guidance: Address consent, least privilege, input validation and untrusted content. Map each to a test. -->

| ID | Concern | Control | Test |
|---|---|---|---|
| MS-01 | User consent before state changes | Write tools marked `readOnlyHint: false`; hosts are expected to confirm with the user; server enforces limits regardless | Manual host test |
| MS-02 | Least privilege | Separate scopes for read and write; service account limited to credit endpoint | Scope test matrix |
| MS-03 | Input validation | JSON Schema validation plus business checks (account ownership, daily cap) | Unit and fuzz tests |
| MS-04 | Untrusted content in results | Invoice memo fields marked as data; no instructions in tool descriptions that depend on returned text | Injection test set |
| MS-05 | Rate limiting | *Example:* 30 `tools/call` per minute per user | Load test |
| MS-06 | Output sanitisation | Card numbers masked; no secrets in results or errors | Snapshot tests |
| MS-07 | DNS rebinding (HTTP) | `Origin` validation; localhost binding for local mode | Integration test |
| MS-08 | Sensitive headers | No secrets or personal data in `x-mcp-header` parameters | Code review |

## 8. Error handling

<!-- Guidance: Distinguish protocol errors from tool execution errors so the model can self-correct where it can. -->

| Situation | Response |
|---|---|
| Unknown tool, malformed request | JSON-RPC error (for example `-32602` Invalid params) |
| Validation or business rule failure | Tool result with `isError: true` and an actionable message, for example "amount_usd must be 50 or less" |
| Backend unavailable | Tool result with `isError: true`, "billing service unavailable, retry later" |
| Unsupported protocol version | 400 with `UnsupportedProtocolVersionError` listing supported versions |
| Expired or unknown handle | `isError: true` explaining that a new handle is needed |

## 9. Logging and observability

<!-- Guidance: Decide what is logged, where, and how personal data is protected. -->

[*Example:* Structured logs to stderr (stdio) or the platform log pipeline
(HTTP) with request ID, method, tool name, user ID, latency and outcome.
Arguments are logged with account IDs hashed. Trace context propagated
through `_meta` (`traceparent`) into OpenTelemetry. Audit log of every
`apply_credit` call kept for [7] years.]

## 10. Versioning and compatibility

<!-- Guidance: Separate the server's own version from the MCP revisions it supports. -->

- Server version follows semantic versioning; a breaking change to any
  tool's input schema or behaviour is a major version.
- Tools are added rather than changed; deprecated tools keep working for
  [90] days and say so in their description.
- Supported MCP revisions: [2026-07-28]; [2025-11-25 via fallback].
- `listChanged` notifications are sent when the tool set changes at runtime.

## 11. Testing

<!-- Guidance: Combine automated tests with interactive checks in an inspector. -->

| Test | Tool | Pass criteria |
|---|---|---|
| Interactive check | MCP Inspector (`npx @modelcontextprotocol/inspector`) | All tools, resources and prompts listed and callable with valid inputs |
| Schema conformance | Contract tests against the published schema | All results validate; `structuredContent` matches `outputSchema` |
| Authorization | Integration tests with tokens of each scope | 401/403 as designed; no cross-tenant access |
| Injection | Adversarial fixtures in invoice memos | No change in tool behaviour |
| Host compatibility | [List of hosts] | Tools usable end to end |

## Standard and licence note

Based on the Model Context Protocol specification, revision 2026-07-28,
published at modelcontextprotocol.io; structure and requirement names
summarised in original wording. Check the specification for the current
revision and normative text. Template licence: MIT.
