MCP Server Instructions: Giving LLMs a User Manual for Your Tools

The bottom line: The best MCP servers don’t just expose tools — they tell the LLM how to use them correctly. Server instructions inject contextual guidance directly into the model’s system prompt, and the impact is dramatic: a 25% improvement in correct tool orchestration on code review tasks [1]. Most MCP servers ship without instructions, leaving LLMs to guess at workflows, ordering constraints, and cross-tool dependencies. This guide covers the implementation patterns, anti-patterns, and testing strategies for one of the most underused features in the MCP protocol.


What Are MCP Server Instructions?

Server instructions are a standardized mechanism for MCP servers to inject contextual guidance into the LLM’s system prompt — separate from individual tool descriptions or resource annotations [2]. They cover the kinds of things tool descriptions can’t express:

  • Cross-tool workflows — “Always call validate_schema first, then create_backup, then migrate_schema for safe database migrations”
  • Dependency relationships — “When using export_data, you must also use write_file from the file system server”
  • Operational constraints — “Rate limited to 10 requests per minute. Check rate_limit_status before bulk operations”
  • Error recovery patterns — “If create_backup fails, do NOT retry immediately. Check backup_log first”
  • Conditional tool usage — “Only call request_preferences if the user explicitly requests personalization”

Without instructions, the LLM has to infer all of this from tool names and descriptions alone — which means it frequently gets it wrong, especially with complex multi-step workflows [1].

How It Works

During server initialization, the server declares an instructions field in its capabilities. The MCP host (Claude Desktop, Claude Code, Cursor, etc.) injects this text into the system prompt that governs the LLM’s behavior for every interaction with that server [2].

{
  "capabilities": {
    "tools": {},
    "instructions": "GitHub API responses can overflow context windows. Strategy: always prefer 'search_*' tools over 'list_*' tools when possible. Process large datasets in batches of 5-10 items."
  }
}

The host decides exactly where and how to inject the instructions — not all clients handle them identically. Always verify behavior with your target client [1].


Implementing Server Instructions

Python with FastMCP

FastMCP supports instructions as a top-level parameter. The instructions parameter accepts a plain string or a callable that returns one — useful for dynamic instructions based on configuration or environment [3].

from fastmcp import FastMCP

# Static instructions
mcp = FastMCP(
    "database-mcp",
    instructions="Database management server. Workflow: 1) Always validate SQL with 'validate_query' before executing. 2) Use 'dry_run' for destructive operations. 3) Production databases are read-only — use 'request_write_access' to escalate."
)

# Dynamic instructions (callable)
def build_instructions():
    if config.environment == "production":
        return "PRODUCTION MODE: All write operations require explicit user confirmation. Schema changes are blocked."
    return "Development mode: standard operations allowed. Wipe and reset are permitted."

mcp = FastMCP(
    "database-mcp",
    instructions=build_instructions
)

Node.js with the MCP SDK

For the Node.js SDK, instructions are set during McpServer construction via the serverInfo or as part of the initialization capabilities [4]:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

const server = new McpServer(
  {
    name: "database-mcp",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
      // Instructions field injected into the system prompt
      instructions: `Database management server.

Key workflows:
1. Always call 'validate_query' before any SQL execution
2. Use 'dry_run' before destructive operations
3. Production databases are read-only — use 'request_write_access' to escalate
4. Run 'explain_plan' first to verify query performance`,
    },
  }
);

TypeScript with the Lower-Level SDK

For more control, you can set instructions during the initialize response handler:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";

