What is an MCP server? Even if you know that MCP stands for Model Context Protocol, that's no that obvious to understand or see the benefits, at least for me.
And, I think the best way to figure this out is to build one, so I started to build the simplest MCP server possible and play with it. After that, I used an existing open source MCP server to understand more. And I wanted to share that experience here.
1) The simplest MCP Server
I could ask Amazon Q (or an LLM like Anthropic Claude) to build the simplest MCP server for me, but I didn't get satisfying answers. It was not relevant or too complex already, so I looked for some examples with a web search engine, and I cherry picked some ideas.
1.1) Using FastMCP v2 to create the simplest MCP server
I discovered that there was a python library that could handle this protocol: FastMCP v2.
Little refresher: a protocol is a set of rules defining how data must be formatted, transmitted, received between systems. In our case how the coding assistant based on LLM (e.g. Q Developer) must communicate with the server and how the server should answer it.
FastMCP can be compared to flask for python or express for node. And like flask or express will handle an HTTP request (containing http method, content type, ...) between a web browser and a remote resources like web pages, FastMCP will handle the communication between the LLM and the server tools like python functions.
After a little exploration, I took that simple example, that we can find in the FastMCP documentation
# server.py
from fastmcp import FastMCP
mcp = FastMCP("Demo ๐")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
if __name__ == "__main__":
mcp.run()
It's very similar to what you would do with a flask server
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello, World!"
if __name__ == '__main__':
app.run()
The difference is that in the first case you will expose a function also called tool (e.g. the 'add' method) to your coding assistant, in the second case you will expose functions to your web browser.
So, that means I can start this server locally like a flask server
$ python3 server.py
[05/04/25 14:39:37] INFO Starting server "Demo ๐"...
That works, but it's not "connected" with Q CLI, which is unaware of this server.
1.2) Integrate the simplest MCP server with Q CLI
Now I want Q CLI to use my 'simplest_mcp_server', and for that I will need to initiate Q CLI with this server.
The way we do that is by creating this file:
~/.aws/amazonq/mcp.json
With the content below.
{
"mcpServers": {
"simplest-mcp-server": {
"command": "python3",
"args": ["server.py"]
}
}
}
Note that the json file describes how to start the server, like we did above, but this time this is Q that will start it.
Now I start Q CLI (make sure you are in 1.9.1 version or above), and I get that result:
$ q
To learn more about MCP safety, see https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-security.html
โ simplest_mcp_server loaded in 0.59 s
โ 1 of 1 mcp servers initialized
Welcome to
โโโโโโ โโโโ โโโโ โโโโโโ โโโโโโโโ โโโโโโโ โโโโ โโโ โโโโโโโ
โโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโ โโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโ โโโ โโโโโโโโโ โโโ โโโ โโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโ โโโ โโโโโโโโโโโโโ โโโโโ โโโ
โโโ โโโโโโ โโโ โโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโ โโโโโโโโโ
โโโ โโโโโโ โโโโโโ โโโโโโโโโโโ โโโโโโโ โโโ โโโโโ โโโโโโโ
โญโโโโโโโโโโโโโโโโโโโโโโโโโ Did you know? โโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ โ
โ You can programmatically inject context to your prompts by โ
โ using hooks. Check out /context hooks help โ
โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
/help all commands โข ctrl + j new lines โข ctrl + k fuzzy search
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
>
You can see the MCP server initialisation
...
โ simplest_mcp_server loaded in 0.59 s
โ 1 of 1 mcp servers initialized
...
You can also verify the 'add' function is in the list of tools by typing '/tools' (it's like listing the routes for a flask server)
> /tools
Tool Permission
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโsimplest_mcp_server (MCP):
- simplest_mcp_server___add * not trusted
Built-in:
- report_issue * trusted
- fs_write * not trusted
- execute_bash * trust read-only commands
- use_aws * trust read-only commands
- fs_read * trusted
Trusted tools can be run without confirmation
* Default settings
>
1.3)Test my simplest MCP server with Q CLI
Now when I ask Q to add 2 numbers, Q will use the 'add' function:
> add 1 + 1
I'll calculate 1 + 1 for you.
๐ ๏ธ Using tool: add from mcp server simplest_mcp_server
โฎ
โ Running add with the param:
โฎ {
โฎ "arguments": {
โฎ "a": 1,
โฎ "b": 1
โฎ },
โฎ "name": "add"
โฎ }
Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:
>
It shows what it will do (i.e. call the add function) and ask if you want to execute this or not.
If you are ok, you can type 'y' to trust the tool this time only, or 't' to trust it all the time (at least until you exit Q CLI).
I choose 't' and I get the result of the 'add' tool
Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:
> t
โฎ
โ Completed in 0.5s
The result of 1 + 1 is 2.
>
Now when I list my tools I can see my 'add' function is trusted
> /tools
Tool Permission
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโsimplest_mcp_server (MCP):
- simplest_mcp_server___add trusted
...
and when I ask another addition it uses the tool automatically
> add 2 + 2
I'll calculate 2 + 2 for you.
๐ ๏ธ Using tool: add (trusted) from mcp server simplest_mcp_server
โฎ
โ Running add with the param:
โฎ {
โฎ "arguments": {
โฎ "a": 2,
โฎ "b": 2
โฎ },
โฎ "name": "add"
โฎ }
โฎ
โ Completed in 0.12s
The result of 2 + 2 is 4.
>
Now when I ask Q CLI to subtract 2 numbers it tells me it doesn't have the tool (i.e. the function) for that. Which is true because I only have one function in my server file. However, Q can make the subtraction (which is quite simple).
> substract 3 - 2
I don't have a direct subtraction function available in my tools, but I can help you with this calculation.
The result of 3 - 2 is 1.
If you'd like me to perform more complex calculations or operations, please let me know!
>
For simple calculation, an MCP server is not necessary, but let see how we can use MCP servers for more specific tasks that the LLM is less good at or need more (up to date) context.
2) Using an existing MCP Server
I will now use a trusted MCP server that has been developed by AWS here https://github.com/awslabs/mcp/blob/main/src/aws-diagram-mcp-server/README.md
This MCP server will help generating diagrams with the python Diagram library. It's diagram as code, but unlike mermaid that used static code, it used python imperative code.
Then, I just follow the documentation here: https://awslabs.github.io/mcp/servers/aws-diagram-mcp-server/
And I create my
~/.aws/amazonq/mcp.json
with
{
"mcpServers": {
"awslabs.aws-diagram-mcp-server": {
"command": "uvx",
"args": ["awslabs.aws-diagram-mcp-server"]
}
}
}
This time I need 'uvx' to be installed.
I start q and list the tools
q
To learn more about MCP safety, see https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-security.html
โ awslabsaws_diagram_mcp_server loaded in 2.34 s
โ 1 of 1 mcp servers initialized
Welcome to
โโโโโโ โโโโ โโโโ โโโโโโ โโโโโโโโ โโโโโโโ โโโโ โโโ โโโโโโโ
โโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโ โโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโ โโโ โโโโโโโโโ โโโ โโโ โโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโ โโโ โโโโโโโโโโโโโ โโโโโ โโโ
โโโ โโโโโโ โโโ โโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโ โโโโโโโโโ
โโโ โโโโโโ โโโโโโ โโโโโโโโโโโ โโโโโโโ โโโ โโโโโ โโโโโโโ
โญโโโโโโโโโโโโโโโโโโโโโโโโโ Did you know? โโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ โ
โ You can use /compact to replace the conversation โ
โ history with its summary to free up the context space โ
โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
/help all commands โข ctrl + j new lines โข ctrl + k fuzzy search
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
> /tools
Tool Permission
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโBuilt-in:
- fs_write * not trusted
- report_issue * trusted
- execute_bash * trust read-only commands
- fs_read * trusted
- use_aws * trust read-only commands
awslabsaws_diagram_mcp_server (MCP):
- awslabsaws_diagram_mcp_server___list_icons * not trusted
- awslabsaws_diagram_mcp_server___get_diagram_examples * not trusted
- awslabsaws_diagram_mcp_server___generate_diagram * not trusted
Trusted tools can be run without confirmation
* Default settings
>
I can see 3 new tools, that can be used:
- list_icons
- get_diagram_examples
- generate_diagram
Then I ask
create a diagram from the code in this folder
And it starts using the list_icons tool
Now that I understand the architecture, I'll create a diagram that represents this serverless application. Based on the SAM template, we have:
1. A landing page function that serves an HTML page
2. A feedback function that records feedback in DynamoDB and sends notifications via SNS
3. A DynamoDB table for storing feedback
4. An SNS topic for email notifications
๐ ๏ธ Using tool: list_icons from mcp server awslabsaws_diagram_mcp_server
โฎ
โ Running list_icons with the param:
โฎ {
โฎ "arguments": {},
โฎ "name": "list_icons"
โฎ }
Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:
> y
And the generate_diagram tool with Diagram python code that Q as generated as an argument.
๐ ๏ธ Using tool: generate_diagram from mcp server awslabsaws_diagram_mcp_server
โฎ
โ Running generate_diagram with the param:
โฎ {
โฎ "arguments": {
โฎ "code": "from diagrams import Diagram, Edge\nfrom diagrams.aws.compute import Lambda\nfrom diagrams.aws.database import Dynamodb\nfrom diagrams.aws.integration import SimpleNotificationServiceSnsTopic\nfrom diagrams.aws.network import APIGateway\nfrom diagrams.aws.general import Users\n\nwith Diagram(\"Serverless Feedback Application\", show=False, direction=\"LR\"):\n # Define components\n users = Users(\"Users\")\n api = APIGateway(\"API Gateway\")\n \n # Lambda functions\n landing_page = Lambda(\"Landing Page\\nFunction\")\n feedback_function = Lambda(\"Record & Confirm\\nFeedback Function\")\n \n # Backend services\n dynamodb = Dynamodb(\"Feedback\\nTable\")\n sns = SimpleNotificationServiceSnsTopic(\"SNS Topic\\n(Email Notifications)\")\n \n # Define relationships\n users >> api\n api >> landing_page\n api >> feedback_function\n \n feedback_function >> dynamodb\n feedback_function >> sns",
โฎ "filename": "serverless_feedback_app_diagram.png",
โฎ "workspace_dir": "/home/olivier/wio-from-diagram-to-code-with-amazon-q-developer/_playground/vscode-app-folder"
โฎ },
โฎ "name": "generate_diagram"
โฎ }
Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:
>
Then I receive that result, which is not bad.
The tools (the python functions) created a new folder 'generated_diagram' and created the png file containing the diagram.
Then I thought, can we get a similar result WITHOUT an MCP server? And I removed my Diagram MCP server and asked
create a diagram with python Diagram package from the code in this folder
I receive a quite similar result
The difference it that it generates the python file and execute it locally (not on the server).
Which means that, as for a simple calculation, an MCP server is not always necessary to draw a simple diagram.
Conclusion
Finally, creating an MCP server that works with Q CLI is not very difficult. Using an existing MCP server is not that hard either. But, I note that we the in-house functionalities of the coding assistant can be sufficient for basic tasks and that MCP servers should be built or used for hard tasks that the LLM cannot deal with.