MCP Go ð ã«ã€ããŠ
MCP Go 㯠Model Context Protocol ã® Go å®è£ ã§ãLLM ã¢ããªã±ãŒã·ã§ã³ãšå€éšã®ããŒã¿ãœãŒã¹ãããŒã«ãæ¥ç¶ããŸãããã€ã©ãŒãã¬ãŒããæããé«ã¬ãã«ãªã€ã³ã¿ãŒãã§ãŒã¹ãæ±ãã Go éçºè åãã§ããREADME ã§ã¯éçºã掻çºã«é²è¡äžã§ãäžéšã®é«åºŠãªæ©èœã¯å®è£ éäžãšæèšãããŠããŸãã
äž»ãªæ©èœ
- 01ãã€ã©ãŒãã¬ãŒããæããé«ã¬ãã«ãªã€ã³ã¿ãŒãã§ãŒã¹
- 02ãªãœãŒã¹ãããŒã«ãããã³ããã®ãµããŒã
- 03stdioãSSEãstreamable-HTTP ã®ãã©ã³ã¹ããŒã
- 04äžŠè¡æ°å¶éä»ãã®éåæã¿ã¹ã¯ããŒã«
- 05HTTP åãã® OAuth ã¡ã¿ããŒã¿ãš CORS èšå®
掻çšã·ãŒã³
- 01ããŒã«ãšããŒã¿ãå ¬éãã Go 補 MCP ãµãŒããŒã®æ§ç¯
- 02ãã©ãŠã¶ããŒã¹ã® MCP ã¯ã©ã€ã¢ã³ãåãã® CORS èšå®
- 03é·æéã®åŠçãéåæããŒã«ãšããŠå®è¡
MCP 察å¿
MCP Go ã¯ããªãœãŒã¹ãããŒã«ãããã³ããã MCP ã¯ã©ã€ã¢ã³ãã«å ¬éãã MCP ãµãŒããŒãæ§ç¯ããããã® Go SDK ã§ããäžéšã®ãããã³ã«æ©èœã¯å®è£ éäžãš README ã«èšèŒãããŠããŸãã
èšå®
ããŒã«ã«ãµãŒããŒã®èšå®ã¯ã©ã®ã¯ã©ã€ã¢ã³ãã§ãå ±éã§ããã³ããŒããŠã¯ã©ã€ã¢ã³ãã® MCP èšå®ãã¡ã€ã«ã«è²Œãä»ããŠãã ããã
ãã®ãµãŒããŒã®ããã±ãŒãžããªã¢ãŒããšã³ããã€ã³ãã¯ãŸã ååŸã§ããŠããŸããããããžã§ã¯ãã® README ã®æé ã«åŸã£ãŠãã ããã
ããŒã«
ããŒã«ã«ãµãŒããŒã®ããŒã«ã¯ãã·ã³äžã§èµ·åããŠåããŠååŸã§ããŸããã¡ã³ãããŒã¯ãŸã ããŒã«äžèЧãæäŸããŠããŸããã
詳现
LLM ã¢ããªã±ãŒã·ã§ã³ãšå€éšããŒã¿ãœãŒã¹ããã³ããŒã«ãã·ãŒã ã¬ã¹ã«çµ±åãããModel Context ProtocolïŒMCPïŒã® Go å®è£
ã§ãã
Discord ã§ SDK ã«ã€ããŠè©±ãåããŸããã
package main
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func main() {
// Create a new MCP server
s := server.NewMCPServer(
"Demo ð",
"1.0.0",
server.WithToolCapabilities(false),
)
// Add tool
tool := mcp.NewTool("hello_world",
mcp.WithDescription("Say hello to someone"),
mcp.WithString("name",
mcp.Required(),
mcp.Description("Name of the person to greet"),
),
)
// Add tool handler
s.AddTool(tool, helloHandler)
// Start the stdio server
if err := server.ServeStdio(s); err != nil {
fmt.Printf("Server error: %v\n", err)
}
}
func helloHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
name, err := request.RequireString("name")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
return mcp.NewToolResultText(fmt.Sprintf("Hello, %s!", name)), nil
}
ããã ãã§ãïŒ
MCP Go ãè€éãªãããã³ã«ã®è©³çްãšãµãŒããŒç®¡çããã¹ãŠåŠçãããããåªããããŒã«ã®æ§ç¯ã«éäžã§ããŸãã髿°Žæºã§äœ¿ããããããšãç®æããŠããŸãã
äž»ãªæ©èœïŒ
- é«éïŒé«æ°Žæºã®ã€ã³ã¿ãŒãã§ãŒã¹ã«ãããã³ãŒãéãæžããéçºãéããªããŸã
- ã·ã³ãã«ïŒæå°éã®å®åã³ãŒãã§ MCP ãµãŒããŒãæ§ç¯ã§ããŸã
- å®å š*ïŒMCP Go 㯠MCP ã®ã³ã¢ä»æ§ã®å®å šãªå®è£ ãç®æããŠããŸã
ïŒ*ãç®æããŠããŸããã匷調ïŒ
ðš ð§ ðïž MCP Go ã¯æŽ»çºã«éçºäžã§ãããMCP 仿§èªäœãåæ§ã§ããã³ã¢æ©èœã¯åäœããŸãããäžéšã®é«åºŠãªæ©èœã¯ãŸã éçºäžã§ãã
ç®æ¬¡
- ã€ã³ã¹ããŒã«
- ã¯ã€ãã¯ã¹ã¿ãŒã
- MCP ãšã¯ïŒ
- ã³ã¢æŠå¿µ
- äŸ
- è¿œå æ å ±
ã€ã³ã¹ããŒã«
go get github.com/mark3labs/mcp-go
ã¯ã€ãã¯ã¹ã¿ãŒã
èšç®ããŒã«ãšããã€ãã®ããŒã¿ãå ¬éãããã·ã³ãã«ãª MCP ãµãŒããŒãäœæããŸãããã
package main
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func main() {
// Create a new MCP server
s := server.NewMCPServer(
"Calculator Demo",
"1.0.0",
server.WithToolCapabilities(false),
server.WithRecovery(),
)
// Add a calculator tool
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("Perform basic arithmetic operations"),
mcp.WithString("operation",
mcp.Required(),
mcp.Description("The operation to perform (add, subtract, multiply, divide)"),
mcp.Enum("add", "subtract", "multiply", "divide"),
),
mcp.WithNumber("x",
mcp.Required(),
mcp.Description("First number"),
),
mcp.WithNumber("y",
mcp.Required(),
mcp.Description("Second number"),
),
)
// Add the calculator handler
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// Using helper functions for type-safe argument access
op, err := request.RequireString("operation")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
x, err := request.RequireFloat("x")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
y, err := request.RequireFloat("y")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
var result float64
switch op {
case "add":
result = x + y
case "subtract":
result = x - y
case "multiply":
result = x * y
case "divide":
if y == 0 {
return mcp.NewToolResultError("cannot divide by zero"), nil
}
result = x / y
}
return mcp.NewToolResultText(fmt.Sprintf("%.2f", result)), nil
})
// Start the server
if err := server.ServeStdio(s); err != nil {
fmt.Printf("Server error: %v\n", err)
}
}
MCP ãšã¯ïŒ
Model Context ProtocolïŒMCPïŒã䜿ããšãLLM ã¢ããªã±ãŒã·ã§ã³ã«ããŒã¿ãæ©èœãå®å šãã€æšæºåãããæ¹æ³ã§å ¬éãããµãŒããŒãæ§ç¯ã§ããŸããLLM ãšã®ããåãå°çšã«èšèšããã Web API ã®ãããªãã®ã ãšèããŠãã ããã
MCP ãµãŒããŒã§ã¯ã次ã®ããšãã§ããŸãã
- ãªãœãŒã¹ãéããŠããŒã¿ãå ¬éããïŒGET ãšã³ããã€ã³ãã®ãããªãã®ã§ãæ å ±ã LLM ã®ã³ã³ããã¹ãã«èªã¿èŸŒãããã«äœ¿çšããŸãïŒ
- ããŒã«ãéããŠæ©èœãæäŸããïŒPOST ãšã³ããã€ã³ãã®ãããªãã®ã§ãã³ãŒãã®å®è¡ããã®ä»ã®å¯äœçšã®çºçã«äœ¿çšããŸãïŒ
- ããã³ãããéããŠããåãã®ãã¿ãŒã³ãå®çŸ©ããïŒLLM ãšã®ããåãã«äœ¿ããåå©çšå¯èœãªãã³ãã¬ãŒãã§ãïŒ
- ãã®ä»ã«ãããŸããŸãªããšãã§ããŸãïŒ
mcp-go 㯠Model Context Protocol 仿§ã®ããŒãžã§ã³ 2025-11-25 ãå®è£ ããŠãããããŒãžã§ã³ 2025-06-18ã2025-03-26ã2024-11-05 ãšã®åŸæ¹äºææ§ããããŸãã
ã³ã¢æŠå¿µ
ãµãŒããŒ
ãµãŒããŒã®äŸã衚瀺
ãµãŒããŒã¯ MCP ãããã³ã«ã®äžæ žãšãªãã€ã³ã¿ãŒãã§ãŒã¹ã§ããæ¥ç¶ç®¡çããããã³ã«ãžã®æºæ ãã¡ãã»ãŒãžã®ã«ãŒãã£ã³ã°ãåŠçããŸãã
// Create a basic server
s := server.NewMCPServer(
"My Server", // Server name
"1.0.0", // Version
)
// Start the server using stdio
if err := server.ServeStdio(s); err != nil {
log.Fatalf("Server error: %v", err)
}
ãªãœãŒã¹ã®äŸã衚瀺
ãªãœãŒã¹ã¯ãLLM ã«ããŒã¿ãå ¬éããããã®ä»çµã¿ã§ãããã¡ã€ã«ãAPI ã¬ã¹ãã³ã¹ãããŒã¿ããŒã¹ã¯ãšãªãã·ã¹ãã æ å ±ãªã©ããããããã®ãæ±ããŸãããªãœãŒã¹ã«ã¯æ¬¡ã®çš®é¡ããããŸãã- éçïŒåºå® URIïŒ
- åçïŒURI ãã³ãã¬ãŒãã䜿çšïŒ
以äžã¯éçãªãªãœãŒã¹ã®ç°¡åãªäŸã§ãã
// Static resource example - exposing a README file
resource := mcp.NewResource(
"docs://readme",
"Project README",
mcp.WithResourceDescription("The project's README file"),
mcp.WithMIMEType("text/markdown"),
)
// Add resource with its handler
s.AddResource(resource, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
content, err := os.ReadFile("README.md")
if err != nil {
return nil, err
}
return []mcp.ResourceContents{
mcp.TextResourceContents{
URI: "docs://readme",
MIMEType: "text/markdown",
Text: string(content),
},
}, nil
})
次ã«ããã³ãã¬ãŒãã䜿çšããåçãªãªãœãŒã¹ã®äŸã§ãã
// Dynamic resource example - user profiles by ID
template := mcp.NewResourceTemplate(
"users://{id}/profile",
"User Profile",
mcp.WithTemplateDescription("Returns user profile information"),
mcp.WithTemplateMIMEType("application/json"),
)
// Add template with its handler
s.AddResourceTemplate(template, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
// Extract ID from the URI using regex matching
// The server automatically matches URIs to templates
userID := extractIDFromURI(request.Params.URI)
profile, err := getUserProfile(userID) // Your DB/API call here
if err != nil {
return nil, err
}
return []mcp.ResourceContents{
mcp.TextResourceContents{
URI: request.Params.URI,
MIMEType: "application/json",
Text: profile,
},
}, nil
})
ãããã®äŸã¯ã·ã³ãã«ã§ãããæ žå¿ãšãªãæŠå¿µã瀺ããŠããŸãããªãœãŒã¹ã¯ãã£ãšé«åºŠã«ã§ããŸããè€æ°ã®ã³ã³ãã³ãã®æäŸãããŒã¿ããŒã¹ãå€éš API ãšã®é£æºãªã©ãå¯èœã§ãã
ããŒã«
ããŒã«ã®äŸã衚瀺
ããŒã«ã䜿ããšãLLM ã¯ãµãŒããŒãéããŠã¢ã¯ã·ã§ã³ãå®è¡ã§ããŸãããªãœãŒã¹ãšã¯ç°ãªããããŒã«ã¯èšç®ãå®è¡ããå¯äœçšãæã€ããšãæ³å®ãããŠããŸããREST API ã® POST ãšã³ããã€ã³ãã«äŒŒãŠããŸãã
ã¿ã¹ã¯æ¡åŒµããŒã«
ã¿ã¹ã¯æ¡åŒµããŒã«ã¯éåæã§å®è¡ãããããŒãªã³ã°ã«ãã£ãŠçµæãè¿ããŸããããã¯ããããã¯ãã¿ã€ã ã¢ãŠããåŒãèµ·ããå¯èœæ§ã®ããé·æéå®è¡ãããæäœã«äŸ¿å©ã§ããã¿ã¹ã¯ããŒã«ã¯ 3 ã€ã®ã¢ãŒãããµããŒãããŠããŸãã
- TaskSupportForbiddenïŒããã©ã«ãïŒ: ããŒã«ãã¿ã¹ã¯ãšããŠåŒã³åºãããšã¯ã§ããŸãã
- TaskSupportOptional: ããŒã«ãã¿ã¹ã¯ãšããŠããŸãã¯åæçã«åŒã³åºãããšãã§ããŸã
- TaskSupportRequired: ããŒã«ãã¿ã¹ã¯ãšããŠåŒã³åºãå¿ èŠããããŸã
// Example: A tool that requires task execution
processBatchTool := mcp.NewTool("process_batch",
mcp.WithDescription("Process a batch of items asynchronously"),
mcp.WithTaskSupport(mcp.TaskSupportRequired),
mcp.WithArray("items",
mcp.Description("Array of items to process"),
mcp.WithStringItems(),
mcp.Required(),
),
)
// Task tool handler returns CreateTaskResult instead of CallToolResult
s.AddTaskTool(processBatchTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CreateTaskResult, error) {
items := request.GetStringSlice("items", []string{})
// Long-running work here
for i, item := range items {
select {
case <-ctx.Done():
// Task was cancelled
return nil, ctx.Err()
default:
// Process item...
processItem(item)
}
}
// Return result - task ID and metadata are managed by the server
return &mcp.CreateTaskResult{
Task: mcp.Task{
// Task fields (ID, status, etc.) are populated by the server
},
}, nil
})
// Enable task capabilities when creating the server
s := server.NewMCPServer(
"Task Server",
"1.0.0",
server.WithTaskCapabilities(
true, // listTasks: allows clients to list all tasks
true, // cancel: allows clients to cancel running tasks
true, // toolCallTasks: enables task augmentation for tools
),
server.WithMaxConcurrentTasks(10), // Optional: limit concurrent running tasks
)
ã¿ã¹ã¯ã®å®è¡ãããŒ:
- ã¯ã©ã€ã¢ã³ããã¿ã¹ã¯ãã©ã¡ãŒã¿ãä»ããŠããŒã«ãåŒã³åºããŸã
- ãµãŒããŒã¯ããã«ã¿ã¹ã¯ ID ãè¿ããŸã
- ããŒã«ã¯ããã¯ã°ã©ãŠã³ãã§éåæã«å®è¡ãããŸã
- ã¯ã©ã€ã¢ã³ãã¯
tasks/resultãããŒãªã³ã°ããŠçµæãååŸããŸã - ãµãŒããŒã¯å®äºæã«ã¿ã¹ã¯ã¹ããŒã¿ã¹éç¥ãéä¿¡ããŸã
ãªãã·ã§ã³ã®ã¿ã¹ã¯ããŒã«ã®å ŽåãåãããŒã«ãåæçã«ïŒã¿ã¹ã¯ãã©ã¡ãŒã¿ãªãã§ïŒãŸãã¯éåæçã«ïŒã¿ã¹ã¯ãã©ã¡ãŒã¿ä»ãã§ïŒåŒã³åºãããšãã§ããŸãã
// Tool with optional task support
analyzeTool := mcp.NewTool("analyze_data",
mcp.WithDescription("Analyze data - can run sync or async"),
mcp.WithTaskSupport(mcp.TaskSupportOptional),
mcp.WithString("data", mcp.Required()),
)
// Use AddTaskTool for hybrid tools that support both modes
s.AddTaskTool(analyzeTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CreateTaskResult, error) {
// This handler runs when called as a task
data := request.GetString("data", "")
result := analyzeData(data)
return &mcp.CreateTaskResult{
Task: mcp.Task{},
}, nil
})
// The server automatically handles both sync and async invocations
// When called without task param: executes handler and returns immediately
// When called with task param: executes handler asynchronously
åæå®è¡ã¿ã¹ã¯ã®å¶é
ãªãœãŒã¹ã®æ¯æžãé²ãããã«ãåæã«å®è¡ãããã¿ã¹ã¯ã®æ°ãå¶éã§ããŸãã
s := server.NewMCPServer(
"Task Server",
"1.0.0",
server.WithTaskCapabilities(true, true, true),
server.WithMaxConcurrentTasks(10), // Allow up to 10 concurrent running tasks
)
å¶éã«éãããšãæ°ããã¿ã¹ã¯ã®äœæãªã¯ãšã¹ãã¯ãšã©ãŒã§å€±æããŸããå®äºã倱æããŸãã¯ãã£ã³ã»ã«ãããã¿ã¹ã¯ã¯å¶éã«ã«ãŠã³ããããŸãããã«ãŠã³ããããã®ã¯ãworkingãã¹ããŒã¿ã¹ã®ã¿ã¹ã¯ã®ã¿ã§ããWithMaxConcurrentTasks ãæå®ãããŠããªãå ŽåããŸã㯠0 ã«èšå®ãããŠããå Žåãåæå®è¡ã¿ã¹ã¯ã«å¶éã¯ãããŸããã
å®è¡ããŠããã«çµæãè¿ãåŸæ¥ã®åæããŒã«ã®å Žå:
åçŽãªèšç®ã®äŸ:
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("Perform basic arithmetic calculations"),
mcp.WithString("operation",
mcp.Required(),
mcp.Description("The arithmetic operation to perform"),
mcp.Enum("add", "subtract", "multiply", "divide"),
),
mcp.WithNumber("x",
mcp.Required(),
mcp.Description("First number"),
),
mcp.WithNumber("y",
mcp.Required(),
mcp.Description("Second number"),
),
)
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
args := request.GetArguments()
op := args["operation"].(string)
x := args["x"].(float64)
y := args["y"].(float64)
var result float64
switch op {
case "add":
result = x + y
case "subtract":
result = x - y
case "multiply":
result = x * y
case "divide":
if y == 0 {
return mcp.NewToolResultError("cannot divide by zero"), nil
}
result = x / y
}
return mcp.FormatNumberResult(result), nil
})
HTTP ãªã¯ãšã¹ãã®äŸ:
httpTool := mcp.NewTool("http_request",
mcp.WithDescription("Make HTTP requests to external APIs"),
mcp.WithString("method",
mcp.Required(),
mcp.Description("HTTP method to use"),
mcp.Enum("GET", "POST", "PUT", "DELETE"),
),
mcp.WithString("url",
mcp.Required(),
mcp.Description("URL to send the request to"),
mcp.Pattern("^https?://.*"),
),
mcp.WithString("body",
mcp.Description("Request body (for POST/PUT)"),
),
)
s.AddTool(httpTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
args := request.GetArguments()
method := args["method"].(string)
url := args["url"].(string)
body := ""
if b, ok := args["body"].(string); ok {
body = b
}
// Create and send request
var req *http.Request
var err error
if body != "" {
req, err = http.NewRequest(method, url, strings.NewReader(body))
} else {
req, err = http.NewRequest(method, url, nil)
}
if err != nil {
return mcp.NewToolResultErrorFromErr("unable to create request", err), nil
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return mcp.NewToolResultErrorFromErr("unable to execute request", err), nil
}
defer resp.Body.Close()
// Return response
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return mcp.NewToolResultErrorFromErr("unable to read request response", err), nil
}
return mcp.NewToolResultText(fmt.Sprintf("Status: %d\nBody: %s", resp.StatusCode, string(respBody))), nil
})
ããŒã«ã¯ããããçš®é¡ã®èšç®ãå¯äœçšã«äœ¿çšã§ããŸãã
- ããŒã¿ããŒã¹ã¯ãšãª
- ãã¡ã€ã«æäœ
- å€éš API åŒã³åºã
- èšç®
- ã·ã¹ãã æäœ
åããŒã«ã¯æ¬¡ã®ããã«ããã¹ãã§ãã
- æç¢ºãªèª¬æãæã€
- å ¥åãæ€èšŒãã
- ãšã©ãŒãé©åã«åŠçãã
- æ§é åãããã¬ã¹ãã³ã¹ãè¿ã
- é©åãªçµæåã䜿çšãã
ããã³ãã
ããã³ããã®äŸã衚瀺
ããã³ããã¯ãLLM ããµãŒããŒãšå¹æçã«ããåãããã®ãå©ããåå©çšå¯èœãªãã³ãã¬ãŒãã§ãããµãŒããŒã«ãšã³ã³ãŒããããããã¹ããã©ã¯ãã£ã¹ãã®ãããªãã®ã§ãã以äžã«ããã€ãã®äŸã瀺ããŸãã
// Simple greeting prompt
s.AddPrompt(mcp.NewPrompt("greeting",
mcp.WithPromptDescription("A friendly greeting prompt"),
mcp.WithArgument("name",
mcp.ArgumentDescription("Name of the person to greet"),
),
), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
name := request.Params.Arguments["name"]
if name == "" {
name = "friend"
}
return mcp.NewGetPromptResult(
"A friendly greeting",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleAssistant,
mcp.NewTextContent(fmt.Sprintf("Hello, %s! How can I help you today?", name)),
),
},
), nil
})
// Code review prompt with embedded resource
s.AddPrompt(mcp.NewPrompt("code_review",
mcp.WithPromptDescription("Code review assistance"),
mcp.WithArgument("pr_number",
mcp.ArgumentDescription("Pull request number to review"),
mcp.RequiredArgument(),
),
), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
prNumber := request.Params.Arguments["pr_number"]
if prNumber == "" {
return nil, fmt.Errorf("pr_number is required")
}
return mcp.NewGetPromptResult(
"Code review assistance",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleUser,
mcp.NewTextContent("Review the changes and provide constructive feedback."),
),
mcp.NewPromptMessage(
mcp.RoleAssistant,
mcp.NewEmbeddedResource(mcp.ResourceContents{
URI: fmt.Sprintf("git://pulls/%s/diff", prNumber),
MIMEType: "text/x-diff",
}),
),
},
), nil
})
// Database query builder prompt
s.AddPrompt(mcp.NewPrompt("query_builder",
mcp.WithPromptDescription("SQL query builder assistance"),
mcp.WithArgument("table",
mcp.ArgumentDescription("Name of the table to query"),
mcp.RequiredArgument(),
),
), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
tableName := request.Params.Arguments["table"]
if tableName == "" {
return nil, fmt.Errorf("table name is required")
}
return mcp.NewGetPromptResult(
"SQL query builder assistance",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleUser,
mcp.NewTextContent("Help construct efficient and safe queries for the provided schema."),
),
mcp.NewPromptMessage(
mcp.RoleUser,
mcp.NewEmbeddedResource(mcp.ResourceContents{
URI: fmt.Sprintf("db://schema/%s", tableName),
MIMEType: "application/json",
}),
),
},
), nil
})
ããã³ããã«ã¯æ¬¡ã®ãã®ãå«ããããšãã§ããŸãã
- ã·ã¹ãã æç€º
- å¿ é åŒæ°
- åã蟌ã¿ãªãœãŒã¹
- è€æ°ã®ã¡ãã»ãŒãž
- ããŸããŸãªã³ã³ãã³ãã¿ã€ãïŒããã¹ããç»åãªã©ïŒ
- ã«ã¹ã¿ã URI ã¹ããŒã
äŸ
äŸã«ã€ããŠã¯ãexamples/ ãã£ã¬ã¯ããªãåç
§ããŠãã ããã
äž»ãªäŸã¯æ¬¡ã®ãšããã§ãã
examples/task_tool/- TaskSupportRequired ã¢ãŒããš TaskSupportOptional ã¢ãŒããåããã¿ã¹ã¯æ¡åŒµããŒã«ã宿ŒããŸãexamples/structured_input_and_output/- åå®å šãªããŒã«ãã³ãã©ãŒã§ struct ããŒã¹ã®å ¥å/åºåã¹ããŒãã䜿çšããæ¹æ³ã瀺ããŸãexamples/typed_tools/- 匷ãåä»ããããåŒæ°ãæã€åå®å šãªããŒã«ãã³ãã©ãŒã宿ŒããŸãexamples/custom_context/- ããŒã«ãã³ãã©ãŒã§ã«ã¹ã¿ã ã³ã³ããã¹ãã䜿çšããæ¹æ³ã瀺ããŸã- ãªãœãŒã¹ãããã³ãããªã©ãæ±ããã®ä»ã®äŸã¯ examples ãã£ã¬ã¯ããªã«ãããŸã
è¿œå æ©èœ
ãã©ã³ã¹ããŒã
MCP-Go 㯠stdioãSSEãstreamable-HTTP ã®ãã©ã³ã¹ããŒãå±€ããµããŒãããŠããŸããSSE ãã©ã³ã¹ããŒãã§ã¯ãSetConnectionLostHandler() ã䜿çšããŠåæãæ€åºããã³åŠçãã忥ç¶ããžãã¯ãå®è£
ã§ããŸãã
net/http 以å€ã®ãã¬ãŒã ã¯ãŒã¯ãžã® StreamableHTTP ã®åã蟌ã¿
StreamableHTTPServer 㯠http.Handler ãªã®ã§ãnet/http ã«å¯Ÿå¿ããä»»æã®ã«ãŒã¿ãŒã«ããŠã³ãã§ããŸããfasthttp ã fiber ãªã©ãnet/http ãçµç±ããªããã¬ãŒã ã¯ãŒã¯ã«ãã¢ããã¿ãŒãä»ããŠã¬ã¹ãã³ã¹ããããã¡ãªã³ã°ããããšãªãåã蟌ãã«ã¯ããã©ã³ã¹ããŒãã«äŸåããªã Handle ãšã³ããªãŒãã€ã³ãã䜿çšããŠãã ããã
func (s *StreamableHTTPServer) Handle(w HTTPResponseWriter, r *HTTPRequest)
HTTPRequest ã¯åçŽãªæ§é äœïŒMethodãURLãHeaderãBodyãContextïŒã§ãHTTPResponseWriter ã¯å°ããªã€ã³ã¿ãŒãã§ãŒã¹ïŒHeaderãWriteHeaderãWriteãFlushãCanStreamïŒã§ããåºç€ãšãªããã©ã³ã¹ããŒããã¹ããªãŒãã³ã°ã«å¯Ÿå¿ããŠããªãå®è£
ã§ã¯ãCanStream ãã false ãè¿ãå¿
èŠããããŸãããã®å ŽåããµãŒããŒã¯ GETïŒSSE ãªã¹ãã³ã°ïŒã 405 Method Not Allowed ã§æåŠããPOST ã¬ã¹ãã³ã¹ã¯ text/event-stream ã«ã¢ããã°ã¬ãŒãããããããã¡ãªã³ã°ããã application/json ã®ãŸãŸã«ããŸãã
å®å
šãª fasthttpïŒfiber ã¢ããã¿ãŒã®äŸã«ã€ããŠã¯ãHTTP ãã©ã³ã¹ããŒãã®ããã¥ã¡ã³ããã芧ãã ãããServeHTTP ã«å€æŽã¯ãªããåŸæ¥ã©ãã net/http ã®ãšã³ããªãŒãã€ã³ããšããŠå©çšã§ããŸãã
OAuth ä¿è·ãªãœãŒã¹ã¡ã¿ããŒã¿
OAuth ãå¿
èŠãšãããµãŒããŒã¯ãMCP èªå¯ä»æ§ã§åç
§ããã RFC 9728 ã® /.well-known/oauth-protected-resource ãšã³ããã€ã³ããéããŠãèªå¯èŠä»¶ãå
¬éã§ããŸããserver.WithProtectedResourceMetadataïŒãŸã㯠server.WithSSEProtectedResourceMetadataïŒã䜿çšãããšãšã³ããã€ã³ããèªåçã«ããŠã³ãã§ããŸãããŸãã¯ãserver.NewProtectedResourceMetadataHandler ã䜿çšããŠã«ã¹ã¿ã ã«ãŒã¿ãŒã«æ¥ç¶ã§ããŸãã䜿çšäŸã«ã€ããŠã¯ãHTTP ãã©ã³ã¹ããŒãã®ããã¥ã¡ã³ããã芧ãã ããã
httpServer := server.NewStreamableHTTPServer(mcpServer,
server.WithProtectedResourceMetadata(server.ProtectedResourceMetadataConfig{
Resource: "https://my-mcp-server.com",
AuthorizationServers: []string{"https://auth.example.com"},
ScopesSupported: []string{"mcp:read", "mcp:write"},
}),
)
ãã©ãŠã¶ãŒããŒã¹ã®ã¯ã©ã€ã¢ã³ãåã CORS
ãã©ãŠã¶ãŒããŒã¹ã® MCP ã¯ã©ã€ã¢ã³ãã«å
¬éãããµãŒããŒã§ã¯ãããããã® HTTP ãã©ã³ã¹ããŒãã§ã¯ãã¹ãªãªãžã³ãªãœãŒã¹å
±æïŒCORSïŒã®åŠçãæå¹ã«ã§ããŸããCORS ã¯ããã©ã«ãã§ã¯ç¡å¹ã§ããserver.WithStreamableHTTPCORS ãŸã㯠server.WithSSECORS ã䜿ã£ãŠæç€ºçã«èšå®ããŠãã ããã
httpServer := server.NewStreamableHTTPServer(mcpServer,
server.WithEndpointPath("/mcp"),
server.WithStreamableHTTPCORS(
server.WithCORSAllowedOrigins("https://my-ai-app.com", "http://localhost:3000"),
server.WithCORSAllowCredentials(),
server.WithCORSMaxAge(300),
),
)
ãã©ã³ã¹ããŒãã¯ããªãã©ã€ãïŒOPTIONSïŒãªã¯ãšã¹ãã«çŽæ¥å¿çããéåžžã®ã¬ã¹ãã³ã¹ã«é©å㪠Access-Control-Allow-OriginãAccess-Control-Allow-CredentialsãAccess-Control-Expose-HeadersãVary ããããŒã远å ããŸãã該åœãããªãã·ã§ã³ãçç¥ããå Žåã¯ãé©åãªããã©ã«ãå€ã䜿çšãããŸãïŒã¡ãœãã㯠GET, POST, DELETE, OPTIONSããªã¯ãšã¹ãããããŒã¯ Content-Type, Mcp-Session-Id, Last-Event-ID, Authorizationãå
¬éããããŒã¯ Mcp-Session-IdïŒãWithCORSAllowedOrigins("*") ãš WithCORSAllowCredentials() ã䜵çšãããšã仿§ã«æºæ ããããããªã¯ãšã¹ãã® Origin ããã®ãŸãŸè¿ãããŸãã
localhost ãµãŒããŒã® DNS ãªãã€ã³ãã£ã³ã°å¯Ÿç
ã©ã¡ãã® HTTP ãã©ã³ã¹ããŒãããDNS ãªãã€ã³ãã£ã³ã°æ»æããããŒã«ã«ãµãŒããŒãèªåçã«ä¿è·ããŸããã«ãŒãããã¯æ¥ç¶ïŒ127.0.0.1ã[::1]ïŒçµç±ã§å°çãããªã¯ãšã¹ãã® Host ããããŒã localhost ã®å€ã§ãªãå Žåã403 Forbidden ã§æåŠãããŸãããã®ãã§ãã¯ã¯å®è¡æã«æ¥ç¶ã®ããŒã«ã«ã¢ãã¬ã¹ããå€å®ãããããããµãŒããŒã localhost ãš 0.0.0.0 ã®ã©ã¡ãã§ãªãã¹ã³ããŠããŠãé©çšãããã«ãŒãããã¯ä»¥å€ã®ã¢ãã¬ã¹çµç±ã§å°çãããªã¯ãšã¹ãã«ã¯åœ±é¿ããŸããã
åããã¹ãäžã®ãªããŒã¹ãããã·ããå
ã® Host ããããŒãä¿æãããŸãŸ localhost çµç±ã§ãªã¯ãšã¹ãã転éããå Žåã¯ããããã·ã§ Host ããããŒã localhost ã«æžãæããããæç€ºçã«ç¡å¹ã«ããŠãã ããã
httpServer := server.NewStreamableHTTPServer(mcpServer,
// Or server.WithSSEDisableLocalhostProtection(true) on NewSSEServer.
server.WithDisableLocalhostProtection(true),
)
ãã¬ãŒã ã¯ãŒã¯ã«äŸåããªã Handle ãšã³ããªãŒãã€ã³ãã«é¢ããæ³šæç¹ãªã©ã詳现ã«ã€ããŠã¯HTTP ãã©ã³ã¹ããŒãã®ããã¥ã¡ã³ããã芧ãã ããã
ã»ãã·ã§ã³ç®¡ç
MCP-Go ã¯ã次ã®ããšãå¯èœã«ããå ç¢ãªã»ãã·ã§ã³ç®¡çã·ã¹ãã ãæäŸããŸãã
- æ¥ç¶ãããåã¯ã©ã€ã¢ã³ãã®ç¶æ ãåå¥ã«ç¶æãã
- ã¯ã©ã€ã¢ã³ãã»ãã·ã§ã³ãç»é²ããŠè¿œè·¡ãã
- ç¹å®ã®ã¯ã©ã€ã¢ã³ãã«éç¥ãéä¿¡ãã
- ã»ãã·ã§ã³ããšã«ããŒã«ãã«ã¹ã¿ãã€ãºãã
ã»ãã·ã§ã³ç®¡çã®äŸã衚瀺
#### åºæ¬çãªã»ãã·ã§ã³åŠç// Create a server with session capabilities
s := server.NewMCPServer(
"Session Demo",
"1.0.0",
server.WithToolCapabilities(true),
)
// Implement your own ClientSession
type MySession struct {
id string
notifChannel chan mcp.JSONRPCNotification
isInitialized bool
// Add custom fields for your application
}
// Implement the ClientSession interface
func (s *MySession) SessionID() string {
return s.id
}
func (s *MySession) NotificationChannel() chan<- mcp.JSONRPCNotification {
return s.notifChannel
}
func (s *MySession) Initialize() {
s.isInitialized = true
}
func (s *MySession) Initialized() bool {
return s.isInitialized
}
// Register a session
session := &MySession{
id: "user-123",
notifChannel: make(chan mcp.JSONRPCNotification, 10),
}
if err := s.RegisterSession(context.Background(), session); err != nil {
log.Printf("Failed to register session: %v", err)
}
// Send notification to a specific client
err := s.SendNotificationToSpecificClient(
session.SessionID(),
"notification/update",
map[string]any{"message": "New data available!"},
)
if err != nil {
log.Printf("Failed to send notification: %v", err)
}
// Unregister session when done
s.UnregisterSession(context.Background(), session.SessionID())
ã»ãã·ã§ã³ããšã®ããŒã«
ããé«åºŠãªãŠãŒã¹ã±ãŒã¹ã§ã¯ãSessionWithTools ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããŠãã»ãã·ã§ã³ããšã«ããŒã«ãã«ã¹ã¿ãã€ãºã§ããŸãã
// Implement SessionWithTools interface for per-session tools
type MyAdvancedSession struct {
MySession // Embed the basic session
sessionTools map[string]server.ServerTool
}
// Implement additional methods for SessionWithTools
func (s *MyAdvancedSession) GetSessionTools() map[string]server.ServerTool {
return s.sessionTools
}
func (s *MyAdvancedSession) SetSessionTools(tools map[string]server.ServerTool) {
s.sessionTools = tools
}
// Create and register a session with tools support
advSession := &MyAdvancedSession{
MySession: MySession{
id: "user-456",
notifChannel: make(chan mcp.JSONRPCNotification, 10),
},
sessionTools: make(map[string]server.ServerTool),
}
if err := s.RegisterSession(context.Background(), advSession); err != nil {
log.Printf("Failed to register session: %v", err)
}
// Add session-specific tools
userSpecificTool := mcp.NewTool(
"user_data",
mcp.WithDescription("Access user-specific data"),
)
// You can use AddSessionTool (similar to AddTool)
err := s.AddSessionTool(
advSession.SessionID(),
userSpecificTool,
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// This handler is only available to this specific session
return mcp.NewToolResultText("User-specific data for " + advSession.SessionID()), nil
},
)
if err != nil {
log.Printf("Failed to add session tool: %v", err)
}
// Or use AddSessionTools directly with ServerTool
/*
err := s.AddSessionTools(
advSession.SessionID(),
server.ServerTool{
Tool: userSpecificTool,
Handler: func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// This handler is only available to this specific session
return mcp.NewToolResultText("User-specific data for " + advSession.SessionID()), nil
},
},
)
if err != nil {
log.Printf("Failed to add session tool: %v", err)
}
*/
// Delete session-specific tools when no longer needed
err = s.DeleteSessionTools(advSession.SessionID(), "user_data")
if err != nil {
log.Printf("Failed to delete session tool: %v", err)
}
ããŒã«ã®ãã£ã«ã¿ãªã³ã°
ãã£ã«ã¿ãŒãé©çšããŠãç¹å®ã®ã»ãã·ã§ã³ã§å©çšã§ããããŒã«ãå¶åŸ¡ããããšãã§ããŸãã
// Add a tool filter that only shows tools with certain prefixes
s := server.NewMCPServer(
"Tool Filtering Demo",
"1.0.0",
server.WithToolCapabilities(true),
server.WithToolFilter(func(ctx context.Context, tools []mcp.Tool) []mcp.Tool {
// Get session from context
session := server.ClientSessionFromContext(ctx)
if session == nil {
return tools // Return all tools if no session
}
// Example: filter tools based on session ID prefix
if strings.HasPrefix(session.SessionID(), "admin-") {
// Admin users get all tools
return tools
} else {
// Regular users only get tools with "public-" prefix
var filteredTools []mcp.Tool
for _, tool := range tools {
if strings.HasPrefix(tool.Name, "public-") {
filteredTools = append(filteredTools, tool)
}
}
return filteredTools
}
}),
)
ã³ã³ããã¹ãã®æäœ
ã»ãã·ã§ã³ã®ã³ã³ããã¹ãã¯ãããŒã«ããã³ãªãœãŒã¹ã®ãã³ãã©ãŒã«èªåçã«æž¡ãããŸãã
s.AddTool(mcp.NewTool("session_aware"), func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// Get the current session from context
session := server.ClientSessionFromContext(ctx)
if session == nil {
return mcp.NewToolResultError("No active session"), nil
}
return mcp.NewToolResultText("Hello, session " + session.SessionID()), nil
})
// When using handlers in HTTP/SSE servers, you need to pass the context with the session
httpHandler := func(w http.ResponseWriter, r *http.Request) {
// Get session from somewhere (like a cookie or header)
session := getSessionFromRequest(r)
// Add session to context
ctx := s.WithContext(r.Context(), session)
// Use this context when handling requests
// ...
}
ãªã¯ãšã¹ãããã¯
å©çšå¯èœãªã³ãŒã«ããã¯ããéžæã㊠Hooks ãªããžã§ã¯ããäœæãããªã¯ãšã¹ãã®ã©ã€ããµã€ã¯ã«ã«ããã¯ããŸããããã«ããããã¹ãŠã®æ©èœã«ããããã¬ã¡ããªãŒãšãããŸããŸãªæ
å ±ã®å¯èŠ³æž¬æ§ãå®çŸã§ããŸããããšãã°ãäžæ£ãªåœ¢åŒã®ãªã¯ãšã¹ãæ°ãæ°ããããåæåäžã«ãšãŒãžã§ã³ãã®è奿
å ±ããã°ã«èšé²ãããã§ããŸãã
server.WithHooks ãªãã·ã§ã³ã䜿ã£ãŠããµãŒããŒã®äœææã« Hooks ã远å ããŸãã
ããŒã«ãã³ãã©ãŒããã«ãŠã§ã¢
server.WithToolHandlerMiddleware ãªãã·ã§ã³ã䜿ã£ãŠãããŒã«åŒã³åºããã³ãã©ãŒã«ããã«ãŠã§ã¢ã远å ããŸããããã«ãŠã§ã¢ã¯ãµãŒããŒã®äœææã«ç»é²ã§ãããã¹ãŠã®ããŒã«åŒã³åºãã«é©çšãããŸãã
ããŒã«åŒã³åºãäžã®ãããã¯ãã埩æ§ããããã®ãªã«ããªãŒããã«ãŠã§ã¢ãªãã·ã§ã³ãå©çšã§ããŸããserver.WithRecovery ãªãã·ã§ã³ã䜿ã£ãŠãµãŒããŒã«è¿œå ã§ããŸãã
ããã³ãããã³ãã©ãŒããã«ãŠã§ã¢
server.WithPromptHandlerMiddleware ãªãã·ã§ã³ã䜿ã£ãŠãããã³ãããã³ãã©ãŒã«ããã«ãŠã§ã¢ã远å ããŸããããã«ãŠã§ã¢ã¯ãµãŒããŒã®äœææã«ç»é²ã§ãããã¹ãŠã® prompts/get åŒã³åºãã«é©çšãããŸãã
ããã³ããã®ãã£ã«ã¿ãªã³ã°
server.WithPromptFilter ãªãã·ã§ã³ã䜿ã£ãŠãã³ã³ããã¹ãã«åºã¥ããŠããã³ããããã£ã«ã¿ãªã³ã°ããŸããããã¯ããŒã«ã®ãã£ã«ã¿ãªã³ã°ãšåãããã«æ©èœããŸãããprompts/list ã®çµæã«é©çšãããŸãã
ãµãŒããŒã³ãŒãã®åçæ
ãµãŒããŒããã¯ãšãªã¯ãšã¹ããã³ãã©ãŒã¯çæãããŸããæ¬¡ã®ã³ãã³ããå®è¡ããŠåçæããŸãã
go generate ./...
go ãã€ã³ã¹ããŒã«ããgoimports ããŒã«ãå©çšã§ããããã«ããå¿
èŠããããŸãããžã§ãã¬ãŒã¿ãŒã¯ãã€ã³ããŒãã®æŽåœ¢ãšä¿®æ£ã®ããã« goimports ãèªåçã«å®è¡ããŸãã
èªåè£å®
ãŠãŒã¶ãŒãç¹å®ã®ããã³ããïŒååã§èå¥ïŒãŸãã¯ãªãœãŒã¹ãã³ãã¬ãŒãïŒURI ã§èå¥ïŒã®åŒæ°å€ãå
¥åãããšãããµãŒããŒã¯ã³ã³ããã¹ãã«å¿ããåè£ãæç€ºã§ããŸãã
è£å®ãæå¹ã«ããã«ã¯ããµãŒããŒã®äœææã« server.WithCompletions() ãªãã·ã§ã³ã䜿çšããŸãã
è£å®ãããã€ããŒ
察å¿ããã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ãããªãã·ã§ã³ãšããŠãµãŒããŒã«æž¡ãããšã§ãããã³ããåŒæ°ãšãªãœãŒã¹ãã³ãã¬ãŒãåŒæ°ã®äž¡æ¹ã«è£å®ããžãã¯ãèšå®ã§ããŸãã
è£å®ãããã€ããŒã®äŸã衚瀺
type MyPromptCompletionProvider struct{}
func (p *MyPromptCompletionProvider) CompletePromptArgument(
ctx context.Context,
promptName string,
argument mcp.CompleteArgument,
context mcp.CompleteContext,
) (*mcp.Completion, error) {
// Example: provide style suggestions for a "code_review" prompt
if promptName == "code_review" && argument.Name == "style" {
styles := []string{"formal", "casual", "technical", "creative"}
var suggestions []string
// Filter based on current input
for _, style := range styles {
if strings.HasPrefix(style, argument.Value) {
suggestions = append(suggestions, style)
}
}
return &mcp.Completion{
Values: suggestions,
}, nil
}
// Return empty suggestions for unhandled cases
return &mcp.Completion{Values: []string{}}, nil
}
type MyResourceCompletionProvider struct{}
func (p *MyResourceCompletionProvider) CompleteResourceArgument(
ctx context.Context,
uri string,
argument mcp.CompleteArgument,
context mcp.CompleteContext,
) (*mcp.Completion, error) {
// Example: provide file path completions
if uri == "file:///{path}" && argument.Name == "path" {
// You can access previously completed arguments from context.Arguments
// context.Arguments is a map[string]string of already-resolved arguments
paths := getMatchingPaths(argument.Value) // Your custom logic
return &mcp.Completion{
Values: paths[:min(len(paths), 100)], // Max 100 items
Total: len(paths), // Total available matches
HasMore: len(paths) > 100, // More results available
}, nil
}
return &mcp.Completion{Values: []string{}}, nil
}
// Register the provider
mcpServer := server.NewMCPServer(
"my-server",
"1.0.0",
server.WithCompletions(),
server.WithPromptCompletionProvider(&MyPromptCompletionProvider{}),
server.WithResourceCompletionProvider(&MyResourceCompletionProvider{}),
)
è£å®ã³ã³ããã¹ã
è€æ°ã®åŒæ°ãæã€ããã³ããããªãœãŒã¹ãã³ãã¬ãŒãã§ã¯ãCompleteContext ãã©ã¡ãŒã¿ãŒã䜿ã£ãŠããã§ã«è£å®ãããåŒæ°ã«ã¢ã¯ã»ã¹ã§ããŸããããã«ããã以åã®éžæã«åºã¥ããŠã³ã³ããã¹ãã«å¿ããåè£ãæç€ºã§ããŸãã
è£å®ã³ã³ããã¹ãã®äŸã衚瀺
func (p *MyProvider) CompleteResourceArgument(
ctx context.Context,
uri string,
argument mcp.CompleteArgument,
context mcp.CompleteContext,
) (*mcp.Completion, error) {
// Access previously completed arguments
if previousValue, ok := context.Arguments["previous_arg"]; ok {
// Provide suggestions based on previous_arg value
return getSuggestionsFor(argument.Value, previousValue), nil
}
return &mcp.Completion{Values: []string{}}, nil
}
å¿çã®å¶çŽ
è£å®çµæãè¿ãéã¯ã次ã®ç¹ã«æ³šæããŠãã ããã
- 1 åã®å¿çã«ã€ãæå€§ 100 é ç®
- å©çšå¯èœãªäžèŽé
ç®ã®ç·æ°ã瀺ãã«ã¯
Totalã䜿çšããŸã - è¿ãããå€ä»¥å€ã«è¿œå ã®çµæãããããšã瀺ãã«ã¯
HasMoreã䜿çšããŸã
ã³ã¡ã³ã
MCP ã¯åããŠã§ããïŒ
ãããã³ã«ã®æŠèŠããæåã®ãµãŒããŒã®å°å ¥ãŸã§ãããããçåã«ãŸãšããŠçããŸãã
AI ã¢ããªã±ãŒã·ã§ã³ãå€éšã®ããŒã«ãããŒã¿ãœãŒã¹ã«çµ±äžçãªæ¹æ³ã§æ¥ç¶ããããã®ãªãŒãã³ãªãããã³ã«ã§ããã¯ã©ã€ã¢ã³ãã¯ã¢ãã«ãšã®å¯Ÿè©±ãæ ããMCP ãµãŒããŒã¯ããŒã«ã»ãªãœãŒã¹ã»ããã³ãããã³ãã¬ãŒããæäŸããŸããæšæºã¡ãã»ãŒãžã§ããåãããããã1 ã€ã®ãµãŒããŒãè€æ°ã®ã¯ã©ã€ã¢ã³ãã§åå©çšã§ããŸãã
