Skip to main content
Glama
souvikdey05

demo-server

by souvikdey05

MCP Tutorial

A minimal Model Context Protocol (MCP) tutorial built with the MCP Python SDK (mcp[cli]). It contains a small FastMCP server and shows how to make Claude Code aware of it through project configuration — without running claude mcp add.

Contents

Related MCP server: Basic MCP Server

The server

The example server lives in examples/snippets/servers/fastmcp_quickstart.py and exposes one of each MCP primitive:

Primitive

Name

Description

Tool

add(a, b)

Adds two numbers

Resource

greeting://{name}

Returns a personalized greeting

Prompt

greet_user(name, style)

Generates a greeting prompt

Prerequisites

  • uv for running the project

  • Dependencies are declared in pyproject.toml (mcp[cli]>=1.28.0)

Install dependencies:

uv sync

Running the server standalone

To run the server directly over streamable HTTP (listens on http://localhost:8000/mcp):

uv run examples/snippets/servers/fastmcp_quickstart.py

This is only required for the HTTP transport option below. With the stdio option, Claude Code launches the server for you, so you don't need to run this manually.

Registering the server with a client

Each MCP client discovers servers from its own config file. The server configuration is nearly identical across clients — the differences are which file holds it and the top-level key name:

Client

Config file

Top-level key

Claude Code

.mcp.json

mcpServers

GitHub Copilot

.vscode/mcp.json

servers

Both files are committed to the repo, so anyone who clones it gets the same server configuration.

Claude Code

Claude Code learns about project-scoped MCP servers from a .mcp.json file at the repository root. This file is the declarative equivalent of claude mcp add — it's committed to the repo, so anyone who clones it gets the same server configuration.

Pick one of the two transport options below.

Option A — stdio (Claude Code launches the server)

Because the server lives in this project, you can let Claude Code spawn it on demand. There's no port and nothing to keep running separately.

.mcp.json:

{
  "mcpServers": {
    "demo-server": {
      "command": "uv",
      "args": ["run", "examples/snippets/servers/fastmcp_quickstart.py"]
    }
  }
}

Note: For stdio, the server script must use the stdio transport. FastMCP uses stdio by default when you call mcp.run() with no arguments, so change the last line of the script to mcp.run() (or run a stdio-specific entry point).

Option B — HTTP transport

If you'd rather run the server yourself as a long-running HTTP process, point .mcp.json at its URL instead. First start the server (see Running the server standalone), then use:

.mcp.json:

{
  "mcpServers": {
    "demo-server": {
      "type": "http",
      "url": "http://localhost:8000/mcp"
    }
  }
}

With this option the server must already be running before Claude Code connects.

Note: For HTTP, the server script must use the streamable HTTP transport. In fastmcp_quickstart.py the default mcp.run() is commented alongside mcp.run(transport="streamable-http") — swap the active line so the script runs over HTTP:

if __name__ == "__main__":
    mcp.run(transport="streamable-http")
    # mcp.run()  # default transport is stdio

Reload and verify

  1. Restart Claude Code (or run /mcp in an interactive session).

  2. From the terminal, check status with:

    claude mcp list
    claude mcp get demo-server
  3. The server should report ✔ Connected and expose the add tool, the greeting://{name} resource, and the greet_user prompt.

GitHub Copilot (VS Code)

VS Code discovers workspace MCP servers from .vscode/mcp.json. Note the top-level key is servers (not mcpServers), and each entry declares its transport with type.

Pick one of the two transport options below.

stdio

VS Code launches the server for you — no port, nothing to keep running separately:

.vscode/mcp.json:

{
  "servers": {
    "demo-server": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "examples/snippets/servers/fastmcp_quickstart.py"]
    }
  }
}

Note: As with Claude Code, the script must use the stdio transport (mcp.run()).

HTTP transport

Run the server yourself first (see Running the server standalone), then point VS Code at its URL:

.vscode/mcp.json:

{
  "servers": {
    "demo-server": {
      "type": "http",
      "url": "http://localhost:8000/mcp"
    }
  }
}

Note: For HTTP, the script must use mcp.run(transport="streamable-http") (see the Claude Code HTTP note).

Start and verify

  1. Open .vscode/mcp.json — VS Code shows a Start action above each server entry. You can also run MCP: List Servers from the Command Palette to start/stop/inspect them.

  2. Open the Copilot Chat view and switch to Agent mode (tools are only available in agent mode).

  3. Click the tools (🛠) icon to confirm demo-server is listed, then ask Copilot to use the add tool.

Approving servers and auto-approving tools (Claude Code)

Claude Code has two independent safety gates for project MCP servers, both configured in .claude/settings.json (shared, committed) or .claude/settings.local.json (personal, git-ignored):

  1. Server approval — whether a server from .mcp.json is allowed to load at all.

  2. Tool-call approval — whether Claude may run a server's tools without prompting you each time.

This section walks through both, using the lifespan-demo server (which exposes the query_db tool) as the example.

Step 1 — Approve the server

Servers declared in .mcp.json start as ⏸ Pending approval as a safety measure — a cloned repo can't auto-run servers without your consent. Grant approval declaratively with enabledMcpjsonServers instead of clicking through the interactive prompt:

{
  "enabledMcpjsonServers": ["demo-server", "lifespan-demo"]
}

Or trust every server defined in .mcp.json at once:

