
随着MCP协议爆火,Dify也增加了支持mcp的插件,本篇分为两个方面来介绍Dify mcp,首先是Dify通过mcp协议调用本地实现的mcp server;然后是Dify把自己的aget 或者流水线封装起来作为mcp server给外界使用。实现这些功能,需要在dify基础上有一个适配层,这个就是Dify的mcp插件。目前比较熟知的有下面四个插件,Mcp Agent策略、Agent 策略、MCP SSE 和mcp-server,其中前三个是调用外界mcp server的,最后一个是把Dify的能力封装成mcp server给外界使用的。下面我们重点介绍下MCP SSE和mcp-server

首先我们在Dify的插件市场安装上述插件,然后开发一个mcp server
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"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.WithResourceCapabilities(true, true),
server.WithLogging(),
server.WithRecovery(),
)
// 实现tools 工具
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"),
),
)
//资源
s.AddResource(mcp.NewResource("test://static/resource",
"Static Resource",
mcp.WithMIMEType("text/plain"),
), handleReadResource)
//动态模板资源
s.AddResourceTemplate(
mcp.NewResourceTemplate(
"test://dynamic/resource/{id}",
"Dynamic Resource",
),
handleResourceTemplate,
)
// Add the calculator handler
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
op := request.Params.Arguments["operation"].(string)
x := request.Params.Arguments["x"].(float64)
y := request.Params.Arguments["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
}
fmt.Println("call mcp tool success")
return mcp.NewToolResultText(fmt.Sprintf("%.2f", result)), nil
})
sseServer := server.NewSSEServer(s,
server.WithSSEContextFunc(authFromRequest),
)
if err := sseServer.Start(":8080"); err != nil {
log.Fatalf("Server error: %v", err)
}
}
func handleResourceTemplate(
ctx context.Context,
request mcp.ReadResourceRequest,
) ([]mcp.ResourceContents, error) {
return []mcp.ResourceContents{
mcp.TextResourceContents{
URI: request.Params.URI,
MIMEType: "text/plain",
Text: fmt.Sprintf("动态模板:%+v ;", request),
},
}, nil
}
func handleReadResource(
ctx context.Context,
request mcp.ReadResourceRequest,
) ([]mcp.ResourceContents, error) {
return []mcp.ResourceContents{
mcp.TextResourceContents{
URI: "test://static/resource",
MIMEType: "text/plain",
Text: fmt.Sprintf("模板 %+v ;", request),
},
}, nil
}
// authKey is a custom context key for storing the auth token.
type authKey struct{}
// withAuthKey adds an auth key to the context.
func withAuthKey(ctx context.Context, auth string) context.Context {
return context.WithValue(ctx, authKey{}, auth)
}
// authFromRequest extracts the auth token from the request headers.
func authFromRequest(ctx context.Context, r *http.Request) context.Context {
return withAuthKey(ctx, r.Header.Get("Authorization"))
}
// authFromEnv extracts the auth token from the environment
func authFromEnv(ctx context.Context) context.Context {
return withAuthKey(ctx, os.Getenv("API_KEY"))
}
// tokenFromContext extracts the auth token from the context.
// This can be used by tools to extract the token regardless of the
// transport being used by the server.
func tokenFromContext(ctx context.Context) (string, error) {
auth, ok := ctx.Value(authKey{}).(string)
if !ok {
return "", fmt.Errorf("missing auth")
}
return auth, nil
}
type response struct {
Args map[string]interface{} `json:"args"`
Headers map[string]string `json:"headers"`
}
// makeRequest makes a request to httpbin.org including the auth token in the request
// headers and the message in the query string.
func makeRequest(ctx context.Context, message, token string) (*response, error) {
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpbin.org/anything", nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", token)
query := req.URL.Query()
query.Add("message", message)
req.URL.RawQuery = query.Encode()
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var r *response
if err := json.Unmarshal(body, &r); err != nil {
return nil, err
}
return r, nil
}
// handleMakeAuthenticatedRequestTool is a tool that makes an authenticated request
// using the token from the context.
func handleMakeAuthenticatedRequestTool(
ctx context.Context,
request mcp.CallToolRequest,
) (*mcp.CallToolResult, error) {
message, ok := request.Params.Arguments["message"].(string)
if !ok {
return nil, fmt.Errorf("missing message")
}
token, err := tokenFromContext(ctx)
if err != nil {
return nil, fmt.Errorf("missing token: %v", err)
}
// Now our tool can make a request with the token, irrespective of where it came from.
resp, err := makeRequest(ctx, message, token)
if err != nil {
return nil, err
}
return mcp.NewToolResultText(fmt.Sprintf("%+v", resp)), nil
}为了验证我们mcp server的可用性,我们使用工具来发现和使用下这个mcp sse server
npx @modelcontextprotocol/inspector
Need to install the following packages:
@modelcontextprotocol/inspector
Ok to proceed? (y) y需要注意的是这个包,需要依赖18.14以上的node
https://github.com/modelcontextprotocol/inspector
nvm use v18.14.0安装成功后如下
% npx @modelcontextprotocol/inspector
Starting MCP inspector...
⚙️ Proxy server listening on port 6277
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀
启动我们的mcp server后,工具就可以发现我们的mcp server,然后就可以使用下

安装完 mcp sse插件之后,我们点击插件,在插件上可以配置我们的mcp server的地址
https://github.com/junjiem/dify-plugin-tools-mcp_sse

注意需要配置为http://host.docker.internal:8080/sse,因为docker for mac。配置成功后的效果如下

然后在我们的聊天工具里尝试使用下mcp,需要注意的是DeepSeek1.5b不支持mcp,这里大模型选智普AI,实验结果如下

至此,Dify调用外界的mcp server 的流程介绍完毕,这也是我们多数场景需要使用的情况。如果我们在Dify中集成了特别厉害的功能,想在本地工具中使用,这个如何操作呢,可以使用mcp-server插件,将Dify的功能作为一个mcp server发布给外界使用。

配置完成后我们得到了链接,需要注意的是,这个插件有bug,这里的
http://localhost/e/fos7gt47jnofl9db}/mcp
http://localhost/e/fos7gt47jnofl9db/mcp链接多了个}导致我们调用失败。然后我们使用mcp客户端工具调用下测试。https://github.com/CherryHQ/cherry-studio V1.2.9 及以上版本以获得更稳定的 MCP 功能支持。配置界面如下,如果能保存成功,说明已经调试成功了

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!