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
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)
| name | description |
|---|
| 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.