Tools List
Content Details
Alternatives
Installation
๐ MCP Testbed
This project showcases sentiment analysis using the Model Context Protocol (MCP), drawing inspiration from the Hugging Face MCP Course. Instead of relying on the gradio library as in the Hugging Face course, it employs the fastmcp library to implement both an MCP server and client.
โจ Features
Architecture Diagram
+-------------------+ +-------------------+
| | | |
| mcp_client_stdio |<----------------->| |
| | stdio | |
+-------------------+ | |
| |
+-------------------+ | |
| |<----------------->| |
| mcp_client_sse |-----/sse--------->| MCP Server |
| | | (app_fastmcp.py) |
+-------------------+ | |
| |
+-------------------+ | |
| |<----------------->| |
| mcp_client_stream-|----/mcp---------->| |
| able.py | | |
+-------------------+ +-------------------+
Each client module communicates with the MCP server using a different transport protocol:
mcp_client_stdio.pyuses stdiomcp_client_sse.pyuses SSE (Server-Sent Events) at/ssemcp_client_streamable.pyuses streamable-http at/mcp
Server
- mcp-sentiment/app_fastmcp.py
Implements the MCP server using FastMCP. Exposes asentiment_analysistool that uses TextBlob to analyze the sentiment of input text and returns polarity, subjectivity, and an overall assessment as JSON.
Clients
-
mcp-sentiment/mcp_client_stdio.py
MCP client using stdio transport. Connects to the server via subprocess, lists available tools, and sends text for sentiment analysis. Uses argparse for CLI. -
mcp-sentiment/mcp_client_sse.py
MCP client using Server-Sent Events (SSE) transport. Connects to the server via HTTP SSE endpoint, lists tools, and sends text for analysis. Uses argparse for CLI. -
mcp-sentiment/mcp_client_streamable.py
MCP client using streamable-http transport. Connects to the server via HTTP with bidirectional streaming, lists tools, and sends text for analysis. Uses argparse for CLI.
Tests
-
tests/test_sentiment_analysis.py
Unit tests for the sentiment analysis tool, checking various input cases and error handling. -
tests/test_client_stdio.py
Tests for the stdio client, including unit tests for request handling and integration tests for end-to-end sentiment analysis. -
tests/test_client_sse.py
Integration tests for the SSE client, including server process management and sentiment analysis checks. -
tests/test_client_streamable.py
Integration tests for the streamable-http client, including server process management and sentiment analysis checks.
Directory Structure
mcp_testlab/
โโโ mcp-sentiment/
โ โโโ app_fastmcp.py # MCP server exposing sentiment_analysis tool
โ โโโ mcp_client_stdio.py # MCP client (stdio transport)
โ โโโ mcp_client_sse.py # MCP client (SSE transport)
โ โโโ mcp_client_streamable.py # MCP client (streamable-http transport)
โโโ tests/
โ โโโ test_sentiment_analysis.py # Unit tests for sentiment_analysis tool
โ โโโ test_client_stdio.py # Tests for stdio client
โ โโโ test_client_sse.py # Tests for SSE client
โ โโโ test_client_streamable.py # Tests for streamable-http client
โโโ requirements.txt # Python dependencies
โโโ README.md # Project documentation and usage
โโโ LICENSE # License file
โโโ .gitignore # Git ignore rules
โโโ .gitattributes # Git LFS attributes
๐ Quick Start
The application uses Model Context Protocol (MCP) to facilitate communication between a client and a sentiment analysis server. When you run the client with a text string, it:
- Connects to the server script (
app_fastmcp.py) orsse/streamable-httpendpoint - Sends your text for sentiment analysis
- Returns the sentiment result (positive, negative, or neutral)
Server (app_fastmcp.py)
The app_fastmcp.py file implements an MCP server using FastMCP that:
- Exposes a sentiment analysis tool via the Model Context Protocol
- Uses TextBlob library to analyze sentiment of provided text
- Returns JSON results with:
- Polarity score (-1 to 1, negative to positive)
- Subjectivity score (0 to 1, objective to subjective)
- Overall assessment (positive, negative, or neutral)
- Supports
stdioorsseorstreamable-httptransport for communication with clients
Client (mcp_client_stdio.py)
The mcp_client_stdio.py file implements an MCP client that:
- Uses the argparse library for command-line argument handling
- Accepts text input as a required positional argument
- Accepts an optional
--serverparameter to specify the server script path - Accepts an optional
--verboseflag to display detailed tool information - Establishes a connection to the MCP server using stdio transport
- Lists available tools on the connected server
- Sends the input text to the sentiment_analysis tool
- Displays formatted sentiment results showing polarity, subjectivity, and assessment
- Properly manages resources with async context managers and AsyncExitStack
Client (mcp_client_sse.py)
The mcp_client_sse.py file implements an MCP client that:
- Uses the argparse library for command-line argument handling
- Accepts text input as a required positional argument
- Accepts an optional
--urlparameter to specify the server endpoint (default: http://localhost:8000/sse) - Accepts an optional
--verboseflag to display detailed tool information - Establishes a connection to the MCP server using SSE transport
- Lists available tools on the connected server
- Sends the input text to the sentiment_analysis tool
- Displays formatted sentiment results showing polarity, subjectivity, and assessment
- Properly manages resources with async context managers and AsyncExitStack
Client (mcp_client_streamable.py)
The mcp_client_streamable.py file implements an MCP client that:
- Uses the argparse library for command-line argument handling
- Accepts text input as a required positional argument
- Accepts an optional
--urlparameter to specify the server endpoint (default: http://localhost:8000/mcp) - Accepts an optional
--verboseflag to display detailed tool information - Establishes a connection to the MCP server using streamable-http transport
- Displays the session ID when available
- Lists available tools on the connected server
- Sends the input text to the sentiment_analysis tool
- Displays formatted sentiment results showing polarity, subjectivity, and assessment
- Properly manages resources with async context managers and AsyncExitStack
๐ป Usage Examples
Basic Usage
Example Usage with stdio Transport
Command-line Arguments
((venv) ) Mac:jim mcp_testlab[529]$ python mcp-sentiment/mcp_client_stdio.py --help
usage: mcp_client_stdio.py [-h] [--server SERVER] [--verbose] text
MCP Client for sentiment analysis using stdio transport
positional arguments:
text Text to analyze for sentiment
options:
-h, --help show this help message and exit
--server SERVER Path to the MCP server script (default: mcp-sentiment/app_fastmcp.py)
--verbose, -v Display detailed information about available tools
Client
((venv) ) Mac:jim mcp_testlab[512]$ python mcp-sentiment/mcp_client_stdio.py "i love mcp"
Connected to MCP server at mcp-sentiment/app_fastmcp.py
Listing available tools...
[07/29/25 13:45:16] INFO Processing request of type ListToolsRequest server.py:619
Connected to MCP server. Listing available tools...
INFO Processing request of type ListToolsRequest server.py:619
Available tools: ['sentiment_analysis']
Analyzing sentiment for: 'i love mcp'
INFO Processing request of type CallToolRequest server.py:619
{'polarity': 0.5, 'subjectivity': 0.6, 'assessment': 'positive'}
Sentiment Analysis Result:
Polarity: 0.5 (-1=negative, 1=positive)
Subjectivity: 0.6 (0=objective, 1=subjective)
Assessment: positive
Sentiment Analysis Result: (0.5, 0.6, 'positive')
((venv) ) Mac:jim mcp_testlab[513]$ python mcp-sentiment/mcp_client_stdio.py "i hate java"
Connected to MCP server at mcp-sentiment/app_fastmcp.py
Listing available tools...
[07/29/25 13:45:38] INFO Processing request of type ListToolsRequest server.py:619
Connected to MCP server. Listing available tools...
INFO Processing request of type ListToolsRequest server.py:619
Available tools: ['sentiment_analysis']
Analyzing sentiment for: 'i hate java'
INFO Processing request of type CallToolRequest server.py:619
{'polarity': -0.8, 'subjectivity': 0.9, 'assessment': 'negative'}
Sentiment Analysis Result:
Polarity: -0.8 (-1=negative, 1=positive)
Subjectivity: 0.9 (0=objective, 1=subjective)
Assessment: negative
Sentiment Analysis Result: (-0.8, 0.9, 'negative')
((venv) ) Mac:jim mcp_testlab[514]$ python mcp-sentiment/mcp_client_stdio.py "i really like python" -v
Connected to MCP server at mcp-sentiment/app_fastmcp.py
Listing available tools...
[07/29/25 13:46:35] INFO Processing request of type ListToolsRequest server.py:619
Connected to MCP server. Listing available tools...
INFO Processing request of type ListToolsRequest server.py:619
sentiment_analysis:
Description:
Analyze the sentiment of the given text.
Args:
text (str): The text to analyze
Returns:
str: A JSON string containing polarity, subjectivity, and assessment
Annotations: None
Inputschema: {'properties': {'text': {'title': 'Text', 'type': 'string'}}, 'required': ['text'], 'title': 'sentiment_analysisArguments', 'type': 'object'}
Meta: None
/Users/jim/Desktop/modelcontextprotocol/mcp_testlab/mcp-sentiment/mcp_client_stdio.py:154: PydanticDeprecatedSince211: Accessing the 'model_computed_fields' attribute on the instance is deprecated. Instead, you should access this attribute from the model class. Deprecated in Pydantic V2.11 to be removed in V3.0.
value = getattr(tool, attr)
Model_computed_fields: {}
Model_config: {'extra': 'allow'}
Model_extra: {}
/Users/jim/Desktop/modelcontextprotocol/mcp_testlab/mcp-sentiment/mcp_client_stdio.py:154: PydanticDeprecatedSince211: Accessing the 'model_fields' attribute on the instance is deprecated. Instead, you should access this attribute from the model class. Deprecated in Pydantic V2.11 to be removed in V3.0.
value = getattr(tool, attr)
Model_fields: {'name': FieldInfo(annotation=str, required=True), 'title': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'description': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'inputSchema': FieldInfo(annotation=dict[str, Any], required=True), 'outputSchema': FieldInfo(annotation=Union[dict[str, Any], NoneType], required=False, default=None), 'annotations': FieldInfo(annotation=Union[ToolAnnotations, NoneType], required=False, default=None), 'meta': FieldInfo(annotation=Union[dict[str, Any], NoneType], required=False, default=None, alias='_meta', alias_priority=2)}
Model_fields_set: {'description', 'inputSchema', 'outputSchema', 'name'}
Outputschema: {'properties': {'result': {'title': 'Result', 'type': 'string'}}, 'required': ['result'], 'title': 'sentiment_analysisOutput', 'type': 'object'}
Title: None
Analyzing sentiment for: 'i really like python'
INFO Processing request of type CallToolRequest server.py:619
{'polarity': 0.2, 'subjectivity': 0.2, 'assessment': 'positive'}
Sentiment Analysis Result:
Polarity: 0.2 (-1=negative, 1=positive)
Subjectivity: 0.2 (0=objective, 1=subjective)
Assessment: positive
Sentiment Analysis Result: (0.2, 0.2, 'positive')
Example Usage with sse Transport
Command-line Arguments
((venv) ) Mac:jim mcp_testlab[532]$ python mcp-sentiment/mcp_client_sse.py --help
usage: mcp_client_sse.py [-h] [--url URL] [--verbose] text_to_test
MCP SSE Client for Sentiment Analysis
positional arguments:
text_to_test Text to analyze for sentiment
options:
-h, --help show this help message and exit
--url URL URL of the SSE server endpoint (default: http://localhost:8000/sse)
--verbose, -v Display detailed information about available tools
Client
python mcp-sentiment/mcp_client_sse.py "i really like python"
Connecting to MCP server at http://localhost:8000/sse...
Connected to MCP server. Listing available tools...
Available tools: ['sentiment_analysis']
Analyzing sentiment for: 'i really like python'
Sentiment Analysis Result:
Polarity: 0.2 (-1=negative, 1=positive)
Subjectivity: 0.2 (0=objective, 1=subjective)
Assessment: positive
SSE Server
((venv) ) Mac:jim mcp_testlab[506]$ python mcp-sentiment/app_fastmcp.py --transport sse
INFO: Started server process [8908]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: 127.0.0.1:49538 - "GET /sse HTTP/1.1" 200 OK
INFO: 127.0.0.1:49540 - "POST /messages/?session_id=fb1a89915f0b40e98f44385af5b6db58 HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:49540 - "POST /messages/?session_id=fb1a89915f0b40e98f44385af5b6db58 HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:49540 - "POST /messages/?session_id=fb1a89915f0b40e98f44385af5b6db58 HTTP/1.1" 202 Accepted
[07/29/25 06:13:08] INFO Processing request of type ListToolsRequest server.py:619
INFO: 127.0.0.1:49540 - "POST /messages/?session_id=fb1a89915f0b40e98f44385af5b6db58 HTTP/1.1" 202 Accepted
INFO Processing request of type CallToolRequest server.py:619
INFO: 127.0.0.1:49543 - "GET /sse HTTP/1.1" 200 OK
INFO: 127.0.0.1:49545 - "POST /messages/?session_id=632a380ef69344eab4bf145158e05051 HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:49545 - "POST /messages/?session_id=632a380ef69344eab4bf145158e05051 HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:49545 - "POST /messages/?session_id=632a380ef69344eab4bf145158e05051 HTTP/1.1" 202 Accepted
[07/29/25 06:13:46] INFO Processing request of type ListToolsRequest server.py:619
INFO: 127.0.0.1:49545 - "POST /messages/?session_id=632a380ef69344eab4bf145158e05051 HTTP/1.1" 202 Accepted
INFO Processing request of type CallToolRequest server.py:619
INFO: 127.0.0.1:49547 - "GET /sse HTTP/1.1" 200 OK
INFO: 127.0.0.1:49549 - "POST /messages/?session_id=f6a51e126c12412398bacc85753174a3 HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:49549 - "POST /messages/?session_id=f6a51e126c12412398bacc85753174a3 HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:49549 - "POST /messages/?session_id=f6a51e126c12412398bacc85753174a3 HTTP/1.1" 202 Accepted
[07/29/25 06:14:17] INFO Processing request of type ListToolsRequest server.py:619
INFO: 127.0.0.1:49549 - "POST /messages/?session_id=f6a51e126c12412398bacc85753174a3 HTTP/1.1" 202 Accepted
INFO Processing request of type CallToolRequest server.py:619
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [8908]
Terminated: 15 python mcp-sentiment/app_fastmcp.py --transport sse
Example Usage with streamable-http Transport
Command-line Arguments
((venv) ) Mac:jim mcp_testlab[533]$ python mcp-sentiment/mcp_client_streamable.py --help
usage: mcp_client_streamable.py [-h] [--url URL] [--verbose] text_to_test
MCP Streamable Client for Sentiment Analysis
positional arguments:
text_to_test Text to analyze for sentiment
options:
-h, --help show this help message and exit
--url URL URL of the streamable-http server endpoint (default: http://localhost:8000/mcp)
--verbose, -v Display detailed information about available tools
Client
# Using the default URL
((venv) ) Mac:jim mcp_testlab[517]$ python mcp-sentiment/mcp_client_streamable.py "MCP is the best"
Connecting to MCP server at http://localhost:8000/mcp...
Session ID: fdc3c721f04441a1ae4c22cadebc9226
Connected to MCP server. Listing available tools...
Available tools: ['sentiment_analysis']
Analyzing sentiment for: 'MCP is the best'
Sentiment Analysis Result:
Polarity: 1.0 (-1=negative, 1=positive)
Subjectivity: 0.3 (0=objective, 1=subjective)
Assessment: positive
Streamable-HTTP Server
((venv) ) Mac:jim mcp_testlab[507]$ python mcp-sentiment/app_fastmcp.py --transport streamable-http
INFO: Started server process [2701]
INFO: Waiting for application startup.
[07/28/25 22:48:20] INFO StreamableHTTP session manager started streamable_http_manager.py:112
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: 127.0.0.1:54049 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
[07/28/25 22:48:29] INFO Created new transport with session ID: 6a17c2206e6e478b830bd0da73771b8b streamable_http_manager.py:229
INFO: 127.0.0.1:54049 - "POST /mcp/ HTTP/1.1" 200 OK
INFO: 127.0.0.1:54052 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
INFO: 127.0.0.1:54053 - "GET /mcp HTTP/1.1" 307 Temporary Redirect
INFO: 127.0.0.1:54052 - "POST /mcp/ HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:54053 - "GET /mcp/ HTTP/1.1" 200 OK
INFO: 127.0.0.1:54055 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
INFO: 127.0.0.1:54055 - "POST /mcp/ HTTP/1.1" 200 OK
INFO Processing request of type ListToolsRequest server.py:619
INFO: 127.0.0.1:54057 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
INFO: 127.0.0.1:54057 - "POST /mcp/ HTTP/1.1" 200 OK
INFO Processing request of type CallToolRequest server.py:619
INFO: 127.0.0.1:54059 - "DELETE /mcp HTTP/1.1" 307 Temporary Redirect
INFO Terminating session: 6a17c2206e6e478b830bd0da73771b8b streamable_http.py:633
INFO: 127.0.0.1:54059 - "DELETE /mcp/ HTTP/1.1" 200 OK
INFO: Shutting down
INFO: Waiting for application shutdown.
[07/28/25 22:48:42] INFO StreamableHTTP session manager shutting down streamable_http_manager.py:116
INFO: Application shutdown complete.
INFO: Finished server process [2701]
Terminated: 15 python mcp-sentiment/app_fastmcp.py --transport streamable-http
๐ง Technical Details
Unit Tests
Unit tests are provided to ensure the functionality of the MCP server and client. To run the tests, use the following command:
$ pytest -v tests
Sample output:
MCP Inspector
The MCP Inspector is a tool for exploring and interacting with Model Context Protocol (MCP) servers. It provides a user-friendly interface for:
- Discovering available tools and their capabilities
- Sending requests to tools and viewing responses
- Debugging and testing MCP interactions
Running MCP Inspector with stdio Transport
To run the MCP Inspector for server using stdio transport, use the following command:
mcp dev mcp-sentiment/app_fastmcp.py
Sample output will show the available tools and their descriptions, allowing you to interact with the sentiment analysis tool.
MCP Inspector Listing Tools
MCP Inspector Testing Sentiment Analysis
Running MCP Inspector with sse Transport
Starting the sse Server for testing
python mcp-sentiment/app_fastmcp.py --transport sse
To run the MCP Inspector for server using sse or streamable-http transport, use the following command:
npx @modelcontextprotocol/inspector
Connecting to the MCP Inspector
Open the browser to access the MCP Inspector interface, change from http to https if necessary. Once the MCP Inspector is running, configure "Transport Type" for sse or streamable-http and set the server URL to point to your running MCP server (e.g., http://localhost:8000/sse or http://localhost:8000/mcp) and click "Connect" button.
sse Server URL: http://localhost:8000/sse
Starting the streamable-http Server for testing
python mcp-sentiment/app_fastmcp.py --transport streamable-http
streamable-http Server URL: http://localhost:8000/mcp
๐ฆ Installation
Requirements
- Python 3.12+
- Dependencies:
pip install -r requirements.txt - Required NLP libraries for sentiment analysis
- Required version of
node> v20.x to run MCP Inspector (see GH Issue on unexpected token)
Alternatives









