Clients are custom applications or scripts that communicate directly with an MCP Server to request resources, tools, and prompts.
Unlike using the inspector tool, which provides a graphical interface for interacting with the server, writing your own client allows for programmatic and automated interactions.
This enables developers to integrate MCP capabilities into their own workflows, automate tasks, and build custom solutions tailored to specific needs.
This lesson introduces the concept of clients within the Model Context Protocol (MCP) ecosystem. You'll learn how to write your own client and have it connect to an MCP Server.
By the end of this lesson, you will be able to:
To write a client, you'll need to do the following:
Now that we understand at high level what we're about to do, let's look at an example next.
Let's have a look at this example client:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
const client = new Client(
{
name: "example-client",
version: "1.0.0"
}
);
await client.connect(transport);
// List prompts
const prompts = await client.listPrompts();
// Get a prompt
const prompt = await client.getPrompt({
name: "example-prompt",
arguments: {
arg1: "value"
}
});
// List resources
const resources = await client.listResources();
// Read a resource
const resource = await client.readResource({
uri: "file:///example.txt"
});
// Call a tool
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
In the preceding code we:
There you have it, a client that can talk to an MCP Server.
Let's take our time in the next exercise section and break down each code snippet and explain what's going on.
As said above, let's take our time explaining the code, and by all means code along if you want.
Let's import the libraries we need, we will need references to a client and to our chosen transport protocol, stdio. stdio is a protocol for things meant to run on your local machine.
SSE is another transport protocol we will show in future chapters but that's your other option.
For now though, let's continue with stdio.
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
For Java, you'll create a client that connects to the MCP server from the previous exercise.
Using the same Java Spring Boot project structure from Getting Started with MCP Server, create a new Java class called SDKClient in the src/main/java/com/microsoft/mcp/sample/client/ folder and add the following imports:
import java.util.Map;
import org.springframework.web.reactive.function.client.WebClient;
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
import io.modelcontextprotocol.spec.McpClientTransport;
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
You will need to add the following dependencies to your Cargo.toml file.
[package]
name = "calculator-client"
version = "0.1.0"
edition = "2024"
[dependencies]
rmcp = { version = "0.5.0", features = ["client", "transport-child-process"] }
serde_json = "1.0.141"
tokio = { version = "1.46.1", features = ["rt-multi-thread"] }
From there, you can import the necessary libraries in your client code.
use rmcp::{
RmcpError,
model::CallToolRequestParam,
service::ServiceExt,
transport::{ConfigureCommandExt, TokioChildProcess},
};
use tokio::process::Command;
Let's move on to instantiation.
We will need to create an instance of the transport and that of our client:
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
const client = new Client(
{
name: "example-client",
version: "1.0.0"
}
);
await client.connect(transport);
In the preceding code we've:
```typescript
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
```
```typescript
const client = new Client(
{
name: "example-client",
version: "1.0.0"
});
```
```typescript
await client.connect(transport);
```
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())
In the preceding code we've:
run that in turn calls stdio_client which starts a client session.run method to asyncio.run.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
var builder = Host.CreateApplicationBuilder(args);
builder.Configuration
.AddEnvironmentVariables()
.AddUserSecrets<Program>();
var clientTransport = new StdioClientTransport(new()
{
Name = "Demo Server",
Command = "dotnet",
Arguments = ["run", "--project", "path/to/file.csproj"],
});
await using var mcpClient = await McpClient.CreateAsync(clientTransport);
In the preceding code we've:
mcpClient. The latter is something we will use to list and invoke features on the MCP Server.Note, in "Arguments", you can either point to the *.csproj* or to the executable.
public class SDKClient {
public static void main(String[] args) {
var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080"));
new SDKClient(transport).run();
}
private final McpClientTransport transport;
public SDKClient(McpClientTransport transport) {
this.transport = transport;
}
public void run() {
var client = McpClient.sync(this.transport).build();
client.initialize();
// Your client logic goes here
}
}
In the preceding code we've:
http://localhost:8080 where our MCP server will be running.run method, we create a synchronous MCP client using the transport and initialize the connection.Note this Rust client assumes the server is a sibling project named "calculator-server" in the same directory. The code below will start the server and connect to it.
async fn main() -> Result<(), RmcpError> {
// Assume the server is a sibling project named "calculator-server" in the same directory
let server_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("failed to locate workspace root")
.join("calculator-server");
let client = ()
.serve(
TokioChildProcess::new(Command::new("cargo").configure(|cmd| {
cmd.arg("run").current_dir(server_dir);
}))
.map_err(RmcpError::transport_creation::<TokioChildProcess>)?,
)
.await?;
// TODO: Initialize
// TODO: List tools
// TODO: Call add tool with arguments = {"a": 3, "b": 2}
client.cancel().await?;
Ok(())
}
Now, we have a client that can connect to should the program be run. However, it doesn't actually list its features so let's do that next:
// List prompts
const prompts = await client.listPrompts();
// List resources
const resources = await client.listResources();
// list tools
const tools = await client.listTools();
# List available resources
resources = await session.list_resources()
print("LISTING RESOURCES")
for resource in resources:
print("Resource: ", resource)
# List available tools
tools = await session.list_tools()
print("LISTING TOOLS")
for tool in tools.tools:
print("Tool: ", tool.name)
Here we list the available resources, list_resources() and tools, list_tools and print them out.
foreach (var tool in await client.ListToolsAsync())
{
Console.WriteLine($"{tool.Name} ({tool.Description})");
}
Above is an example how we can list the tools on the server. For each tool, we then print out its name.
// List and demonstrate tools
ListToolsResult toolsList = client.listTools();
System.out.println("Available Tools = " + toolsList);
// You can also ping the server to verify connection
client.ping();
In the preceding code we've:
listTools() to get all available tools from the MCP server.ping() to verify that the connection to the server is working.ListToolsResult contains information about all tools including their names, descriptions, and input schemas.Great, now we've captures all the features.
Now the question is when do we use them?
Well, this client is pretty simple, simple in the sense that we will need to explicitly call the features when we want them.
In the next chapter, we will create a more advanced client that has access to it's own large language model, LLM.
For now though, let's see how we can invoke the features on the server:
In the main function, after initializing the client, we can initialize the server and list some of its features.
// Initialize
let server_info = client.peer_info();
println!("Server info: {:?}", server_info);
// List tools
let tools = client.list_tools(Default::default()).await?;
println!("Available tools: {:?}", tools);
To invoke the features we need to ensure we specify the correct arguments and in some cases the name of what we're trying to invoke.
// Read a resource
const resource = await client.readResource({
uri: "file:///example.txt"
});
// Call a tool
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
// call prompt
const promptResult = await client.getPrompt({
name: "review-code",
arguments: {
code: "console.log(\"Hello world\")"
}
})
In the preceding code we:
readResource() specifying uri. Here's what it most likely look like on the server side:```typescript
server.resource(
"readFile",
new ResourceTemplate("file://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: Hello, ${name}!
}]
})
);
```
Our uri value file://example.txt matches file://{name} on the server. example.txt will be mapped to name.
name and its arguments like so:```typescript
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
```
getPrompt() with name and arguments. The server code looks like so:```typescript
server.prompt(
"review-code",
{ code: z.string() },
({ code }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: Please review this code:\n\n${code}
}
}]
})
);
```
and your resulting client code therefore looks like so to match what's declared on the server:
```typescript
const promptResult = await client.getPrompt({
name: "review-code",
arguments: {
code: "console.log(\"Hello world\")"
}
})
```
# Read a resource
print("READING RESOURCE")
content, mime_type = await session.read_resource("greeting://hello")
# Call a tool
print("CALL TOOL")
result = await session.call_tool("add", arguments={"a": 1, "b": 7})
print(result.content)
In the preceding code, we've:
greeting using read_resource.add using call_tool.1. Let's add some code to call a tool:
```csharp
var result = await mcpClient.CallToolAsync(
"Add",
new Dictionary
cancellationToken:CancellationToken.None);
```
1. To print out the result, here's some code to handle that:
```csharp
Console.WriteLine(result.Content.First(c => c.Type == "text").Text);
// Sum 4
```
// Call various calculator tools
CallToolResult resultAdd = client.callTool(new CallToolRequest("add", Map.of("a", 5.0, "b", 3.0)));
System.out.println("Add Result = " + resultAdd);
CallToolResult resultSubtract = client.callTool(new CallToolRequest("subtract", Map.of("a", 10.0, "b", 4.0)));
System.out.println("Subtract Result = " + resultSubtract);
CallToolResult resultMultiply = client.callTool(new CallToolRequest("multiply", Map.of("a", 6.0, "b", 7.0)));
System.out.println("Multiply Result = " + resultMultiply);
CallToolResult resultDivide = client.callTool(new CallToolRequest("divide", Map.of("a", 20.0, "b", 4.0)));
System.out.println("Divide Result = " + resultDivide);
CallToolResult resultHelp = client.callTool(new CallToolRequest("help", Map.of()));
System.out.println("Help = " + resultHelp);
In the preceding code we've:
callTool() method with CallToolRequest objects.Map of arguments required by that tool.CallToolResult objects containing the response from the server.
// Call add tool with arguments = {"a": 3, "b": 2}
let a = 3;
let b = 2;
let tool_result = client
.call_tool(CallToolRequestParam {
name: "add".into(),
arguments: serde_json::json!({ "a": a, "b": b }).as_object().cloned(),
})
.await?;
println!("Result of {:?} + {:?}: {:?}", a, b, tool_result);
To run the client, type the following command in the terminal:
Add the following entry to your "scripts" section in *package.json*:
"client": "tsc && node build/client.js"
npm run client
Call the client with the following command:
python client.py
dotnet run
First, ensure your MCP server is running on http://localhost:8080. Then run the client:
# Build you project
./mvnw clean compile
# Run the client
./mvnw exec:java -Dexec.mainClass="com.microsoft.mcp.sample.client.SDKClient"
Alternatively, you can run the complete client project provided in the solution folder 03-GettingStarted\02-client\solution\java:
# Navigate to the solution directory
cd 03-GettingStarted/02-client/solution/java
# Build and run the JAR
./mvnw clean package
java -jar target/calculator-client-0.0.1-SNAPSHOT.jar
cargo fmt
cargo run
In this assignment, you'll use what you've learned in creating a client but create a client of your own.
Here's a server you can use that you need to call via your client code, see if you can add more features to the server to make it more interesting.
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create an MCP server
const server = new McpServer({
name: "Demo",
version: "1.0.0"
});
// Add an addition tool
server.tool("add",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// Add a dynamic greeting resource
server.resource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: `Hello, ${name}!`
}]
})
);
// Start receiving messages on stdin and sending messages on stdout
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCPServer started on stdin/stdout");
}
main().catch((error) => {
console.error("Fatal error: ", error);
process.exit(1);
});
# server.py
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;
var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
// Configure all logs to go to stderr
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();
await builder.Build().RunAsync();
[McpServerToolType]
public static class CalculatorTool
{
[McpServerTool, Description("Adds two numbers")]
public static string Add(int a, int b) => $"Sum {a + b}";
}
See this project to see how you can add prompts and resources.
Also, check this link for how to invoke prompts and resources.
In the previous section, you learned how to create a simple MCP server with Rust.
You can continue to build on that or check this link for more Rust-based MCP server examples: MCP Server Examples
The solution folder contains complete, ready-to-run client implementations that demonstrate all the concepts covered in this tutorial. Each solution includes both client and server code organized in separate, self-contained projects.
The solution directory is organized by programming language:
solution/
βββ typescript/ # TypeScript client with npm/Node.js setup
β βββ package.json # Dependencies and scripts
β βββ tsconfig.json # TypeScript configuration
β βββ src/ # Source code
βββ java/ # Java Spring Boot client project
β βββ pom.xml # Maven configuration
β βββ src/ # Java source files
β βββ mvnw # Maven wrapper
βββ python/ # Python client implementation
β βββ client.py # Main client code
β βββ server.py # Compatible server
β βββ README.md # Python-specific instructions
βββ dotnet/ # .NET client project
β βββ dotnet.csproj # Project configuration
β βββ Program.cs # Main client code
β βββ dotnet.sln # Solution file
βββ rust/ # Rust client implementation
| βββ Cargo.lock # Cargo lock file
| βββ Cargo.toml # Project configuration and dependencies
| βββ src # Source code
| β βββ main.rs # Main client code
βββ server/ # Additional .NET server implementation
βββ Program.cs # Server code
βββ server.csproj # Server project file
Each language-specific solution provides:
1. Navigate to your preferred language folder:
```bash
cd solution/typescript/ # For TypeScript
cd solution/java/ # For Java
cd solution/python/ # For Python
cd solution/dotnet/ # For .NET
```
2. Follow the README instructions in each folder for:
- Installing dependencies
- Building the project
- Running the client
3. Example output you should see:
```text
Prompt: Please review this code: console.log("hello");
Resource template: file
Tool result: { content: [ { type: 'text', text: '9' } ] }
```
For complete documentation and step-by-step instructions, see: π Solution Documentation
We've provided complete, working client implementations for all programming languages covered in this tutorial.
These examples demonstrate the full functionality described above and can be used as reference implementations or starting points for your own projects.
| Language | File | Description |
|----------|------|-------------|
| Java | [client_example_java.java](./client_example_java.java) | Complete Java client using SSE transport with comprehensive error handling |
| C# | [client_example_csharp.cs](./client_example_csharp.cs) | Complete C# client using stdio transport with automatic server startup |
| TypeScript | [client_example_typescript.ts](./client_example_typescript.ts) | Complete TypeScript client with full MCP protocol support |
| Python | [client_example_python.py](./client_example_python.py) | Complete Python client using async/await patterns |
| Rust | [client_example_rust.rs](./client_example_rust.rs) | Complete Rust client using Tokio for async operations |
Each complete example includes:
1. Choose your preferred language from the table above
2. Review the complete example file to understand the full implementation
3. Run the example following the instructions in [complete_examples.md](./complete_examples.md)
4. Modify and extend the example for your specific use case
For detailed documentation about running and customizing these examples, see: π Complete Examples Documentation
| Solution Folder | Complete Examples |
|--------------------|--------------------- |
| Full project structure with build files | Single-file implementations |
| Ready-to-run with dependencies | Focused code examples |
| Production-like setup | Educational reference |
| Language-specific tooling | Cross-language comparison |
Both approaches are valuable - use the solution folder for complete projects and the complete examples for learning and reference.
The key takeaways for this chapter is the following about clients:
ν΄λΌμ΄μΈνΈλ MCP μλ²μ μ§μ ν΅μ νμ¬ λ¦¬μμ€, λꡬ λ° ν둬ννΈλ₯Ό μμ²νλ λ§μΆ€ν μ ν리μΌμ΄μ λλ μ€ν¬λ¦½νΈμ λλ€. μλ²μ μνΈμμ©νκΈ° μν κ·Έλν½ μΈν°νμ΄μ€λ₯Ό μ 곡νλ κ²μ¬ λꡬμ λ¬λ¦¬, μμ λ§μ ν΄λΌμ΄μΈνΈλ₯Ό μμ±νλ©΄ νλ‘κ·Έλλ° λ°©μμΌλ‘ μλνλ μνΈμμ©μ΄ κ°λ₯ν©λλ€. μ΄λ₯Ό ν΅ν΄ κ°λ°μλ MCP κΈ°λ₯μ μμ μ μν¬νλ‘μ°μ ν΅ν©νκ³ μμ μ μλννλ©° νΉμ μꡬ μ¬νμ λ§μΆ λ§μΆ€ μ루μ μ ꡬμΆν μ μμ΅λλ€.
μ΄ μμ μμλ Model Context Protocol(MCP) μνκ³ λ΄ ν΄λΌμ΄μΈνΈμ κ°λ μ μκ°ν©λλ€. μ§μ ν΄λΌμ΄μΈνΈλ₯Ό μμ±νκ³ MCP μλ²μ μ°κ²°νλ λ°©λ²μ λ°°μ°κ² λ©λλ€.
μ΄ μμ μ΄ λλλ©΄ λ€μμ ν μ μμ΅λλ€:
ν΄λΌμ΄μΈνΈλ₯Ό μμ±νλ €λ©΄ λ€μ μμ μ μνν΄μΌ ν©λλ€:
μ΄μ νμ΄λ λ²¨λ‘ μ€λΉν λ΄μ©μ μ΄ν΄νμΌλ, λ€μμΌλ‘ μμ λ₯Ό μ΄ν΄λ΄ μλ€.
μ΄ ν΄λΌμ΄μΈνΈ μμ λ₯Ό λ³΄κ² μ΅λλ€:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
const client = new Client(
{
name: "example-client",
version: "1.0.0"
}
);
await client.connect(transport);
// ν둬ννΈ λͺ©λ‘
const prompts = await client.listPrompts();
// ν둬ννΈ κ°μ Έμ€κΈ°
const prompt = await client.getPrompt({
name: "example-prompt",
arguments: {
arg1: "value"
}
});
// 리μμ€ λͺ©λ‘
const resources = await client.listResources();
// 리μμ€ μ½κΈ°
const resource = await client.readResource({
uri: "file:///example.txt"
});
// λꡬ νΈμΆ
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
μ μ½λμμ:
μ΄λ κ² MCP μλ²μ ν΅μ ν μ μλ ν΄λΌμ΄μΈνΈκ° μμ±λμμ΅λλ€.
λ€μ μ°μ΅ μΉμ μμ κ° μ½λ μ‘°κ°μ μμΈν λΆμνκ³ λ΄μ©μ μ€λͺ νκ² μ΅λλ€.
μμμ λ§νλ―μ΄, μ½λλ₯Ό μ²μ²ν μ΄ν΄λ³΄κ³ μνλ©΄ μ§μ λ°λΌ μ½λ©ν΄λ³΄μΈμ.
νμν λΌμ΄λΈλ¬λ¦¬λ₯Ό μν¬νΈν©λλ€. ν΄λΌμ΄μΈνΈμ μ νν μ μ‘ νλ‘ν μ½ stdioμ λν μ°Έμ‘°κ° νμν©λλ€. stdioλ λ‘컬 λ¨Έμ μμ μ€νλλ μ ν리μΌμ΄μ μ© νλ‘ν μ½μ λλ€. SSEλ μ΄ν μ₯μμ μκ°ν λ λ€λ₯Έ μ μ‘ λ°©μμ λλ€. μ§κΈμ stdioλ₯Ό κ³μ μ¬μ©ν©μλ€.
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
Javaμμλ μ΄μ μ€μ΅μ MCP μλ²μ μ°κ²°νλ ν΄λΌμ΄μΈνΈλ₯Ό μμ±ν©λλ€. Getting Started with MCP Serverμ Java Spring Boot νλ‘μ νΈ κ΅¬μ‘°λ₯Ό κ·Έλλ‘ μ¬μ©νλ©°, src/main/java/com/microsoft/mcp/sample/client/ ν΄λμ SDKClientλΌλ μ Java ν΄λμ€λ₯Ό μμ±νκ³ λ€μ μν¬νΈλ₯Ό μΆκ°ν©λλ€:
import java.util.Map;
import org.springframework.web.reactive.function.client.WebClient;
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
import io.modelcontextprotocol.spec.McpClientTransport;
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
Cargo.toml νμΌμ λ€μ μμ‘΄μ±μ μΆκ°ν΄μΌ ν©λλ€.
[package]
name = "calculator-client"
version = "0.1.0"
edition = "2024"
[dependencies]
rmcp = { version = "0.5.0", features = ["client", "transport-child-process"] }
serde_json = "1.0.141"
tokio = { version = "1.46.1", features = ["rt-multi-thread"] }
κ·Έ ν ν΄λΌμ΄μΈνΈ μ½λμμ νμν λΌμ΄λΈλ¬λ¦¬λ₯Ό μν¬νΈν μ μμ΅λλ€.
use rmcp::{
RmcpError,
model::CallToolRequestParam,
service::ServiceExt,
transport::{ConfigureCommandExt, TokioChildProcess},
};
use tokio::process::Command;
λ€μμΌλ‘ μΈμ€ν΄μ€νλ₯Ό ν΄λ΄ μλ€.
μ μ‘κ³Ό ν΄λΌμ΄μΈνΈ μΈμ€ν΄μ€λ₯Ό μμ±ν΄μΌ ν©λλ€:
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
const client = new Client(
{
name: "example-client",
version: "1.0.0"
}
);
await client.connect(transport);
μ μ½λμμλ:
```typescript
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
```
```typescript
const client = new Client(
{
name: "example-client",
version: "1.0.0"
});
```
```typescript
await client.connect(transport);
```
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
# stdio μ°κ²°μ μν μλ² λ§€κ°λ³μ μμ±
server_params = StdioServerParameters(
command="mcp", # μ€ν νμΌ
args=["run", "server.py"], # μ νμ λͺ
λ Ήμ€ μΈμ
env=None, # μ νμ νκ²½ λ³μ
)
async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(
read, write
) as session:
# μ°κ²° μ΄κΈ°ν
await session.initialize()
if __name__ == "__main__":
import asyncio
asyncio.run(run())
μ μ½λμμλ:
stdio_clientλ₯Ό νΈμΆνλ run λΉλκΈ° λ©μλλ₯Ό μ μνμ΅λλ€.asyncio.runμ run λ©μλλ₯Ό μ λ¬νμ¬ μ§μ
μ μ λ§λ€μμ΅λλ€.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
var builder = Host.CreateApplicationBuilder(args);
builder.Configuration
.AddEnvironmentVariables()
.AddUserSecrets<Program>();
var clientTransport = new StdioClientTransport(new()
{
Name = "Demo Server",
Command = "dotnet",
Arguments = ["run", "--project", "path/to/file.csproj"],
});
await using var mcpClient = await McpClient.CreateAsync(clientTransport);
μ μ½λμμλ:
mcpClientλΌλ ν΄λΌμ΄μΈνΈλ₯Ό λ§λ€μμ΅λλ€. μ΄λ₯Ό ν΅ν΄ MCP μλ²μ κΈ°λ₯μ λμ΄ λ° νΈμΆν μ μμ΅λλ€.μ°Έκ³ λ‘, Argumentsμλ *.csproj* νμΌμ΄λ μ€ν νμΌ κ²½λ‘λ₯Ό μ§μ ν μ μμ΅λλ€.
public class SDKClient {
public static void main(String[] args) {
var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080"));
new SDKClient(transport).run();
}
private final McpClientTransport transport;
public SDKClient(McpClientTransport transport) {
this.transport = transport;
}
public void run() {
var client = McpClient.sync(this.transport).build();
client.initialize();
// ν΄λΌμ΄μΈνΈ λ‘μ§μ μ¬κΈ°μ μμ±νμΈμ
}
}
μ μ½λμμλ:
http://localhost:8080λ₯Ό κ°λ¦¬ν€λ SSE μ μ‘μ μ€μ νλ main λ©μλλ₯Ό λ§λ€μμ΅λλ€.run λ©μλμμ μ μ‘μ μ¬μ©ν΄ λκΈ° MCP ν΄λΌμ΄μΈνΈλ₯Ό λ§λ€κ³ μ°κ²°μ μ΄κΈ°ννμ΅λλ€.μ΄ Rust ν΄λΌμ΄μΈνΈλ μλ²κ° κ°μ λλ ν°λ¦¬ λ΄ "calculator-server"λΌλ νμ νλ‘μ νΈλΌκ³ κ°μ ν©λλ€. μλ μ½λλ μλ²λ₯Ό μμνκ³ μ°κ²°ν©λλ€.
async fn main() -> Result<(), RmcpError> {
// μλ²κ° κ°μ λλ ν 리μ μλ νμ νλ‘μ νΈμΈ "calculator-server"λΌκ³ κ°μ ν©λλ€
let server_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("failed to locate workspace root")
.join("calculator-server");
let client = ()
.serve(
TokioChildProcess::new(Command::new("cargo").configure(|cmd| {
cmd.arg("run").current_dir(server_dir);
}))
.map_err(RmcpError::transport_creation::<TokioChildProcess>)?,
)
.await?;
// ν μΌ: μ΄κΈ°ν
// ν μΌ: λꡬ λͺ©λ‘ μμ±
// ν μΌ: μΈμ = {"a": 3, "b": 2}λ‘ add λꡬ νΈμΆ
client.cancel().await?;
Ok(())
}
νλ‘κ·Έλ¨μ΄ μ€νλλ©΄ ν΄λΌμ΄μΈνΈκ° μλ²μ μ°κ²°ν μ μμ΅λλ€. νμ§λ§ μλ²μ κΈ°λ₯μ λμ΄νμ§λ μμΌλ―λ‘, μ΄λ₯Ό ν΄λ΄ μλ€:
// ν둬ννΈ λͺ©λ‘
const prompts = await client.listPrompts();
// 리μμ€ λͺ©λ‘
const resources = await client.listResources();
// λꡬ λͺ©λ‘
const tools = await client.listTools();
# μ¬μ© κ°λ₯ν 리μμ€ λμ΄
resources = await session.list_resources()
print("LISTING RESOURCES")
for resource in resources:
print("Resource: ", resource)
# μ¬μ© κ°λ₯ν λꡬ λμ΄
tools = await session.list_tools()
print("LISTING TOOLS")
for tool in tools.tools:
print("Tool: ", tool.name)
μ¬κΈ°μλ μ¬μ© κ°λ₯ν 리μμ€ list_resources()μ λꡬ list_toolsλ₯Ό λμ΄νκ³ μΆλ ₯ν©λλ€.
foreach (var tool in await client.ListToolsAsync())
{
Console.WriteLine($"{tool.Name} ({tool.Description})");
}
μ μ½λλ μλ²μ λꡬλ₯Ό λμ΄νλ μμ μ λλ€. λꡬ κ°κ°μ μ΄λ¦μ μΆλ ₯ν©λλ€.
// λꡬ λμ΄ λ° μμ°
ListToolsResult toolsList = client.listTools();
System.out.println("Available Tools = " + toolsList);
// μ°κ²° νμΈμ μν΄ μλ²μ νμ λ³΄λΌ μλ μμ΅λλ€
client.ping();
μ μ½λμμλ:
listTools()λ₯Ό νΈμΆν΄ MCP μλ²μ λͺ¨λ λꡬλ₯Ό κ°μ Έμμ΅λλ€.ping()μΌλ‘ μλ² μ°κ²° μν νμΈμ νμ΅λλ€.ListToolsResultμλ λꡬ μ΄λ¦, μ€λͺ
, μ
λ ₯ μ€ν€λ§ λ±μ μ λ³΄κ° ν¬ν¨λμ΄ μμ΅λλ€.μ’μ΅λλ€. μ΄μ λͺ¨λ κΈ°λ₯μ κ°μ Έμμ΅λλ€. κ·ΈλΌ μΈμ μ΄ κΈ°λ₯λ€μ μ¬μ©νλ κ±ΈκΉμ? μ΄ ν΄λΌμ΄μΈνΈλ κ°λ¨ν΄μ, κΈ°λ₯μ μ¬μ©νλ €λ©΄ λͺ μμ μΌλ‘ νΈμΆν΄μΌ ν©λλ€. λ€μ μ₯μμλ μ체 λν μΈμ΄ λͺ¨λΈ(LLM)μ μ κ·Όν μ μλ λ μ§λ³΄λ ν΄λΌμ΄μΈνΈλ₯Ό λ§λ€ κ²μ λλ€. μ§κΈμ μλ² κΈ°λ₯μ νΈμΆνλ λ²μ μ΄ν΄λ΄ μλ€.
main ν¨μμμ ν΄λΌμ΄μΈνΈλ₯Ό μ΄κΈ°νν ν μλ²λ₯Ό μ΄κΈ°ννκ³ λͺ κ°μ§ κΈ°λ₯μ λμ΄ν μ μμ΅λλ€.
// μ΄κΈ°ν
let server_info = client.peer_info();
println!("Server info: {:?}", server_info);
// λꡬ λͺ©λ‘
let tools = client.list_tools(Default::default()).await?;
println!("Available tools: {:?}", tools);
κΈ°λ₯μ νΈμΆνλ €λ©΄ μ¬λ°λ₯Έ μΈμμ, κ²½μ°μ λ°λΌ νΈμΆνλ €λ μ΄λ¦μ μ§μ ν΄μΌ ν©λλ€.
// 리μμ€λ₯Ό μ½μ΅λλ€
const resource = await client.readResource({
uri: "file:///example.txt"
});
// λꡬλ₯Ό νΈμΆν©λλ€
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
// ν둬ννΈ νΈμΆ
const promptResult = await client.getPrompt({
name: "review-code",
arguments: {
code: "console.log(\"Hello world\")"
}
})
μ μ½λμμλ:
readResource()λ₯Ό νΈμΆνκ³ uriλ₯Ό μ§μ ν©λλ€. μλ² μΈ‘ μ½λλ λ€μκ³Ό μ μ¬ν©λλ€:```typescript
server.resource(
"readFile",
new ResourceTemplate("file://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: Hello, ${name}!
}]
})
);
```
uriκ° file://example.txtλ μλ²μ file://{name}μ λ§€νλλ©°, example.txtλ nameμΌλ‘ μ²λ¦¬λ©λλ€.
name)κ³Ό μΈμ(arguments)λ₯Ό μ§μ νμ¬ νΈμΆν©λλ€:```typescript
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
```
getPrompt()λ₯Ό μ΄λ¦κ³Ό μΈμμ ν¨κ» νΈμΆν©λλ€. μλ² μ½λλ λ€μκ³Ό κ°μ΅λλ€:```typescript
server.prompt(
"review-code",
{ code: z.string() },
({ code }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: Please review this code:\n\n${code}
}
}]
})
);
```
λ°λΌμ ν΄λΌμ΄μΈνΈ μ½λλ μλ² μ μΈκ³Ό μΌμΉνλλ‘ λ€μκ³Ό κ°μ΅λλ€:
```typescript
const promptResult = await client.getPrompt({
name: "review-code",
arguments: {
code: "console.log(\"Hello world\")"
}
})
```
# 리μμ€λ₯Ό μ½μ΅λλ€
print("READING RESOURCE")
content, mime_type = await session.read_resource("greeting://hello")
# λꡬλ₯Ό νΈμΆν©λλ€
print("CALL TOOL")
result = await session.call_tool("add", arguments={"a": 1, "b": 7})
print(result.content)
μ μ½λμμ:
greeting 리μμ€λ₯Ό read_resourceλ‘ νΈμΆνμ΅λλ€.add λꡬλ₯Ό call_toolλ‘ νΈμΆνμ΅λλ€.1. λꡬλ₯Ό νΈμΆνλ μ½λλ₯Ό μΆκ°ν©μλ€:
```csharp
var result = await mcpClient.CallToolAsync(
"Add",
new Dictionary
cancellationToken:CancellationToken.None);
```
2. κ²°κ³Όλ₯Ό μΆλ ₯νλ μ½λλ λ€μκ³Ό κ°μ΅λλ€:
```csharp
Console.WriteLine(result.Content.First(c => c.Type == "text").Text);
// Sum 4
```
// λ€μν κ³μ°κΈ° λꡬ νΈμΆ
CallToolResult resultAdd = client.callTool(new CallToolRequest("add", Map.of("a", 5.0, "b", 3.0)));
System.out.println("Add Result = " + resultAdd);
CallToolResult resultSubtract = client.callTool(new CallToolRequest("subtract", Map.of("a", 10.0, "b", 4.0)));
System.out.println("Subtract Result = " + resultSubtract);
CallToolResult resultMultiply = client.callTool(new CallToolRequest("multiply", Map.of("a", 6.0, "b", 7.0)));
System.out.println("Multiply Result = " + resultMultiply);
CallToolResult resultDivide = client.callTool(new CallToolRequest("divide", Map.of("a", 20.0, "b", 4.0)));
System.out.println("Divide Result = " + resultDivide);
CallToolResult resultHelp = client.callTool(new CallToolRequest("help", Map.of()));
System.out.println("Help = " + resultHelp);
μ μ½λμμλ:
callTool() λ©μλμ CallToolRequest κ°μ²΄λ‘ νΈμΆνμ΅λλ€.MapμΌλ‘ μ λ¬νμ΅λλ€.CallToolResult κ°μ²΄λ‘ λ°νλ©λλ€.
// μΈμ = {"a": 3, "b": 2}λ‘ add λꡬλ₯Ό νΈμΆνμμμ€
let a = 3;
let b = 2;
let tool_result = client
.call_tool(CallToolRequestParam {
name: "add".into(),
arguments: serde_json::json!({ "a": a, "b": b }).as_object().cloned(),
})
.await?;
println!("Result of {:?} + {:?}: {:?}", a, b, tool_result);
ν΄λΌμ΄μΈνΈλ₯Ό μ€ννλ €λ©΄ ν°λ―Έλμμ λ€μ λͺ λ Ήμ΄λ₯Ό μ λ ₯νμΈμ:
*package.json*μ "scripts" μΉμ μ λ€μ νλͺ©μ μΆκ°ν©λλ€:
"client": "tsc && node build/client.js"
npm run client
λ€μ λͺ λ Ήμ΄λ‘ ν΄λΌμ΄μΈνΈλ₯Ό νΈμΆν©λλ€:
python client.py
dotnet run
λ¨Όμ MCP μλ²κ° http://localhost:8080μμ μ€ν μ€μΈμ§ νμΈνμΈμ. κ·Έλ¬κ³ λμ ν΄λΌμ΄μΈνΈλ₯Ό μ€νν©λλ€:
# νλ‘μ νΈλ₯Ό λΉλνμΈμ
./mvnw clean compile
# ν΄λΌμ΄μΈνΈλ₯Ό μ€ννμΈμ
./mvnw exec:java -Dexec.mainClass="com.microsoft.mcp.sample.client.SDKClient"
λλ μ루μ
ν΄λ 03-GettingStarted\02-client\solution\javaμ μ 곡λ μμ±λ ν΄λΌμ΄μΈνΈ νλ‘μ νΈλ₯Ό μ€νν μ μμ΅λλ€:
# μ루μ
λλ ν λ¦¬λ‘ μ΄λ
cd 03-GettingStarted/02-client/solution/java
# JARμ λΉλνκ³ μ€ν
./mvnw clean package
java -jar target/calculator-client-0.0.1-SNAPSHOT.jar
cargo fmt
cargo run
μ΄λ² κ³Όμ μμλ λ°°μ΄ λ΄μ©μ νμ©ν΄ μ§μ ν΄λΌμ΄μΈνΈλ₯Ό λ§λ€μ΄ λ΄ λλ€.
μλ μλ²λ₯Ό ν΄λΌμ΄μΈνΈ μ½λλ‘ νΈμΆν μ μμ΅λλ€. μλ²μ λ ν₯λ―Έλ‘μ΄ κΈ°λ₯μ μΆκ°ν΄ 보μΈμ.
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// MCP μλ²λ₯Ό μμ±ν©λλ€
const server = new McpServer({
name: "Demo",
version: "1.0.0"
});
// λ§μ
λꡬλ₯Ό μΆκ°ν©λλ€
server.tool("add",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// λμ μΈμ¬λ§ 리μμ€λ₯Ό μΆκ°ν©λλ€
server.resource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: `Hello, ${name}!`
}]
})
);
// stdinμμ λ©μμ§λ₯Ό μμ νκ³ stdoutμΌλ‘ λ©μμ§λ₯Ό μ μ‘νκΈ° μμν©λλ€
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCPServer started on stdin/stdout");
}
main().catch((error) => {
console.error("Fatal error: ", error);
process.exit(1);
});
# server.py
from mcp.server.fastmcp import FastMCP
# MCP μλ² μμ±
mcp = FastMCP("Demo")
# μΆκ° λꡬ μΆκ°
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# λμ μΈμ¬λ§ 리μμ€ μΆκ°
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;
var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
// Configure all logs to go to stderr
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();
await builder.Build().RunAsync();
[McpServerToolType]
public static class CalculatorTool
{
[McpServerTool, Description("Adds two numbers")]
public static string Add(int a, int b) => $"Sum {a + b}";
}
μ΄ νλ‘μ νΈμμ ν둬ννΈμ 리μμ€ μΆκ° λ°©λ²μ μ°Έμ‘°νμΈμ.
λν, ν둬ννΈμ 리μμ€ νΈμΆ λ°©λ²λ νμΈνμΈμ.
μ΄μ μΉμ (../01-first-server)μμ Rustλ‘ κ°λ¨ν MCP μλ²λ₯Ό λ§λλ λ°©λ²μ λ°°μ μ΅λλ€.
κ·Έ μ½λλ₯Ό νμ₯νκ±°λ λ€μ λ§ν¬μμ λ λ§μ Rust κΈ°λ° MCP μλ² μμ λ₯Ό νμΈνμΈμ: MCP Server Examples
μ루μ ν΄λμλ λ³Έ νν 리μΌμμ λ€λ£¬ κ°λ λ€μ λͺ¨λ ν¬ν¨ν, μ€ν κ°λ₯ν μμ ν ν΄λΌμ΄μΈνΈ ꡬν μμ κ° λ€μ΄ μμ΅λλ€. κ° μ루μ μ ν΄λΌμ΄μΈνΈμ μλ² μ½λλ₯Ό λ³λμ λ 립ν νλ‘μ νΈλ‘ μ 리νμ΅λλ€.
μ루μ λλ ν°λ¦¬λ νλ‘κ·Έλλ° μΈμ΄λ³λ‘ ꡬμ±λ©λλ€:
solution/
βββ typescript/ # TypeScript client with npm/Node.js setup
β βββ package.json # Dependencies and scripts
β βββ tsconfig.json # TypeScript configuration
β βββ src/ # Source code
βββ java/ # Java Spring Boot client project
β βββ pom.xml # Maven configuration
β βββ src/ # Java source files
β βββ mvnw # Maven wrapper
βββ python/ # Python client implementation
β βββ client.py # Main client code
β βββ server.py # Compatible server
β βββ README.md # Python-specific instructions
βββ dotnet/ # .NET client project
β βββ dotnet.csproj # Project configuration
β βββ Program.cs # Main client code
β βββ dotnet.sln # Solution file
βββ rust/ # Rust client implementation
| βββ Cargo.lock # Cargo lock file
| βββ Cargo.toml # Project configuration and dependencies
| βββ src # Source code
| β βββ main.rs # Main client code
βββ server/ # Additional .NET server implementation
βββ Program.cs # Server code
βββ server.csproj # Server project file
κ° μΈμ΄λ³ μ루μ μλ λ€μμ΄ ν¬ν¨λμ΄ μμ΅λλ€:
1. μ νΈνλ μΈμ΄ ν΄λλ‘ μ΄λν©λλ€:
```bash
cd solution/typescript/ # TypeScript μ©
cd solution/java/ # Java μ©
cd solution/python/ # Python μ©
cd solution/dotnet/ # .NET μ©
```
2. κ° ν΄λ λ΄ README μ§μΉ¨μ λ°λΌ:
- μμ‘΄μ± μ€μΉ
- νλ‘μ νΈ λΉλ
- ν΄λΌμ΄μΈνΈ μ€ν
3. μμ μΆλ ₯ μμ:
```text
Prompt: Please review this code: console.log("hello");
Resource template: file
Tool result: { content: [ { type: 'text', text: '9' } ] }
```
μμΈν λ¬Έμμ λ¨κ³λ³ μλ΄λ λ€μμ μ°Έμ‘°νμΈμ: π μ루μ λ¬Έμ
νν 리μΌμμ λ€λ£¬ λͺ¨λ νλ‘κ·Έλλ° μΈμ΄μ© μμ±λ ν΄λΌμ΄μΈνΈ ꡬν μμ λ₯Ό μ 곡νμ΅λλ€. μ΄ μμ λ€μ μμμ μ€λͺ ν μ 체 κΈ°λ₯μ ꡬννλ©° μ°Έκ³ λλ μμ λ§μ νλ‘μ νΈ μμμ μΌλ‘ μ¬μ©ν μ μμ΅λλ€.
| μΈμ΄ | νμΌ | μ€λͺ |
|--------|-----------------------------|-----------------------------------------------------------|
| Java | [client_example_java.java](../../../../03-GettingStarted/02-client/client_example_java.java) | SSE μ μ‘μ μ¬μ©νλ μμ ν Java ν΄λΌμ΄μΈνΈλ‘ ν¬κ΄μ μλ¬ μ²λ¦¬ ν¬ν¨ |
| C# | [client_example_csharp.cs](../../../../03-GettingStarted/02-client/client_example_csharp.cs) | stdio μ μ‘ λ° μλ μλ² μμ κΈ°λ₯μ κ°μΆ μμ ν C# ν΄λΌμ΄μΈνΈ |
| TypeScript | [client_example_typescript.ts](../../../../03-GettingStarted/02-client/client_example_typescript.ts) | μλ²½ν MCP νλ‘ν μ½ μ§μμ μ 곡νλ μμ ν TypeScript ν΄λΌμ΄μΈνΈ |
| Python | [client_example_python.py](../../../../03-GettingStarted/02-client/client_example_python.py) | async/await ν¨ν΄μ μ¬μ©νλ μμ ν Python ν΄λΌμ΄μΈνΈ |
| Rust | [client_example_rust.rs](../../../../03-GettingStarted/02-client/client_example_rust.rs) | Tokio κΈ°λ° λΉλκΈ° μμ
μ μ§μνλ μμ ν Rust ν΄λΌμ΄μΈνΈ |
κ° μμ± μμ μλ:
1. μ νμμ μ νΈνλ μΈμ΄ μ ν
2. μ 체 ꡬνμ μ΄ν΄νκΈ° μν΄ μμ ν μμ νμΌ κ²ν
3. [complete_examples.md](./complete_examples.md) μμ μ§μΉ¨μ λ°λΌ μμ μ€ν
4. νΉμ μ¬μ© μ¬λ‘μ λ§κ² μμ μμ λ° νμ₯
μμΈν μ€ν λ° μ¬μ©μ μ μ λ¬Έμλ λ€μμ μ°Έμ‘°νμΈμ: π μμ ν μμ λ¬Έμ
| μ루μ ν΄λ | μμ ν μμ |
|--------------------------|--------------------------|
| λΉλ νμΌμ ν¬ν¨ν μ 체 νλ‘μ νΈ κ΅¬μ‘° | λ¨μΌ νμΌ κ΅¬ν |
| μ’ μμ± ν¬ν¨ μ¦μ μ€ν κ°λ₯ | μ§μ€λ μ½λ μμ |
| νλ‘λμ νκ²½κ³Ό μ μ¬ν μ€μ | κ΅μ‘μ© μ°Έκ³ μλ£ |
| μΈμ΄λ³ ν΄λ§ | μΈμ΄ κ° λΉκ΅ |
λ μ κ·Όλ² λͺ¨λ μ μ©ν©λλ€ - μ 체 νλ‘μ νΈλ μ루μ ν΄λλ₯Ό, νμ΅κ³Ό μ°Έμ‘°λ μμ ν μμ λ₯Ό μ¬μ©νμΈμ.
μ΄λ² μ₯μμ ν΄λΌμ΄μΈνΈμ λν μ£Όμ λ΄μ©μ λ€μκ³Ό κ°μ΅λλ€:
---
λ©΄μ± μ‘°ν:
μ΄ λ¬Έμλ AI λ²μ μλΉμ€ Co-op Translatorλ₯Ό μ¬μ©νμ¬ λ²μλμμ΅λλ€.
μ νμ±μ μν΄ λ Έλ ₯νκ³ μμΌλ, μλ λ²μμλ μ€λ₯λ λΆμ νν λ΄μ©μ΄ ν¬ν¨λ μ μμμ μ μνμκΈ° λ°λλλ€.
μλ¬Έ λ¬Έμκ° κΆμ μλ μΆμ²λ‘ κ°μ£Όλμ΄μΌ ν©λλ€.
μ€μν μ 보μ κ²½μ°, μ λ¬Έμ μΈ μΈκ° λ²μμ κΆμ₯ν©λλ€.
λ³Έ λ²μ μ¬μ©μΌλ‘ μΈν μ€ν΄λ μλͺ»λ ν΄μμ λν΄ λΉμ¬λ μ± μμ μ§μ§ μμ΅λλ€.