@zigrivers/scaffold 3.32.1 → 3.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -18
- package/content/guides/knowledge-freshness/.diagrams/diagram-0.svg +1 -1
- package/content/guides/knowledge-freshness/.diagrams/manifest.json +1 -1
- package/content/guides/knowledge-freshness/index.html +9 -5
- package/content/guides/knowledge-freshness/index.md +5 -4
- package/content/guides/pipeline/index.html +2 -2
- package/content/guides/pipeline/index.md +2 -2
- package/content/knowledge/mcp-server/mcp-authentication.md +100 -0
- package/content/knowledge/mcp-server/mcp-deployment-patterns.md +119 -0
- package/content/knowledge/mcp-server/mcp-error-handling.md +131 -0
- package/content/knowledge/mcp-server/mcp-observability.md +125 -0
- package/content/knowledge/mcp-server/mcp-prompt-primitives.md +119 -0
- package/content/knowledge/mcp-server/mcp-protocol-fundamentals.md +130 -0
- package/content/knowledge/mcp-server/mcp-resource-design.md +111 -0
- package/content/knowledge/mcp-server/mcp-sdk-selection.md +136 -0
- package/content/knowledge/mcp-server/mcp-testing-strategies.md +127 -0
- package/content/knowledge/mcp-server/mcp-tool-design.md +125 -0
- package/content/knowledge/mcp-server/mcp-transport-patterns.md +122 -0
- package/content/knowledge/mcp-server/mcp-versioning.md +115 -0
- package/content/methodology/custom-defaults.yml +2 -0
- package/content/methodology/deep.yml +2 -0
- package/content/methodology/mcp-server-overlay.yml +88 -0
- package/content/methodology/mvp.yml +2 -0
- package/content/pipeline/build/multi-agent-resume.md +107 -11
- package/content/pipeline/build/multi-agent-start.md +104 -11
- package/content/pipeline/build/single-agent-resume.md +74 -8
- package/content/pipeline/build/single-agent-start.md +69 -12
- package/content/pipeline/finalization/materialize-plan-to-beads.md +473 -0
- package/content/pipeline/foundation/beads.md +6 -0
- package/content/pipeline/planning/implementation-plan-review.md +25 -0
- package/content/pipeline/planning/implementation-plan.md +75 -1
- package/content/pipeline/specification/mcp-tool-resource-contract.md +77 -0
- package/dist/cli/commands/adopt.d.ts.map +1 -1
- package/dist/cli/commands/adopt.js +33 -1
- package/dist/cli/commands/adopt.js.map +1 -1
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +46 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/init-flag-families.d.ts +6 -1
- package/dist/cli/init-flag-families.d.ts.map +1 -1
- package/dist/cli/init-flag-families.js +59 -2
- package/dist/cli/init-flag-families.js.map +1 -1
- package/dist/cli/init-flag-families.test.js +86 -1
- package/dist/cli/init-flag-families.test.js.map +1 -1
- package/dist/config/schema.d.ts +2310 -126
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +26 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/config/schema.test.js +75 -2
- package/dist/config/schema.test.js.map +1 -1
- package/dist/config/validators/index.d.ts.map +1 -1
- package/dist/config/validators/index.js +2 -0
- package/dist/config/validators/index.js.map +1 -1
- package/dist/config/validators/mcp-server.d.ts +4 -0
- package/dist/config/validators/mcp-server.d.ts.map +1 -0
- package/dist/config/validators/mcp-server.js +37 -0
- package/dist/config/validators/mcp-server.js.map +1 -0
- package/dist/config/validators/mcp-server.test.d.ts +2 -0
- package/dist/config/validators/mcp-server.test.d.ts.map +1 -0
- package/dist/config/validators/mcp-server.test.js +47 -0
- package/dist/config/validators/mcp-server.test.js.map +1 -0
- package/dist/core/assembly/materialize-plan-to-beads-assembly.test.d.ts +2 -0
- package/dist/core/assembly/materialize-plan-to-beads-assembly.test.d.ts.map +1 -0
- package/dist/core/assembly/materialize-plan-to-beads-assembly.test.js +75 -0
- package/dist/core/assembly/materialize-plan-to-beads-assembly.test.js.map +1 -0
- package/dist/e2e/project-type-overlays.test.js +83 -0
- package/dist/e2e/project-type-overlays.test.js.map +1 -1
- package/dist/project/adopt.d.ts.map +1 -1
- package/dist/project/adopt.js +3 -1
- package/dist/project/adopt.js.map +1 -1
- package/dist/project/detectors/coverage.test.js +1 -0
- package/dist/project/detectors/coverage.test.js.map +1 -1
- package/dist/project/detectors/disambiguate.d.ts.map +1 -1
- package/dist/project/detectors/disambiguate.js +6 -1
- package/dist/project/detectors/disambiguate.js.map +1 -1
- package/dist/project/detectors/disambiguate.test.js +18 -0
- package/dist/project/detectors/disambiguate.test.js.map +1 -1
- package/dist/project/detectors/index.d.ts.map +1 -1
- package/dist/project/detectors/index.js +2 -1
- package/dist/project/detectors/index.js.map +1 -1
- package/dist/project/detectors/mcp-server.d.ts +4 -0
- package/dist/project/detectors/mcp-server.d.ts.map +1 -0
- package/dist/project/detectors/mcp-server.js +91 -0
- package/dist/project/detectors/mcp-server.js.map +1 -0
- package/dist/project/detectors/mcp-server.test.d.ts +2 -0
- package/dist/project/detectors/mcp-server.test.d.ts.map +1 -0
- package/dist/project/detectors/mcp-server.test.js +115 -0
- package/dist/project/detectors/mcp-server.test.js.map +1 -0
- package/dist/project/detectors/types.d.ts +6 -2
- package/dist/project/detectors/types.d.ts.map +1 -1
- package/dist/project/detectors/types.js.map +1 -1
- package/dist/types/config.d.ts +8 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/wizard/copy/core.d.ts.map +1 -1
- package/dist/wizard/copy/core.js +4 -0
- package/dist/wizard/copy/core.js.map +1 -1
- package/dist/wizard/copy/index.d.ts.map +1 -1
- package/dist/wizard/copy/index.js +2 -0
- package/dist/wizard/copy/index.js.map +1 -1
- package/dist/wizard/copy/mcp-server.d.ts +3 -0
- package/dist/wizard/copy/mcp-server.d.ts.map +1 -0
- package/dist/wizard/copy/mcp-server.js +40 -0
- package/dist/wizard/copy/mcp-server.js.map +1 -0
- package/dist/wizard/copy/types.d.ts +5 -1
- package/dist/wizard/copy/types.d.ts.map +1 -1
- package/dist/wizard/flags.d.ts +9 -1
- package/dist/wizard/flags.d.ts.map +1 -1
- package/dist/wizard/questions.d.ts +4 -2
- package/dist/wizard/questions.d.ts.map +1 -1
- package/dist/wizard/questions.js +37 -0
- package/dist/wizard/questions.js.map +1 -1
- package/dist/wizard/questions.test.js +107 -0
- package/dist/wizard/questions.test.js.map +1 -1
- package/dist/wizard/wizard.d.ts +3 -2
- package/dist/wizard/wizard.d.ts.map +1 -1
- package/dist/wizard/wizard.js +3 -1
- package/dist/wizard/wizard.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-error-handling
|
|
3
|
+
description: MCP protocol errors (JSON-RPC error codes) vs tool execution errors (isError content), partial failures, error message design, and client recovery patterns
|
|
4
|
+
topics: [mcp, error-handling, json-rpc, tool-errors, protocol-errors]
|
|
5
|
+
volatility: evolving
|
|
6
|
+
last-reviewed: null
|
|
7
|
+
version-pin: 'MCP spec 2025-11-25'
|
|
8
|
+
sources:
|
|
9
|
+
- url: https://modelcontextprotocol.io/specification/2025-11-25/server/tools
|
|
10
|
+
- url: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
|
|
11
|
+
- url: https://www.jsonrpc.org/specification
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
MCP has two distinct error channels. Mixing them up is one of the most common MCP server bugs: using protocol errors for domain failures causes the LLM to lose context about what went wrong; using isError for protocol failures breaks client error-handling logic.
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
|
|
18
|
+
**Protocol errors** (JSON-RPC error responses) signal that a request could not be processed at all — unknown method, invalid parameters, server crash. Use standard JSON-RPC error codes. **Tool execution errors** (`isError: true` in the tool result) signal that the tool ran but the operation failed — API error, resource not found, business logic rejection. The LLM can read and react to tool errors; it cannot generally recover from protocol errors. Always prefer `isError: true` for domain-level failures that a well-behaved caller might encounter.
|
|
19
|
+
|
|
20
|
+
## Deep Guidance
|
|
21
|
+
|
|
22
|
+
### Protocol errors: JSON-RPC error responses
|
|
23
|
+
|
|
24
|
+
A protocol error is a JSON-RPC error response object. It replaces the `result` field entirely:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"jsonrpc": "2.0",
|
|
29
|
+
"id": 3,
|
|
30
|
+
"error": {
|
|
31
|
+
"code": -32602,
|
|
32
|
+
"message": "Unknown tool: invalid_tool_name"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Use protocol errors for:
|
|
38
|
+
- **Method not found** (`-32601`): the client called a method the server does not implement.
|
|
39
|
+
- **Invalid params** (`-32602`): structural/wire-level request problems that prevent dispatch entirely — unknown tool name in `tools/call`, unknown method, missing required prompt arguments to `prompts/get`, invalid resource URI in `resources/read`, malformed params shape at the JSON-RPC level. **Do NOT use `-32602` for a tool that dispatched successfully but whose arguments fail the tool's own `inputSchema` or business validation** — those are tool execution errors (see `isError` below).
|
|
40
|
+
- **Internal error** (`-32603`): unhandled exception or server bug. Include enough detail in `message` to diagnose, but sanitize sensitive data.
|
|
41
|
+
- **Parse error** (`-32700`): malformed JSON received. The SDK handles this automatically.
|
|
42
|
+
- **Invalid request** (`-32600`): request is not valid JSON-RPC 2.0 structure. Also SDK-handled.
|
|
43
|
+
|
|
44
|
+
Custom server-defined error codes MUST be in the JSON-RPC server-error range `-32099` to `-32000` (most-negative to least-negative). Standard resource error code: `-32002` (resource not found).
|
|
45
|
+
|
|
46
|
+
The `error` object MAY include a `data` field with additional structured context:
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"code": -32602,
|
|
50
|
+
"message": "Missing required argument",
|
|
51
|
+
"data": { "argument": "location", "required": true }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Tool execution errors: isError
|
|
56
|
+
|
|
57
|
+
When a tool runs but the operation it performs fails, return the failure as a normal result with `isError: true`:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"jsonrpc": "2.0",
|
|
62
|
+
"id": 4,
|
|
63
|
+
"result": {
|
|
64
|
+
"content": [
|
|
65
|
+
{
|
|
66
|
+
"type": "text",
|
|
67
|
+
"text": "Failed to fetch weather data: API returned 429 Too Many Requests. Rate limit resets at 14:00 UTC. Suggest retrying after that time."
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"isError": true
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Use `isError: true` for:
|
|
76
|
+
- **Tool input/schema validation failures** — when a tool dispatches but its arguments fail the tool's own `inputSchema` or business validation rules (wrong value, out-of-range number, unsupported enum value, failed cross-field constraint). Per SEP-1303 (2025-11-25), these MUST be `isError: true` so the model can self-correct, NOT `-32602`.
|
|
77
|
+
- External API failures (HTTP 4xx/5xx from downstream services)
|
|
78
|
+
- Resource not found in a domain sense (file doesn't exist at the path the user specified)
|
|
79
|
+
- Business logic rejections (insufficient permissions in the target system, invalid state for the operation)
|
|
80
|
+
- Network timeouts when calling downstream services
|
|
81
|
+
- Partial failures where the overall result is a failure
|
|
82
|
+
|
|
83
|
+
**Why this distinction matters**: when `isError: true`, the result is a successful JSON-RPC response — the protocol layer worked correctly. The LLM receives the content and can read the error message, decide to retry with different parameters, inform the user, or take an alternative approach. Protocol errors, on the other hand, are invisible to the LLM in most client implementations — they're handled at the transport/client layer. The 2025-11-25 spec revision (SEP-1303) explicitly directs that tool input validation errors MUST be returned as Tool Execution Errors (`isError: true`) rather than Protocol Errors (`-32602`), specifically to enable model self-correction. This applies to any argument that dispatches to a real tool but fails schema/business validation once there.
|
|
84
|
+
|
|
85
|
+
### Error message quality
|
|
86
|
+
|
|
87
|
+
Both protocol error messages and `isError` content messages are read by either developers (protocol errors) or LLMs (isError). Write them to be actionable:
|
|
88
|
+
|
|
89
|
+
**For isError messages** (LLM-readable):
|
|
90
|
+
- State what failed specifically, not just "an error occurred".
|
|
91
|
+
- Include any relevant IDs, timestamps, or context the LLM can use.
|
|
92
|
+
- Suggest what to do next when recovery is possible.
|
|
93
|
+
- Include rate limit reset times, retry suggestions, or alternative approaches.
|
|
94
|
+
|
|
95
|
+
**For protocol error messages** (developer-readable):
|
|
96
|
+
- Name the specific field or method that caused the error.
|
|
97
|
+
- Quote the invalid value or describe the expected format.
|
|
98
|
+
- Avoid exposing internal file paths, stack traces, or secrets.
|
|
99
|
+
|
|
100
|
+
### Partial failures in multi-item operations
|
|
101
|
+
|
|
102
|
+
When a tool processes multiple items and some succeed while others fail:
|
|
103
|
+
|
|
104
|
+
**Option A (partial success)**: Return successful results and error descriptions in the `content` array, without setting `isError: true`. Use this when partial output is useful:
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"content": [
|
|
108
|
+
{ "type": "text", "text": "Processed 3 of 5 items:\n✓ item1: success\n✓ item2: success\n✗ item3: rate limited\n✓ item4: success\n✗ item5: not found" }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Option B (total failure)**: If no items succeeded or the partial result is not useful, set `isError: true` and describe the failure.
|
|
114
|
+
|
|
115
|
+
Never silently drop failures — always include what failed and why, even in partial success responses.
|
|
116
|
+
|
|
117
|
+
### Initialization and lifecycle errors
|
|
118
|
+
|
|
119
|
+
During the `initialize` handshake, return a protocol error if:
|
|
120
|
+
- The client requests a protocol version the server does not support (respond with your supported version per spec, or error if incompatible).
|
|
121
|
+
- Required capabilities cannot be negotiated.
|
|
122
|
+
|
|
123
|
+
After initialization, if a client calls a method whose capability was not declared (e.g., calls `tools/list` but the server did not declare `tools` capability), return `-32601` (method not found) or `-32602` (invalid params) to indicate the feature is not available.
|
|
124
|
+
|
|
125
|
+
### Client-side recovery patterns
|
|
126
|
+
|
|
127
|
+
MCP clients should handle these error patterns from servers:
|
|
128
|
+
- **Protocol error on tool call**: log the error, surface to user if relevant, do not retry automatically (likely a programming error).
|
|
129
|
+
- **`isError: true` on tool result**: pass the error content to the LLM — it can decide whether to retry, use a different tool, or report to the user.
|
|
130
|
+
- **Server disconnect / connection reset**: attempt reconnection and re-run the `initialize` handshake before resuming operations. Do not silently drop in-flight requests.
|
|
131
|
+
- **`notifications/tools/list_changed`**: re-issue `tools/list` before the next tool call to ensure the cached tool list is current.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-observability
|
|
3
|
+
description: MCP server structured logging, stderr discipline for stdio transport, log message notifications, request tracing, debugging with MCP Inspector, and performance monitoring
|
|
4
|
+
topics: [mcp, observability, logging, tracing, debugging, monitoring]
|
|
5
|
+
volatility: evolving
|
|
6
|
+
last-reviewed: null
|
|
7
|
+
version-pin: null
|
|
8
|
+
sources:
|
|
9
|
+
- url: https://modelcontextprotocol.io/docs/tools/debugging
|
|
10
|
+
- url: https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/logging
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Good observability in an MCP server means you can diagnose problems without attaching a debugger. The fundamental constraint is the stdio transport's stdout-is-protocol-only rule, which makes naive logging dangerous. Structured logging to the right channel is non-negotiable.
|
|
14
|
+
|
|
15
|
+
## Summary
|
|
16
|
+
|
|
17
|
+
For **stdio servers**, write all logging to **stderr** — stdout is reserved exclusively for JSON-RPC protocol messages. Any stray write to stdout corrupts the protocol stream. For **HTTP servers**, use standard structured logging to files, stdout, or an aggregator — stderr is not captured by clients. MCP also provides a protocol-level logging mechanism via `notifications/message` (usable on any transport). Always include a correlation ID per request. Use the MCP Inspector as your first debugging tool.
|
|
18
|
+
|
|
19
|
+
## Deep Guidance
|
|
20
|
+
|
|
21
|
+
### Stderr discipline for stdio transport
|
|
22
|
+
|
|
23
|
+
The stdio transport reserves stdout entirely for JSON-RPC protocol messages. Even a single line of non-JSON output to stdout — a startup banner, a debug print, a library that logs to stdout by default — will corrupt the message stream and cause parse errors in the client. This is the most common cause of "MCP server not responding" problems.
|
|
24
|
+
|
|
25
|
+
**TypeScript/Node.js**: use `process.stderr.write(...)` or a logging library configured to stderr:
|
|
26
|
+
```typescript
|
|
27
|
+
import { createWriteStream } from 'node:fs'
|
|
28
|
+
// write to stderr or a log file — never process.stdout
|
|
29
|
+
const log = (msg: string) => process.stderr.write(`[server] ${msg}\n`)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Python**: use `print(..., file=sys.stderr)` or configure `logging` to use stderr:
|
|
33
|
+
```python
|
|
34
|
+
import logging, sys
|
|
35
|
+
logging.basicConfig(
|
|
36
|
+
level=logging.INFO,
|
|
37
|
+
stream=sys.stderr, # critical: must be stderr, not stdout
|
|
38
|
+
format='%(asctime)s %(levelname)s %(name)s: %(message)s'
|
|
39
|
+
)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The Python SDK's FastMCP does this correctly by default. Watch for third-party libraries that configure their own logging handlers pointing at stdout.
|
|
43
|
+
|
|
44
|
+
**Go**: `log.Println` writes to stderr by default — safe for stdio servers. Avoid `fmt.Println` which goes to stdout.
|
|
45
|
+
|
|
46
|
+
### MCP protocol-level logging (all transports)
|
|
47
|
+
|
|
48
|
+
For any transport, the server can send log messages to the client via the `notifications/message` notification. The server must declare `logging: {}` in its capabilities during initialization.
|
|
49
|
+
|
|
50
|
+
Log levels follow RFC 5424: `debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, `emergency`. Clients can set the minimum level via `logging/setLevel`.
|
|
51
|
+
|
|
52
|
+
TypeScript SDK:
|
|
53
|
+
```typescript
|
|
54
|
+
await server.sendLoggingMessage({ level: 'info', data: 'Tool execution started', logger: 'weather-tool' })
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Python FastMCP:
|
|
58
|
+
```python
|
|
59
|
+
await ctx.session.send_log_message(level="info", data="Processing request", logger="my-server")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Protocol-level logging is visible to the MCP client (and to the Inspector's Notifications pane), making it useful for surfacing server state to the host application without relying on stderr capture.
|
|
63
|
+
|
|
64
|
+
### Structured logging format
|
|
65
|
+
|
|
66
|
+
Use structured logs (JSON or key=value) rather than unstructured strings. Include:
|
|
67
|
+
- `timestamp`: ISO 8601 or epoch milliseconds
|
|
68
|
+
- `level`: debug/info/warning/error
|
|
69
|
+
- `request_id` or `correlation_id`: unique per MCP request (use the JSON-RPC `id` field value)
|
|
70
|
+
- `method`: the JSON-RPC method being handled
|
|
71
|
+
- `tool_name` / `resource_uri` / `prompt_name`: the specific capability invoked
|
|
72
|
+
- `duration_ms`: time taken (for completed requests)
|
|
73
|
+
- `error`: error type and message (for failures)
|
|
74
|
+
|
|
75
|
+
Example structured log entry:
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"timestamp": "2025-06-18T14:32:01.234Z",
|
|
79
|
+
"level": "info",
|
|
80
|
+
"request_id": "42",
|
|
81
|
+
"method": "tools/call",
|
|
82
|
+
"tool_name": "get_weather",
|
|
83
|
+
"duration_ms": 234,
|
|
84
|
+
"location": "New York"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Request tracing
|
|
89
|
+
|
|
90
|
+
Assign a correlation ID to each incoming MCP request using the JSON-RPC `id` field (for requests) or a generated UUID (for notifications). Thread this ID through all log entries, downstream API calls, and database queries generated by that request. This makes it possible to reconstruct the full execution path for a single tool call when debugging a failure.
|
|
91
|
+
|
|
92
|
+
For HTTP transport, also include the `Mcp-Session-Id` in logs to correlate all requests within a session.
|
|
93
|
+
|
|
94
|
+
### Debugging with MCP Inspector
|
|
95
|
+
|
|
96
|
+
The MCP Inspector is the most effective debugging tool for local development:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Launch your server with the Inspector
|
|
100
|
+
npx @modelcontextprotocol/inspector node dist/server.js
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Inspector debugging workflow:
|
|
104
|
+
1. Check the Notifications pane for server log messages and error notifications.
|
|
105
|
+
2. Invoke a failing tool and inspect the raw request/response in the tool result pane.
|
|
106
|
+
3. Verify capability negotiation — check that the capabilities shown in the Inspector match what your server declares.
|
|
107
|
+
4. Test error paths explicitly: call tools with invalid inputs and verify `isError: true` responses display correctly.
|
|
108
|
+
|
|
109
|
+
For Claude Desktop specifically, tail the MCP log files:
|
|
110
|
+
```bash
|
|
111
|
+
# macOS
|
|
112
|
+
tail -F ~/Library/Logs/Claude/mcp*.log
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Performance monitoring
|
|
116
|
+
|
|
117
|
+
Log operation timing for all tool calls and resource reads. Track:
|
|
118
|
+
- **p50/p95/p99 latency** per tool: identify slow tools before users complain.
|
|
119
|
+
- **Error rate** per tool: high error rates indicate API instability or logic bugs.
|
|
120
|
+
- **Payload size**: large tool results consume LLM context; log result byte sizes to catch runaway responses.
|
|
121
|
+
- **Downstream API latency**: separately log time spent waiting for external APIs vs. server-side processing.
|
|
122
|
+
|
|
123
|
+
For HTTP-transport servers, standard HTTP middleware (Morgan, Express's req timing) captures request-level metrics. For stdio servers, implement timing within each tool handler and write to stderr/log file.
|
|
124
|
+
|
|
125
|
+
Set alerts on: error rate above 5%, tool latency p99 above 5 seconds, and any `SIGTERM` not followed by clean exit within 30 seconds (hung shutdown).
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-prompt-primitives
|
|
3
|
+
description: MCP prompts as user-controlled primitives, prompts/list and prompts/get methods, arguments, message roles, and when to use prompts vs tools
|
|
4
|
+
topics: [mcp, prompts, ux, slash-commands, prompt-templates]
|
|
5
|
+
volatility: evolving
|
|
6
|
+
last-reviewed: null
|
|
7
|
+
version-pin: 'MCP spec 2025-11-25'
|
|
8
|
+
sources:
|
|
9
|
+
- url: https://modelcontextprotocol.io/specification/2025-11-25/server/prompts
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Prompts in MCP are structured, reusable message templates that users explicitly select. They are different from tools (model-controlled, automatic) and resources (application-controlled, passive context). Understanding the distinction shapes how you expose server capabilities.
|
|
13
|
+
|
|
14
|
+
## Summary
|
|
15
|
+
|
|
16
|
+
Servers declare prompts via `prompts/list`; clients retrieve a populated prompt via `prompts/get` with filled-in arguments. Each prompt returns a `messages` array with `role`/`content` pairs ready to inject into a conversation. Prompts are **user-controlled** — they appear as slash commands or UI-selectable templates. Declare `prompts: { listChanged: true }` if the available prompts can change at runtime. Use prompts when a user needs to explicitly invoke a repeatable interaction pattern; use tools when the LLM should autonomously execute an action.
|
|
17
|
+
|
|
18
|
+
## Deep Guidance
|
|
19
|
+
|
|
20
|
+
### Prompts as user-controlled primitives
|
|
21
|
+
|
|
22
|
+
The defining characteristic of MCP prompts is that they are **user-initiated**, not model-initiated. The host surfaces them as discoverable, selectable commands — typically slash commands in a chat UI, menu items in an IDE, or shortcut buttons in a desktop app. The user explicitly chooses a prompt, fills in any arguments, and the resulting message sequence is injected into the conversation.
|
|
23
|
+
|
|
24
|
+
This contrasts sharply with tools (which the LLM invokes automatically based on context) and resources (which the host includes in context based on application logic). Prompts are neither automatic nor passive — they are deliberate user actions.
|
|
25
|
+
|
|
26
|
+
### prompts/list — discovery
|
|
27
|
+
|
|
28
|
+
`prompts/list` returns available prompt templates. Each entry includes `name`, optional `title` (display name), optional `description`, and an optional `arguments` array:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"prompts": [
|
|
33
|
+
{
|
|
34
|
+
"name": "code_review",
|
|
35
|
+
"title": "Request Code Review",
|
|
36
|
+
"description": "Ask the model to review code for quality, bugs, and improvements",
|
|
37
|
+
"arguments": [
|
|
38
|
+
{
|
|
39
|
+
"name": "code",
|
|
40
|
+
"description": "The source code to review",
|
|
41
|
+
"required": true
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "language",
|
|
45
|
+
"description": "Programming language, e.g. TypeScript",
|
|
46
|
+
"required": false
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`prompts/list` supports cursor-based pagination. If the server can add or remove prompts dynamically, declare `prompts: { listChanged: true }` and send `notifications/prompts/list_changed` when the set changes.
|
|
55
|
+
|
|
56
|
+
### prompts/get — retrieval and argument injection
|
|
57
|
+
|
|
58
|
+
`prompts/get` takes a `name` and an `arguments` map (matching the declared argument names to concrete values). The server returns a `messages` array — fully formed conversation messages ready to send to an LLM:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"method": "prompts/get",
|
|
63
|
+
"params": {
|
|
64
|
+
"name": "code_review",
|
|
65
|
+
"arguments": {
|
|
66
|
+
"code": "function add(a, b) { return a + b }",
|
|
67
|
+
"language": "JavaScript"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Response:
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"result": {
|
|
77
|
+
"description": "Code review prompt for JavaScript",
|
|
78
|
+
"messages": [
|
|
79
|
+
{
|
|
80
|
+
"role": "user",
|
|
81
|
+
"content": {
|
|
82
|
+
"type": "text",
|
|
83
|
+
"text": "Please review this JavaScript code for quality, potential bugs, and improvements:\n\nfunction add(a, b) { return a + b }"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The server does the argument substitution and structures the messages — the client does not template-expand arguments itself. This lets the server implement sophisticated logic: injecting relevant resources, fetching live data to embed in the prompt, or constructing multi-turn conversation starters.
|
|
92
|
+
|
|
93
|
+
### Message roles and content types
|
|
94
|
+
|
|
95
|
+
Prompt messages support `role: "user"` and `role: "assistant"`. Use `"user"` for the human turn and `"assistant"` for pre-seeded model responses (useful for few-shot examples or to prime a specific response style).
|
|
96
|
+
|
|
97
|
+
Content types within messages match tool result content types: `text`, `image`, `audio`, and `resource` (embedded resource). Use embedded resources to include relevant file contents, API data, or database records directly in the prompt without requiring a separate `resources/read` call.
|
|
98
|
+
|
|
99
|
+
### When to use prompts vs tools vs resources
|
|
100
|
+
|
|
101
|
+
These three primitives answer different questions:
|
|
102
|
+
|
|
103
|
+
| Primitive | Controlled by | When to use |
|
|
104
|
+
|-----------|--------------|-------------|
|
|
105
|
+
| **Prompt** | User (explicit selection) | Repeatable interaction patterns a user deliberately invokes: code review, explain concept, generate commit message |
|
|
106
|
+
| **Tool** | LLM (autonomous invocation) | Actions the LLM should take as part of its reasoning: fetch data, write file, call API |
|
|
107
|
+
| **Resource** | Application (contextual inclusion) | Background context the LLM should be aware of: current file, open database schema, active configuration |
|
|
108
|
+
|
|
109
|
+
A prompt for "generate a commit message" is appropriate — the user explicitly decides to invoke this pattern. A tool for "get_current_file" is appropriate — the LLM decides when fetching the current file is relevant to its task. A resource for "current_project_schema" is appropriate — the host automatically includes the schema as background context.
|
|
110
|
+
|
|
111
|
+
Avoid turning every capability into a prompt. Prompts that should be tools (because the LLM should invoke them automatically) create friction. Prompts that should be resources (because they're background context) waste a user action.
|
|
112
|
+
|
|
113
|
+
### Argument design
|
|
114
|
+
|
|
115
|
+
Keep prompt arguments minimal. Each required argument is a burden on the user. Design prompts that work well with few arguments and use the server's access to context (active files, project config, authenticated user state) to fill in the rest.
|
|
116
|
+
|
|
117
|
+
Use required arguments for inputs the server genuinely cannot infer: the code to review, the ticket ID to reference. Use optional arguments with sensible defaults for refinements: language hint, verbosity level, output format.
|
|
118
|
+
|
|
119
|
+
Validate all arguments before building the messages. Return a JSON-RPC `-32602` (invalid params) error for missing required arguments or invalid values, with a clear message identifying which argument is problematic and what a valid value looks like.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-protocol-fundamentals
|
|
3
|
+
description: MCP client/server model, JSON-RPC 2.0 message format, capability negotiation, initialize handshake, connection lifecycle, and host/client/server roles
|
|
4
|
+
topics: [mcp, protocol, json-rpc, lifecycle, capability-negotiation]
|
|
5
|
+
volatility: fast-moving
|
|
6
|
+
last-reviewed: null
|
|
7
|
+
version-pin: 'MCP spec 2025-11-25'
|
|
8
|
+
sources:
|
|
9
|
+
- url: https://modelcontextprotocol.io/specification/2025-11-25/
|
|
10
|
+
- url: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
|
|
11
|
+
- url: https://www.jsonrpc.org/specification
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
The Model Context Protocol (MCP) is a JSON-RPC 2.0 based protocol that standardizes how LLM applications connect to external data sources and tools. Understanding the three-role model and the initialize handshake is prerequisite knowledge for every other MCP concept.
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
|
|
18
|
+
MCP uses JSON-RPC 2.0 over a stateful transport. Three roles: **hosts** (LLM applications that initiate connections), **clients** (connectors within the host), and **servers** (services that expose capabilities). The connection lifecycle has three phases — initialization, operation, and shutdown — and always begins with an `initialize` request/response exchange followed by an `initialized` notification. Capabilities are declared during initialization; neither side may use a capability it did not declare.
|
|
19
|
+
|
|
20
|
+
## Deep Guidance
|
|
21
|
+
|
|
22
|
+
### Three-role model
|
|
23
|
+
|
|
24
|
+
The MCP architecture separates concerns into three distinct roles:
|
|
25
|
+
|
|
26
|
+
- **Host**: The LLM application (e.g., Claude Desktop, an IDE plugin) that orchestrates connections. The host owns the user interface and decides which servers to connect to.
|
|
27
|
+
- **Client**: A connector embedded in the host that manages a single server connection, handles the protocol lifecycle, and mediates capability negotiation.
|
|
28
|
+
- **Server**: An independent process or service that exposes tools, resources, or prompts. A server has no knowledge of other servers the client may be connected to.
|
|
29
|
+
|
|
30
|
+
One host typically manages multiple client-server pairs. Each server connection is isolated — servers do not communicate with each other.
|
|
31
|
+
|
|
32
|
+
### JSON-RPC 2.0 message format
|
|
33
|
+
|
|
34
|
+
All MCP messages are JSON-RPC 2.0 objects, UTF-8 encoded. Three message types:
|
|
35
|
+
|
|
36
|
+
**Requests** (expect a response):
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"jsonrpc": "2.0",
|
|
40
|
+
"id": 1,
|
|
41
|
+
"method": "tools/list",
|
|
42
|
+
"params": {}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Responses** (reply to a request):
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"jsonrpc": "2.0",
|
|
50
|
+
"id": 1,
|
|
51
|
+
"result": { "tools": [] }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Notifications** (no response expected, no `id` field):
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"jsonrpc": "2.0",
|
|
59
|
+
"method": "notifications/initialized"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Error responses use a standard error object with `code` (integer) and `message` (string). Standard JSON-RPC error codes apply: `-32700` (parse error), `-32600` (invalid request), `-32601` (method not found), `-32602` (invalid params), `-32603` (internal error).
|
|
64
|
+
|
|
65
|
+
### The initialize handshake
|
|
66
|
+
|
|
67
|
+
The `initialize` request MUST be the first message sent by the client. It carries the protocol version the client supports (should be the latest), the client's capabilities, and client implementation information. The server responds with its own protocol version, capabilities, and an optional `instructions` string for the client.
|
|
68
|
+
|
|
69
|
+
After a successful response, the client MUST send an `initialized` notification (`notifications/initialized`) to signal readiness. Neither side should send substantive requests before this exchange completes — the only exception is ping messages.
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"jsonrpc": "2.0",
|
|
74
|
+
"id": 1,
|
|
75
|
+
"method": "initialize",
|
|
76
|
+
"params": {
|
|
77
|
+
"protocolVersion": "2025-11-25",
|
|
78
|
+
"capabilities": {
|
|
79
|
+
"roots": { "listChanged": true },
|
|
80
|
+
"sampling": {},
|
|
81
|
+
"elicitation": {}
|
|
82
|
+
},
|
|
83
|
+
"clientInfo": { "name": "MyClient", "version": "1.0.0" }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The server responds with its capabilities. Example server capability declaration:
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"protocolVersion": "2025-11-25",
|
|
92
|
+
"capabilities": {
|
|
93
|
+
"tools": { "listChanged": true },
|
|
94
|
+
"resources": { "subscribe": true, "listChanged": true },
|
|
95
|
+
"prompts": { "listChanged": true },
|
|
96
|
+
"logging": {}
|
|
97
|
+
},
|
|
98
|
+
"serverInfo": { "name": "MyServer", "version": "1.0.0" }
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Version negotiation
|
|
103
|
+
|
|
104
|
+
The client sends the latest protocol version it supports. If the server supports it, it echoes the same version. If the server does not support the requested version, it responds with the latest version it does support. If the client cannot handle the server's version, it should disconnect. The currently active spec version is `2025-11-25`; clients sending this should receive it back from any compliant modern server.
|
|
105
|
+
|
|
106
|
+
### Capability negotiation
|
|
107
|
+
|
|
108
|
+
Capabilities declared during `initialize` govern which protocol features are available for the session. Key capability categories:
|
|
109
|
+
|
|
110
|
+
| Side | Capability | Enables |
|
|
111
|
+
|--------|---------------|-------------------------------------------------|
|
|
112
|
+
| Server | `tools` | `tools/list`, `tools/call` |
|
|
113
|
+
| Server | `resources` | `resources/list`, `resources/read`, subscriptions |
|
|
114
|
+
| Server | `prompts` | `prompts/list`, `prompts/get` |
|
|
115
|
+
| Server | `logging` | Log message notifications to client |
|
|
116
|
+
| Client | `sampling` | Server-initiated LLM sampling requests |
|
|
117
|
+
| Client | `roots` | Server can query filesystem root boundaries |
|
|
118
|
+
| Client | `elicitation` | Server can request additional info from user |
|
|
119
|
+
|
|
120
|
+
Sub-capabilities like `listChanged` (support for list-change notifications) and `subscribe` (resources only, per-resource change subscriptions) are nested within their parent capability. A server that declares `tools: { listChanged: true }` MUST send `notifications/tools/list_changed` when its tool set changes.
|
|
121
|
+
|
|
122
|
+
### Lifecycle phases
|
|
123
|
+
|
|
124
|
+
1. **Initialization**: `initialize` request → server response → `initialized` notification. No tool/resource/prompt calls before this completes.
|
|
125
|
+
2. **Operation**: Normal message exchange. Both sides respect negotiated capabilities.
|
|
126
|
+
3. **Shutdown**: For stdio, the client closes the server's stdin and waits for the process to exit (sending `SIGTERM` then `SIGKILL` if needed). For HTTP, closing connections signals shutdown. No formal shutdown request message exists — transport-level signals are used.
|
|
127
|
+
|
|
128
|
+
### Timeouts and error handling
|
|
129
|
+
|
|
130
|
+
Implementations should set timeouts on all sent requests to prevent hung connections. When a timeout fires, send a `CancelledNotification` for the pending request ID. Progress notifications can optionally reset a timeout clock, but a hard maximum timeout should always be enforced regardless. Protocol version mismatch, required capability negotiation failure, and request timeouts are the standard error cases to handle at startup.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-resource-design
|
|
3
|
+
description: MCP resource URIs, URI templates (RFC 6570), MIME types, resources/list + resources/read + resources/subscribe, listChanged notifications, annotations, pagination
|
|
4
|
+
topics: [mcp, resources, uri-templates, mime-types, subscriptions]
|
|
5
|
+
volatility: evolving
|
|
6
|
+
last-reviewed: null
|
|
7
|
+
version-pin: 'MCP spec 2025-11-25'
|
|
8
|
+
sources:
|
|
9
|
+
- url: https://modelcontextprotocol.io/specification/2025-11-25/server/resources
|
|
10
|
+
- url: https://datatracker.ietf.org/doc/html/rfc6570
|
|
11
|
+
- url: https://datatracker.ietf.org/doc/html/rfc3986
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Resources are the MCP primitive for exposing data that provides context to LLMs — files, database records, API responses, or any addressable content. Unlike tools, resources are application-driven (the host decides what to expose), not model-driven.
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
|
|
18
|
+
Each resource has a `URI` as its unique identifier, a `name`, optional `description` and `mimeType`. Clients discover resources via `resources/list` and fetch content via `resources/read`. Parameterized resources use URI templates (RFC 6570) via `resources/templates/list`. Servers declare `resources: { subscribe: true }` to support `resources/subscribe` for change notifications. Both list and content endpoints support cursor-based pagination.
|
|
19
|
+
|
|
20
|
+
## Deep Guidance
|
|
21
|
+
|
|
22
|
+
### Resource URI design
|
|
23
|
+
|
|
24
|
+
Every resource MUST have a globally unique URI conforming to RFC 3986. The URI scheme signals the resource's nature:
|
|
25
|
+
|
|
26
|
+
- `file:///absolute/path/to/file.txt` — filesystem-like resources (the resource need not be a real file; use this for any content that behaves like a file).
|
|
27
|
+
- `https://example.com/api/data` — web-fetchable resources. Use only when the client can fetch the URL directly; otherwise use a custom scheme.
|
|
28
|
+
- `git://repo/path/to/file@main` — git-versioned content.
|
|
29
|
+
- Custom schemes (e.g., `db://`, `github://`, `slack://`) — use freely for domain-specific resources. Custom schemes MUST conform to RFC 3986.
|
|
30
|
+
|
|
31
|
+
Avoid embedding credentials, tokens, or session state in URIs — URIs are logged and passed between systems. Keep URIs stable across server restarts for resources that represent persistent entities.
|
|
32
|
+
|
|
33
|
+
### Static resources vs URI templates
|
|
34
|
+
|
|
35
|
+
**Static resources** have fully-specified URIs and appear in `resources/list`. Use for a bounded, known set of resources (a fixed set of config files, a fixed list of database tables, etc.).
|
|
36
|
+
|
|
37
|
+
**URI templates** (RFC 6570) use `resources/templates/list` and allow parameterized resource access. The `uriTemplate` field contains an RFC 6570 Level 1 template:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"uriTemplate": "github://repos/{owner}/{repo}/issues/{number}",
|
|
42
|
+
"name": "GitHub Issue",
|
|
43
|
+
"description": "A specific GitHub issue by owner, repo, and number",
|
|
44
|
+
"mimeType": "application/json"
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The template parameters (`owner`, `repo`, `number`) can be auto-completed by the server via the completions API if declared as server capability. Clients expand the template with concrete values and use the result as the URI in a `resources/read` request. Use templates for unbounded or large collections (user files, database rows, API records) where listing all resources statically is impractical.
|
|
49
|
+
|
|
50
|
+
### resources/list and pagination
|
|
51
|
+
|
|
52
|
+
`resources/list` returns available static resources. The response includes a `resources` array and an optional `nextCursor`. If `nextCursor` is present, pass it as `cursor` in the next request to get the next page. Always handle pagination — a server serving a filesystem may return thousands of entries.
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"method": "resources/list",
|
|
57
|
+
"params": { "cursor": "eyJwYWdlIjogMn0=" }
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Response resources include `uri`, `name`, optional `title`, optional `description`, optional `mimeType`, and optional `size` (bytes). The `mimeType` is advisory — always re-check the `mimeType` in the actual content returned by `resources/read`.
|
|
62
|
+
|
|
63
|
+
### resources/read and content types
|
|
64
|
+
|
|
65
|
+
`resources/read` takes a `uri` and returns a `contents` array. Each content item carries:
|
|
66
|
+
|
|
67
|
+
- For text: `{ "uri": "...", "mimeType": "text/plain", "text": "..." }`
|
|
68
|
+
- For binary: `{ "uri": "...", "mimeType": "image/png", "blob": "<base64>" }`
|
|
69
|
+
|
|
70
|
+
A single read can return multiple content items if the URI expands to multiple files (e.g., a directory URI). The `blob` field contains standard base64-encoded binary data; the `text` field is a UTF-8 string.
|
|
71
|
+
|
|
72
|
+
Standard MIME type conventions: `text/plain`, `text/markdown`, `application/json`, `application/octet-stream` for unknown binary, `image/png`, `image/jpeg`, `text/html`. Use `inode/directory` (XDG MIME) for directory resources without a standard MIME type.
|
|
73
|
+
|
|
74
|
+
### Subscriptions
|
|
75
|
+
|
|
76
|
+
Declare `resources: { subscribe: true }` to support per-resource change notifications. The flow:
|
|
77
|
+
|
|
78
|
+
1. Client sends `resources/subscribe` with a specific `uri`.
|
|
79
|
+
2. Server responds with success (empty result).
|
|
80
|
+
3. When the resource changes, server sends `notifications/resources/updated` with the `uri`.
|
|
81
|
+
4. Client re-fetches the resource with `resources/read`.
|
|
82
|
+
|
|
83
|
+
Subscriptions are stateful — track them in the server. If a client disconnects and reconnects, subscriptions are lost and must be re-established. Implement subscriptions when resources represent live data (open files in an editor, real-time database records, live API state).
|
|
84
|
+
|
|
85
|
+
### listChanged notifications
|
|
86
|
+
|
|
87
|
+
If the set of available resources can change (files added/removed, database tables created/dropped), declare `resources: { listChanged: true }` and send `notifications/resources/list_changed` when the list changes. The client re-issues `resources/list` to refresh. This is separate from subscriptions: `listChanged` is for the catalog, subscriptions are for individual resource content.
|
|
88
|
+
|
|
89
|
+
### Annotations
|
|
90
|
+
|
|
91
|
+
Resources support optional `annotations` that hint at audience and priority:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"annotations": {
|
|
96
|
+
"audience": ["assistant"],
|
|
97
|
+
"priority": 0.9,
|
|
98
|
+
"lastModified": "2025-06-18T10:00:00Z"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- `audience`: `["user"]`, `["assistant"]`, or `["user", "assistant"]`. Use `["assistant"]` for machine-readable data the LLM should process but not display to users. Use `["user"]` for human-readable content.
|
|
104
|
+
- `priority`: 0.0 to 1.0. Higher values indicate more important context to include when token budgets are limited.
|
|
105
|
+
- `lastModified`: ISO 8601 timestamp. Enables clients to sort by recency or skip stale resources.
|
|
106
|
+
|
|
107
|
+
Annotations appear on the resource list entry, the content item, or both. They are hints — clients may ignore them.
|
|
108
|
+
|
|
109
|
+
### Error handling
|
|
110
|
+
|
|
111
|
+
Standard JSON-RPC error codes for resource operations: `-32002` for resource not found, `-32603` for internal server errors. Always return a proper JSON-RPC error when a `resources/read` URI does not exist — do not return an empty `contents` array. Validate all incoming URIs for scheme and path safety before accessing the underlying data source.
|