Ollama和LangChain快速入门:多模态链路(MCP)
Quick Primer on MCP Using Ollama and LangChain

原始链接: https://www.polarsparc.com/xhtml/MCP.html

模型上下文协议 (MCP) 通过提供集成外部工具和数据的行业标准,正在彻底改变企业大型语言模型 (LLM) 应用的开发。它充当统一层,使像 LangChain 这样的智能框架与各种企业资源(数据库、API 等)之间能够无缝通信。 MCP 包含三个核心组件:MCP 服务器(公开工具功能)、MCP 客户端(标准化交互)和 MCP 宿主(LLM 应用)。演示展示了它在 Ubuntu 上与 Ollama 和 LangChain 的使用,利用标准 IO (stdio) 和服务器发送事件 (SSE) 传输。 最初,LangChain 应用难以进行利息计算。通过实现具有简单和复利计算工具的 MCP 服务器,充当 MCP 宿主的 LLM 应用成功地通过 MCP 客户端利用了这些工具。进一步的示例演示了连接到多个 MCP 服务器,包括一个执行 shell 命令的服务器,证明了 MCP 集成各种功能的多功能性。最后,指南说明了使用 SSE 传输进行网络连接的 MCP 服务器以及基于 stdio 的服务器,巩固了 MCP 桥接各种企业服务的能力。

Hacker News 上关于“使用 Ollama 和 LangChain 快速入门 MCP”的讨论总结如下: 讨论的中心在于使用大型语言模型进行 Agent/MCP 开发的实际价值。虽然原帖旨在快速入门,但评论者 minimaxir 认为 Agent/MCP 开发感觉像是一团乱麻的复杂代码,本质上是低级的 ReAct 范式加上夸大的宣传,反而可能会让人困惑。 其他人讨论了大型语言模型在根据用户输入选择正确的函数或工具方面的应用。一些人强调了 MCP 的用例,特别是针对本地 IDE 集成,但也指出了在更强大的应用程序中关于安全性和多用户支持的重大缺陷。他们批评了 MCP 服务器缺乏安全性和身份验证功能,以及 API 密钥管理方面的挑战。一位评论者请求提供解决这些问题的替代方法。大家普遍认为这项技术仍处于早期阶段。链接网站的设计也被赞扬为“回归过去”。

原文
Quick Primer on Model Context Protocol (MCP)

Quick Primer on Model Context Protocol (MCP)




When LLMs first made their first appearance, the Enterprise apps built using LLMs were restricted to the knowledge on what the LLMs where trained on. These apps were useful for a set of tasks such as, text generation, text sentiment analysis, text summarization, etc.

The next evolution for LLM apps was the integration with Enterprise data assets via the Vector Stores for contextual knowledge retrieval using RAGs.

As agentic frameworks like LangChain came along with support for tools integration for automating manual tasks, the LLM apps evolved to drive automation in the Enterprise environment.

The challenge however was that there was no industry standard for tools integration and every framework had its own approach to tools integration.

Enter the Model Context Protocol (or MCP) that has changed the landscape for tools integration.

Think of MCP as a industry standard layer on top of the other Enterprise services that allows any agentic framework (such as LangChain, LlamaIndex, etc) to consistently integrate with the Enterprise tools.

In other words, MCP is an open protocol that enables seamless integration between the LLM apps and the external data sources (databases, files, etc) and tools (github, servicenow, etc).

The MCP specification consists of the following core components:

  • MCP Server: connects to various external as well as internal data sources and tools for exposing specific capabilities to the agentic LLM apps. Think of these as service providers
  • MCP Client: connects and interacts with the MCP Server(s) in a standardized manner
  • MCP Host: the LLM app(s) that use the MCP Client to access the MCP Server(s)

The installation and setup will be on a Ubuntu 24.04 LTS based Linux desktop. Ensure that Python 3.x programming language is installed and setup on the desktop.

In addition, ensure that Ollama is installed and setup on the Linux desktop (refer to for instructions).

Assuming that the ip address on the Linux desktop is 192.168.1.25, start the Ollama platform by executing the following command in the terminal window:


$ docker run --rm --name ollama --network=host -p 192.168.1.25:11434:11434 -v $HOME/.ollama:/root/.ollama ollama/ollama:0.6.2


For the LLM model, we will be using the recently released IBM Granite 3.1 model.

Open a new terminal window and execute the following docker command to download the LLM model:


$ docker exec -it ollama ollama run granite3.1-moe:1b


To install the necessary Python modules for this primer, execute the following command:


$ pip install dotenv langchain lanchain-core langchain-ollama langgraph mcp langchain-mcp-adapters starlette sse-starlette uvicorn


This completes all the installation and setup for the MCP hands-on demonstrations using Python.


Hands-on with MCP (using Python)


In the following sections, we will get our hands dirty with the MCP using Ollama and LangChain. So, without further ado, let us get started !!!

Create a file called .env with the following environment variables defined:


.env

LLM_TEMPERATURE=0.2
OLLAMA_MODEL='granite3.1-moe:1b'
OLLAMA_BASE_URL='http://192.168.1.25:11434'
PY_PROJECT_DIR='/projects/python/MCP/'
SSE_BASE_URL='http://192.168.1.25:8000/sse'

The following is a simple LangChain based ReACT app:


interest_client.py

#
# @Author: Bhaskar S
# @Blog:   https://www.polarsparc.com
# @Date:   06 April 2025
#

import asyncio
import logging
import os

from dotenv import load_dotenv, find_dotenv
from langchain_core.tools import tool
from langchain_ollama import ChatOllama
from langgraph.prebuilt import create_react_agent

logging.basicConfig(format='%(levelname)s %(asctime)s - %(message)s', level=logging.INFO)

logger = logging.getLogger('interest_client')

load_dotenv(find_dotenv())

home_dir = os.getenv('HOME')
llm_temperature = float(os.getenv('LLM_TEMPERATURE'))
ollama_model = os.getenv('OLLAMA_MODEL')
ollama_base_url = os.getenv('OLLAMA_BASE_URL')
py_project_dir = os.getenv('PY_PROJECT_DIR')

ollama_chat_llm = ChatOllama(base_url=ollama_base_url, model=ollama_model, temperature=llm_temperature)

@tool
def dummy():
  """This is a dummy tool"""
  return None

