Skip to content

Commit 1c7ab6d

Browse files
committed
fix server
1 parent 95e766d commit 1c7ab6d

File tree

2 files changed

+262
-1
lines changed

2 files changed

+262
-1
lines changed

go/samples/mcp-ception/mcp_ception.go

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"log"
21+
"os"
22+
"os/signal"
23+
"syscall"
24+
25+
"github.com/firebase/genkit/go/ai"
26+
"github.com/firebase/genkit/go/core"
27+
"github.com/firebase/genkit/go/core/logger"
28+
"github.com/firebase/genkit/go/genkit"
29+
"github.com/firebase/genkit/go/plugins/googlegenai"
30+
"github.com/firebase/genkit/go/plugins/mcp"
31+
)
32+
33+
// MCP self-hosting example: Genkit serves itself through MCP
34+
// 1. Start a Go MCP server that exposes Genkit resources
35+
// 2. Connect to that server as an MCP client
36+
// 3. Use the resources from the server for AI generation
37+
38+
// Create the MCP Server (runs in background)
39+
func createMCPServer() {
40+
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
41+
defer cancel()
42+
43+
logger.FromContext(ctx).Info("Starting Genkit MCP Server")
44+
45+
// Initialize Genkit for the server
46+
g, err := genkit.Init(ctx)
47+
if err != nil {
48+
logger.FromContext(ctx).Error("Failed to initialize Genkit server", "error", err)
49+
os.Exit(1)
50+
}
51+
52+
// Define a tool that generates creative content (this will be auto-exposed via MCP)
53+
genkit.DefineTool(g, "genkit-brainstorm", "Generate creative ideas about a topic",
54+
func(ctx *ai.ToolContext, input struct {
55+
Topic string `json:"topic" description:"The topic to brainstorm about"`
56+
}) (map[string]interface{}, error) {
57+
logger.FromContext(ctx.Context).Debug("Executing genkit-brainstorm tool", "topic", input.Topic)
58+
59+
ideas := fmt.Sprintf(`Creative Ideas for "%s":
60+
61+
1. Interactive Experience: Create an immersive, hands-on workshop
62+
2. Digital Innovation: Develop a mobile app or web platform
63+
3. Community Building: Start a local meetup or online community
64+
4. Educational Content: Design a course or tutorial series
65+
5. Collaborative Project: Partner with others for cross-pollination
66+
6. Storytelling Approach: Create narratives around the topic
67+
7. Gamification: Turn learning into an engaging game
68+
8. Real-world Application: Find practical, everyday uses
69+
9. Creative Challenge: Host competitions or hackathons
70+
10. Multi-media Approach: Combine video, audio, and interactive elements
71+
72+
These ideas can be mixed, matched, and customized for "%s".`, input.Topic, input.Topic)
73+
74+
return map[string]interface{}{
75+
"topic": input.Topic,
76+
"ideas": ideas,
77+
}, nil
78+
})
79+
80+
// Define a resource that contains Genkit knowledge (this will be auto-exposed via MCP)
81+
err = genkit.DefineResource(g, genkit.ResourceOptions{
82+
Name: "genkit-knowledge",
83+
URI: "knowledge://genkit-docs",
84+
}, func(ctx context.Context, input core.ResourceInput) (genkit.ResourceOutput, error) {
85+
knowledge := `# Genkit Knowledge Base
86+
87+
## What is Genkit?
88+
Genkit is Firebase's open-source framework for building AI-powered applications.
89+
90+
## Key Features:
91+
- Multi-modal AI generation (text, images, audio)
92+
- Tool calling and function execution
93+
- RAG (Retrieval Augmented Generation) support
94+
- Evaluation and testing frameworks
95+
- Multi-language support (TypeScript, Go, Python)
96+
97+
## Popular Models:
98+
- Google AI: Gemini 1.5 Flash, Gemini 2.0 Flash
99+
- Vertex AI: All Gemini models
100+
- OpenAI Compatible models via plugins
101+
102+
## Use Cases:
103+
- Chatbots and conversational AI
104+
- Content generation and editing
105+
- Code analysis and generation
106+
- Document processing and summarization
107+
- Creative applications (story writing, brainstorming)
108+
109+
## Architecture:
110+
Genkit follows a plugin-based architecture where models, retrievers, evaluators, and other components are provided by plugins.`
111+
112+
return genkit.ResourceOutput{
113+
Content: []*ai.Part{ai.NewTextPart(knowledge)},
114+
}, nil
115+
})
116+
if err != nil {
117+
logger.FromContext(ctx).Error("Failed to create resource", "error", err)
118+
os.Exit(1)
119+
}
120+
121+
// Create MCP server (automatically exposes all defined tools and resources)
122+
server := mcp.NewMCPServer(g, mcp.MCPServerOptions{
123+
Name: "genkit-mcp-server",
124+
Version: "1.0.0",
125+
})
126+
127+
logger.FromContext(ctx).Info("Genkit MCP Server configured successfully")
128+
logger.FromContext(ctx).Info("Starting MCP server on stdio")
129+
logger.FromContext(ctx).Info("Registered tools", "count", len(server.ListRegisteredTools()))
130+
logger.FromContext(ctx).Info("Registered resources", "count", len(server.ListRegisteredResources()))
131+
132+
// Start the server
133+
if err := server.ServeStdio(); err != nil && err != context.Canceled {
134+
logger.FromContext(ctx).Error("MCP server failed", "error", err)
135+
os.Exit(1)
136+
}
137+
}
138+
139+
// Create the MCP Client that connects to our server
140+
func mcpSelfConnection() {
141+
ctx := context.Background()
142+
143+
logger.FromContext(ctx).Info("MCP self-connection demo")
144+
logger.FromContext(ctx).Info("Genkit will connect to itself via MCP")
145+
146+
// Initialize Genkit with Google AI for the client
147+
g, err := genkit.Init(ctx,
148+
genkit.WithPlugins(&googlegenai.GoogleAI{}),
149+
genkit.WithDefaultModel("googleai/gemini-2.0-flash"),
150+
)
151+
if err != nil {
152+
log.Fatalf("Failed to initialize Genkit client: %v", err)
153+
}
154+
155+
logger.FromContext(ctx).Info("Connecting to our own MCP server")
156+
logger.FromContext(ctx).Info("Note: Server process will be spawned automatically")
157+
158+
// Create MCP Host that connects to our Genkit server
159+
host, err := mcp.NewMCPHost(g, mcp.MCPHostOptions{
160+
Name: "mcp-ception-host",
161+
MCPServers: []mcp.MCPServerConfig{
162+
{
163+
Name: "genkit-server",
164+
Config: mcp.MCPClientOptions{
165+
Name: "genkit-mcp-server",
166+
Version: "1.0.0",
167+
Stdio: &mcp.StdioConfig{
168+
Command: "go",
169+
Args: []string{"run", "mcp_ception.go", "server"},
170+
},
171+
},
172+
},
173+
},
174+
})
175+
if err != nil {
176+
logger.FromContext(ctx).Error("Failed to create MCP host", "error", err)
177+
return
178+
}
179+
180+
// Get resources from our Genkit server
181+
logger.FromContext(ctx).Info("Getting resources from Genkit MCP server")
182+
resources, err := host.GetActiveResources(ctx)
183+
if err != nil {
184+
logger.FromContext(ctx).Error("Failed to get resources", "error", err)
185+
return
186+
}
187+
188+
logger.FromContext(ctx).Info("Retrieved resources from server", "count", len(resources))
189+
190+
// Debug: examine retrieved resources
191+
for i, resource := range resources {
192+
logger.FromContext(ctx).Info("Resource details", "index", i, "name", resource.Name())
193+
// Test if the resource matches our target URI
194+
matches := resource.Matches("knowledge://genkit-docs")
195+
logger.FromContext(ctx).Info("Resource URI matching", "matches_target_uri", matches)
196+
}
197+
198+
// Get tools from our Genkit server
199+
logger.FromContext(ctx).Info("Getting tools from Genkit MCP server")
200+
tools, err := host.GetActiveTools(ctx, g)
201+
if err != nil {
202+
logger.FromContext(ctx).Error("Failed to get tools", "error", err)
203+
return
204+
}
205+
206+
logger.FromContext(ctx).Info("Retrieved tools from server", "count", len(tools))
207+
208+
// Convert tools to refs
209+
var toolRefs []ai.ToolRef
210+
for _, tool := range tools {
211+
toolRefs = append(toolRefs, tool)
212+
}
213+
214+
// Use resources and tools from our own server for AI generation
215+
logger.FromContext(ctx).Info("Asking AI about Genkit using our own MCP resources")
216+
217+
// Use ai.NewResourcePart to explicitly reference the resource
218+
logger.FromContext(ctx).Info("Starting generation call", "resource_count", len(resources), "tool_count", len(toolRefs))
219+
220+
response, err := genkit.Generate(ctx, g,
221+
ai.WithMessages(ai.NewUserMessage(
222+
ai.NewTextPart("Based on this Genkit knowledge:"),
223+
ai.NewResourcePart("knowledge://genkit-docs"), // Explicit resource reference
224+
ai.NewTextPart("What are the key features of Genkit and what models does it support?\n\nAlso, use the brainstorm tool to generate ideas for \"AI-powered cooking assistant\""),
225+
)),
226+
ai.WithResources(resources), // Makes resources available for lookup
227+
ai.WithTools(toolRefs...), // Using tools from our own server!
228+
ai.WithToolChoice(ai.ToolChoiceAuto),
229+
)
230+
if err != nil {
231+
logger.FromContext(ctx).Error("AI generation failed", "error", err)
232+
return
233+
}
234+
235+
logger.FromContext(ctx).Info("MCP self-connection completed successfully")
236+
logger.FromContext(ctx).Info("Genkit used itself via MCP to answer questions")
237+
fmt.Printf("\nAI Response using our own MCP resources:\n%s\n\n", response.Text())
238+
239+
// Clean disconnect (skip for now to avoid hanging)
240+
logger.FromContext(ctx).Info("MCP self-connection complete")
241+
}
242+
243+
func main() {
244+
if len(os.Args) < 2 {
245+
fmt.Println("Usage: go run mcp_ception.go [server|demo]")
246+
fmt.Println(" server - Run as MCP server (exposes Genkit resources)")
247+
fmt.Println(" demo - Run MCP self-connection demo (connects to server)")
248+
os.Exit(1)
249+
}
250+
251+
switch os.Args[1] {
252+
case "server":
253+
createMCPServer()
254+
case "demo":
255+
mcpSelfConnection()
256+
default:
257+
fmt.Printf("Unknown command: %s\n", os.Args[1])
258+
fmt.Println("Use 'server' or 'demo'")
259+
os.Exit(1)
260+
}
261+
}

go/samples/mcp-server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func main() {
152152
logger.FromContext(ctx).Info("Starting MCP server", "name", "text-utilities", "tools", server.ListRegisteredTools())
153153
logger.FromContext(ctx).Info("Ready! Run: go run client.go")
154154

155-
if err := server.ServeStdio(ctx); err != nil && err != context.Canceled {
155+
if err := server.ServeStdio(); err != nil && err != context.Canceled {
156156
logger.FromContext(ctx).Error("MCP server error", "error", err)
157157
os.Exit(1)
158158
}

0 commit comments

Comments
 (0)