Rand Stats

MCP::Client

zef:antononcube

MCP::Client

This Raku package, "MCP::Client", implements a thin Model Context Protocol (MCP) client.

"MCP::Client" provides the class MCP::Client which creates from MCP server's methods LLM::Tool objects that can be used with Raku's Large Language Model (LLM) framework implemented with "LLM::Functions", "LLM::Prompts", "Text::SubParsers"; see [AA1÷4, AAp1÷3].


Installation

From Zef ecosystem:

zef install MCP::Client

From GitHub:

zef install https://github.com/antononcube/Raku-MCP-Client.git

Example

This section has a complete usage example.

The MCP server is created and run in Python -- see the file "simple_mcp_server.py". That MCP server provides the methods add, random_words_list, random_pet_names_list, and random_pretentious_job_title_list. The corresponding Python packages have to be installed -- see the from ... import ... statements in that Python file.

Remark: The Raku file "MCP-client-demo.raku" has all the code below.

Packages

Load the packages used below:

use LLM::Functions;
use LLM::Prompts;
use Text::SubParsers;
use Data::Translators;

use MCP::Client;

Setup and initialization

Setup MCP server process creation command elements:

my $python = $*HOME ~ '/miniforge3/bin/python';
my $mcp-server-file =  $*HOME ~ '/Python/MCP/simple_mcp_server.py';

die "Cannot find Python executable ⎡$python⎦." unless $python.IO.f;
die "Cannot find MCP server file ⎡$mcp-server-file⎦." unless $mcp-server-file.IO.f;

# say "Using the Python executable ⎡$python⎦.";
# say "Using the MCP server file ⎡$mcp-server-file⎦.";

Create the MCP client object:

my Bool:D $echo = False;
my Numeric:D $sleep = 0.7;
my $client = MCP::Client.new(:$echo, :$sleep);

sink $client.start([$python, '-i', $mcp-server-file]);

Initialize the client:

$client.initialize;
# True

Tools discovery and creation

Get the MCP server tools list (and tabulate parts of it):

my @mcp-tools = |$client.list-tools();
@mcp-tools
andthen .&to-html(field-names => <name description>, align => 'left').subst("\n", '<br>', :g)
namedescription
add
Add two numbers.

Args:
a: First number.
b: Second number.
random_words_list
Generate a list of random words.

Args:
n: number of random words do generate.
kind: kind of word, one of "Any", "Common", "Known", "Stopword".
random_pet_names_list
Generate a list of random pet names.

Args:
n: number of random pet names do generate.
species: species, one of "Cat", "Dog", "Goat", "Pig", or Non.
random_pretentious_job_title_list
Generate a list of random pretentious job titles.

Args:
n: number of random pretentious job titles.
lang: language, one of "Bulgarian", "English", or None.

Make LLM::Tool objects:

my @tools = @mcp-tools.map({ $client.to-llm-tool($_) });
# [LLMTool(add, 
#     Add two numbers.
# 
#     Args:
#         a: First number.
#         b: Second number.
#     ) LLMTool(random_words_list, 
#     Generate a list of random words.
# 
#     Args:
#         n: number of random words do generate.
#         kind: kind of word, one of "Any", "Common", "Known", "Stopword".
#     ) LLMTool(random_pet_names_list, 
#     Generate a list of random pet names.
# 
#     Args:
#         n: number of random pet names do generate.
#         species: species, one of "Cat", "Dog", "Goat", "Pig", or Non.
#     ) LLMTool(random_pretentious_job_title_list, 
#     Generate a list of random pretentious job titles.
# 
#     Args:
#         n: number of random pretentious job titles.
#         lang: language, one of "Bulgarian", "English", or None.
#     )]

LLM invocations

Using an LLM request generate a list of random words (via a MCP server provided tool):

my $conf = llm-configuration('ChatGPT', model => 'gpt-4.1-mini', :@tools);
say llm-synthesize('Generate a list of 12 random cat pet names.', e => $conf);
# Here is a list of 12 random cat pet names:
# 1. Cricket
# 2. Habibi
# 3. Phoebe Cent
# 4. Oliver
# 5. Qwerty
# 6. Kat
# 7. Cleopatra
# 8. Emma
# 9. Armani
# 10. Olive
# 11. Doon
# 12. Cutie

Generate a JSON object of random pretentious jobs, and deserialize and print it:

my $res = llm-synthesize([
    'Generate a list of six random bullshit jobs, in English, and three in Bulgarian.)',
    llm-prompt('NothingElse')('JSON')
    ],
    e => $conf,
    form => sub-parser('JSON'):drop
);

$res
==> to-html(align => 'left')
Bulgarian
  • Корпоративен Плановик по Комуникации
  • Водещ Синергист по Качество
  • Корпоративен Архитект на Отговори
English
  • Investor Ideation Producer
  • Investor Solutions Strategist
  • National Impact Planner
  • Investor Assurance Consultant
  • Relational Branding Developer
  • International Implementation Executive

Stopping the MCP server process

Kill the MCP client process:

$client.kill;
# 1

References

Articles, blog posts

[AA1] Anton Antonov, "LLM function calling workflows (Part 1, OpenAI)", (2025), RakuForPrediction at WordPress.

[AA2] Anton Antonov, "LLM function calling workflows (Part 2, Google's Gemini)", (2025), RakuForPrediction at WordPress.

[AA3] Anton Antonov, "LLM function calling workflows (Part 3, Facilitation)", (2025), RakuForPrediction at WordPress.

[AA4] Anton Antonov, "LLM function calling workflows (Part 4, Universal specs)", (2025), RakuForPrediction at WordPress.

Packages

[AAp1] Anton Antonov, LLM::Functions, Raku package, (2023-2026), GitHub/antononcube.

[AAp2] Anton Antonov, LLM::Prompts, Raku package, (2023-2026), GitHub/antononcube.

[AAp3] Anton Antonov, Text::SubParsers, Raku package, (2023), GitHub/antononcube.