{
  "enableAllProjectMcpServers": true
}

After this, the server loads and its tools become visible — but Claude will still ask permission each time it wants to call one.

Step 2 — Auto-approve tool calls

To stop the per-call prompts, add a permissions.allow rule. The MCP rule format is:

Rule

Matches

mcp__lifespan-demo

Every tool from the lifespan-demo server

mcp__lifespan-demo__query_db

Only the query_db tool

Note: the tool part does not support * wildcards — use the server-only form (mcp__<server>) to cover all tools, or name a specific tool (mcp__<server>__<tool>).

Combined with Step 1, .claude/settings.json looks like:

{
  "enabledMcpjsonServers": ["demo-server", "lifespan-demo"],
  "permissions": {
    "allow": ["mcp__lifespan-demo"]
  }
}

Reload Claude Code (restart or /mcp), then ask:

Use the query_db tool to run SELECT * FROM users

It runs without a permission prompt and returns Result of 'SELECT * FROM users'.

Scope tip: keep server approval (enabledMcpjsonServers) in the shared settings.json so teammates get the server, but consider putting auto-approval (permissions.allow) in settings.local.json if you don't want to silently grant tool execution to everyone who clones the repo.

Debugging with the MCP Inspector

The MCP Inspector is an interactive, browser-based tool for poking at a server directly — without wiring it into Claude Code or Copilot. It's the quickest way to call tools by hand and watch logs and progress notifications live.

Launch it against any server in this repo:


uv run mcp dev examples/snippets/servers/<server_file>.py

uv run mcp dev examples/snippets/servers/basic_tool.py

What this does:

  • uv run runs inside the project virtualenv (so mcp and your deps are available).

  • mcp dev starts the server over stdio and attaches the Inspector to it.

  • It prints a localhost URL — open it in a browser.

The Inspector uses two ports: 6274 (the web UI) and 6277 (the proxy). In the UI you can:

  • List and call tools — e.g. run long_running_task with a task_name and steps.

  • Browse resources and prompts.

  • Watch logs and progress notifications live — the best way to see Context calls (ctx.info, ctx.debug, ctx.report_progress) as they happen.

Requires Node.js. The Inspector is a Node package (@modelcontextprotocol/inspector) launched via npx; the first run downloads it.

Auth token. Recent versions print a URL that includes a session token, e.g. http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=… — use that full link from the terminal.

Port already in use? ❌ Proxy Server PORT IS IN USE at port 6277 means an Inspector is already running — just open http://localhost:6274, or stop the existing one first. It's a long-running process; stop it with Ctrl-C.

Configuration reference

File

Purpose

Committed?

.mcp.json

Declares the project MCP server for Claude Code

Yes (shared)

.vscode/mcp.json

Declares the workspace MCP server for Copilot

Yes (shared)

.claude/settings.json

Approves servers + auto-approves tools for the team

Yes (shared)

.claude/settings.local.json

Approves servers + auto-approves tools just for you

No (git-ignored)

Available Tools

1 tool
addA

Add two numbers

ParametersJSON Schema
NameRequiredDescriptionDefault
aYes
bYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description is a pure function with no side effects, and the sole behavior 'Add two numbers' is fully disclosed. With no annotations to contradict, the description provides complete behavioral transparency for this simple operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no unnecessary words; it is front-loaded and earns its place. It communicates everything needed in the most compact form possible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simple nature and the presence of an output schema (per context signal), the description sufficiently covers the function. There are no complex behaviors, side effects, or conditional logic to document.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, yet the description only generically mentions 'two numbers' without explaining the meaning or constraints of parameters a and b. It does not compensate for the lack of schema descriptions, leaving parameter semantics under-specified.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'Add' and identifies the resource as 'two numbers', clearly distinguishing it from the sibling arithmetic tools subtract, multiply, and divide. It is unambiguous and precisely states the tool's function.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description is concise but does not explicitly state when to use this tool over alternatives; however, the operation is self-evident for the sibling context. It lacks explicit exclusions or alternative guidance, but the clear context of adding numbers implicitly covers the main use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.1.0
    • First observedadd

TDQS

A3.5/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of ambiguity. The tool's purpose is clear and distinct.

Naming Consistency5/5

The single tool name 'add' follows a simple verb pattern, and there are no other tools to create inconsistency.

Tool Count1/5

A single tool for addition is extremely limited, lacking any broader functionality. This is a trivial tool count that does not justify a full server.

Completeness1/5

The server only provides addition, missing essential arithmetic operations like subtraction, multiplication, or division. The surface is severely incomplete for any practical use.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A minimal demonstration server showcasing MCP protocol capabilities including tools, resources, and prompts with basic examples like hello world functionality.
    7
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A minimal template MCP server demonstrating basic tools, resources, and prompts functionality. Includes example implementations like a hello tool, history resource, and greet prompt for learning MCP development.
    7
    ISC
  • F
    license
    Not graded
    quality
    D
    maintenance
    A minimal Model Context Protocol server built with FastMCP that provides basic utility tools including user greetings, number addition, and file listing operations. Includes examples of exposing tools, resources, and prompts for MCP-aware clients.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A minimal learning-focused MCP server that demonstrates core primitives like tools and resources through simple greeting functions. It provides a foundational example for connecting AI models to external data using both Streamable HTTP and stdio transports.
    5
    MIT