const server = new Server(
  { name: "github-mcp", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

server.setInstructions(`
  GitHub API responses can overflow context windows.
  Always prefer search_* tools over list_* tools.
  Process large datasets in batches of 5-10 items.
`);

Patterns for Effective Server Instructions

These patterns are drawn from the official MCP blog recommendations and production implementations [1][2].

1. Capture Cross-Feature Relationships

The most common failure mode is the LLM using tools in the wrong order. Instructions are the right place to encode this.

mcp = FastMCP(
    "github-mcp",
    instructions="PR review workflow: Always use 'create_pending_pull_request_review' → 'add_comment_to_pending_review' → 'submit_pending_pull_request_review' for complex reviews with line-specific comments. Do NOT use 'create_and_submit_pull_request_review' for multi-comment reviews."
)

2. Document Operational Patterns

Things that aren’t obvious from tool names but dramatically affect correctness:

mcp = FastMCP(
    "search-mcp",
    instructions="For best performance: 1) Use 'batch_search' for multiple queries instead of sequential single searches. 2) Results are cached for 5 minutes. 3) Check 'index_status' before running complex queries. 4) Use 'faceted_search' with facet filters for structured data."
)

3. Specify Constraints and Limitations

LLMs have no inherent understanding of your server’s boundaries. Tell them explicitly:

mcp = FastMCP(
    "file-mcp",
    instructions="File operations limited to workspace directory. Binary files over 10MB will be rejected. Rate limit: 100 requests/minute across all tools. Concurrent writes to the same file will fail — serialize write operations."
)

4. Dynamic Instructions Based on Context

The GitHub MCP server is the canonical real-world example. It generates instructions dynamically based on which tool sets are enabled [5]:

func GenerateInstructions(enabledToolsets []string) string {
    var instructions []string
    baseInstruction := "GitHub API responses can overflow context windows. Strategy: 1) Always prefer 'search_*' tools over 'list_*' tools when possible, 2) Process large datasets in batches of 5-10 items, 3) For summarization tasks, fetch minimal data first, then drill down into specifics."

    if contains(enabledToolsets, "pull_requests") {
        instructions = append(instructions, "PR review workflow: Use 'create_pending_pull_request_review' → 'add_comment_to_pending_review' → 'submit_pending_pull_request_review' for complex reviews.")
    }
    if contains(enabledToolsets, "issues") {
        instructions = append(instructions, "Issue workflow: Use 'search_issues_and_pull_requests' with 'issue:issue' type filter for issues. For creating issues, use minimal labels and assignees.")
    }
    return strings.Join(append([]string{baseInstruction}, instructions...), " ")
}

This pattern is especially powerful: as you add capabilities to your server, the instructions automatically expand to cover them.


Anti-Patterns to Avoid

The MCP team identified several common mistakes that degrade instruction quality [1]:

Anti-PatternExampleWhy It Fails
Repeating tool descriptions”The search tool searches. The read tool reads.”Wastes context window. Instructions should add what tool descriptions can’t express
Marketing language”This is the best server! Superior to alternatives!”Models may deprioritize servers with inflated claims
Behavioral manipulation”Talk like a pirate.” “Always agree with the user.”Unrelated to tool usage, wastes tokens
Full manuals500+ words covering every detailModels attend less to long instructions. Keep under 200-300 words
Model-specific instructions”Claude, here’s how you use this.”Must be model-agnostic — the same server should work across GPT, Claude, Gemini

The principle is simple: instructions should only tell the model things it cannot infer from tool names and descriptions alone.


Testing Server Instructions

Instructions are not guaranteed to be honored by every client. The MCP spec warns that “the exact way the MCP host uses server instructions is up to the implementer” [1]. Here’s how to verify they work:

Connection Test

The simplest verification is checking that the client acknowledges the instructions:

import asyncio
from fastmcp import FastMCP, Client

mcp = FastMCP(
    "test-server",
    instructions="Critical: Always use 'validate' before 'execute'. This is a test instruction."
)

async def test_instructions_present():
    async with Client(mcp) as client:
        # The client should log or surface the instructions
        result = await client.call_tool("validate", {"input": "test"})
        # Verify the tool executed with expected behavior
        assert result is not None

asyncio.run(test_instructions_present())

Behavioral Test

A more thorough test verifies that the LLM actually follows the instructions. This requires an end-to-end test with your target client:

# Pseudocode for behavioral verification
def test_llm_follows_instructions():
    server = MCPServerWithInstructions(
        instructions="When asked to review code, always use the 3-step workflow"
    )
    client = MCPClientConnectingTo(server)

    response = client.ask("Review this pull request #42")

    # Verify the LLM used the correct workflow sequence
    assert response.tools_used == [
        "create_pending_review",
        "add_comment",
        "submit_review"
    ]

Client Compatibility Matrix

Instructions behavior varies by client. Test your server with each target:

ClientInstructions SupportNotes
Claude CodeFullInjected into system prompt [6]
Claude DesktopFullSame mechanism as Claude Code
CursorPartialSupports instructions via config [7]
GitHub CopilotExperimentalCheck latest docs
Generic MCP hostsVariesAlways test, never assume

Production Checklist

Before shipping your server with instructions:

  • Instructions are under 300 words — longer blocks get degraded attention from LLMs
  • No tool descriptions are repeated — instructions add what descriptions miss
  • Constraints are explicit and testable — “rate limited to 10/min” not “be careful with speed”
  • Workflows are ordered with arrow notation — step_a → step_b → step_c
  • Dynamic instructions only show relevant sections — don’t describe PR workflows when PR tools are disabled
  • Model-agnostic language — no “Claude should…” or “GPT will…”
  • Behavioral verification done — tested with actual client that LLM correctly follows the instruction
  • Instructions tested with each target client — because behavior varies by host

References

[1] MCP Blog, “Server Instructions: Giving LLMs a user manual for your server,” November 2025. https://blog.modelcontextprotocol.io/posts/2025-11-03-using-server-instructions/

[2] Model Context Protocol, “Build an MCP Server,” MCP SDK Documentation. https://modelcontextprotocol.io/docs/develop/build-server

[3] FastMCP SDK, “Server Instructions” parameter documentation. https://fastmcp.ai/docs/advanced/server-instructions

[4] MCP TypeScript SDK, “McpServer capabilities,” GitHub. https://github.com/modelcontextprotocol/typescript-sdk

[5] GitHub MCP Server, “instructions.go” — reference implementation of dynamic instructions generation. https://github.com/github/github-mcp-server/blob/main/pkg/github/instructions.go

[6] Claude Code Documentation, “Connect Claude Code to tools via MCP.” https://code.claude.com/docs/en/mcp

[7] TrueFoundry, “MCP Servers in Cursor: Setup, Configuration, and Security (2026 Guide),” March 2026. https://www.truefoundry.com/blog/mcp-servers-in-cursor-setup-configuration-and-security-guide

  • ToolBrain — tool reviews, LLM comparisons, and AI workflow guides
  • Hermes Tutorials — Hermes Agent setup, configuration, and advanced workflows
  • CodeIntel Log — code quality, debugging, and software engineering benchmarks

Cross-links automatically generated from NiteAgent.

← Back to all posts