Lab assignment
Design and test an MCP server
Design narrow MCP capabilities for a synthetic note catalog and test every trust boundary.
The brief
Your assignment
Create three to five fake study notes, then design a local, read-mostly MCP server around them. Include one application-controlled resource, one user-invoked prompt, and two model-invoked tools with non-overlapping responsibilities.
Architecture path: draft the schemas, then walk through valid, empty, invalid-input, and execution-error traces on paper; no account is required. Build path: run the server through MCP Inspector. Connecting it to Claude Code is an optional extension; never commit credentials.
Before you build
Set up a safe workspace
- Create three to five fake notes.
- Choose the architecture path or install the SDK and MCP Inspector for the build path.
- List the intended caller and trust boundary for every capability.
Build in checkpoints
One observable behavior at a time
- 01Classify each capability as a resource, prompt, or tool.
- 02Draft bounded input and output schemas.
- 03Separate valid-empty, invalid-input, and execution-error results.
- 04Exercise the schemas in Inspector or with synthetic traces.
- 05Compare each custom capability with available built-in behavior.
What you'll practice
- Distinguish resources, prompts, and tools by who controls invocation.
- Validate and bound inputs and results.
- Represent valid-empty and execution-error states differently.
- Treat annotations as metadata, not authorization.
Your lab files
Four files for each lab
- 01
decision.mdState the requirement, chosen pattern, rejected alternatives, and the reason for the tradeoff.
- 02
implementation/Keep the smallest working example, configuration, diagram, or synthetic-trace analysis.
- 03
evidence.mdRecord test cases, observed results, failure behavior, limitations, and evidence locations.
- 04
review.mdExplain what must be deterministic, what may remain model-directed, and where a human is required.
What to save
- A capability matrix and trust-boundary diagram.
- Schemas, descriptions, and an error catalog.
- An Inspector transcript or synthetic-trace analysis.
- A redacted project configuration and built-in-versus-MCP comparison.
Test bench
What good work includes
- Malformed input fails clearly.
- No matching notes remains a valid success.
- Business or upstream failure is visible with
isError: true. - Stdout remains protocol-only for stdio transport.
- Results are bounded and annotations match behavior.
- Approval and authorization do not rely on annotations alone.
Review questions
- Why is one capability a resource rather than a tool?
- When should a maintained server be adopted?
- What security guarantee does an annotation not provide?
Strong solutions tend to
- Narrow capabilities and sanitized outputs.
- Diagnostics on stderr for stdio transport.
- Least privilege and explicit approval for mutations.
Partial example
What useful evidence can look like
This is one small example, not a complete solution or a template you must copy. Use the notes to see why the evidence is useful.
Open annotated example from implementation/ / tool contract excerpt
tool: search_notes
input: { query: string, limit: integer 1..20 }
success: { matches: NoteSummary[] }
failure: { isError: true, errorCategory, isRetryable }- limit
- Bounds the result before it can flood the model context.
- failure
- Separates a tool execution failure from a successful search with no matches.
Review your work
Use evidence from your work—not confidence alone. For each area, run the check and choose the strongest stage your work fully demonstrates.
Capability roles
Resources, prompts, and tools are separated by who chooses to invoke them and by the job each capability performs.
For every capability, name its caller, job, non-job, input, and result. Compare each tool with its closest alternative for overlap.
Needs another pass
Capabilities are classified by convenience, or two tools have descriptions and responsibilities that substantially overlap.
Partly demonstrated
Most capability types fit their caller, but at least one boundary or tool comparison remains unclear.
Demonstrated
The application controls the resource, the user invokes the prompt, and the model invokes two distinct tools with clear comparative descriptions and no competing responsibility.
Schemas and result states
Clear schemas define valid data and keep empty success, invalid input, and execution failure separate.
Walk or run the valid, valid-empty, malformed-input, and execution-error cases. Compare their protocol fields and downstream recovery choices.
Needs another pass
Inputs are loosely bounded, no results and failed access look the same, or errors are returned as ordinary successful text.
Partly demonstrated
Input validation works, but at least one output bound or distinction between empty success and execution error is missing.
Demonstrated
Inputs and outputs are bounded, malformed input fails clearly, no matches is valid success, and execution failure is structured with isError: true and useful recovery context.
Protocol and trust boundaries
Transport, authorization, approval, credentials, and capability annotations each have an explicit and honest role.
Inspect the configuration and one trace for stdout noise, committed secrets, excessive permissions, and any security decision that relies only on annotations.
Needs another pass
Diagnostics can corrupt stdio stdout, credentials are exposed, or annotations are treated as authorization or approval.
Partly demonstrated
Secrets and transport are handled safely, but the authorization or mutation-approval boundary is not enforced outside metadata.
Demonstrated
Stdout is protocol-only, diagnostics use stderr, credentials stay outside version control, permissions are minimal, and code or a person—not annotations—controls protected actions.
Testing and adoption evidence
The packet demonstrates each boundary and explains why custom MCP capabilities are preferable to available built-in or maintained options.
Use the Inspector transcript or synthetic traces to find every required case, then review the built-in-versus-MCP comparison for a concrete decision.
Needs another pass
Only a successful call is shown, or the custom server is chosen without comparing simpler existing capabilities.
Partly demonstrated
Most required traces exist, but observed results, output bounds, or the adoption tradeoff are incomplete.
Demonstrated
The evidence covers every required result state and trust boundary, and the comparison explains the specific control or contract that justifies the custom server.