-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🎨 Improve structure / format of the code: MCP client support
- Loading branch information
Showing
17 changed files
with
570 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# if working from a container | ||
#OLLAMA_HOST=http://host.docker.internal:11434 | ||
OLLAMA_HOST=http://localhost:11434 | ||
LLM_WITH_TOOLS_SUPPORT=qwen2.5:0.5b | ||
LLM_CHAT=qwen2.5:0.5b |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# MCP: model context protocol | ||
|
||
First, build the MCP server, see: [/mcp-server/README.md](/mcp-server/README.md), then, run: | ||
```bash | ||
go run main.go | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module 67-mcp | ||
|
||
go 1.23.1 | ||
|
||
require ( | ||
github.com/mark3labs/mcp-go v0.8.3 | ||
github.com/parakeet-nest/parakeet v0.0.0-00010101000000-000000000000 | ||
) | ||
|
||
replace github.com/parakeet-nest/parakeet => ../.. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
github.com/mark3labs/mcp-go v0.8.3 h1:IzlyN8BaP4YwUMUDqxOGJhGdZXEDQiAPX43dNPgnzrg= | ||
github.com/mark3labs/mcp-go v0.8.3/go.mod h1:cjMlBU0cv/cj9kjlgmRhoJ5JREdS7YX83xeIG9Ko/jE= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/joho/godotenv" | ||
"github.com/parakeet-nest/parakeet/completion" | ||
"github.com/parakeet-nest/parakeet/enums/option" | ||
"github.com/parakeet-nest/parakeet/llm" | ||
"github.com/parakeet-nest/parakeet/mcphelpers" | ||
) | ||
|
||
func main() { | ||
|
||
err := godotenv.Load() | ||
if err != nil { | ||
log.Fatalln("😡", err) | ||
} | ||
|
||
ollamaUrl := os.Getenv("OLLAMA_HOST") | ||
if ollamaUrl == "" { | ||
ollamaUrl = "http://localhost:11434" | ||
} | ||
|
||
modelWithToolsSupport := os.Getenv("LLM_WITH_TOOLS_SUPPORT") | ||
if modelWithToolsSupport == "" { | ||
modelWithToolsSupport = "qwen2.5:0.5b" | ||
} | ||
|
||
chatModel := os.Getenv("LLM_CHAT") | ||
if chatModel == "" { | ||
chatModel = "qwen2.5:0.5b" | ||
} | ||
|
||
// Create context with timeout | ||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | ||
defer cancel() | ||
|
||
// Create a new mcp client | ||
mcpClient, _, err := mcphelpers.GetMCPClient(ctx, "docker", | ||
[]string{}, // Empty ENV | ||
"run", | ||
"--rm", | ||
"-i", | ||
"mcp-curl", | ||
) | ||
|
||
if err != nil { | ||
log.Fatalln("😡", err) | ||
} | ||
defer mcpClient.Close() | ||
|
||
ollamaTools, err := mcphelpers.GetTools(mcpClient) | ||
|
||
if err != nil { | ||
log.Fatalln("😡", err) | ||
} | ||
|
||
// Send request to a LLM with tools suppot | ||
messages := []llm.Message{ | ||
{Role: "user", Content: "Fetch this page: https://raw.githubusercontent.com/parakeet-nest/parakeet/main/README.md"}, | ||
} | ||
|
||
options := llm.SetOptions(map[string]interface{}{ | ||
option.Temperature: 0.0, | ||
option.RepeatLastN: 2, | ||
option.RepeatPenalty: 2.0, | ||
}) | ||
|
||
toolsQuery := llm.Query{ | ||
Model: modelWithToolsSupport, | ||
Messages: messages, | ||
Tools: ollamaTools, | ||
Options: options, | ||
Format: "json", | ||
} | ||
|
||
answer, err := completion.Chat(ollamaUrl, toolsQuery) | ||
if err != nil { | ||
log.Fatalln("😡", err) | ||
} | ||
|
||
// Get the first tool call from the answer (what the LLM wants to do / understand) | ||
toolCall := answer.Message.ToolCalls[0] | ||
|
||
// 🖐️ Call the mcp server | ||
fmt.Println("🦙🛠️ 📣 calling:", toolCall.Function.Name, toolCall.Function.Arguments) | ||
|
||
mcpResult, err := mcphelpers.CallTool(ctx, mcpClient, toolCall.Function.Name, toolCall.Function.Arguments) | ||
if err != nil { | ||
log.Fatalln("😡", err) | ||
} | ||
// Get the text from the result | ||
contentOfTheWebPage, _ := mcphelpers.GetTextFromResult(mcpResult) | ||
|
||
// add this {Role: "user", Content: contentForThePrompt} to the messages | ||
messages = append(messages, | ||
llm.Message{Role: "user", Content: "Make a summary of the below page:"}, | ||
llm.Message{Role: "user", Content: contentOfTheWebPage}, | ||
) | ||
|
||
chatOptions := llm.SetOptions(map[string]interface{}{ | ||
option.Temperature: 0.5, | ||
option.RepeatLastN: 2, | ||
option.RepeatPenalty: 3.0, | ||
}) | ||
|
||
query := llm.Query{ | ||
Model: chatModel, | ||
Messages: messages, | ||
Options: chatOptions, | ||
} | ||
|
||
_, err = completion.ChatStream(ollamaUrl, query, | ||
func(answer llm.Answer) error { | ||
fmt.Print(answer.Message.Content) | ||
return nil | ||
}) | ||
|
||
if err != nil { | ||
log.Fatalln("😡", err) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
FROM golang:1.23.4-alpine AS builder | ||
WORKDIR /app | ||
COPY go.mod . | ||
COPY main.go . | ||
|
||
RUN <<EOF | ||
go mod tidy | ||
go build | ||
EOF | ||
|
||
FROM curlimages/curl:8.6.0 | ||
WORKDIR /app | ||
COPY --from=builder /app/mcp-curl . | ||
ENTRYPOINT ["./mcp-curl"] | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# MCP Curl server | ||
|
||
This is a simple server that creates a tool which can fetch web pages using the `curl` command. Let me break it down: | ||
|
||
1. The server part: | ||
- Creates an MCP server called "mcp-curl" with version "1.0.0" | ||
- MCP stands for Model Control Protocol - it's a way for AI models to interact with external tools | ||
|
||
2. The tool part: | ||
- Creates a tool called "use_curl" | ||
- The tool takes one required parameter: a URL string | ||
- When called, it will fetch the webpage at that URL | ||
|
||
3. The handler part: | ||
- The `curlHandler` function is what actually does the work | ||
- It takes the URL from the request | ||
- Uses the system's `curl` command to fetch the webpage | ||
- Returns the webpage content as text | ||
- If anything goes wrong, it returns an error message | ||
|
||
4. Server operation: | ||
- Runs over standard input/output (stdio) | ||
|
||
This server essentially acts as a bridge between an AI model and the `curl` command, allowing the AI to fetch web content when needed. | ||
|
||
|
||
## Build it | ||
|
||
```bash | ||
docker build -t mcp-curl . | ||
``` | ||
|
||
## Use it with a MCP client (like Claude.AI Desktop) | ||
|
||
```bash | ||
{ | ||
"mcpServers": { | ||
"mcp-curl-with-docker" :{ | ||
"command": "docker", | ||
"args": [ | ||
"run", | ||
"--rm", | ||
"-i", | ||
"mcp-curl" | ||
] | ||
} | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module mcp-curl | ||
|
||
go 1.23.1 | ||
|
||
require github.com/mark3labs/mcp-go v0.8.2 | ||
|
||
require github.com/google/uuid v1.6.0 // indirect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
github.com/mark3labs/mcp-go v0.8.2 h1:OtqqXlRqjXs6zuMhf1uiuQ2iqBrhMGgLpDeVDUWMKFc= | ||
github.com/mark3labs/mcp-go v0.8.2/go.mod h1:cjMlBU0cv/cj9kjlgmRhoJ5JREdS7YX83xeIG9Ko/jE= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= | ||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os/exec" | ||
|
||
"github.com/mark3labs/mcp-go/mcp" | ||
"github.com/mark3labs/mcp-go/server" | ||
) | ||
|
||
func main() { | ||
// Create MCP server | ||
s := server.NewMCPServer( | ||
"mcp-curl", | ||
"1.0.0", | ||
) | ||
|
||
// Add a tool | ||
tool := mcp.NewTool("use_curl", | ||
mcp.WithDescription("fetch this webpage"), | ||
mcp.WithString("url", | ||
mcp.Required(), | ||
mcp.Description("url of the webpage to fetch"), | ||
), | ||
) | ||
|
||
// Add a tool handler | ||
s.AddTool(tool, curlHandler) | ||
|
||
fmt.Println("🚀 Server started") | ||
// Start the stdio server | ||
if err := server.ServeStdio(s); err != nil { | ||
fmt.Printf("😡 Server error: %v\n", err) | ||
} | ||
fmt.Println("👋 Server stopped") | ||
} | ||
|
||
func curlHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||
|
||
url, ok := request.Params.Arguments["url"].(string) | ||
if !ok { | ||
return mcp.NewToolResultError("url must be a string"), nil | ||
} | ||
cmd := exec.Command("curl", "-s", url) | ||
output, err := cmd.Output() | ||
if err != nil { | ||
return mcp.NewToolResultError(err.Error()), nil | ||
} | ||
content := string(output) | ||
|
||
return mcp.NewToolResultText(content), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.