Eddig láthattad, hogyan hozhatsz létre szervert és klienst. A kliens képes volt kifejezetten hívni a szervert, hogy listázza annak eszközeit, erőforrásait és promptjait. Ez azonban nem túl praktikus megközelítés. A felhasználód az ügynöki korszakban él, és elvárja, hogy természetes nyelven használhassa a promptokat és kommunikálhasson egy LLM-mel. A felhasználót nem érdekli, hogy MCP-t használsz-e a képességeid tárolására, de elvárja, hogy természetes nyelven tudjon interakcióba lépni. Hogyan oldjuk meg ezt? A megoldás az, hogy hozzáadunk egy LLM-et a klienshez.
Ebben a leckében arra koncentrálunk, hogyan adjunk hozzá egy LLM-et a klienshez, és bemutatjuk, hogy ez hogyan biztosít sokkal jobb élményt a felhasználó számára.
A lecke végére képes leszel:
- Létrehozni egy LLM-et használó klienst.
- Zökkenőmentesen interakcióba lépni egy MCP szerverrel LLM segítségével.
- Jobb felhasználói élményt nyújtani a kliens oldalon.
Próbáljuk megérteni, milyen megközelítést kell alkalmaznunk. Egy LLM hozzáadása egyszerűnek hangzik, de tényleg így van?
Így fog a kliens interakcióba lépni a szerverrel:
-
Kapcsolatot létesít a szerverrel.
-
Listázza a képességeket, promptokat, erőforrásokat és eszközöket, majd elmenti azok sémáját.
-
Hozzáad egy LLM-et, és átadja a mentett képességeket és azok sémáját olyan formátumban, amelyet az LLM megért.
-
Kezeli a felhasználói promptot úgy, hogy átadja azt az LLM-nek, az eszközökkel együtt, amelyeket a kliens listázott.
Nagyszerű, most már értjük, hogyan tudjuk ezt magas szinten megvalósítani. Próbáljuk ki az alábbi gyakorlatban.
Ebben a gyakorlatban megtanuljuk, hogyan adjunk hozzá egy LLM-et a kliensünkhöz.
GitHub token létrehozása egyszerű folyamat. Így teheted meg:
- Menj a GitHub Beállításokhoz – Kattints a profilképedre a jobb felső sarokban, majd válaszd a Beállítások lehetőséget.
- Navigálj a Fejlesztői Beállításokhoz – Görgess le, és kattints a Fejlesztői Beállítások lehetőségre.
- Válaszd a Személyes Hozzáférési Tokeneket – Kattints a Személyes hozzáférési tokenekre, majd a "Új token létrehozása" gombra.
- Konfiguráld a Tokenedet – Adj hozzá egy megjegyzést referenciaként, állíts be lejárati dátumot, és válaszd ki a szükséges jogosultságokat.
- Generáld és másold a Tokenedet – Kattints a "Token generálása" gombra, és győződj meg róla, hogy azonnal lemásolod, mivel később nem fogod tudni újra megtekinteni.
Először hozzuk létre a kliensünket:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import OpenAI from "openai";
import { z } from "zod"; // Import zod for schema validation
class MCPClient {
private openai: OpenAI;
private client: Client;
constructor(){
this.openai = new OpenAI({
baseURL: "https://models.inference.ai.azure.com",
apiKey: process.env.GITHUB_TOKEN,
});
this.client = new Client(
{
name: "example-client",
version: "1.0.0"
},
{
capabilities: {
prompts: {},
resources: {},
tools: {}
}
}
);
}
}A fenti kódban:
- Importáltuk a szükséges könyvtárakat.
- Létrehoztunk egy osztályt két taggal,
clientésopenai, amelyek segítenek a kliens kezelésében és az LLM-mel való interakcióban. - Konfiguráltuk az LLM példányunkat, hogy a GitHub Modelleket használja, a
baseUrlbeállításával az inference API-ra mutatva.
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="mcp", # Executable
args=["run", "server.py"], # Optional command line arguments
env=None, # Optional environment variables
)
async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(
read, write
) as session:
# Initialize the connection
await session.initialize()
if __name__ == "__main__":
import asyncio
asyncio.run(run())A fenti kódban:
- Importáltuk az MCP-hez szükséges könyvtárakat.
- Létrehoztunk egy klienst.
using Azure;
using Azure.AI.Inference;
using Azure.Identity;
using System.Text.Json;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;
using System.Text.Json;
var clientTransport = new StdioClientTransport(new()
{
Name = "Demo Server",
Command = "/workspaces/mcp-for-beginners/03-GettingStarted/02-client/solution/server/bin/Debug/net8.0/server",
Arguments = [],
});
await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport);Először hozzá kell adnod a LangChain4j függőségeket a pom.xml fájlodhoz. Add hozzá ezeket a függőségeket az MCP integráció és a GitHub Modellek támogatásának engedélyezéséhez:
<properties>
<langchain4j.version>1.0.0-beta3</langchain4j.version>
</properties>
<dependencies>
<!-- LangChain4j MCP Integration -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mcp</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- OpenAI Official API Client -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-official</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- GitHub Models Support -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-github-models</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- Spring Boot Starter (optional, for production apps) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>Ezután hozd létre a Java kliens osztályodat:
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.http.HttpMcpTransport;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openaiofficial.OpenAiOfficialChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.tool.ToolProvider;
import java.time.Duration;
import java.util.List;
public class LangChain4jClient {
public static void main(String[] args) throws Exception { // Configure the LLM to use GitHub Models
ChatLanguageModel model = OpenAiOfficialChatModel.builder()
.isGitHubModels(true)
.apiKey(System.getenv("GITHUB_TOKEN"))
.timeout(Duration.ofSeconds(60))
.modelName("gpt-4.1-nano")
.build();
// Create MCP transport for connecting to server
McpTransport transport = new HttpMcpTransport.Builder()
.sseUrl("http://localhost:8080/sse")
.timeout(Duration.ofSeconds(60))
.logRequests(true)
.logResponses(true)
.build();
// Create MCP client
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.build();
}
}A fenti kódban:
- Hozzáadtuk a LangChain4j függőségeket: Szükséges az MCP integrációhoz, az OpenAI hivatalos klienséhez és a GitHub Modellek támogatásához.
- Importáltuk a LangChain4j könyvtárakat: Az MCP integrációhoz és az OpenAI chat modell funkcionalitásához.
- Létrehoztunk egy
ChatLanguageModel-t: Konfiguráltuk, hogy a GitHub Modelleket használja a GitHub tokeneddel. - Beállítottuk a HTTP transportot: Server-Sent Events (SSE) használatával kapcsolódtunk az MCP szerverhez.
- Létrehoztunk egy MCP klienst: Amely kezeli a kommunikációt a szerverrel.
- Használtuk a LangChain4j beépített MCP támogatását: Ami egyszerűsíti az integrációt az LLM-ek és MCP szerverek között.
Ez a példa feltételezi, hogy van egy Rust alapú MCP szervered futtatva. Ha nincs, térj vissza az 01-first-server leckéhez, hogy létrehozd a szervert.
Miután megvan a Rust MCP szervered, nyiss meg egy terminált, és navigálj ugyanabba a könyvtárba, mint a szerver. Ezután futtasd az alábbi parancsot egy új LLM kliens projekt létrehozásához:
mkdir calculator-llmclient
cd calculator-llmclient
cargo initAdd hozzá a következő függőségeket a Cargo.toml fájlodhoz:
[dependencies]
async-openai = { version = "0.29.0", features = ["byot"] }
rmcp = { version = "0.5.0", features = ["client", "transport-child-process"] }
serde_json = "1.0.141"
tokio = { version = "1.46.1", features = ["rt-multi-thread"] }Note
Nincs hivatalos Rust könyvtár az OpenAI-hoz, azonban az async-openai crate egy közösség által karbantartott könyvtár, amelyet gyakran használnak.
Nyisd meg a src/main.rs fájlt, és cseréld le annak tartalmát az alábbi kódra:
use async_openai::{Client, config::OpenAIConfig};
use rmcp::{
RmcpError,
model::{CallToolRequestParam, ListToolsResult},
service::{RoleClient, RunningService, ServiceExt},
transport::{ConfigureCommandExt, TokioChildProcess},
};
use serde_json::{Value, json};
use std::error::Error;
use tokio::process::Command;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Initial message
let mut messages = vec![json!({"role": "user", "content": "What is the sum of 3 and 2?"})];
// Setup OpenAI client
let api_key = std::env::var("OPENAI_API_KEY")?;
let openai_client = Client::with_config(
OpenAIConfig::new()
.with_api_base("https://models.github.ai/inference/chat")
.with_api_key(api_key),
);
// Setup MCP client
let server_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.join("calculator-server");
let mcp_client = ()
.serve(
TokioChildProcess::new(Command::new("cargo").configure(|cmd| {
cmd.arg("run").current_dir(server_dir);
}))
.map_err(RmcpError::transport_creation::<TokioChildProcess>)?,
)
.await?;
// TODO: Get MCP tool listing
// TODO: LLM conversation with tool calls
Ok(())
}Ez a kód beállít egy alapvető Rust alkalmazást, amely kapcsolódik egy MCP szerverhez és a GitHub Modellekhez LLM interakciókhoz.
Important
Győződj meg róla, hogy beállítod az OPENAI_API_KEY környezeti változót a GitHub tokeneddel, mielőtt futtatnád az alkalmazást.
Nagyszerű, a következő lépésben listázzuk a szerver képességeit.
Hozzáadjuk az alábbi függvényt a main.rs fájlhoz:
async fn call_llm(
client: &Client<OpenAIConfig>,
messages: &[Value],
tools: &ListToolsResult,
) -> Result<Value, Box<dyn Error>> {
let response = client
.completions()
.create_byot(json!({
"messages": messages,
"model": "openai/gpt-4.1",
"tools": format_tools(tools).await?,
}))
.await?;
Ok(response)
}Ez a függvény fogadja az LLM kliensét, az üzenetek listáját (beleértve a felhasználói promptot), az MCP szerver eszközeit, és elküldi a kérést az LLM-nek, majd visszaadja a választ.
Az LLM válasza tartalmazni fog egy choices tömböt. Feldolgoznunk kell az eredményt, hogy lássuk, vannak-e benne tool_calls. Ez jelzi, hogy az LLM egy adott eszközt szeretne meghívni argumentumokkal. Adjuk hozzá az alábbi kódot a main.rs fájl aljára, hogy definiáljunk egy függvényt az LLM válaszának kezelésére:
async fn process_llm_response(
llm_response: &Value,
mcp_client: &RunningService<RoleClient, ()>,
openai_client: &Client<OpenAIConfig>,
mcp_tools: &ListToolsResult,
messages: &mut Vec<Value>,
) -> Result<(), Box<dyn Error>> {
let Some(message) = llm_response
.get("choices")
.and_then(|c| c.as_array())
.and_then(|choices| choices.first())
.and_then(|choice| choice.get("message"))
else {
return Ok(());
};
// Print content if available
if let Some(content) = message.get("content").and_then(|c| c.as_str()) {
println!("🤖 {}", content);
}
// Handle tool calls
if let Some(tool_calls) = message.get("tool_calls").and_then(|tc| tc.as_array()) {
messages.push(message.clone()); // Add assistant message
// Execute each tool call
for tool_call in tool_calls {
let (tool_id, name, args) = extract_tool_call_info(tool_call)?;
println!("⚡ Calling tool: {}", name);
let result = mcp_client
.call_tool(CallToolRequestParam {
name: name.into(),
arguments: serde_json::from_str::<Value>(&args)?.as_object().cloned(),
})
.await?;
// Add tool result to messages
messages.push(json!({
"role": "tool",
"tool_call_id": tool_id,
"content": serde_json::to_string_pretty(&result)?
}));
}
// Continue conversation with tool results
let response = call_llm(openai_client, messages, mcp_tools).await?;
Box::pin(process_llm_response(
&response,
mcp_client,
openai_client,
mcp_tools,
messages,
))
.await?;
}
Ok(())
}Ha tool_calls található, a függvény kinyeri az eszköz információit, meghívja az MCP szervert az eszköz kérésével, és hozzáadja az eredményeket a beszélgetési üzenetekhez. Ezután folytatja a beszélgetést az LLM-mel, és az üzenetek frissülnek az asszisztens válaszával és az eszközhívás eredményeivel.
Az MCP hívásokhoz szükséges eszközhívási információk kinyeréséhez adjunk hozzá egy segédfüggvényt, amely mindent kinyer, ami a híváshoz szükséges. Adjuk hozzá az alábbi kódot a main.rs fájl aljára:
fn extract_tool_call_info(tool_call: &Value) -> Result<(String, String, String), Box<dyn Error>> {
let tool_id = tool_call
.get("id")
.and_then(|id| id.as_str())
.unwrap_or("")
.to_string();
let function = tool_call.get("function").ok_or("Missing function")?;
let name = function
.get("name")
.and_then(|n| n.as_str())
.unwrap_or("")
.to_string();
let args = function
.get("arguments")
.and_then(|a| a.as_str())
.unwrap_or("{}")
.to_string();
Ok((tool_id, name, args))
}Most, hogy minden részlet a helyén van, kezelhetjük a kezdeti felhasználói promptot és meghívhatjuk az LLM-et. Frissítsük a main függvényt az alábbi kóddal:
// LLM conversation with tool calls
let response = call_llm(&openai_client, &messages, &tools).await?;
process_llm_response(
&response,
&mcp_client,
&openai_client,
&tools,
&mut messages,
)
.await?;Ez lekérdezi az LLM-et a kezdeti felhasználói prompttal, amely két szám összegét kéri, és feldolgozza a választ, hogy dinamikusan kezelje az eszközhívásokat.
Nagyszerű, sikerült!
Vegyük az eddigi gyakorlat kódját, és bővítsük ki a szervert további eszközökkel. Ezután hozzunk létre egy klienst egy LLM-mel, mint a gyakorlatban, és teszteljük különböző promptokkal, hogy megbizonyosodjunk arról, hogy az összes szervereszköz dinamikusan meghívható. Ez a kliensépítési módszer biztosítja, hogy a végfelhasználó nagyszerű élményt kapjon, mivel képes lesz promptokat használni ahelyett, hogy pontos kliensparancsokat kellene megadnia, és nem is kell tudnia az MCP szerver létezéséről.
- Egy LLM hozzáadása a klienshez jobb felhasználói élményt nyújt az MCP szerverekkel való interakció során.
- Az MCP szerver válaszát olyan formátumba kell alakítani, amelyet az LLM megért.
- Java Számológép
- .Net Számológép
- JavaScript Számológép
- TypeScript Számológép
- Python Számológép
- Rust Számológép
Felelősségkizárás:
Ez a dokumentum az Co-op Translator AI fordítási szolgáltatás segítségével készült. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Kritikus információk esetén javasolt a professzionális, emberi fordítás igénybevétele. Nem vállalunk felelősséget a fordítás használatából eredő félreértésekért vagy téves értelmezésekért.