Design Narrow MCP Read and Write Tools
Snapshot
~85 sec
A useful MCP tool performs one named operation with typed inputs, a bounded target, and structured output. Keep reads separate from writes. Validate arguments before execution, cap result size, and make mutating tools expose the exact proposed change before approval.
You will learn
- Turn a broad project tool into one read contract and one write contract.
- Bound targets and results with typed fields, limits, and validation.
- Place dry-run, approval, deterministic checks, and post-change evidence around mutation.
Target outcome
You can design a narrow MCP read or write tool whose responsibility, authority, and evidence are inspectable.
Visual walkthrough
Visual walkthrough
~7 min
Five properties of a narrow tool
One operation
The name states one action, such as read_console or rename_scene_object.
Typed input
Fields declare valid values, required identifiers, and bounded limits.
Bounded target
A stable scene path or object identifier replaces vague instructions like fix the project.
Structured output
The result separates items, status, truncation, and evidence instead of returning an unshaped text dump.
Read/write boundary
Inspection cannot mutate; mutation is separately named, reviewed, approved, and verified.
One broad tool versus two inspectable contracts
Approach Responsibility Target and result bounds Authority Evidence do_project_taskOne tool can inspect, edit, save, and return an open-ended response. The caller cannot tell which operation will happen from the tool name. The target may expand from one invented object to unrelated scenes and assets. Read and write permissions collapse into one ambiguous approval. A prose success message may hide what changed or what was skipped. read_consoleRead only filtered error or warning entries with a limit and cursor. The operation reads console entries and cannot edit the project. Severity, text filter, limit, and pagination constrain the response. Read-only policy can allow this tool without granting a scene write. Stable entry IDs and truncation state show what the result covers. rename_scene_objectRename one invented object identified by an exact scene path. The operation changes one name and does not save unrelated assets. Scene, object ID, expected current name, and proposed name are required. Dry-run output is reviewed before a separate write approval. The result returns before and after names plus the exact changed object ID. Keep read, write, and proof on distinct layers
The smallest useful surface starts with inspection. A proposed mutation crosses explicit validation and approval before it reaches the project, then returns post-change evidence.
Read layer
Inspect exact target
Read the invented object ID, current name, and owning scene.
Return dry-run
Show the one intended rename and declare that no write has occurred.
Write layer
Validate inputs
Reject a missing object, stale expected name, invalid new name, or target outside the allowed scene.
Approve exact call
Review tool name, target ID, before value, after value, and verification plan.
Apply one mutation
Rename only the approved object; do not save or edit unrelated content.
Proof layer
Return structured proof
Read the object again and report changed ID, before, after, and check status.
- Inspect exact targetReturn dry-rundescribes
- Return dry-runValidate inputsif requested
- Validate inputsApprove exact callthen review
- Approve exact callApply one mutationpermits
- Apply one mutationReturn structured proofmust prove
The smallest useful surface starts with inspection. A proposed mutation crosses explicit validation and approval before it reaches the project, then returns post-change evidence. Reading order
- Inspect exact target
Read the invented object ID, current name, and owning scene.
- Return dry-run
Show the one intended rename and declare that no write has occurred.
- Validate inputs
Reject a missing object, stale expected name, invalid new name, or target outside the allowed scene.
- Approve exact call
Review tool name, target ID, before value, after value, and verification plan.
- Apply one mutation
Rename only the approved object; do not save or edit unrelated content.
- Return structured proof
Read the object again and report changed ID, before, after, and check status.
Connection explanations
- Inspect exact target → Return dry-run (describes)
A dry-run is credible only when it is based on the current exact target.
- Return dry-run → Validate inputs (if requested)
The write path receives explicit values rather than reinterpreting the original intent.
- Validate inputs → Approve exact call (then review)
Schema and target validation remove invalid calls before a person considers authority.
- Approve exact call → Apply one mutation (permits)
Approval applies to the reviewed tool and arguments, not to every future write.
- Apply one mutation → Return structured proof (must prove)
The tool must return evidence from the post-change project state, not only claim success.
Make the read contract visible
Conceptual MCP tool contract. The exact schema representation depends on the server implementation, but the responsibility and bounds should remain explicit.
Languagejson { "name": "read_console", "description": "Read filtered console entries without changing the project.", "input": { "severity": "error | warning", "contains": "optional string", "limit": "integer, 1..50", "cursor": "optional opaque string" }, "output": { "items": [{ "id": "string", "severity": "string", "message": "string" }], "nextCursor": "string | null", "truncated": "boolean" } }Code annotations
Lines 2-3
One honest operation
The name and description say this is a console read and that it does not change the project.
Effect: A client can distinguish it from every mutating capability before use.
Lines 4-9
Bound the query
Enumerated severity, optional text filter, finite limit, and opaque cursor constrain input.
Effect: The server can reject invalid requests before reading project state.
Lines 10-14
Report coverage
Items, next cursor, and truncation state tell the caller what evidence was returned.
Effect: The caller can request more detail deliberately rather than assume the first page was complete.
Split a broad tool
An invented manage_scene tool can list objects, rename any match, delete missing-reference objects, save the scene, and return a paragraph. What is the first redesign?
Expected reasoning
Split inspection from mutation. Start with bounded read tools, such as list_scene_objects(scene, parentId, limit, cursor) and inspect_object(id). Give each write one operation, such as rename_scene_object(id, expectedName, newName, dryRun). Keep deletion separate or unavailable until exact-target validation, dependency preview, explicit approval, deterministic checks, and recovery evidence exist. Return structured fields rather than a success paragraph.
Go deeper
- MCP specification: ToolsThe current tool discovery, invocation, schema, result, and human-in-the-loop contract.
- Unity MCP: Register custom toolsUnity's official registration patterns for built-in and project-specific MCP tools.