async def main():
  tools = [dummy]

  # Initialize a ReACT agent
  agent = create_react_agent(ollama_chat_llm, tools)

  # Case - 1 : Simple interest definition
  agent_response_1 = await agent.ainvoke(
    {'messages': 'what is the simple interest ?'})
  logger.info(agent_response_1['messages'][::-1])

  # Case - 2 : Simple interest calculation
  agent_response_2 = await agent.ainvoke(
    {'messages': 'compute the simple interest for a principal of 1000 at rate 3.75 ?'})
  logger.info(agent_response_2['messages'][::-1])

  # Case - 3 : Compound interest calculation
  agent_response_3 = await agent.ainvoke(
    {'messages': 'compute the compound interest for a principal of 1000 at rate 4.25 ?'})
  logger.info(agent_response_3['messages'][::-1])


if __name__ == '__main__':
  asyncio.run(main())

To execute the above Python code, execute the following command in a terminal window:


$ python interest_client.py


The following would be the typical output:


Output.1

INFO 2025-04-13 09:54:41,426 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 09:54:41,428 - [AIMessage(content='The simple interest (SI) is calculated using the formula:\n\nSI = P * R * T / 100\n\nWhere:\n- P is the principal amount (the initial sum of money)\n- R is the rate of interest per annum\n- T is the time in years\n\nFor example, if you have Rs. 1000 as a principal amount with an annual interest rate of 5% for 2 years, then:\n\nSI = 1000 * 5/100 * 2 / 100\nSI = 1000 * 0.05 * 2 / 100\nSI = 1000 * 0.10 / 100\nSI = Rs. 10', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T13:54:41.425392119Z', 'done': True, 'done_reason': 'stop', 'total_duration': 1338038780, 'load_duration': 6784726, 'prompt_eval_count': 84, 'prompt_eval_duration': 31132026, 'eval_count': 172, 'eval_duration': 1298733422, 'message': Message(role='assistant', content='The simple interest (SI) is calculated using the formula:\n\nSI = P * R * T / 100\n\nWhere:\n- P is the principal amount (the initial sum of money)\n- R is the rate of interest per annum\n- T is the time in years\n\nFor example, if you have Rs. 1000 as a principal amount with an annual interest rate of 5% for 2 years, then:\n\nSI = 1000 * 5/100 * 2 / 100\nSI = 1000 * 0.05 * 2 / 100\nSI = 1000 * 0.10 / 100\nSI = Rs. 10', images=None, tool_calls=None)}, id='run-d5a4f021-1a87-4bac-b6a4-5dc3239e6f7b-0', usage_metadata={'input_tokens': 84, 'output_tokens': 172, 'total_tokens': 256}), HumanMessage(content='what is the simple interest ?', additional_kwargs={}, response_metadata={}, id='aee2669b-36d3-42aa-bdb6-53fd2454ea12')]
INFO 2025-04-13 09:54:41,604 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 09:54:41,605 - [AIMessage(content='{"code":200,"message":"Interest Calculation Completed"}', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T13:54:41.603723234Z', 'done': True, 'done_reason': 'stop', 'total_duration': 173677918, 'load_duration': 6716296, 'prompt_eval_count': 99, 'prompt_eval_duration': 36381866, 'eval_count': 15, 'eval_duration': 129621404, 'message': Message(role='assistant', content='{"code":200,"message":"Interest Calculation Completed"}', images=None, tool_calls=None)}, id='run-a73da0a1-6862-4aba-ba1d-095df8a85e0c-0', usage_metadata={'input_tokens': 99, 'output_tokens': 15, 'total_tokens': 114}), HumanMessage(content='compute the simple interest for a principal of 1000 at rate 3.75 ?', additional_kwargs={}, response_metadata={}, id='2d929265-e096-4275-aaa1-001f15d34047')]
INFO 2025-04-13 09:54:41,771 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 09:54:41,773 - [AIMessage(content='{"code":301,"message":"Compound Interest Formula Calculation"}', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T13:54:41.771498307Z', 'done': True, 'done_reason': 'stop', 'total_duration': 164399085, 'load_duration': 6787425, 'prompt_eval_count': 99, 'prompt_eval_duration': 43029403, 'eval_count': 17, 'eval_duration': 113471897, 'message': Message(role='assistant', content='{"code":301,"message":"Compound Interest Formula Calculation"}', images=None, tool_calls=None)}, id='run-7dfd2c78-0847-461c-a822-eb4b4c4f54a3-0', usage_metadata={'input_tokens': 99, 'output_tokens': 17, 'total_tokens': 116}), HumanMessage(content='compute the compound interest for a principal of 1000 at rate 4.25 ?', additional_kwargs={}, response_metadata={}, id='284397b4-2575-46d6-bebc-83bff0c6f64f')]

It is evident from the above Output.1 that the LLM app was able to define what simple interest was, however was not able to compute either the simple interest or the compound interest.

Let us now build our first MCP Server for computing both the simple interest (for a year) and the compound interest (for a year).

The following is our first MCP Server code in Python:


interest_mcp_server.py

#
# @Author: Bhaskar S
# @Blog:   https://www.polarsparc.com
# @Date:   06 April 2025
#

from mcp.server.fastmcp import FastMCP

import logging

logging.basicConfig(format='%(levelname)s %(asctime)s - %(message)s', level=logging.INFO)

logger = logging.getLogger('interest_mcp_server')

mcp = FastMCP('InterestCalculator')

@mcp.tool()
def yearly_simple_interest(principal: float, rate:float) -> float:
  """Tool to compute simple interest rate for a year."""
  logger.info(f'Simple interest -> Principal: {principal}, Rate: {rate}')
  return principal * rate / 100.00

@mcp.tool()
def yearly_compound_interest(principal: float, rate:float) -> float:
  """Tool to compute compound interest rate for a year."""
  logger.info(f'Compound interest -> Principal: {principal}, Rate: {rate}')
  return principal * (1 + rate / 100.0)

if __name__ == '__main__':
  logger.info(f'Starting the interest MCP server...')
  mcp.run(transport='stdio')

There are two types of transports supported by the MCP specification which are as follows:

  • Standard IO (stdio): enables communication through standard input and output streams that is useful for integrations with command-line tools
  • Server Sent Events (sse): enables server to client streaming with HTTP POST requests that is useful for integrations with network enabled services

In our example, we choose the stdio transport.

The next step is to build a MCP Host (LLM app) that uses a MCP Client to access the above MCP Server for computing both the simple interest and the compound interest.

The following is our first MCP Host LLM app code in Python:


interest_mcp_client.py

#
# @Author: Bhaskar S
# @Blog:   https://www.polarsparc.com
# @Date:   06 April 2025
#

from dotenv import load_dotenv, find_dotenv
from langchain_ollama import ChatOllama
from langchain_mcp_adapters.tools import load_mcp_tools
from langgraph.prebuilt import create_react_agent
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

import asyncio
import logging
import os

logging.basicConfig(format='%(levelname)s %(asctime)s - %(message)s', level=logging.INFO)

logger = logging.getLogger('interest_mcp_client')

load_dotenv(find_dotenv())

home_dir = os.getenv('HOME')
llm_temperature = float(os.getenv('LLM_TEMPERATURE'))
ollama_model = os.getenv('OLLAMA_MODEL')
ollama_base_url = os.getenv('OLLAMA_BASE_URL')
py_project_dir = os.getenv('PY_PROJECT_DIR')

server_params = StdioServerParameters(
  command='python',
  # Full absolute path to mcp server
  args=[home_dir + py_project_dir + 'interest_mcp_server.py'],
)

ollama_chat_llm = ChatOllama(base_url=ollama_base_url, model=ollama_model, temperature=llm_temperature)

async def main():
  # Will launch the MCP server and communicate via stdio/stdout
  async with stdio_client(server_params) as (read, write):
    # Create a MCP client session
    async with ClientSession(read, write) as session:
      # Connect to the MCP server
      await session.initialize()

      # Get the list of all the registered tools
      tools = await load_mcp_tools(session)

      logger.info(f'Loaded MCP Tools -> {tools}')

      # Initialize a ReACT agent
      agent = create_react_agent(ollama_chat_llm, tools)

      # Case - 1 : Simple interest definition
      agent_response_1 = await agent.ainvoke(
        {'messages': 'explain the definition of simple interest ?'})
      logger.info(agent_response_1['messages'][::-1])

      # Case - 2 : Simple interest calculation
      agent_response_2 = await agent.ainvoke(
        {'messages': 'compute the simple interest for a principal of 1000 at rate 3.75 ?'})
      logger.info(agent_response_2['messages'][::-1])

      # Case - 3 : Compound interest calculation
      agent_response_3 = await agent.ainvoke(
        {'messages': 'compute the compound interest for a principal of 1000 at rate 4.25 ?'})
      logger.info(agent_response_3['messages'][::-1])

if __name__ == '__main__':
  asyncio.run(main())

To execute the above Python code, execute the following command in a terminal window:


$ python interest_mcp_client.py


The following would be the typical output:


Output.2

INFO 2025-04-13 10:24:36,353 - Starting the interest MCP server...
INFO 2025-04-13 10:24:36,358 - Processing request of type ListToolsRequest
INFO 2025-04-13 10:24:36,359 - Loaded MCP Tools -> [StructuredTool(name='yearly_simple_interest', description='Tool to compute simple interest rate for a year.', args_schema={'properties': {'principal': {'title': 'Principal', 'type': 'number'}, 'rate': {'title': 'Rate', 'type': 'number'}}, 'required': ['principal', 'rate'], 'title': 'yearly_simple_interestArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x76293a568720>), StructuredTool(name='yearly_compound_interest', description='Tool to compute compound interest rate for a year.', args_schema={'properties': {'principal': {'title': 'Principal', 'type': 'number'}, 'rate': {'title': 'Rate', 'type': 'number'}}, 'required': ['principal', 'rate'], 'title': 'yearly_compound_interestArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x76293a568900>)]
INFO 2025-04-13 10:24:38,406 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 10:24:38,408 - [AIMessage(content='Simple Interest (SI) is a method of calculating interest where only the principal amount (the initial sum of money) and not the accumulated interest, is used to calculate the total interest paid or earned over a specific period. The formula for Simple Interest is:\n\nSI = P * R * T / 100\n\nWhere:\n- P is the principal amount (the initial sum of money)\n- R is the rate of interest per annum\n- T is the time in years\n\nThe SI is calculated by multiplying the principal by the rate and then dividing it by 100. The result gives you the total interest for that period, expressed as a percentage of the principal amount. For example, if you have $1000 as your principal, an annual interest rate of 5%, and you want to know how much you would earn in one year, you would calculate:\n\nSI = 1000 * 5/100 * 1 = $50\n\nThis means that for every $1000 you have, you would earn $50 in interest over the course of a year.', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T14:24:38.405888113Z', 'done': True, 'done_reason': 'stop', 'total_duration': 2038184289, 'load_duration': 4645995, 'prompt_eval_count': 179, 'prompt_eval_duration': 34893791, 'eval_count': 248, 'eval_duration': 1997458315, 'message': Message(role='assistant', content='Simple Interest (SI) is a method of calculating interest where only the principal amount (the initial sum of money) and not the accumulated interest, is used to calculate the total interest paid or earned over a specific period. The formula for Simple Interest is:\n\nSI = P * R * T / 100\n\nWhere:\n- P is the principal amount (the initial sum of money)\n- R is the rate of interest per annum\n- T is the time in years\n\nThe SI is calculated by multiplying the principal by the rate and then dividing it by 100. The result gives you the total interest for that period, expressed as a percentage of the principal amount. For example, if you have $1000 as your principal, an annual interest rate of 5%, and you want to know how much you would earn in one year, you would calculate:\n\nSI = 1000 * 5/100 * 1 = $50\n\nThis means that for every $1000 you have, you would earn $50 in interest over the course of a year.', images=None, tool_calls=None)}, id='run-4877f653-8e87-44b9-9f23-3ead28ba5441-0', usage_metadata={'input_tokens': 179, 'output_tokens': 248, 'total_tokens': 427}), HumanMessage(content='explain the definition of simple interest ?', additional_kwargs={}, response_metadata={}, id='046aef94-62e2-4b38-a398-84d3a57fba4d')]
INFO 2025-04-13 10:24:38,872 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 10:24:38,882 - Processing request of type CallToolRequest
INFO 2025-04-13 10:24:38,882 - Simple interest -> Principal: 1000.0, Rate: 3.75
INFO 2025-04-13 10:24:39,170 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 10:24:39,171 - [AIMessage(content='The simple interest for a principal of $1000 at an annual rate of 3.75% is $37.50.', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T14:24:39.170273321Z', 'done': True, 'done_reason': 'stop', 'total_duration': 285605746, 'load_duration': 6872903, 'prompt_eval_count': 239, 'prompt_eval_duration': 46254681, 'eval_count': 32, 'eval_duration': 227943217, 'message': Message(role='assistant', content='The simple interest for a principal of $1000 at an annual rate of 3.75% is $37.50.', images=None, tool_calls=None)}, id='run-8bd6ce67-d04e-4320-a1e1-2fcc94811fac-0', usage_metadata={'input_tokens': 239, 'output_tokens': 32, 'total_tokens': 271}), ToolMessage(content='37.5', name='yearly_simple_interest', id='a7e69290-1162-41a7-bd05-08e4738e7a51', tool_call_id='eea9e5ab-d0a5-4092-9b80-9a7f7bfa9e11'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T14:24:38.879515025Z', 'done': True, 'done_reason': 'stop', 'total_duration': 469244684, 'load_duration': 6761794, 'prompt_eval_count': 193, 'prompt_eval_duration': 38995191, 'eval_count': 60, 'eval_duration': 422119871, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-f32cbb8e-2f7b-41b6-a144-f403fb30f956-0', tool_calls=[{'name': 'yearly_simple_interest', 'args': {'principal': 1000, 'rate': 3.75}, 'id': 'eea9e5ab-d0a5-4092-9b80-9a7f7bfa9e11', 'type': 'tool_call'}], usage_metadata={'input_tokens': 193, 'output_tokens': 60, 'total_tokens': 253}), HumanMessage(content='compute the simple interest for a principal of 1000 at rate 3.75 ?', additional_kwargs={}, response_metadata={}, id='2bf88431-a08e-4679-9d31-0c62bfbac9a5')]
INFO 2025-04-13 10:24:39,478 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 10:24:39,494 - Processing request of type CallToolRequest
INFO 2025-04-13 10:24:39,494 - Compound interest -> Principal: 1000.0, Rate: 4.25
INFO 2025-04-13 10:24:39,858 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 10:24:39,860 - [AIMessage(content='The compound interest for a principal of $1000 at a rate of 4.25% per year is approximately $1,042.50.', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T14:24:39.858215452Z', 'done': True, 'done_reason': 'stop', 'total_duration': 362158794, 'load_duration': 6921843, 'prompt_eval_count': 241, 'prompt_eval_duration': 39011381, 'eval_count': 37, 'eval_duration': 312756614, 'message': Message(role='assistant', content='The compound interest for a principal of $1000 at a rate of 4.25% per year is approximately $1,042.50.', images=None, tool_calls=None)}, id='run-13a4f3b1-603e-44f1-963b-585b2b8fc0e5-0', usage_metadata={'input_tokens': 241, 'output_tokens': 37, 'total_tokens': 278}), ToolMessage(content='1042.5', name='yearly_compound_interest', id='6914a123-c9e0-4ea6-8070-7aa72b830c00', tool_call_id='597e2076-eb5c-4767-ad73-33b5d7810dbf'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T14:24:39.49171724Z', 'done': True, 'done_reason': 'stop', 'total_duration': 317826794, 'load_duration': 6408858, 'prompt_eval_count': 193, 'prompt_eval_duration': 37113360, 'eval_count': 39, 'eval_duration': 272645313, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-087af799-5faa-4b2d-9d99-480026fb63bc-0', tool_calls=[{'name': 'yearly_compound_interest', 'args': {'principal': 1000, 'rate': 4.25}, 'id': '597e2076-eb5c-4767-ad73-33b5d7810dbf', 'type': 'tool_call'}], usage_metadata={'input_tokens': 193, 'output_tokens': 39, 'total_tokens': 232}), HumanMessage(content='compute the compound interest for a principal of 1000 at rate 4.25 ?', additional_kwargs={}, response_metadata={}, id='81328b6c-5277-49e5-b9e6-da08da988a85')]

BINGO - it is evident from the above Output.2 that the LLM app was able to not only define what simple interest is, but also able to compute the simple interest and the compound interest using the tools exposed by the MCP server.

A typical Enterprise LLM agentic app invokes multiple MCP servers to perform a particular task. For our next example, the LLM host app will demonstrate how one can setup and use multiple tools.

The following is our second MCP Server code in Python that will invoke shell commands:


shell_mcp_server.py

#
# @Author: Bhaskar S
# @Blog:   https://www.polarsparc.com
# @Date:   12 April 2025
#

import subprocess

from mcp.server.fastmcp import FastMCP

import logging

logging.basicConfig(format='%(levelname)s %(asctime)s - %(message)s', level=logging.INFO)

logger = logging.getLogger('shell_mcp_server')

mcp = FastMCP('ShellCommandExecutor')

# DISCLAIMER: This is purely for demonstration purposes and NOT to be used in production environment

@mcp.tool()
def execute_shell_command(command: str) -> str:
  """Tool to execute shell commands"""
  logger.info(f'Executing shell command: {command}')
  try:
    result = subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
    if result.returncode != 0:
      return f'Error executing shell command - {command}'
    return result.stdout
  except subprocess.CalledProcessError as e:
    logger.error(e)

if __name__ == '__main__':
  logger.info(f'Starting the shell executor MCP server...')
  mcp.run(transport='stdio')

The following is our second MCP Host LLM app code in Python using multiple tools:


multi_mcp_client.py

#
# @Author: Bhaskar S
# @Blog:   https://www.polarsparc.com
# @Date:   12 April 2025
#

from dotenv import load_dotenv, find_dotenv
from langchain_ollama import ChatOllama
from  langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent

import asyncio
import logging
import os

logging.basicConfig(format='%(levelname)s %(asctime)s - %(message)s', level=logging.INFO)

logger = logging.getLogger('multi_mcp_client')

load_dotenv(find_dotenv())

home_dir = os.getenv('HOME')
llm_temperature = float(os.getenv('LLM_TEMPERATURE'))
ollama_model = os.getenv('OLLAMA_MODEL')
ollama_base_url = os.getenv('OLLAMA_BASE_URL')
py_project_dir = os.getenv('PY_PROJECT_DIR')

ollama_chat_llm = ChatOllama(base_url=ollama_base_url, model=ollama_model, temperature=llm_temperature)

async def main():
  async with MultiServerMCPClient() as client:
    await client.connect_to_server(
      'InterestCalculator',
      command='python',
      args=[home_dir + py_project_dir + 'interest_mcp_server.py'],
      transport='stdio',
    )

    await client.connect_to_server(
      'ShellCommandExecutor',
      command='python',
      args=[home_dir + py_project_dir + 'shell_mcp_server.py'],
      transport='stdio',
    )

    tools = client.get_tools()

    logger.info(f'Loaded Multiple MCP Tools -> {tools}')

    # Initialize a ReACT agent with multiple tools
    agent = create_react_agent(ollama_chat_llm, tools)

    # Case - 1 : Compound interest definition
    agent_response_1 = await agent.ainvoke(
      {'messages': 'explain the definition of compound interest'})
    logger.info(agent_response_1['messages'][::-1])

    # Case - 2 : Compound interest calculation
    agent_response_2 = await agent.ainvoke(
      {'messages': 'what is the compound interest for a principal of 1000 at rate 3.75 ?'})
    logger.info(agent_response_2['messages'][::-1])

    # Case - 3 : Execute a shell command
    agent_response_3 = await agent.ainvoke(
      {'messages': 'Execute the free shell command to find how much system memory'})
    logger.info(agent_response_3['messages'][::-1])

if __name__ == '__main__':
  asyncio.run(main())

To execute the above Python code, execute the following command in a terminal window:


$ python multi_mcp_client.py


The following would be the typical output:


Output.3

INFO 2025-04-13 12:09:03,259 - Starting the interest MCP server...
INFO 2025-04-13 12:09:03,265 - Processing request of type ListToolsRequest
INFO 2025-04-13 12:09:03,536 - Starting the shell executor MCP server...
INFO 2025-04-13 12:09:03,540 - Processing request of type ListToolsRequest
INFO 2025-04-13 12:09:03,541 - Loaded Multiple MCP Tools -> [StructuredTool(name='yearly_simple_interest', description='Tool to compute simple interest rate for a year.', args_schema={'properties': {'principal': {'title': 'Principal', 'type': 'number'}, 'rate': {'title': 'Rate', 'type': 'number'}}, 'required': ['principal', 'rate'], 'title': 'yearly_simple_interestArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x767fbd756160>), StructuredTool(name='yearly_compound_interest', description='Tool to compute compound interest rate for a year.', args_schema={'properties': {'principal': {'title': 'Principal', 'type': 'number'}, 'rate': {'title': 'Rate', 'type': 'number'}}, 'required': ['principal', 'rate'], 'title': 'yearly_compound_interestArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x767fbd756340>), StructuredTool(name='execute_shell_command', description='Tool to execute shell commands', args_schema={'properties': {'command': {'title': 'Command', 'type': 'string'}}, 'required': ['command'], 'title': 'execute_shell_commandArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x767fbd756f20>)]
INFO 2025-04-13 12:09:06,897 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 12:09:06,899 - [AIMessage(content="Compound interest is a type of interest calculated on the initial principal amount and also on any accumulated interest from previous periods. It's different from simple interest, which only considers the principal amount and the interest paid or earned during a single period. \n\nIn other words, with compound interest, your money grows at an increasing rate over time because it earns interest not just on the initial deposit but also on any previous interest accumulated. This results in a higher total value compared to simple interest for the same amount of principal and rate.\n\nFor example, if you invest $100 with an annual interest rate of 5% (simple interest) and leave it for one year, after one year, you would have $105 ($100 + $5). However, if you had invested the same amount at a 5% annual interest rate compounded annually, your money would grow to $107.20 ($100 * (1 + 0.05)^1) after one year. This is because the interest earned in the first year is added back to your principal for the second year, leading to a higher total amount.", additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T16:09:06.896491193Z', 'done': True, 'done_reason': 'stop', 'total_duration': 3346516305, 'load_duration': 1212696126, 'prompt_eval_count': 225, 'prompt_eval_duration': 246604191, 'eval_count': 247, 'eval_duration': 1885047710, 'message': Message(role='assistant', content="Compound interest is a type of interest calculated on the initial principal amount and also on any accumulated interest from previous periods. It's different from simple interest, which only considers the principal amount and the interest paid or earned during a single period. \n\nIn other words, with compound interest, your money grows at an increasing rate over time because it earns interest not just on the initial deposit but also on any previous interest accumulated. This results in a higher total value compared to simple interest for the same amount of principal and rate.\n\nFor example, if you invest $100 with an annual interest rate of 5% (simple interest) and leave it for one year, after one year, you would have $105 ($100 + $5). However, if you had invested the same amount at a 5% annual interest rate compounded annually, your money would grow to $107.20 ($100 * (1 + 0.05)^1) after one year. This is because the interest earned in the first year is added back to your principal for the second year, leading to a higher total amount.", images=None, tool_calls=None)}, id='run-3a71822d-690b-49f0-899d-d4b21980c94f-0', usage_metadata={'input_tokens': 225, 'output_tokens': 247, 'total_tokens': 472}), HumanMessage(content='explain the definition of compound interest', additional_kwargs={}, response_metadata={}, id='03a3e2e6-e77c-4f61-9edf-20bb26357e53')]
INFO 2025-04-13 12:09:07,182 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 12:09:07,193 - Processing request of type CallToolRequest
INFO 2025-04-13 12:09:07,193 - Compound interest -> Principal: 1000.0, Rate: 3.75
INFO 2025-04-13 12:09:07,531 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 12:09:07,533 - [AIMessage(content='The compound interest for a principal of 1000 at a rate of 3.75% per year is approximately $1,037.50.', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T16:09:07.531146164Z', 'done': True, 'done_reason': 'stop', 'total_duration': 335663713, 'load_duration': 6423396, 'prompt_eval_count': 289, 'prompt_eval_duration': 39621454, 'eval_count': 37, 'eval_duration': 285564222, 'message': Message(role='assistant', content='The compound interest for a principal of 1000 at a rate of 3.75% per year is approximately $1,037.50.', images=None, tool_calls=None)}, id='run-be2948e7-7d6e-453a-9664-b6d8dde52047-0', usage_metadata={'input_tokens': 289, 'output_tokens': 37, 'total_tokens': 326}), ToolMessage(content='1037.5', name='yearly_compound_interest', id='c9efadd2-3c8c-40b0-be34-93af5aab986a', tool_call_id='b7ae46e6-8914-4960-b596-bb2bb0cce231'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T16:09:07.190388182Z', 'done': True, 'done_reason': 'stop', 'total_duration': 287410324, 'load_duration': 5683334, 'prompt_eval_count': 241, 'prompt_eval_duration': 40192209, 'eval_count': 35, 'eval_duration': 240304994, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-af8e8189-b525-4fc9-af51-6a3338e19ebd-0', tool_calls=[{'name': 'yearly_compound_interest', 'args': {'principal': 1000, 'rate': 3.75}, 'id': 'b7ae46e6-8914-4960-b596-bb2bb0cce231', 'type': 'tool_call'}], usage_metadata={'input_tokens': 241, 'output_tokens': 35, 'total_tokens': 276}), HumanMessage(content='what is the compound interest for a principal of 1000 at rate 3.75 ?', additional_kwargs={}, response_metadata={}, id='89096fbd-19af-4a16-9540-e035a9d4e183')]
INFO 2025-04-13 12:09:07,760 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 12:09:07,776 - Processing request of type CallToolRequest
INFO 2025-04-13 12:09:07,776 - Executing shell command: free -m
INFO 2025-04-13 12:09:08,391 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 12:09:08,393 - [AIMessage(content='The system has a total of 64,222 bytes of memory. The used amount is 9,178 bytes, the free amount is 47,677 bytes, and there are shared buffers with 151 bytes of cache usage. The available memory for swap is 15,257 bytes.', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T16:09:08.391432514Z', 'done': True, 'done_reason': 'stop', 'total_duration': 609505861, 'load_duration': 4779022, 'prompt_eval_count': 330, 'prompt_eval_duration': 50039311, 'eval_count': 73, 'eval_duration': 550864336, 'message': Message(role='assistant', content='The system has a total of 64,222 bytes of memory. The used amount is 9,178 bytes, the free amount is 47,677 bytes, and there are shared buffers with 151 bytes of cache usage. The available memory for swap is 15,257 bytes.', images=None, tool_calls=None)}, id='run-2924e9d9-9d0f-43c8-a8a2-409b34ad7d30-0', usage_metadata={'input_tokens': 330, 'output_tokens': 73, 'total_tokens': 403}), ToolMessage(content='               total        used        free      shared  buff/cache   available\nMem:           64222        9178       47677         151        8224       55043\nSwap:          15257           0       15257\n', name='execute_shell_command', id='54260c02-0158-4684-9cf4-3f4b54ffa395', tool_call_id='22df639e-4a76-4c1c-9d04-56bf2670f82c'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T16:09:07.772932152Z', 'done': True, 'done_reason': 'stop', 'total_duration': 237102765, 'load_duration': 6630294, 'prompt_eval_count': 230, 'prompt_eval_duration': 32947181, 'eval_count': 27, 'eval_duration': 196225453, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-41b782eb-3be8-4aa6-8159-37e73ce14f28-0', tool_calls=[{'name': 'execute_shell_command', 'args': {'command': 'free -m'}, 'id': '22df639e-4a76-4c1c-9d04-56bf2670f82c', 'type': 'tool_call'}], usage_metadata={'input_tokens': 230, 'output_tokens': 27, 'total_tokens': 257}), HumanMessage(content='Execute the free shell command to find how much system memory', additional_kwargs={}, response_metadata={}, id='007cf4c8-28e8-4643-8b4c-0973cb46aea0')]

BOOM - it is evident from the above Output.3 that the LLM app was able to multiple tools exposed by the different MCP servers.

Until now we have used the stdio transport as the mode off communication between the MCP Client and the MCP Client. As indicated earlier, the other transport mode is the sse transport. In order to use this mode, we will need a web server with SSE enabled.

For this demonstration, we will leverage to the Starlette framework along with the uvicorn server.

The following is our MCP Server code in Python using the sse transport:


interest_mcp_server2.py

#
# @Author: Bhaskar S
# @Blog:   https://www.polarsparc.com
# @Date:   12 April 2025
#

import logging
import uvicorn

from mcp.server.fastmcp import FastMCP
from mcp.server.sse import SseServerTransport
from starlette.requests import Request
from starlette.routing import Mount, Route
from starlette.applications import Starlette

logging.basicConfig(format='%(levelname)s %(asctime)s - %(message)s', level=logging.INFO)

logger = logging.getLogger('interest_mcp_server2')

mcp = FastMCP('InterestCalculator')

@mcp.tool()
def yearly_simple_interest(principal: float, rate:float) -> float:
  """Tool to compute simple interest rate for a year."""
  logger.info(f'Simple interest -> Principal: {principal}, Rate: {rate}')
  return principal * rate / 100.00

@mcp.tool()
def yearly_compound_interest(principal: float, rate:float) -> float:
  """Tool to compute compound interest rate for a year."""
  logger.info(f'Compound interest -> Principal: {principal}, Rate: {rate}')
  return principal * (1 + rate / 100.0)

if __name__ == "__main__":
  logger.info(f'Starting the interest calculator MCP server using SSE ...')

  async def handle_sse(request: Request):
    async with sse.connect_sse(
      request.scope, request.receive, request._send
    ) as (read_stream, write_stream):
      await mcp._mcp_server.run(
        read_stream, write_stream, mcp._mcp_server.create_initialization_options()
      )

  sse = SseServerTransport('/messages/')

  app = Starlette(
    routes=[
      Route("/sse", endpoint=handle_sse),
      Mount("/messages/", app=sse.handle_post_message),
    ]
  )

  uvicorn.run(app, host='192.168.1.25', port=8000)

To execute the above Python code, execute the following command in a terminal window:


$ python interest_mcp_server2.py


The following would be the typical output:


Output.4

INFO 2025-04-13 14:02:02,761 - Starting the interest calculator MCP server using SSE ...
INFO:     Started server process [124909]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://192.168.1.25:8000 (Press CTRL+C to quit)

The following is our MCP Host LLM app code in Python, which invokes multiple tools, one of which is exposed as a network service:


multi_mcp_client2.py

#
# @Author: Bhaskar S
# @Blog:   https://www.polarsparc.com
# @Date:   12 April 2025
#

from dotenv import load_dotenv, find_dotenv
from langchain_ollama import ChatOllama
from  langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent

import asyncio
import logging
import os

logging.basicConfig(format='%(levelname)s %(asctime)s - %(message)s', level=logging.INFO)

logger = logging.getLogger('multi_mcp_client2')

load_dotenv(find_dotenv())

home_dir = os.getenv('HOME')
llm_temperature = float(os.getenv('LLM_TEMPERATURE'))
ollama_model = os.getenv('OLLAMA_MODEL')
ollama_base_url = os.getenv('OLLAMA_BASE_URL')
py_project_dir = os.getenv('PY_PROJECT_DIR')
sse_base_url = os.getenv('SSE_BASE_URL')

ollama_chat_llm = ChatOllama(base_url=ollama_base_url, model=ollama_model, temperature=llm_temperature)

async def main():
  async with MultiServerMCPClient() as client:
    await client.connect_to_server(
      'InterestCalculator',
      url=sse_base_url,
      transport='sse',
    )

    await client.connect_to_server(
      'ShellCommandExecutor',
      command='python',
      args=[home_dir + py_project_dir + 'shell_mcp_server.py'],
      transport='stdio',
    )

    tools = client.get_tools()

    logger.info(f'Loaded Multiple MCP Tools -> {tools}')

    # Initialize a ReACT agent with multiple tools
    agent = create_react_agent(ollama_chat_llm, tools)

    # Case - 1 : Compound interest definition
    agent_response_1 = await agent.ainvoke(
      {'messages': 'explain the definition of compound interest'})
    logger.info(agent_response_1['messages'][::-1])

    # Case - 2 : Compound interest calculation
    agent_response_2 = await agent.ainvoke(
      {'messages': 'what is the compound interest for a principal of 1000 at rate 3.75 ?'})
    logger.info(agent_response_2['messages'][::-1])

    # Case - 3 : Execute a shell command
    agent_response_3 = await agent.ainvoke(
      {'messages': 'Execute the free shell command to find how much system memory'})
    logger.info(agent_response_3['messages'][::-1])

if __name__ == '__main__':
  asyncio.run(main())

To execute the above Python code, execute the following command in a terminal window:


$ python multi_mcp_client2.py


The following would be the typical output:


Output.5

INFO 2025-04-13 14:09:17,172 - Connecting to SSE endpoint: http://192.168.1.25:8000/sse
INFO 2025-04-13 14:09:17,194 - HTTP Request: GET http://192.168.1.25:8000/sse "HTTP/1.1 200 OK"
INFO 2025-04-13 14:09:17,195 - Received endpoint URL: http://192.168.1.25:8000/messages/?session_id=9898861e27c04ee0b5e243e98216c9f7
INFO 2025-04-13 14:09:17,195 - Starting post writer with endpoint URL: http://192.168.1.25:8000/messages/?session_id=9898861e27c04ee0b5e243e98216c9f7
INFO 2025-04-13 14:09:17,197 - HTTP Request: POST http://192.168.1.25:8000/messages/?session_id=9898861e27c04ee0b5e243e98216c9f7 "HTTP/1.1 202 Accepted"
INFO 2025-04-13 14:09:17,198 - HTTP Request: POST http://192.168.1.25:8000/messages/?session_id=9898861e27c04ee0b5e243e98216c9f7 "HTTP/1.1 202 Accepted"
INFO 2025-04-13 14:09:17,199 - HTTP Request: POST http://192.168.1.25:8000/messages/?session_id=9898861e27c04ee0b5e243e98216c9f7 "HTTP/1.1 202 Accepted"
INFO 2025-04-13 14:09:17,472 - Starting the shell executor MCP server...
INFO 2025-04-13 14:09:17,477 - Processing request of type ListToolsRequest
INFO 2025-04-13 14:09:17,477 - Loaded Multiple MCP Tools -> [StructuredTool(name='yearly_simple_interest', description='Tool to compute simple interest rate for a year.', args_schema={'properties': {'principal': {'title': 'Principal', 'type': 'number'}, 'rate': {'title': 'Rate', 'type': 'number'}}, 'required': ['principal', 'rate'], 'title': 'yearly_simple_interestArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x72c72802a7a0>), StructuredTool(name='yearly_compound_interest', description='Tool to compute compound interest rate for a year.', args_schema={'properties': {'principal': {'title': 'Principal', 'type': 'number'}, 'rate': {'title': 'Rate', 'type': 'number'}}, 'required': ['principal', 'rate'], 'title': 'yearly_compound_interestArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x72c72802a840>), StructuredTool(name='execute_shell_command', description='Tool to execute shell commands', args_schema={'properties': {'command': {'title': 'Command', 'type': 'string'}}, 'required': ['command'], 'title': 'execute_shell_commandArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=.call_tool at 0x72c72802afc0>)]
INFO 2025-04-13 14:09:21,695 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 14:09:21,697 - [AIMessage(content="Compound interest is a type of interest calculated on the initial principal amount and also on any accumulated interest from previous periods. It's a powerful tool that can significantly increase the value of an investment over time, especially when compounded regularly. Here's how it works:\n\n1. **Simple Interest**: This is the simplest form of interest calculation where you only pay back the principal amount and no additional interest for each period. For example, if you invest $100 at a 5% annual interest rate (simple interest), after one year, you would have $105 ($100 + $5).\n\n2. **Compound Interest**: In this case, the interest is calculated on both the principal amount and any accumulated interest from previous periods. This means that for each compounding period, your total investment grows by a certain percentage (the annual rate of compounding) because some of your initial principal has already been added to the new principal.\n\nFor instance, if you have an investment of $100 with a 5% annual interest rate compounded annually, after one year, you would have:\n\n- Principal = $100\n- Interest from this period = $5 (since $100 * 5% = $5)\n- New Principal = $100 + $5 = $105\n\nAnd the interest for the next period would be calculated on the new principal of $105, which is $6.25 ($105 * 5%) because you've already earned $5 in the previous year. This process continues until the end of the compounding period.", additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T18:09:21.694022052Z', 'done': True, 'done_reason': 'stop', 'total_duration': 4206780120, 'load_duration': 1221121502, 'prompt_eval_count': 225, 'prompt_eval_duration': 229759310, 'eval_count': 350, 'eval_duration': 2754143527, 'message': Message(role='assistant', content="Compound interest is a type of interest calculated on the initial principal amount and also on any accumulated interest from previous periods. It's a powerful tool that can significantly increase the value of an investment over time, especially when compounded regularly. Here's how it works:\n\n1. **Simple Interest**: This is the simplest form of interest calculation where you only pay back the principal amount and no additional interest for each period. For example, if you invest $100 at a 5% annual interest rate (simple interest), after one year, you would have $105 ($100 + $5).\n\n2. **Compound Interest**: In this case, the interest is calculated on both the principal amount and any accumulated interest from previous periods. This means that for each compounding period, your total investment grows by a certain percentage (the annual rate of compounding) because some of your initial principal has already been added to the new principal.\n\nFor instance, if you have an investment of $100 with a 5% annual interest rate compounded annually, after one year, you would have:\n\n- Principal = $100\n- Interest from this period = $5 (since $100 * 5% = $5)\n- New Principal = $100 + $5 = $105\n\nAnd the interest for the next period would be calculated on the new principal of $105, which is $6.25 ($105 * 5%) because you've already earned $5 in the previous year. This process continues until the end of the compounding period.", images=None, tool_calls=None)}, id='run-3569b9ac-8cda-4196-b330-bbd315ecbaec-0', usage_metadata={'input_tokens': 225, 'output_tokens': 350, 'total_tokens': 575}), HumanMessage(content='explain the definition of compound interest', additional_kwargs={}, response_metadata={}, id='68e3e2da-7d30-4c25-9b6e-2d3cdc879d2f')]
INFO 2025-04-13 14:09:21,999 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 14:09:22,012 - HTTP Request: POST http://192.168.1.25:8000/messages/?session_id=9898861e27c04ee0b5e243e98216c9f7 "HTTP/1.1 202 Accepted"
INFO 2025-04-13 14:09:22,366 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 14:09:22,400 - [AIMessage(content='The compound interest for a principal of $1000 at a rate of 3.75% per year is approximately $1,037.50.', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T18:09:22.365832725Z', 'done': True, 'done_reason': 'stop', 'total_duration': 350469941, 'load_duration': 8795119, 'prompt_eval_count': 289, 'prompt_eval_duration': 46233452, 'eval_count': 37, 'eval_duration': 290352383, 'message': Message(role='assistant', content='The compound interest for a principal of $1000 at a rate of 3.75% per year is approximately $1,037.50.', images=None, tool_calls=None)}, id='run-556cd53b-f38e-4549-af34-2fb333cd9b7f-0', usage_metadata={'input_tokens': 289, 'output_tokens': 37, 'total_tokens': 326}), ToolMessage(content='1037.5', name='yearly_compound_interest', id='fd0e7bec-a339-4bda-9bd6-981f59ab43a1', tool_call_id='abf08575-e66a-4b80-8b80-e042ea5156c3'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T18:09:22.008555615Z', 'done': True, 'done_reason': 'stop', 'total_duration': 309797162, 'load_duration': 4476504, 'prompt_eval_count': 241, 'prompt_eval_duration': 39846647, 'eval_count': 35, 'eval_duration': 264010946, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-a613074b-f9ea-4ae7-88fe-07e3718ef033-0', tool_calls=[{'name': 'yearly_compound_interest', 'args': {'principal': 1000, 'rate': 3.75}, 'id': 'abf08575-e66a-4b80-8b80-e042ea5156c3', 'type': 'tool_call'}], usage_metadata={'input_tokens': 241, 'output_tokens': 35, 'total_tokens': 276}), HumanMessage(content='what is the compound interest for a principal of 1000 at rate 3.75 ?', additional_kwargs={}, response_metadata={}, id='aef4e123-e2b7-4df6-ae88-b20f568b9f4a')]
INFO 2025-04-13 14:09:22,661 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 14:09:22,672 - Processing request of type CallToolRequest
INFO 2025-04-13 14:09:22,672 - Executing shell command: free -m
INFO 2025-04-13 14:09:23,169 - HTTP Request: POST http://192.168.1.25:11434/api/chat "HTTP/1.1 200 OK"
INFO 2025-04-13 14:09:23,171 - [AIMessage(content='The total system memory is 64222 bytes, with used (available) 8912 bytes. The shared memory is 47739 bytes and the buffer/cache is 8424 bytes. There are no swap files in use.', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T18:09:23.168976868Z', 'done': True, 'done_reason': 'stop', 'total_duration': 491777277, 'load_duration': 7048507, 'prompt_eval_count': 330, 'prompt_eval_duration': 55078090, 'eval_count': 58, 'eval_duration': 425383285, 'message': Message(role='assistant', content='The total system memory is 64222 bytes, with used (available) 8912 bytes. The shared memory is 47739 bytes and the buffer/cache is 8424 bytes. There are no swap files in use.', images=None, tool_calls=None)}, id='run-3d476b30-de7c-4e9c-b7d0-dd0f852898b7-0', usage_metadata={'input_tokens': 330, 'output_tokens': 58, 'total_tokens': 388}), ToolMessage(content='               total        used        free      shared  buff/cache   available\nMem:           64222        8912       47739         147        8424       55309\nSwap:          15257           0       15257\n', name='execute_shell_command', id='10c6e82b-be8e-4626-a14c-4064a875f20f', tool_call_id='3629aadf-5f11-4bcb-85f6-83834240de42'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'granite3.1-moe:1b', 'created_at': '2025-04-13T18:09:22.668700619Z', 'done': True, 'done_reason': 'stop', 'total_duration': 265012706, 'load_duration': 9351983, 'prompt_eval_count': 230, 'prompt_eval_duration': 35290845, 'eval_count': 27, 'eval_duration': 218086931, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-670e9ec2-5087-4835-9ce6-faf17e3ab53f-0', tool_calls=[{'name': 'execute_shell_command', 'args': {'command': 'free -m'}, 'id': '3629aadf-5f11-4bcb-85f6-83834240de42', 'type': 'tool_call'}], usage_metadata={'input_tokens': 230, 'output_tokens': 27, 'total_tokens': 257}), HumanMessage(content='Execute the free shell command to find how much system memory', additional_kwargs={}, response_metadata={}, id='5352ed8a-04b6-4b13-bce2-9dbbbbe921ec')]

WALLA - it is evident from the above Output.5 that the LLM app was able to sucessfully able to communicate with the MCP server using both transport modes !!!

With this, we conclude the various hands-on demonstrations on using the MCP framework for building and deploying agentic LLM apps !!!




联系我们 contact @ memedata.com