learn_mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@learn_mcp@learn_mcp get John's balance"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Simple MCP Server + LLM Agent
A small learning project that demonstrates how to build an MCP (Model Context Protocol) server from scratch using Python, connect to it with an MCP client, and let an LLM discover and call MCP tools.
The project uses:
Python 3.10+
uv for Python project/dependency management
MCP Python SDK 2.x
OpenRouter for the LLM
OpenAI Python SDK as an OpenRouter-compatible API client
STDIO transport between the MCP client and server
Architecture
User | v LLM (OpenRouter) | | decides which MCP tool to call v MCP Client | | STDIO / JSON-RPC v MCP Server | | executes tool v Tool Result | v LLM | v Final Answer
The important idea is that the LLM does not directly access the application's Python data. It receives MCP tool definitions, decides which tool to use, and the MCP client executes the selected tool on the server.
Project Structure
test_mcp/ ├── server.py ├── client.py ├── llm_test.py ├── pyproject.toml ├── uv.lock └── README.md
server.py
Contains the MCP server and exposes tools such as:
add
subtract
multiply
get_customer
get_customer_balance
find_customer
It also demonstrates MCP resources and prompts.
client.py
Connects to the MCP server over STDIO, discovers its tools, converts MCP tool definitions into an LLM-compatible format, sends them to the LLM, executes requested MCP tools, and feeds tool results back to the LLM.
llm_test.py
A small standalone test to verify that the OpenRouter API connection works before integrating the LLM with MCP.
Prerequisites
Install:
Python 3.10 or newer
uv
An OpenRouter API key
Check Python:
python3 --version
Check uv:
uv --version
Setup
Clone or create the project and enter the directory:
cd ~/test_mcp
If dependencies are not already installed:
uv sync
The project should contain the MCP SDK and OpenAI Python SDK.
If needed, they can be added with:
uv add "mcp[cli]" uv add openai
Configure OpenRouter
Set your API key as an environment variable.
macOS/Linux:
export OPENROUTER_API_KEY="your-api-key"
Verify it exists:
echo $OPENROUTER_API_KEY
Do not commit the API key to Git.
For a persistent shell configuration, you can add the export to your shell profile, but be careful not to expose the key in source code or public repositories.
Run the MCP Server
The server can be started directly:
uv run server.py
The server uses STDIO, so it will normally appear to wait silently for requests. That is expected.
The server also contains:
if name == "main": mcp.run()
which starts the MCP server using the default STDIO transport.
Inspect the MCP Server
The MCP CLI/Inspector can be used to inspect the server:
uv run mcp dev server.py
The Inspector allows you to see:
Available tools
Tool descriptions
Input schemas
Resources
Prompts
Tool execution results
This is useful for debugging the MCP server before involving an LLM.
Test the LLM Separately
Before connecting the LLM to MCP, test OpenRouter:
uv run python llm_test.py
The test sends a simple question to OpenRouter and prints the model response.
The project currently uses an OpenRouter free model. Free model availability and limits can change over time.
Run the MCP + LLM Client
Run:
uv run python client.py
The client performs the following steps.
Connect to the MCP server
server = StdioServerParameters( command="uv", args=["run", "server.py"], )
The MCP client starts the server as a subprocess.
Discover tools
mcp_result = await client.list_tools()
The client asks the MCP server which tools it provides.
Convert MCP tools for the LLM
MCP tool definitions are converted into the OpenAI-compatible function/tool format:
{ "type": "function", "function": { "name": tool.name, "description": tool.description, "parameters": tool.input_schema, }, }
This gives the LLM enough information to decide which tool it should use.
Send the user question and tools to the LLM
The client sends:
User question + Available MCP tools
For example:
What is John's balance?
LLM requests a tool
The LLM may decide:
find_customer(name="John")
The client parses the requested tool and arguments.
MCP client executes the tool
The client calls:
await client.call_tool( tool_name, arguments, )
The MCP server executes the corresponding Python function.
For example:
find_customer("John")
returns:
{ "id": 1, "name": "John", "balance": 5000, "status": "active" }
Tool result is sent back to the LLM
The MCP result is added to the conversation as a tool message:
messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result_text, })
The LLM now knows what the tool returned.
Agent loop
The client repeats the LLM/tool process:
LLM | | tool call? +---- No ----> Final answer | Yes | v MCP tool | v Tool result | v LLM again
The loop ends when the LLM returns a normal response without requesting another tool.
Example
Input:
What is John's balance?
Possible flow:
LLM requested tool: Tool: find_customer Arguments: {'name': 'John'}
MCP result: { "id": 1, "name": "John", "balance": 5000, "status": "active" }
Final LLM response: John's balance is 5000.
MCP Concepts Demonstrated
Tools
Tools are executable functions exposed by the MCP server.
Example:
@mcp.tool() def get_customer_balance(customer_id: int) -> int: ...
The LLM can decide when to call them.
Resources
Resources represent data that can be exposed through MCP resource URIs.
Example:
customer://1
Resources are conceptually different from tools: a tool represents an action/function, while a resource represents information/data.
Prompts
Prompts are reusable prompt templates exposed by the MCP server.
Example:
@mcp.prompt() def analyze_customer(customer_id: int) -> str: ...
MCP Client
The client connects to the MCP server and provides operations such as:
await client.list_tools()
and:
await client.call_tool(...)
STDIO Transport
In this project, the client launches the MCP server locally and communicates with it over standard input/output.
client.py | | stdin/stdout | server.py
This is convenient for local development and learning.
Why the LLM Does Not Know the Python Dictionary
The server contains customer data:
customers = { 1: {"name": "John", "balance": 5000, "status": "active"}, ... }
The LLM does not directly see this Python variable.
Instead, it sees tool definitions such as:
find_customer(name) get_customer_balance(customer_id)
The LLM asks the MCP client to execute a tool, and the tool result is returned to the LLM.
This separation is an important part of the architecture.
Learning Progression
This project was built incrementally:
Learn basic Python/MCP concepts
Create a basic MCP server
Add simple tools
Add customer-related tools
Add MCP resources
Add MCP prompts
Inspect the server using MCP Inspector
Build an MCP client
Connect the client to an LLM
Convert MCP tools into LLM-compatible tool definitions
Let the LLM choose a tool
Execute the tool through MCP
Send the tool result back to the LLM
Implement the basic agent/tool-calling loop
Important Mental Model
Keep these four components separate:
MCP Server | | provides capabilities v MCP Tools | | are executed by v MCP Client | | orchestrated by decisions from v LLM
More precisely:
LLM = decides what to do
MCP Client = connects to the MCP server and invokes tools
MCP Server = exposes tools/resources/prompts
Tool = performs the actual operation
The LLM provides the intelligence for deciding which capability to use, while MCP provides a standardized way to expose and invoke those capabilities.
Next Steps
Potential extensions to this project:
Add a proper maximum tool-call limit
Handle MCP tool errors
Validate LLM-generated tool arguments
Support multiple tool calls
Use structured MCP tool outputs
Separate the agent loop into reusable functions/classes
Add real backend/API calls instead of in-memory customer data
Explore MCP resources more deeply
Explore MCP prompts
Run the MCP server over Streamable HTTP instead of STDIO
Add authentication and authorization
Connect the MCP server to a real application
Build a small chat interface on top of the agent
Security Notes
This project is intentionally simple and is for learning.
For production:
Never hardcode API keys
Validate LLM-generated tool arguments
Restrict which tools the model can invoke
Validate authorization before executing sensitive operations
Handle tool failures and timeouts
Add logging/observability
Add limits to the number of tool calls
Avoid exposing sensitive data unnecessarily
Treat LLM-generated tool arguments as untrusted input
License
This project is intended as a learning/demo project.
Available Tools
6 toolsaddA
Add two numbers together.
| Name | Required | Description | Default |
|---|---|---|---|
| a | Yes | ||
| b | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The behavior is transparent for a pure arithmetic operation: it takes two numbers and returns their sum. It does not describe edge cases or return details, but the operation is simple and output schema is available.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, concise sentence with no unnecessary words. It is well-structured and immediately understandable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple arithmetic tool, the description is complete enough for correct use. It lacks explicit edge-case or return-type details, but the operation's simplicity and available output schema reduce the need for further explanation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description says 'two numbers,' which collectively defines both parameters as addends. It does not individually describe a or b, but for addition the individual roles are clear and order is irrelevant.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's exact purpose: adding two numbers together. It is a specific verb and resource, and it naturally distinguishes from sibling tools like subtract and multiply.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes it clear that this tool is for addition, and sibling names imply when to use other operations. However, it does not explicitly state when not to use this tool or provide alternative selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_customerB
Find a customer using their name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations and the description does not mention whether the operation is read-only, what it returns, or how it handles missing or ambiguous names. Since 'find' suggests a lookup, the lack of explicit side-effect or result information leaves uncertainty.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence that directly states the tool's purpose and key parameter. No unnecessary words or redundant details are present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple lookup tool, the description gives the essential action and input, but it omits output shape and error behavior. Without an output schema, more detail about what is returned would improve completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, 'name', is mentioned in the description as the lookup key, so its basic purpose is clear. However, the description does not clarify exact matching, case sensitivity, or whether multiple matches are possible.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool finds a customer using their name, which identifies both the action and the resource. It is distinguishable from sibling tools like get_customer and get_customer_balance, though 'find' is slightly less precise than 'get'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'using their name' implies the intended use when a customer name is available. However, it does not explicitly contrast with get_customer or explain when to prefer this tool over alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_customerB
Get customer details using the customer ID.
| Name | Required | Description | Default |
|---|---|---|---|
| customer_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations and the description does not mention side effects, read-only behavior, permissions, or potential errors, so the agent is not informed about behavioral expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single clear sentence with no unnecessary words or repetition, making it easy to parse and act on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is adequate for a simple lookup but does not specify what 'customer details' includes or what the response shape will be, especially since no output schema is provided.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The customer_id parameter is only described as 'customer ID', adding little beyond the schema title. With 0% schema description coverage, the description should provide more detail about the parameter's format or meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Get'), the resource ('customer details'), and the required input ('customer ID'), distinguishing it from arithmetic tools and the balance-specific sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus get_customer_balance or find_customer, leaving the agent to infer the appropriate choice from the tool names alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_customer_balanceA
Get the current balance of a customer.
| Name | Required | Description | Default |
|---|---|---|---|
| customer_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The word 'get' implies a read-only operation, but the description does not explicitly disclose side effects, error behavior (e.g., customer not found), or output format. With no annotations, the description carries the full burden and only partially covers transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence with no redundancy or unnecessary details. It efficiently conveys the core functionality without fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple getter, the description provides enough context to understand the primary purpose. However, it does not mention potential error cases, return value specifics, or interaction with sibling tools, leaving minor gaps in completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, customer_id, is self-explanatory by name, but the schema description coverage is 0%, and the tool description adds no clarifying details about its meaning, constraints, or typical usage. Since coverage is low, the description should have compensated but did not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: retrieving a customer's balance. It distinguishes from sibling tools like get_customer and find_customer by focusing specifically on balance retrieval, making the action unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not explicitly explain when to use this tool versus the sibling tools. While the purpose is clear, it lacks guidance on scenarios where this tool is preferred over alternatives, such as when only balance is needed rather than full customer details.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
multiplyA
multiply two numbers together.
| Name | Required | Description | Default |
|---|---|---|---|
| a | Yes | ||
| b | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations to supplement the description, so the full burden falls on the text. It does not disclose return type, error behavior, or any side effects, leaving the agent to assume the operation is pure and returns a numeric result.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, focused sentence with no extraneous information. It is highly concise and directly conveys the operation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simplicity of the tool and the presence of an output schema, the description is adequate for an agent to understand the operation. It could mention the result type, but the schema likely covers that, so nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description mentions 'two numbers' which maps directly to the parameters a and b, but it does not elaborate beyond that. The schema defines them as integers, and the description adds minimal semantic value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('multiply') and the resource ('two numbers'), leaving no ambiguity about the tool's purpose. It distinguishes itself from the sibling tools add and subtract by specifying the multiplication operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description directly implies the use case (performing multiplication), but it does not explicitly state when to choose this tool over alternatives like add or subtract. The usage is inferred from the verb, but no conditional guidance is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
subtractA
Subtract one number from another.
| Name | Required | Description | Default |
|---|---|---|---|
| a | Yes | ||
| b | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It accurately describes the core behavior without mentioning side effects, which is acceptable for a pure arithmetic function. However, it does not explicitly confirm the absence of side effects or describe return behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, concise sentence with no extraneous details. It effectively communicates the core operation in minimal words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple arithmetic tool, the description is mostly adequate, but it lacks critical parameter details (order of operands) and any mention of return format or errors. The minimal schema and absence of annotations increase the need for a more thorough description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description does not clarify the order of subtraction. The phrase 'subtract one number from another' is ambiguous regarding whether a - b or b - a is intended. Since subtraction is non-commutative, this is a significant gap for the two integer parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb 'subtract' and the object 'one number from another', making it distinct from sibling tools like add and multiply.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description is self-explanatory for a simple arithmetic operation, but it does not explicitly state when to use this tool versus the sibling add or multiply tools. The scoping is implied by the operation rather than stated.
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. Dates show when Glama detected each change.
6 tool updates
v0.1.0- First observed
add - First observed
find_customer - First observed
get_customer - First observed
get_customer_balance - First observed
multiply - First observed
subtract
TDQS
Each tool performs a distinct action: arithmetic operations are clearly separate, and customer tools differentiate by ID (get_customer), balance (get_customer_balance), and name search (find_customer). No functional overlap exists.
All tool names use lowercase with underscores, but there is a slight inconsistency between the 'get_' prefix for two customer tools and the 'find_' prefix for another. Arithmetic tools follow a simple verb pattern, but overall the naming is fairly consistent.
Six tools is a reasonable size for a server covering two small domains (arithmetic and customer lookup). It is neither too sparse nor overwhelming.
The arithmetic set lacks division, and the customer tools cover only read/lookup operations, missing create, update, or delete. While the scope may be intentional, it leaves common operations absent for a full-featured server.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Create guides as MCP servers to instruct coding agents to use your software (library, API, etc).
MCP server for generating rough-draft project plans from natural-language prompts.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA tutorial MCP server for learning the Model Context Protocol by building file and system tools. Provides hands-on experience creating custom tools that enable AI models to interact with files and execute system commands.-
- FlicenseNot gradedqualityDmaintenanceAn educational MCP server example built with FastMCP that demonstrates how to expose tools, resources, and prompts to AI clients. Provides a learning foundation for building MCP servers with Python and integrating them with AI applications like IDEs and chatbots.-
- FlicenseNot gradedqualityDmaintenanceAn educational example demonstrating how to build MCP servers in Python using FastMCP, showing how to expose tools, resources, and prompts to AI clients.-
- FlicenseNot gradedqualityDmaintenanceA Python template for building MCP servers with Streamable HTTP transport, providing example tools, resources, and prompts.1-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/tusharkotlapure/learn_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server